if (!Object.create) {
    Object.create = function(o){
        var newType = function(){};
        newType.prototype = o;
        return new newType();
    }
}

(function($, window, document, undefined)
{
    var H5Video = 
    {
        options : null, target : null, video : null, jig : null, poster : null, controls : null, animating : null, buttons : null, 
        
        init: function(element, options)
        {
            this.options   = $.extend({}, $.fn.H5Video.Options, options);
            this.controls  = null;
            this.target    = element;
            this.animating = false;
            this.buttons   = {};
            this.video     = $("<video></video>");
            this.jig	   = $("<div></div>"    ).attr({ "class": "h5video"});
            this.poster    = $("<div></div>"    ).attr({ "class": "poster" });

            var videoFormat = null;
            try
            {
                for (var format in this.options.source)
                {
                    if (this.video.dom().canPlayType(format))
                    {
                        videoFormat = format;
                        break;
                    }
                }
            }
            catch(e)
            {}
            
            if (!videoFormat)
            {
                this.buildBrowserSupportMessage();
                return;
            }
                    
            if (this.options.preload)
                this.video.attr({ "autobuffer": "true", "preload" : "true" });
                
            this.jig.append(this.video);
            this.video.attr("src", this.options.source[videoFormat]);

            if (this.options.loop) 
                this.video.attr("loop", "true");

            $(document.body).append(this.jig);

            this.assignVideoEvents();

            if (!this.isIphoneOrIpod())
            {
                if (this.options.poster) 
                {
                    this.poster.css("background-image", "url(" + this.options.poster + ")");
                    this.jig.append(this.poster);
                }

                this.buildControl();
                this.minimize();
            }
            else
            {
                this.video.attr("controls", "controls");
            }	
            
            if (this.options.autoPlay) 
                this.play();
                
            var self = this;
            $(window).bind("fullscreen-toggle", function(e, fullscreen) {
                if (!fullscreen)
                    self.minimize();
            });            
        },
        
        isIphoneOrIpod: function()
        {
            return navigator.userAgent.match(/(iPad|iPhone|iPod)/i) != null;
        },

        buildBrowserSupportMessage: function()
        {
             var errorMessage = (this.options.supportMessage) ? this.options.supportMessage : "This browser is not able to playback HTML5 videos. We encourage you to upgrade your internet browser to one of the following modern and more secure browsers:";

             this.target.append(jQuery("<div></div>")).addClass("support-message").append(
                '<p>' + errorMessage + '</p>' +
                '<p>' + 
                    '<a href="http://getfirefox.com"><img src="images/browser_firefox.png" />Firefox</a>' +
                    '<a href="http://www.google.com/chrome"><img src="images/browser_chrome.png" />Chrome</a>' +
                    '<a href="http://www.apple.com/safari"><img src="images/browser_safari.png" />Safari</a>' +
                    '<a href="http://www.opera.com/"><img src="images/browser_opera.png" />Opera</a>' +
                '</p>'
             );	
        },
        
        buildControl: function()
        {
            var self = this;
            this.controls = $("<div></div>")
                .attr({ "class" : "control-panel" });

            var btnPlay = $("<a></a>")
                .attr({ 
                    "class" : "play" , 
                    "href" : "", 
                    "onclick": "return false;" 
                })
                .text(" ")
                .bind("click", function(e){
                    self.play(e);
                });
            
            var seekBar = $("<div></div>")
                .attr({ "class" : "seek-bar rounded" })
                .bind("click", function(e){
                    self.seek(e)
                }
            );
            
            var buffer = $("<div></div>")
                .attr({ "class" : "seek-bar-buffer rounded" });
            
            var guage = $("<div></div>")
                .attr({ "class" : "seek-bar-guage rounded" });

            var btnFullscreen = $("<a></a>")
                .attr({ 
                    "class" : "size full", 
                    "href" : "", 
                    "onclick": "return false;" 
                })
                .text(" ")
                .bind("click", function(e){
                    self.resize(e)
                });
                

            var btnMute = $("<a></a>")
                .attr({
                    "class" : "muter mute", 
                    "href" : "", 
                    "onclick": "return false;" 
                })
                .text(" ")
                .bind("click", function(e){
                    self.mute(e)
                });
            

            var interval = $("<span></span>")
                .attr({ "class" : "interval" })
                .text("00:00 / 00:00");

            this.jig.append(this.controls);
            
            this.controls.append(btnPlay);
            this.controls.append(seekBar);
            this.controls.append(btnFullscreen);
            this.controls.append(btnMute);
            this.controls.append(interval);
            
            seekBar.append(buffer);
            seekBar.append(guage);

            this.buttons.play       = btnPlay;
            this.buttons.fullscreen = btnFullscreen;
            this.buttons.mute       = btnMute;
            this.buttons.interval   = interval;
            this.buttons.seekBar    = seekBar;
            this.buttons.buffer     = buffer;
            this.buttons.guage      = guage;
            
            this.updateSeekbarWidth();
        },

        assignVideoEvents: function()
        {
            var self = this;
            
            this.video.bind("error"         , function(e){ self.handleError     (e)} );	
            this.video.bind("volumechange"  , function(e){ self.mute            (e)} );
            this.video.bind("playing"       , function(e){ self.onPlayingStart  (e)} );
            this.video.bind("pause"         , function(e){ self.onPause         (e)} );	
            this.video.bind("ended"         , function(e){ self.onEnd           (e)} );	
            this.video.bind("loadedmetadata", function(e){ self.onLoadedMetadata(e)} );	
            this.video.bind("timeupdate"    , function(e){ self.onDurationChange(e)} );
            this.video.bind("progress"      , function(e){ self.onProgress      (e)} );
            
/*            
            this.video.bind("canplay"       , function(e){ self.resumePlay      (e)} );
            this.video.bind("waiting"       , function(e){ self.waiting         (e)} );
            this.video.bind("stalled"       , function(e){ self.waiting         (e)} );
*/
            
            this.jig.bind("mouseenter", function(){
                self.showControls();
            });

            this.jig.bind("mouseleave", function(){
                self.hideControls();
            });

            window.setInterval(function(){
                if (!self.isMaximized())
                    self.repositionJig();
            }, 100);
        },

        repositionJig: function()
        {
            var offset = this.target.offset();
            var width  = this.target.outerWidth();
            var height = this.target.outerHeight();
            
            this.jig.css({
                "position" : "absolute",
                "width"    : width       + "px",
                "height"   : height      + "px",
                "top"      : offset.top  + "px",
                "left"     : offset.left + "px"
            }); 
        },
        
        minimize: function(e)
        {
            if (e) e.preventDefault();
            
            if (this.isIphoneOrIpod())
                return;

            this.repositionJig();
                
            this.buttons.fullscreen.removeClass("shrink").addClass("expand");
            this.jig.css("background-color", "transparent");
            this.updateSeekbarWidth();
        },

        maximize: function(e)
        {
            if (e) e.preventDefault();
            
            this.jig.css({
                "position" : "fixed",
                "width"    : "100%",
                "height"   : "100%",
                "top"      : "0px",
                "left"     : "0px"
            }); 

            this.buttons.fullscreen.removeClass("expand").addClass("shrink");
            this.jig.css("background-color", "#000");
            this.updateSeekbarWidth();
        },
        
        updateSeekbarWidth: function()
        {
            var o = this.buttons;
            var width = (o.play.width() + o.fullscreen.width() + o.mute.width() + o.interval[0].offsetWidth);

            width = this.controls.width() - width - 15; 
            
            o.seekBar.css("width", width + "px");
        },
        
        showControls: function(e)
        {
            this.updateSeekbarWidth();
            
            if (this.animating == false)
            {
                this.animating = true;
                this.controls.fadeTo(this.options.animationDuration, 1.0, function(){ 
                    this.animating = false; 
                });
            }
        },

        hideControls: function(e)
        {
            if (this.animating == false && this.controls.find(".play").length == 0)
            {
                this.animating = true;
                this.controls.fadeTo(this.options.animationDuration, 0.0, function(){ 
                    this.animating = false; 
                });
            }
        },

        isMaximized: function()	
        {
            if (this.isIphoneOrIpod())
                return false;
            return this.buttons.fullscreen ? this.buttons.fullscreen.hasClass("shrink") : false;
        },

        onPlayingStart: function(e)
        {
            if (!this.isIphoneOrIpod())
            {
                this.controls.find(".play").removeClass("play").addClass("pause");
                this.poster.fadeOut(this.options.animationDuration);
            }
            
            this.callUserCallback("play");
        },
        
/*        
        waiting: function(e)
        {
            console.log("waiting");
        },
        
        resumePlay: function(e)
        {
            console.log("resuming");
        },
*/        
        
        secondsToTime: function(duration)
        {
            var minutes  = 0;
            if (duration < 60)
            {
                var second = Math.floor(duration);
                if (isNaN(second))
                    return "00:00";
                
                minutes = "00:" + ((second < 10) ? "0" + second : second);
            }
            else
            {
                minutes = Math.floor(duration / 60);
                if (minutes < 10)
                    minutes = "0" + minutes;
                    
                var remainingMinutes = Math.floor(duration % 60);

                if (isNaN(minutes) || isNaN(remainingMinutes))
                    return "00:00";

                minutes += ":" + ((remainingMinutes < 10) ? "0" + remainingMinutes : remainingMinutes); 
            }
            
            return minutes;
        },
        
        onDurationChange: function(e)
        {
            if (!this.isIphoneOrIpod())
            {
                var percentComplete = Math.ceil((e.target.currentTime / e.target.duration) * 100);
                this.controls.find(".seek-bar-guage").css("width", percentComplete + "%");	
        
                var currentTime = this.secondsToTime(e.target.currentTime) + " / " + this.secondsToTime(e.target.duration); 
                this.controls.find(".interval").text(currentTime);	
            }
        },
        
        onProgress: function(e)
        {
            if (!this.isIphoneOrIpod())
            {
                try
                {
                    var percentComplete = Math.ceil((e.originalEvent.loaded / e.originalEvent.total) * 100);
                    
                    if (isNaN(percentComplete))
                        percentComplete = Math.ceil((e.target.buffered.end(0) / e.target.duration) * 100);
        
                    if (isNaN(percentComplete))
                        percentComplete = Math.ceil((e.target.buffered.end(0) / e.target.duration) * 100);
            
                    this.controls.find(".seek-bar-buffer").css("width", percentComplete + "%");	
                }
                catch(e) {}
            }
        },
        
        onPause: function(e)
        {
            if (!this.isIphoneOrIpod())
                this.controls.find(".pause").removeClass("pause").addClass("play");

            this.callUserCallback("pause");
        },
        
        onLoadedMetadata: function(e)
        {
            if (!this.isIphoneOrIpod())
            {
                var text = this.secondsToTime(e.target.currentTime) + " / " + this.secondsToTime(e.target.duration); 
                this.controls.find(".interval").text(text);
            }
        },
        
        onEnd: function(e)
        {
            var self = this;
            if (!this.isIphoneOrIpod())
            {
                if (this.isMaximized())
                    this.minimize();
                
                if (this.options.loop === true && jQuery.browser.mozilla)
                {
                    this.seekToTime(0);
                    return;	
                }
                    
                this.controls.find(".pause").removeClass("pause").addClass("play");
                this.poster.fadeIn(this.options.animationDuration, function(){
                    self.callUserCallback("end");
                });
                
                this.showControls(e);
            }	

            this.callUserCallback("end");
        },

        play: function(e)
        {
            if (e)
                e.preventDefault();
            
            if (this.controls.find(".play").length > 0)
            {
                this.video.dom().play();

                if ($.browser.safari || $.browser.opera)
                {
                    // since "playing" event is fired oly once in webkit and opera browsers I call it manually
                    this.onPlayingStart(e);
                }
            }
            else
            {
                this.video.dom().pause();
            }
            
            return false;
        },
        
        mute: function(e)
        {
            e.preventDefault();

            if (!this.video.dom().muted)
            {
                this.controls.find(".muter").removeClass("un-mute").addClass("mute");
                this.video.dom().muted = (e.target.tagName == "A");
            }
            else
            {
                this.controls.find(".muter").removeClass("mute").addClass("un-mute");
                this.video.dom().muted = (e.target.tagName != "A");;
            }
            
            return false;
        },
        
        resize: function(e)
        {
            if (this.isMaximized()) 
                this.minimize(e); 
            else 
                this.maximize(e);
            
            return false;
        },
        
        seek: function(e)
        {
            var seekBar        = this.controls.find(".seek-bar");
            var seekPixel      = $.browser.opera ? e.offsetX : e.layerX - e.target.offsetLeft;
            var seekPercentage = Math.floor((seekPixel / seekBar.width()) * 100);
            var seekTime       = Math.floor((seekPercentage / 100) * this.video.dom().duration);
            
            if (this.video.dom().seekable <= seekTime)
            {
                alert("can't seek to yet!");
                return;
            }

            this.video.dom().pause();
            
            try { 
                this.video.dom().currentTime = seekTime; 
            } 
            catch(e){}
            
            this.video.dom().play();
        },
        
        seekToTime: function(time)
        {
            this.video.dom().pause();
            
            try { 
                this.video.dom().currentTime = seekTime; 
            } 
            catch(e){}
            
            this.video.dom().play();
        },
        
        handleError: function(e)
        {
            switch (e.target.error.code) {
                case e.target.error.MEDIA_ERR_ABORTED:
                    alert('You aborted the video playback.');
                    break;

                case e.target.error.MEDIA_ERR_NETWORK:
                    alert('A network error caused the video download to fail part-way.');
                    break;

                case e.target.error.MEDIA_ERR_DECODE:
                    alert('The video playback was aborted due to a corruption problem or because the video used features your browser did not support.');
                    break;

                case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
                    alert('The video could not be loaded, either because the server or network failed or because the format is not supported.');
                    break;

                default:
                    alert('An unknown error occurred.');
                    break;
            }
        },
        
        callUserCallback: function(event)
        {
            var events = this.options.events;
            if (events && typeof events[event] == "function")
                window.setTimeout(events[event], 1);
        }
    };

    $.fn.H5Video = function(options) 
    {
        return this.each(function(){
            var player = Object.create(H5Video);
            player.init($(this), options)
        });
    };

    $.fn.H5Video.Options = {
        source : "",
        poster : "",			
        hideControls: false,
        animationDuration : 350,
        loop : false,			
        preload: true,
        autoPlay : true,
        supportMessage : "This browser cannot playback HTML5 videos. We encourage you to upgrade your internet browser to one of the following modern browsers:",
        preload : false,
        events : {}
    };

    $.fn.dom = function() 
    {
        return this.first()[0];
    };
    
})(jQuery, window, document);