/// <reference path="../../../jquery/jquery-1.5.js" />
/// <reference path="../../../jquery.cookie/jquery.cookie.js" />

lightplayer.register("lightplayer.html.surfaces");
lightplayer.html.surfaces.Builder = function (player, surface, options) {
    this.player = player;
    this.media = player.media;
    this.$media = $(this.media);
    this.surface = surface;
    this.options = options;
    this.playedTimes = 0;
    this.isPlay = player.isPlay = false;
    this.isPlaying = player.isPlaying = false;
    this.descendants = {};
    var self = this;
    if (this.surface.build == undefined) {
        this.surface.build = function () { self.build_surface(); };
    }
    if (this.surface.adjust == undefined) {
        this.surface.adjust = function () { self.adjust_surface(); };
    }
    if (this.surface.ready == undefined) {
        this.surface.ready = function () {
            self.surface.adjust();

            self.$element.bind('mouseenter', function () {
                self.element_live(self.$controls);
            }).bind('mouseleave', function () {
                if (!self.media.isPaused() && !self.media.isEnded()) {
                    self.element_dead(self.$controls);
                }
            });
            self.media.addEventListener('ended', function (e) {
                if (self.options.rewind) {
                    self.media.currentTime = 0;
                    self.media.pause();
                }

                if (self.player.options.loop) {
                    self.media.play();
                } else {
                    self.element_live(self.$controls);
                }
            }, true);

            self.media.addEventListener('play', function () {
                self.isPlay = self.player.isPlay = true;
            }, false);
            self.media.addEventListener('playing', function () {
                self.isPlaying = self.player.isPlaying = true;
            }, false);
        };
    }
}
lightplayer.html.surfaces.Builder.prototype = {
    element_live: function ($element) {
        $element.removeClass('dead').addClass('live');
    },
    element_dead: function ($element) {
        $element.removeClass('live').addClass('dead');
    },
    adjust_surface: function () {
        var self = this, $progress = this.descendants.$progress, usedWidth = 0, railWidth = 0;
        if ($progress) {
            var $progressleader = $progress.find('.progress-leader'),
                $timeLoaded = $progressleader.find('.time-loaded'),
                $timePlayed = $progressleader.find('.time-played'),
				$others = this.descendants.$progress.siblings();

            // find the size of all the other controls besides the rail
            $others.each(function () {
                if (jQuery(this).css('position') != 'absolute') {
                    usedWidth += jQuery(this).outerWidth(true);
                }
            });
            // fit the rail into the remaining space
            railWidth = self.$controls.width() - usedWidth - ($progress.outerWidth(true) - $progress.outerWidth(false)) - 1; //ie -1
            $progress.width(railWidth);
            $progressleader.width(railWidth - ($progressleader.outerWidth(true) - $progressleader.width()));
            $progressleader.find('.time-total').width($progressleader.width());
            if (self.timeLoaded) {
                $timeLoaded.width(self.timeLoaded * $progressleader.width());
            }
            $timePlayed.width(self.media.currentTime / self.media.duration * $progressleader.width());
        }
    },
    build_surface: function () {
        var self = this;
        this.$element = this.surface.$element = jQuery('<div class="surface"></div>');
        this.element = this.surface.element = this.surface.$element[0]
        this.descendants.$controls = this.$controls = this.surface.$controls = jQuery('<div class="controls"></div>').appendTo(this.surface.element);
        this.controls = this.surface.controls = this.surface.$controls[0];
        this.player.$element.addClass(this.surface.cssClass).addClass('theme-' + this.player.options.theme);

        this.build_poster();
        for (var f in this.player.options.features) {
            if (this['build_' + this.player.options.features[f]]) {
                this['build_' + this.player.options.features[f]]();
            }
        }
        this.player.$element.find('.surface').remove();
        this.player.$element.append(this.surface.element);
    },
    build_poster: function () {
        var self = this;
        this.descendants.$poster = $('<div class="poster"></div>')
					.appendTo(this.element);
        var posterUrl = this.options.poster;

        if (posterUrl !== '' && posterUrl != null) {
            this.descendants.$poster.append('<img src="' + posterUrl + '" />');
        } else {
            self.element_dead(this.descendants.$poster);
        }

        this.active_poster();
    },
    build_overlay: function () {
        this.descendants.$overlay = $('<div class="overlay"><div class="button control overlay-control"><span></span></div></div>')
					.appendTo(this.element);
        this.active_overlay();
    },
    build_spinner: function () {
        this.descendants.$spinner = $('<div class="control spinner"><span></span></div>')
					.appendTo(this.element);
        this.active_spinner();
    },
    build_play: function () {
        this.descendants.$play = $('<div class="button control play-control play"><span></span></div>')
			.appendTo(this.controls);

        this.active_play();
    },
    build_progress: function () {
        this.descendants.$progress = $('<div class="control progress-control"><span class="progress-leader">' +
        '<span class="time-total"></span><span class="time-loaded"></span><span class="time-played"></span><span class="button time-handle"></span>' +
        '<span class="time-float"><span class="float-value">00:00</span><span class="float-corner"></span></span>' +
        '</span></div>')
					.appendTo(this.controls);

        this.active_progress();
    },
    build_time: function () {
        this.descendants.$time = $('<div class="time-control"><span class="current">00:00</span><span class="slash">/</span>' +
        '<span class="duration">00:00</span></div>')
					.appendTo(this.controls);

        this.active_time();
    },
    build_track: function () {
        var self = this;
        if (self.player.tracks && self.player.tracks.length > 0) {
            var hasCaptions = false;
            var hasChapters = false;
            for (var i in self.player.tracks) {
                var track = self.player.tracks[i];
                if (track.kind == 'chapters' && !hasChapters) {
                    hasChapters = true;
                }
                if (track.kind == 'chapters' && !hasChapters) {
                    hasChapters = true;
                }
            }
            if (!this.$captions) {
                this.build_captions();
            }
            if (!this.$chapters) {
                this.build_chapters();
            }

            this.descendants.$language = $('<div class="button language-control"><span></span></div>')
            .appendTo(this.controls);
            this.descendants.$langbox = $('<div class="language-box"><div class="language-selector"><ul><li>' +
            '<input type="radio" name="' + this.player.id + '_captions" id="' + this.player.id + '_captions_none" value="none" checked="checked" />' +
            '<label for="' + this.player.id + '_captions_none">None</label>' +
            '</li></ul></div></div>')
            .appendTo(self.$controls);
            this.active_track();
        }
    },
    build_captions: function () {
        this.descendants.$caption = $('<div class="captions"><div class="leader"><span></span></div></div>')
        .appendTo(this.element);

        this.active_captions();
    },
    build_chapters: function () {
        this.descendants.$chapters = $('<div class="chapters"><div class="leader"></div></div>')
        .appendTo(this.element);

        this.active_chapters();
    },
    build_volume: function () {
        this.descendants.$volume = $('<div class="button volume-control mute"><span></span><div class="volume-slider"><div class="slider-leader">' +
        '<div class="volume-total"></div><div class="volume-current"></div><div class="volume-handle">' +
        '</div></div></div></div>')
					.appendTo(this.controls);

        this.active_volume();
    },
    build_fullscreen: function (player, surface, options) {
        this.descendants.$fullScreen = $('<div class="button fullscreen-control fullscreen"><span></span></div>')
					.appendTo(this.controls);

        this.active_fullscreen();
    },
    active_poster: function () {
        var self = this;
        this.media.addEventListener('play', function () {
            self.element_dead(self.descendants.$poster);
        }, false);
        this.media.addEventListener('ended', function () {
            if (self.options.rewind) {
                self.element_live(self.descendants.$poster);
            }
        }, false);
    },
    active_overlay: function () {
        var self = this;
        this.descendants.$overlay.click(function () {
            if (self.media.isPaused() || self.media.isEnded()) {
                self.media.play();
            } else {
                self.media.pause();
            }
        });

        this.media.addEventListener('play', function () {
            self.descendants.$overlay.removeClass('play').addClass('pause');
        }, false);
        this.media.addEventListener('playing', function () {
            self.descendants.$overlay.removeClass('play').addClass('pause');
        }, false);
        this.media.addEventListener('seeking', function () {
            self.descendants.$overlay.removeClass('play').addClass('pause');
        }, false);
        this.media.addEventListener('pause', function () {
            self.descendants.$overlay.removeClass('pause').addClass('play');
        }, false);
        this.media.addEventListener('ended', function () {
            if (!self.player.options.loop) {
                self.descendants.$overlay.removeClass('pause').addClass('play');
            }
        }, false);
    },
    active_spinner: function () {
        var self = this;
        self.media.addEventListener("loadeddata", function () { self.element_dead(self.descendants.$spinner); }, false);
        self.media.addEventListener("loadstart", function () { if (self.isPlay) { self.element_live(self.descendants.$spinner); } }, false);
        //self.media.addEventListener("seeking", function () { self.element_live(this.descendants.$spinner); }, false);
        //self.media.addEventListener("seeked", function () {  self.element_dead(this.descendants.$spinner); }, false);
        self.media.addEventListener("canplay", function () { self.element_dead(self.descendants.$spinner); }, false);
        self.media.addEventListener("canplaythrough", function () { self.element_dead(self.descendants.$spinner); }, false);
        self.media.addEventListener("waiting", function () { if (self.isPlay) { self.element_live(self.descendants.$spinner); } }, false);
        //self.media.addEventListener("stalled",function () { } , false);
        //self.media.addEventListener("suspend", function () { } , false);
        self.media.addEventListener("playing", function () { self.element_dead(self.descendants.$spinner); }, false);
        self.media.addEventListener("timeupdate", function () {
            self.element_dead(self.descendants.$spinner);
        }, false);
    },
    active_play: function () {
        var self = this;
        this.descendants.$play.click(function () {
            if (self.media.isPaused() || self.media.isEnded()) {
                self.media.play();
            } else {
                self.media.pause();
            }
        });

        this.media.addEventListener('play', function () {
            self.descendants.$play.removeClass('play').addClass('pause');
        }, false);
        this.media.addEventListener('playing', function () {
            self.descendants.$play.removeClass('play').addClass('pause');
        }, false);
        this.media.addEventListener('seeking', function () {
            self.descendants.$play.removeClass('play').addClass('pause');
        }, false);
        this.media.addEventListener('pause', function () {
            self.descendants.$play.removeClass('pause').addClass('play');
        }, false);
        this.media.addEventListener('paused', function () {
            self.descendants.$play.removeClass('pause').addClass('play');
        }, false);
        this.media.addEventListener('ended', function () {
            self.descendants.$play.removeClass('pause').addClass('play');
        }, false);
    },
    active_progress: function () {
        var self = this,
            $leader = self.descendants.$progress.find('.progress-leader'),
			$loaded = $leader.find('.time-loaded'),
			$played = $leader.find('.time-played'),
			$handle = $leader.find('.time-handle'),
			$timeFloat = $leader.find('.time-float'),
			$timeFloatValue = $timeFloat.find('.float-value'),
            setLoadedProgress = function (e) {
                if (!e) {
                    return;
                }

                var 
					target = e.target,
					percent = null;

                // newest HTML5 spec has buffered array (FF4, Webkit)
                if (target && target.buffered && target.buffered.length > 0 && target.buffered.end && target.duration) {
                    // TODO: account for a real array with multiple values (only Firefox 4 has this so far) 
                    percent = target.buffered.end(0) / target.duration;
                }
                // Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
                // to be anything other than 0. If the byte count is available we use this instead.
                // Browsers that support the else if do not seem to have the bufferedBytes value and
                // should skip to there. Tested in Safari 5, Webkit head, FF3.6, Chrome 6, IE 7/8.
                else if (target && target.bytesTotal != undefined && target.bytesTotal > 0 && target.bufferedBytes != undefined) {
                    percent = target.bufferedBytes / target.bytesTotal;
                }
                // Firefox 3 with an Ogg file seems to go this way
                else if (e.lengthComputable && e.total != 0) {
                    percent = e.loaded / e.total;
                }

                // finally update the progress bar
                if (percent !== null) {
                    self.timeLoaded = percent = Math.min(1, Math.max(0, percent));
                    // update loaded bar
                    $loaded.width($leader.width() * percent);
                    if ($loaded.width() < $played.width()) {
                        $loaded.width($played.width());
                    }
                }
            },
			setCurrentTime = function (e) {
			    if (self.media.currentTime && self.media.duration) {
			        // update bar and handle
			        var 
						newWidth = $leader.width() * self.media.currentTime / self.media.duration,
						handlePos = newWidth * ($leader.width() - $handle.outerWidth(true)) / $leader.width();

			        $played.width(newWidth);
			        $handle.css('left', handlePos);
			    }
			},
			onMouseMove = function (e) {
			    // mouse position relative to the object
			    var x = e.pageX,
					offset = $leader.offset(),
					width = $leader.outerWidth(),
					percentage = 0,
					newTime = 0;


			    if (x > offset.left && x <= width + offset.left && self.media.duration) {
			        percentage = ((x - offset.left) / width);
			        newTime = (percentage <= 0.02) ? 0 : percentage * self.media.duration;

			        // seek to where the mouse is
			        if (isMouseDown) {
			            self.media.currentTime = newTime;
			            if (self.media.isPaused()) {
			                self.media.play();
			            }
			        }

			        // position floating time box
			        var pos = x - offset.left;
			        $timeFloat.css('left', pos);
			        $timeFloatValue.html(lightplayer.utilies.secondsToTimeCode(newTime));
			    }
			},
			isMouseDown = false,
            isMouseOver = false;
        $leader.bind('mousedown', function (e) {
            isMouseDown = true;
            onMouseMove(e);
            return false;
        });

        self.descendants.$progress.bind('mouseenter', function (e) {
            isMouseOver = true;
        })
		.bind('mouseleave', function (e) {
		    isMouseOver = false;
		});

        $(document).bind('mouseup', function (e) {
		    isMouseDown = false;
		}).bind('mousemove', function (e) {
		    if (isMouseDown || isMouseOver) {
		        onMouseMove(e);
		    }
		});

        self.media.addEventListener('progress', function (e) {
            setLoadedProgress(e);
        }, false);

        // current time
        self.media.addEventListener('timeupdate', function (e) {
            setLoadedProgress(e);
            setCurrentTime(e);
        }, false);
    },
    active_time: function () {
        var self = this;
        this.media.addEventListener('timeupdate', function () {
            if (self.media.currentTime) {
                self.descendants.$time.find('.current').html(lightplayer.utilies.secondsToTimeCode(self.media.currentTime));
                self.descendants.$time.find('.duration').html(lightplayer.utilies.secondsToTimeCode(self.media.duration));
            }
        }, false);
    },
    active_track: function () {
        var self = this,
            $langbox = self.descendants.$langbox;

        this.descendants.$language.hover(function () {
            self.element_live($langbox);
        }, function () {
            self.element_dead($langbox);
        });

        $langbox.find('input[type=radio]').click(function () {
            var lang = this.value;

            if (lang == 'none') {
                self.player.selectedTrack = null;
            } else {
                for (i = 0; i < self.player.captions.length; i++) {
                    self.player.selectedTrack = player.captions[i];
                    self.player.captions.attr('lang', player.selectedTrack.srclang);
                    self.player.displayCaptions();
                    break;
                }
            }
        });
    },
    active_captions: function () {
        //TODO
    },
    active_chapters: function () {
        //TODO
        var displayChapters = function () {
            var 
				self = this,
				i;

            for (i = 0; i < self.tracks.length; i++) {
                if (self.tracks[i].kind == 'chapters' && self.tracks[i].isLoaded) {
                    self.drawChapters(self.tracks[i]);
                    break;
                }
            }
        },
		drawChapters = function (chapters) {
		    var 
				self = this,
				i,
				dur,
				percent = 0,
				usedPercent = 0;

		    self.descendants.$chapters.empty();

		    for (i = 0; i < chapters.entries.times.length; i++) {
		        dur = chapters.entries.times[i].stop - chapters.entries.times[i].start;
		        percent = Math.floor(dur / t.media.duration * 100);
		        if (percent + usedPercent > 100 || // too large
					i == chapters.entries.times.length - 1 && percent + usedPercent < 100) // not going to fill it in
		        {
		            percent = 100 - usedPercent;
		        }

		        self.chapters.append($(
					'<div class="item" rel="' + chapters.entries.times[i].start + '" style="left: ' + usedPercent.toString() + '%;width: ' + percent.toString() + '%;">' +
						'<div class="item-block' + ((i == chapters.entries.times.length - 1) ? ' item-block-last' : '') + '">' +
							'<span class="item-title">' + chapters.entries.text[i] + '</span>' +
							'<span class="item-time">' + lightplayer.utilies.secondsToTimeCode(chapters.entries.times[i].start) + '&ndash;' + lightplayer.utilies.secondsToTimeCode(chapters.entries.times[i].stop) + '</span>' +
						'</div>' +
					'</div>'));
		        usedPercent += percent;
		    }

		    self.descendants.$chapters.find('div.item').click(function () {
		        self.media.setCurrentTime(parseFloat($(this).attr('rel')));
		        if (self.media.isPaused()) {
		            self.media.play();
		        }
		    });

		    self.element_live(self.descendants.$chapters);
		};
    },
    active_volume: function () {
        var self = this,
		$volumeSlider = self.descendants.$volume.find('.volume-slider'),
		$volumeTotal = $volumeSlider.find('.volume-total'),
		$volumeCurrent = $volumeSlider.find('.volume-current'),
		$volumeHandle = $volumeSlider.find('.volume-handle'),
        positionVolumeHandle = function (volume) {
            if ($volumeTotal.height() > $volumeTotal.width()) {
                var top = $volumeTotal.height() - $volumeTotal.height() * volume;

                // handle must set leader css postion relative, for volumeTotal.position().top will always return 0 if it invisible(first time).
                var handleTop = top * ($volumeTotal.height() - $volumeHandle.height()) / $volumeTotal.height();
                $volumeHandle.css('top', handleTop + 'px');
                // show the current visibility
                $volumeCurrent.height($volumeTotal.height() - handleTop);
                $volumeCurrent.css('top', handleTop + 'px');
            } else {
                var left = $volumeTotal.width() * volume;

                // handle must set leader css postion relative, for volumeTotal.position().top will always return 0 if it invisible(first time).
                var handleLeft = left * ($volumeTotal.width() - $volumeHandle.width()) / $volumeTotal.width();
                $volumeHandle.css('left', handleLeft + 'px'); //
                // show the current visibility
                $volumeCurrent.width(handleLeft);
            }
        },
        onVolumeMove = function (e) {
            var totalOffset = $volumeTotal.offset(), volume = 0;
            if ($volumeTotal.height() > $volumeTotal.width()) {
                var railHeight = $volumeTotal.height(), newY = e.pageY - totalOffset.top;
                volume = (railHeight - newY) / railHeight;
            } else {
                var railWidth = $volumeTotal.width(), newX = e.pageX - totalOffset.left;
                volume = newX / railWidth;
            }

            // set mute status

            //console.log('set volume:' + volume);
            volume = Math.max(0, volume);
            volume = Math.min(volume, 1);

            // set the volume
            self.media.setVolume(volume);
            //console.log("  volume:" + volume);
            if (volume > 0) {
                self.media.setMute(false);
            }
        },
        onVolumeChange = function (e) {
            //if (!isMouseDown) {//before mouse up event
            if (self.media.isMuted()) {
                self.descendants.$volume.removeClass('mute').addClass('unmute');
                positionVolumeHandle(0);
            } else {
                //$element.removeClass('unmute').addClass('mute');
                positionVolumeHandle(self.media.getVolume());
                if (self.media.getVolume() == 0) {
                    self.descendants.$volume.removeClass('mute').addClass('unmute');
                } else {
                    self.descendants.$volume.removeClass('unmute').addClass('mute');
                }
                if (jQuery.cookie && self.player.options.saveVolume) {
                    jQuery.cookie('lightplayer.volume', self.media.getVolume());
                }
            }
            //console.log('self.player.options.useSavedMuted:' + self.player.options.useSavedMuted + "  jQuery.cookie('lightplayer.muted'):" + jQuery.cookie('lightplayer.muted'));
            if (jQuery.cookie && self.player.options.saveMuted) {
                jQuery.cookie('lightplayer.muted', self.media.isMuted());
            }
            //}
        },
		isMouseDown = false;
        isMouseOn = false;
        self.descendants.$volume.find('span').click(function () {
            if (self.media.isMuted()) {
                self.media.setMute(false);
            } else {
                self.media.setMute(true);
            }
        });
        self.descendants.$volume.hover(function () {
            isMouseOn = true;
            self.element_live($volumeSlider);
        }, function () {
            isMouseOn = false;
            if (!isMouseDown) {
                self.element_dead($volumeSlider);
            }
        });
        // SLIDER
        $volumeSlider.bind('mousedown', function (e) {
            onVolumeMove(e);
            isMouseDown = true;
            self.element_live($volumeSlider);
            return false;
        });
        var mouseUpHandler = function (e) {
            isMouseDown = false;
            if (!isMouseOn) {
                self.element_dead($volumeSlider);
            }
        };
        $(document).bind('mouseup', mouseUpHandler)
            .bind('focusout', mouseUpHandler)
            .bind('mousemove', function (e) {
                if (isMouseDown) {
                    onVolumeMove(e);
                }
            });

        // listen for volume change events from other sources
        self.media.addEventListener('volumechange', onVolumeChange, true);

        // set initial volume
        //player.options.startVolume = Math.min(Math.max(0,player.options.startVolume),1);
        //positionVolumeHandle(self.player.options.startVolume);
        if (self.player.options.useSavedMuted) {
            self.media.setMute(jQuery.cookie('lightplayer.muted') == 'true');
        } else {
            self.media.setMute(self.player.options.startMuted);
        }
        var volume = self.player.options.startVolume;
        if (self.player.options.useSavedVolume && jQuery.cookie('lightplayer.volume') !== undefined) {
            volume = Number(jQuery.cookie('lightplayer.volume'));
            if (volume <= 0) {
                volume = self.player.options.startVolume;
                self.media.setMute(true);
            }
        }
        self.media.setVolume(volume);
    },
    active_fullscreen: function () {
        var self = this;
        self.$media.bind('fullscreen', function () {
            self.descendants.$fullScreen.removeClass('fullscreen').addClass('unfullscreen');
            self.adjust_surface();
        }).bind('unfullscreen', function () {
            self.descendants.$fullScreen.removeClass('unfullscreen').addClass('fullscreen');
            self.adjust_surface();
        });
        self.descendants.$fullScreen.click(function () {
            self.media.setFullScreen(!self.media.isFullScreen);
        });
    }
}
