var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf(" chrome/") >= 0 || ua.indexOf(" firefox/") >= 0 || ua.indexOf(' gecko/') >= 0) {
    var StringMaker = function () {
        this.str = "";
        this.length = 0;
        this.append = function (s) {
            this.str += s;
            this.length += s.length;
        }
        this.prepend = function (s) {
            this.str = s + this.str;
            this.length += s.length;
        }
        this.toString = function () {
            return this.str;
        }
    }
} else {
    var StringMaker = function () {
        this.parts = [];
        this.length = 0;
        this.append = function (s) {
            this.parts.push(s);
            this.length += s.length;
        }
        this.prepend = function (s) {
            this.parts.unshift(s);
            this.length += s.length;
        }
        this.toString = function () {
            return this.parts.join('');
        }
    }
}

(function($){

    var elm
    var data
    var player
    var playing
    var playerelm
    var controls
    var sound
    var directory
    var directoryelm
    var played_sound_ids = {}
    var reverse_data = {}

    var methods = {

        init : function(data_object){

            elm = this[0]
            data = data_object

            playerelm = $('<div class="phlayer-player"></div>')
            $(elm).append(playerelm)
            player = new Player()

            directory = new Directory()
            directory.draw()

            player.play()

	    // loop to generate reverse data to lookup directory location by url
	    for (var i in data) { 
	        for (var ii in data[i]['items']){
		    var l = data[i]['items'][ii]['sounds'].length
		    for (var iii=0;iii<l;iii++){
			reverse_data[data[i]['items'][ii]['sounds'][iii]['url']] = i+','+ii+','+iii
		    }
		}
	    }

            return this
        },

	play_next : function(path){
            var p = path.split(',')	    
            var s1 = data[p[0]]
            selected = s1['items'][p[1]]
	    var l = selected['sounds'].length
	    var n = parseInt(p[2]) + 1
	    if(n == l) {
		methods['play_random']()
	    } else {
		methods['load'](p[0]+','+p[1]+','+n)
	    }
	},

        activate_eplay : function(){
            $('.phlayer-eplay').click(function(){
	        methods['eplay']($(this).attr('data'), true)
            })
        },

	eplay : function(data, autoplay){

            // This code was written by Tyler Akins and has been placed in the
            // public domain.  It would be nice if you left this header intact.
            // Base64 code from Tyler Akins -- http://rumkin.com

            var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

            function base64_decode(input) {
                var output = new StringMaker();
                var chr1, chr2, chr3;
                var enc1, enc2, enc3, enc4;
                var i = 0;

                // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
                input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

                while (i < input.length) {
                    enc1 = keyStr.indexOf(input.charAt(i++));
                    enc2 = keyStr.indexOf(input.charAt(i++));
                    enc3 = keyStr.indexOf(input.charAt(i++));
                    enc4 = keyStr.indexOf(input.charAt(i++));

                    chr1 = (enc1 << 2) | (enc2 >> 4);
                    chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                    chr3 = ((enc3 & 3) << 6) | enc4;

                    output.append(String.fromCharCode(chr1));

                    if (enc3 != 64) {
                        output.append(String.fromCharCode(chr2));
                    }
                    if (enc4 != 64) {
                        output.append(String.fromCharCode(chr3));
                    }
                }

                return output.toString();
            }
	    
	    player.play($.parseJSON(base64_decode(data)), autoplay)
	},

        resize : function(){
            var window_height = $(window).height()
            var offset = directoryelm.offset()
            var scrolltop = $(window).scrollTop()
            var directory_height = window_height - offset.top + scrolltop
            directoryelm.css('overflow-y', 'scroll').css('height', directory_height)
        },

	play_random : function(){
	    
	    // random channel
	    var len = 0, keys = []
	    for (var k in data) { keys.push(k); len++ }
	    var r1 = keys[Math.floor(Math.random()*len)]
	    var s1 = data[r1]

	    // random item
	    len = 0, keys = []
	    for (var k in s1['items']) { keys.push(k); len++ }
	    var r2 = keys[Math.floor(Math.random()*len)]
            selected = s1['items'][r2]

	    // random track
	    if(selected['sounds'].length > 1){
		var r3 = Math.floor(Math.random()*selected['sounds'].length)
	    } else {
		var r3 = 0
	    }
	    
	    // unique identifier for the sound
	    sound_id = 'sound-'+r1+','+r2+','+r3

	    // play the sound if not played before
	    if (sound_id in played_sound_ids){
		methods['play_random']()
	    } else {
		// add to played list
		played_sound_ids[sound_id] = 1

		// the link to the mp3
		stream_url = selected['sounds'][r3]['url']
		
		// title of the sound
		if ( selected['sounds'][r3]['title'] ) {
		    stream_title = selected['title'] + ' - ' + selected['sounds'][r3]['title']
		} else {
		    stream_title = selected['title']
		}

		// play using our player object
		player.play({ 
		    id : sound_id,
		    pid : selected['id'],
		    url : stream_url,
		    image : selected['images']['album'],
		    title : stream_title,
		    artist : selected['artist'],
		    artist_url : selected['artist_url'],
		    permalink : selected['url'],
		    purchase_urls : selected['purchase_urls'],
		    trackcount : selected['trackcount']
		}, true)
	    }

	},

	navigate : function(path){
            directory.navigate(path)
	},

        load : function(path){

            var p = path.split(',')
            var p1 = p[0]
            var p2 = p[1]

	    if (p.length == 3){
		var p3 = p[2]
	    } else {
		var p3 = 0
	    }
            
            var s1 = data[p1]
            selected = s1['items'][p2]

            //todo: also be able to put the track number in the path 

            stream_url = selected['sounds'][p3]['url']

	    if ( selected['sounds'][p3]['title'] ) {
		stream_title = selected['title'] + ' - ' + selected['sounds'][p3]['title']
	    } else {
		stream_title = selected['title']
	    }

            player.play({ 
                id : 'sound'+ (Math.random() * 100),
		pid : selected['id'],
                url : stream_url,
                image : selected['images']['album'],
                title : stream_title,
                artist : selected['artist'],
                artist_url : selected['artist_url'],
                permalink : selected['url'],
                purchase_urls : selected['purchase_urls'],
                trackcount : selected['trackcount']
	    }, true)

        }

    }

    var Directory = function(){

        this.draw = function(){
            var d = $('<ul id="phlayer-directory" class="phlayer-directory"></ul>')
            directoryelm = d
            for(var i in data){
                var title = data[i]['title'] == '' ? 'Untitled' : data[i]['title']
                var soundtitle = $('<li id="phlayer-channel-'+i+'" class="phlayer-channel-title">' + title + '</li>')
                var soundul = $('<ul class="phlayer-channel-items"></ul>')
                soundul.hide()
                soundtitle.click(function(){
                    if($(this).hasClass('open')){
                        var t = $(this)
                        t.next().slideUp(1000)
                        t.removeClass('open')
                    } else {
                        $('.phlayer-channel-items').hide()
                        $('.phlayer-channel-title').removeClass('open')
                        var t = $(this)
                        t.next().slideDown(1000)
                        t.addClass('open')
                    }
                })

                var cycle_class = ' odd'

                for(var ii in data[i]['items']){

                    cycle_class = cycle_class == ' odd' ? ' even' : ' odd';

                    var item = data[i]['items'][ii]

                    var s = $('<li id="phlayer-channel-item-'+i+'-'+ii+'" class="phlayer-channel-item'+cycle_class+'"></li>')

                    if(item['release_id'] == '' ||
                       item['release_id'] == null || 
                       !item.hasOwnProperty('release_id')){
                        var release_id = '&nbsp;';
                    } else {
                        var release_id = item['release_id']
                    }

                    s.append($('<div class="phlayer-channel-item-releaseid">' + release_id + '</div>'))
                    s.append($('<div class="phlayer-channel-item-author"><a href="'+item['artist_url']+'">' + item['artist'] + '</a></div>'))
                    s.append($('<div class="phlayer-channel-item-title"><a href="'+item['url']+'">' + item['title'] + '</a></div>'))

                    if (item.hasOwnProperty('trackcount')){
                        s.append($('<div class="phlayer-channel-item-trackcount">' + item['trackcount'] + ' Tracks </div>'))
                    }

                    var play = $('<span class="phlayer-channel-item-play">Play</span>')
                    play.attr('path', i.toString() + ',' +  ii.toString())
                    play.click(function(ev){
                        methods['load']($(this).attr('path'))
                    })

                    var build = $('<div class="phlayer-channel-item-buttons"></div>').append(play)

                    var buy_html = ''
                    if(item['purchase_urls']){
                        for(var key in item['purchase_urls']){
                            var url = item['purchase_urls'][key]['url']
                            if (key == 'default'){
                                url = url.replace('http://', 'itms://')
                            }
                            buy_html += '<span class="phlayer-channel-item-buy"><a href="'+url+'">Buy '+item['purchase_urls'][key]['title']+'</a></span>'
                        }
                        build.append($(buy_html))
                    }

                    s.append(build)

                    soundul.append(s)
                }
                d.append(soundtitle)
                d.append(soundul)
            }
            
            $(elm).append(d)

            // change the size when the size of the screen changes
            $(window).resize(methods['resize'])

            // give it enough time to enter the dom to get the dimensions
            var resize_delay=setTimeout(methods['resize'], 400);

        }

        this.navigate = function(path){
	    if (path){
		var p = path.split(',',2)
		var c = $('#phlayer-channel-'+p[0])
		$('.phlayer-channel-title').removeClass('open')
		c.addClass('open')
		$('.phlayer-channel-items').hide()
		c.next().show()
		$('#phlayer-directory').scrollTo($('#phlayer-channel-item-'+p[0]+'-'+p[1]), 800, {})
	    } else {
		$('.phlayer-channel-title').removeClass('open')
		$('.phlayer-channel-items').hide()
	    }
        }

    }

    var Player = function(){

        this.play = function(args, autoplay){

            var playrandom = $('<div class="phlayer-controls-playrandom">♫ Play Random</div>')

            playrandom.click(function(){

		// play random track
		methods['play_random']()

		// hide large play button
		$('.phlayer-controls-largeplay').addClass('off')

            })

	    var largeplay  = $('<div class="phlayer-controls-largeplay"></div>')
	    largeplay.css('cursor', 'pointer')

            largeplay.click(function(){
                $(this).addClass('off')
		controls['pause'].removeClass('off')

		if(!playing) {
		    sound.play()
		    //this.play()
		    playing = true
		} else {
		    player.resume()
		}
            })

            if(args == null){
                var cover = $('<div class="phlayer-cover"></div>')
                c = $('<div class="phlayer-controls"></div>')
                playerelm.append(cover).append(c).append(playrandom)
            } else {

                var cover = $('<div class="phlayer-cover"><img src="'+args['image'][0]+'"/></div>')
                var info = $('<div class="phlayer-info"><div class="phlayer-info-nowplaying"><span>Now Playing</span></div><div class="phlayer-info-title"><span><a href="'+args['permalink']+'">'+args['title']+'</a></span></div><div class="phlayer-info-artist"><span><a href="'+args['artist_url']+'">'+args['artist']+'</a></span></div></div>')

                var buy_html = ''
                if(args['purchase_urls']){
                    for(var key in args['purchase_urls']){
                        var url = args['purchase_urls'][key]['url']
                        if (key == 'default'){
                            url = url.replace('http://', 'itms://')
                        }
                        buy_html += '<div class="phlayer-info-buy"><span class="phlayer-channel-item-buy"><a href="'+url+'">Buy '+args['purchase_urls'][key]['title']+'</a></span></div>'
                    }
                    info.append($(buy_html))
                }

                if(args.hasOwnProperty('trackcount') && args['trackcount'] > 1){
                    info.append($('<div class="phlayer-info-view"><span><a href="'+args['permalink']+'">View '+args['trackcount']+' Tracks</a></span></div>'))
                }

		var share_basic_html = '<p>Listen to "<a href="'+args['permalink']+'">'+args['title']+'</a>" by <a href="'+args['artist_url']+'">'+args['artist'] + '</a> at <a href="http://halocyan.com">Halocyan.com</a></p><a href="'+args['permalink']+'"><img src="'+args['image'][0]+'" width="'+args['image'][1]+'" height="'+args['image'][2]+'"/></a>'

		var short_text_1 = 'Listen to "'
		var short_text_3 = '" by ' + args['artist'] +' at ' + window.location.protocol + '//' + window.location.hostname + '/?p=' + args['pid']

		var chars_left = 140 - short_text_1.length - short_text_3.length

		if (args['title'].length > chars_left) {
		    var short_text_2 = args['title'].substring(0, chars_left-3)+'...'
		} else {
		    var short_text_2 = args['title']
		}

		var short_text = short_text_1 + short_text_2 + short_text_3

		var share_close = $('<div class="phlayer-info-share-close">[x] Close</div>')

		var share_box = $('<div class="phlayer-info-sharebox"><div class="phlayer-info-sharebox-url"><h4>URL</h4> <div><input value="'+args['permalink']+'"></div></div><div class="phlayer-info-sharebox-short"><h4>'+short_text.length+' Characters</h4><textarea rows="4">'+short_text+'</textarea></div><div class="phlayer-info-sharebox-basic"><h4>Basic HTML</h4><div><textarea rows="4">'+share_basic_html+'</textarea></div></div></div>')

		share_close.click(function(){
		    share_box.hide()
		})

		share_box.append(share_close)

		$("input, textarea", share_box).focus(
		    function(){
		        // only select if the text has not changed
			if(this.value == this.defaultValue){
			    this.select();
			}
		    }
		)

		share_box.hide()

		info.append(share_box)

		var share_button = $('<div class="phlayer-info-share"><span>Share</span></div>')
		share_button.css('cursor', 'pointer')
		$('span', share_button).hover(function(){
		    share_box.css('top', share_button.position().top + 24)
		    share_box.show()
		},function(){
		    //share_box.hide()
                })

		info.append(share_button)

                controls = { 
                    play : $('<div class="phlayer-controls-play"></div>'),
                    pause : $('<div class="phlayer-controls-pause"></div>'),
                    duration : $('<div class="phlayer-controls-duration"></div>'),
                    loaded : $('<div class="phlayer-controls-loaded"></div>'),
                    position : $('<div class="phlayer-controls-position"></div>'),
                    time : $('<div class="phlayer-controls-time"></div>')
                }

                controls['play'].css('cursor', 'pointer')
                controls['pause'].css('cursor', 'pointer')

		controls['loaded'].click(function(e){
		    var self = $(this)
		    sound.setPosition(Math.floor((e.pageX - self.offset().left) / controls['duration'].outerWidth() * sound.duration))
		})

		controls['position'].click(function(e){
		    var self = $(this)
		    sound.setPosition(Math.floor((e.pageX - self.offset().left) / controls['duration'].outerWidth() * sound.duration))
		})

                controls['play'].click(function(){
                    $(this).addClass('off')
                    $('.phlayer-controls-largeplay').addClass('off')
                    controls['pause'].removeClass('off')

		    if(!playing) {
			sound.play()
			//this.play()
			playing = true
		    } else {
			player.resume()
		    }


                })

                controls['pause'].click(function(){
                    $(this).addClass('off')
                    $('.phlayer-controls-largeplay').removeClass('off')
                    controls['play'].removeClass('off')
                    player.pause()
                })

                controls['play'].hover(function(){
                    var t = $(this)
                    if(t.hasClass('hover')){
                        t.removeClass('hover')
                    } else {
                        t.addClass('hover')
                    }
                })

                controls['pause'].hover(function(){
                    var t = $(this)
                    if(t.hasClass('hover')){
                        t.removeClass('hover')
                    } else {
                        t.addClass('hover')
                    }
                })

                c = $('<div class="phlayer-controls"></div>')
                for(var k in controls){ c.append(controls[k]) }

                if(playerelm.children().size() > 0) { 
                    playerelm.empty()
                } 
                playerelm.append(cover).append(info).append(c).append(playrandom.addClass('minimized')).append(largeplay)

		soundManager.stopAll()

		playing = false
		if(sound != undefined){
		    sound.stop()
		    sound.destruct()
		}

                sound = soundManager.createSound({
                        id: args['id'],
                        volume: 100,
                        url: args['url'],
                        stream: true,
                        onfinish: function(x) {
                            //this.destruct()
			    var path = reverse_data[args['url']]
			    if (path){
				methods['play_next'](path)
			    } else {
				methods['play_random']()
 			    }

                        },
                        onpause: function(x) {
                            // change icons
                            //console.log('pause')                            
                        },
                        onplay: function(x) {
                            // change icons
                            controls['loaded'].css(
                                'width', 
                                controls['duration'].outerWidth() * this.bytesLoaded / this.bytesTotal
                            )
                        },
                        ondataerror: function(x) {
                            controls['time'].html('<span>error</span>')
                        },
                        whileloading: function(x) {
                            if(!playing && autoplay) {
				$('.phlayer-controls-largeplay').addClass('off')
                                sound.play()
                                playing = true
                            }
                            
                            // update controls display
                            controls['loaded'].css(
                                'width', 
                                controls['duration'].outerWidth() * this.bytesLoaded / this.bytesTotal
                            )
                         
                        },
                        whileplaying: function(x) {
                            // update controls display

                            var duration = this.durationEstimate

                            controls['position'].css(
                                'width', 
                                Math.round(controls['loaded'].outerWidth() * this.position / duration )
                            )

                            function format_milliseconds(x){
                                var t = []
                                var seconds = Math.round(x / 1000)
                                var minutes = seconds / 60
                                if (minutes >= 1) {
                                    minutes = Math.floor(minutes)
                                    seconds = seconds - (minutes * 60)
                                    var hours = minutes / 60
                                    if (hours >= 1) {
                                        hours = Math.floor(hours)
                                        minutes = minutes - (hours * 60)
                                    } else {
                                        hours = false
                                    }
                                } else {
                                   minutes = false
                                   hours = false
                                }

                                if(seconds != 'NaN' && seconds > 0){
                                    if(seconds <= 9){
                                        seconds = '0' + seconds
                                    }
                                } else {
                                    seconds = '00'
                                }

                                t.push(seconds)

                                if(minutes) {
                                    if(minutes <= 9) {
                                        minutes = '0' + minutes
                                    }
                                    t.push(minutes)
                                } else {
                                    t.push('00')
                                }

                                if(hours) {
                                    t.push(hours)
                                }

                                t.reverse()

                                return t.join(':')
                            }

                            controls['time'].html('<span>'+format_milliseconds(this.position)+' | '+format_milliseconds(duration)+'</span>')
                        }
                    })
                    sound.load()

		// scroll to the right position
		var path = reverse_data[args['url']]
		if (!path) path = false
		methods['navigate'](path)
            }
        }

        this.resume = function(){
            soundManager.resumeAll()
        }

        this.pause = function(){
	    soundManager.pauseAll()
            // pause audio through sound manager
        }

        this.next = function(){
            // play next track in sound manager
        }

        this.previous = function(){
            // play previous track in sound manager
        }

    }

    $.fn.phlayer = function(method){

        if (methods[method]){

            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));

        } else if (typeof method === 'object' || ! method) {

            return methods.init.apply(this, arguments);

        } else {

            $.error('Method ' + method + ' does not exist on jQuery.phlayer');
        } 

    };

})(jQuery);

