/*
* @author Nick Lockwood
* A simple video player enhancement script.
* Adds CSS controls and Flash fallback if specified.
* Requires jQuery core to function.
* jQuery.UI and SWFObject are required for some features.
*/

(function ($) {

    $.fn.videoplayer = function (options) {

        var userOptions = options;
        $self = this;

        //replace or modify video
        return this.each(function () {

            //get video element
            var video = this;
            if (video.tagName.toLowerCase() == 'video') {
                var $video = $(this);
                var $controller = $('xxx'); //empty set
                var $container = $video.parent();
            } else {
                var $container = $(video);
                var $video = $container.children('video');
                if ($video.length) {
                    video = $video[0];
                } else {
                    video = null;
                }
            }

            //detect browser capabilities
            function flashAvailable() {
                if (!swfobject) {
                    return false;
                } else {
                    return swfobject.hasFlashPlayerVersion(options.flashVersion);
                }
            }
            function nativeVideoAvailable() {
                if (navigator.userAgent.match("Safari|Chrome")) {
                    if (!video) {
                        $video = $('<video><source type="video/mp4" src="' + options.videoURL + '"/></video>');
                        $container.html($video);
                        video = $video[0];
                    }
                    return video && video.play;
                }
                return false;
            }
            function nativeFullscreenAvailable() {
                return useFlash() || (video && (video.webkitEnterFullScreen || navigator.platform.match(/iPhone|iPad|iPod/i)) && !navigator.userAgent.match("Chrome|Windows"));
            }
            function muteAvailable() {
                return !navigator.platform.match(/iPhone|iPad|iPod/i);
            }

            //set defaults
            var options = $.extend({
                nativeControls: ((video) ? $video.attr('controls') : false),
                autoplay: ((video) ? $video.attr('autoplay') : false),
                videoURL: ((video) ? ($video.attr('src') || $video.find('source').attr('src')) : null),
                customControls: false,
                cssPrefix: 'videoplayer-',
                closeButton: false,
                expandButton: true,
                flashVersion: '9.0.0',
                flashUrl: false,
                expressInstallUrl: false,
                flashVars: {},
                flashParams: {},
                flashAttributes: {},
                useFlashIfNoFullscreen: false,
                useFlashIfAvailable: false,
                placeholder: '<p>This browser does not support video.</p>',
                timeDisplay: 'total', //alternative is 'remaining'
                autoHideControls: 'slide', //false, true, fade or slide
                autoHideDelay: 3000 //milliseconds
            }, userOptions);

            //set default flash vars
            options.flashVars = $.extend({
                videoURL: options.videoURL
            }, options.flashVars);

            //set default flash params
            options.flashParams = $.extend({
                quality: 'high',
                allowscriptaccess: 'sameDomain',
                allowfullscreen: options.expandButton
            }, options.flashParams);

            if (useFlash()) {

                //native video/flash
                var videoId = 'video_' + Math.random();
                var $placeholder = $('<div id="' + videoId + '"></div>');
                $container.html($placeholder);
                swfobject.embedSWF(
                    options.flashUrl, videoId,
                    $container.width(), $container.height(),
                    options.flashVersion, options.expressInstallUrl,
                    options.flashVars, options.flashParams,
                    options.flashAttributes, function () {
                        //simulate html5 video canplay event for hiding loader, etc
                        $self.trigger('ready');
                    }
                );

            } else if (nativeVideoAvailable()) {

                //set video attributes
                video.controls = options.nativeControls;
                video.autoplay = options.autoplay;

            } else {

                //inject placeholder content
                $noVideo = $('<div class="' + controlClass('no-video') + '"></div>');
                $noVideo.html(options.placeholder);
                $noVideo.children().hide().delay(500).fadeIn();
                $container.html($noVideo);
                if (options.closeButton) {
                    $container.append('<div class="' + controlClass('controls') + '">' +
                        '<button class="' + controlClass('close') + '" title="Close">Close</button>' +
                    '</div>');
                    $container.find('.' + controlClass('close')).click(function () {
                        $self.trigger('close');
                    });
                } else {
                    $container.css({
                        cursor: 'pointer'
                    }).click(function () {
                        $self.trigger('close');
                    });
                }

                //hide loader
                setTimeout(function () {
                    $self.trigger('ready');
                }, 10);
            }

            //eliminate inconsistent options
            options.nativeControls = options.nativeControls && !options.customControls;
            options.autoHideControls = (options.nativeControls) ? true : options.autoHideControls; //safari specific?
            options.expandButton = options.expandButton && nativeFullscreenAvailable(); //don't support any other kind right now

            //define methods
            function controlClass(name) {
                return options.cssPrefix + name;
            }
            function $control(name) {
                return $controller.find('.' + options.cssPrefix + name);
            }
            function padNumber(number, digits) {
                number = '' + number;
                while (number.length < digits) {
                    number = '0' + number;
                }
                return number;
            }
            function formatTime(seconds) {
                if (seconds < 0 || isNaN(seconds)) {
                    return '--:--';
                } else {
                    return padNumber(Math.floor(seconds / 60), 2) + ':' + padNumber(Math.floor(seconds) % 60, 2);
                }
            }
            function useFlash() {
                if (options.flashUrl && flashAvailable()) {
                    return options.useFlashIfAvailable || !nativeVideoAvailable() ||
						(options.useFlashIfNoFullscreen && !nativeFullscreenAvailable());
                } else {
                    return false;
                }
            }
            function play() {
                video.play();
            }
            var userPaused = false;
            function pause() {
                userPaused = true;
                video.pause();
            }
            function paused() {
                return video.paused;
            }
            function mute() {
                video.muted = true;
            }
            function unmute() {
                video.muted = false;
            }
            function muted() {
                return video.muted;
            }
            function seek(time) {
                try {
                    video.currentTime = time;
                    return true;
                } catch (e) {
                    return false;
                }
            }
            function duration() {
                return video.duration;
            }
            function currentTime() {
                return Math.round(video.currentTime);
            }
            var previousMaxBufferedValue = 0;
            function buffered() {
                var ranges = video.buffered;
                if (ranges) {
                    var total = 0;
                    for (var i = 0; i < ranges.length; i++) {
                        total += ranges.end(i) - ranges.start(i);
                    }
                    //work around bug in buffer reporting when seeking
                    previousMaxBufferedValue = Math.max(previousMaxBufferedValue, total);
                    return previousMaxBufferedValue / duration();
                } else {
                    return 0;
                }
            }
            var startedLoading = false;
            function loadingStarted() {
                return startedLoading || buffered() > 0.0;
            }
            function played() {
                return currentTime() / duration();
            }
            function expand() {
                video.webkitEnterFullScreen();
            }

            if (!useFlash() && options.customControls) {

                //create controller
                $controller = $(
					'<div class="' + controlClass('controls') + '">' +
						'<button class="' + controlClass('play') + '" title="Play">Play</button>' +
						'<div class="' + controlClass('timeline') + '">' +
							'<div class="' + controlClass('buffer') + '">' +
								'<div class="' + controlClass('scrubber') + '"></div>' +
							'</div>' +
						'</div>' +
						'<div class="' + controlClass('time') + '">--:-- / --:--</div>' +
					'</div>'
				);
                if (muteAvailable()) {
                    $controller.append('<button class="' + controlClass('mute') + '" title="Mute">Mute</button>');
                }
                if (options.expandButton) {
                    $controller.append('<button class="' + controlClass('expand') + '" title="Expand">Expand</button>');
					if (AKQA.DeviceManager.isiOS()) {
						$control('expand').hide();
					}
                }
                if (options.closeButton) {
                    $controller.append('<button class="' + controlClass('close') + '" title="Close">Close</button>');
                }
                if (options.autoHideControls) {
                    if (options.autoHideControls == 'slide') {
                        $controller.css('display', 'none');
                    } else {
                        $controller.hide();
                    }
                }
                $video.after($controller);
                $controller.css({
                    width: $video.width(),
                    position: 'relative'
                });

                //set optional classes
                (muteAvailable()) ? $controller.addClass(options.cssPrefix + 'has-mute') : $controller.removeClass(options.cssPrefix + 'has-mute');
                (options.expandButton) ? $controller.addClass(options.cssPrefix + 'has-expand') : $controller.removeClass(options.cssPrefix + 'has-expand');
                (options.closeButton) ? $controller.addClass(options.cssPrefix + 'has-close') : $controller.removeClass(options.cssPrefix + 'has-close');

                //bind events
                $control('play').click(function () {
                    (paused()) ? play() : pause();
                });
                $control('pause').click(function () {
                    (paused()) ? play() : pause();
                });
                $control('mute').click(function () {
                    (muted()) ? unmute() : mute();
                });
                $control('unmute').click(function () {
                    (muted()) ? unmute() : mute();
                });
                $control('timeline').click(function (event) {
                    seek((event.pageX - $(this).offset().left) / $(this).width() * duration());
                });
                $control('expand').click(function () {
                    expand();
                });
                $control('close').click(function () {
                    $self.trigger('close');
                });

                //autohide controls
                var autoHideTimer = null;
                if (options.autoHideControls) {
                    $(document).mousemove(function (event) {
                        if ($video.parents('body').length == 0) {
                            $(document).unbind('mousemove', arguments.callee);
                            clearTimeout(autoHideTimer);
                            autoHideTimer = null;
                            return;
                        }
                        var pos = $video.offset();
                        var mouse = { x: event.pageX, y: event.pageY };
                        if (mouse.x >= pos.left &&
							mouse.x <= pos.left + $video.width() &&
							mouse.y >= pos.top &&
							mouse.y <= pos.top + $video.height() + ((options.controlsBelow) ? $controller.height() : 0)
                        ) {
                            if (options.autoHideControls == 'slide') {
                                $controller.slideDown();
                            } else {
                                $controller.fadeIn();
                            }
                            clearTimeout(autoHideTimer);
                            autoHideTimer = null;
                        }
                        var pos = $controller.offset();
                        if (startedLoading && !autoHideTimer && (mouse.x < pos.left ||
				            mouse.x > pos.left + $controller.width() ||
				            mouse.y < pos.top ||
				            mouse.y > pos.top + $controller.height())
                        ) {
                            autoHideTimer = setTimeout(function () {
                                if (options.autoHideControls == 'slide') {
                                    $controller.slideUp();
                                } else {
                                    $controller.fadeOut();
                                }
                            }, options.autoHideDelay);
                        }
                    });
                }

                //scrubber dragging - requires jquery ui
                if ($control('scrubber').draggable) {
                    $control('scrubber').draggable({
                        axis: 'x',
                        containment: $control('timeline'),
                        drag: function (event, ui) {
                            seek((ui.position.left / ($control('timeline').width() - $control('scrubber').width())) * duration());
                        }
                    });
                }

                //use timer to track video progress
                var controlMonitor = setInterval(function () {
                    if ($controller.parents('body').length == 0) {
                        //check if video has been closed
                        clearInterval(controlMonitor);
                        return;
                    }
                    $control('buffer').width(Math.round(buffered() * $control('timeline').width()));
                    $control('scrubber').css('left', Math.round(played() * ($control('timeline').width() - $control('scrubber').width())));
                    var timePassed = formatTime(currentTime());
                    var timeRemaining = '-' + formatTime(duration() - currentTime());
                    var totalTime = formatTime(duration());
                    $control('time').text(timePassed + ' / ' + ((options.timeDisplay == 'total') ? totalTime : timeRemaining));
                    if (paused()) {
                        $control('pause').
							removeClass(controlClass('pause')).
							addClass(controlClass('play')).
							text('Play').attr('title', 'Play');
                    } else {
                        $control('play').
							removeClass(controlClass('play')).
							addClass(controlClass('pause')).
							text('Pause').attr('title', 'Pause');
                    }
                    if (muted()) {
                        $control('mute').
							removeClass(controlClass('mute')).
							addClass(controlClass('unmute')).
							text('Unmute').attr('title', 'Unmute');
                    } else {
                        $control('unmute').
							removeClass(controlClass('unmute')).
							addClass(controlClass('mute')).
							text('Mute').attr('title', 'Mute');
                    }

                }, 100);

                //autoplay
                if (options.autoplay && nativeVideoAvailable()) {
                    $control('timeline').addClass(controlClass('loading'));
                    if (navigator.platform.match(/iPhone|iPod|iPad/i)) {
                        //if (navigator.appVersion.match(/OS (.)/i)[1] < 4) {
                        $control('timeline').removeClass(controlClass('loading'));
                        /* } else {
                        video.load();
                        video.play();
                        }*/
                    }
                }

                //autoshow controls
                if (options.autoHideControls == 'slide') {
                    $controller.slideDown();
                } else {
                    $controller.fadeIn();
                }
            }

            //monitor when video finishes loading
            $video.bind('canplay', function () {
				if (AKQA.DeviceManager.isiOS() && options.expandButton) {
					$control('expand').show().click(function () {
						expand();
					});
				}
			
                $self.trigger('ready');
                $control('timeline').removeClass(controlClass('loading'));
                startedLoading = true;
            });

            //monitor when video finishes playing
            $video.bind('ended', function () {
                $self.trigger('ended');
            });

        });
    };

})(jQuery);
