/**
 * UltimatePlayer (copyright 2011)
 * @author zbigniew.labacz@gmail.com
 * @package UltimatePlayer
 */
;(function($) {
    
    LIB.namespace('UltimatePlayer');
    
    /**
     * Player
     */
    UltimatePlayer.Base = $.inherit({

        /**
         * Konfiguracja
         * @var {}
         */
        config: undefined,
        
        /**
         * DomElement
         * @var [ DOMElement ]
         */
        dom: undefined,
        
        /**
         * Wrapper
         * @var [ DOMElement ]
         */
        slider: undefined,

        /**
         * Lista obrazków
         * @var [ Images ]
         */
        images: undefined,

        /**
         * Lista obiektów do animacji
         * @var [ DOMElements ]
         */
        elements: undefined,
        
        /**
         * Ilość klatek
         * @var int
         */
        count: 0,

        /**
         * Nawigacja
         * @var [ DOMElement ]
         */
        nav: undefined,

        /**
         * Preloader
         * @var [ DOMElement ]
         */
        preloader: undefined,
        
        /**
         * Bierzący włączony widoczny element
         * @var [ DOMElement ]
         */
        currentElement: undefined,
        
        /**
         * Index obecnego elementu
         * @var int
         */
        offset: 0,
        
        /**
         * Czy player gotowy do akcji?
         * @var bool
         */
        loaded: false,
        
        /**
         * Główny timer playera
         */
        timer: undefined,
        
        /**
         * Timer czekania na załadowanie
         */
        timerWait: undefined,
        
        /**
         * Czy player został zatrzymany 
         * @var bool
         */
        stopped: false,
        
        /**
         * Kierunek ruchu playera 
         * @var int   1 | -1
         */
        direction: 1,
        
        /**
         * Konstruktor
         */
        __constructor: function(dom, config)
        {
            this.config = config;
            this.dom = dom;
            this.slider = this.config.sliderSchema(dom);
            this.elements = this.slider.children();
            this.count = this.elements.length;
            this.images = [];
            this.timer = 0;
            this.slider.addClass('ultimate-player-slider');
            this.dom.addClass('ultimate-player').css({
                width: this.config.width,
                height: this.config.height
            });

            this.baseCustomize();
        },
        
        /**
         * Czy załadowano?
         */
        isLoaded: function()
        {
            return this.loaded;
        },
        
        /**
         * Czy player został zatrzymany?
         * @return bool
         */
        isStopped: function()
        {
            return this.stopped;
        },

        /**
         * Dom
         * @return [ DOMElement ]
         */
        getDom: function()
        {
            return this.dom;
        },

        /**
         * Podstawowe dostosowanie elementów playera
         * @return void
         */
        baseCustomize: function()
        {
            var _this = this;
            this.getElements().each(function() {
                $(this).css({
                    width: _this.config.width,
                    height: _this.config.height
                });
            });
            
            // Reakcja na najechanie myszką: należy zatrzymać timer
            this.getDom().hover(
                function() {
                    if (_this.isLoaded())
                    {
                        _this.killTimer();
                    }
                },
                function() {
                    if (_this.isLoaded())
                    {
                        _this.resetTimer();
                    }
                }
            );
            
            // Detkcja uruchomienia karty:
            $(window).focus(function() {
                if (_this.isLoaded())
                {
                    _this.getDom().find(':animated').stop(true, true);
                    _this.resetTimer();
                }
            });
            
            // Detekcja przełączanie na inną kartę:
            $(window).blur(function() {
                if (_this.isLoaded())
                {
                    _this.getDom().find(':animated').stop(true, true);
                    _this.killTimer();
                }
            });

            this.customize();
        },

        /**
         * Abstract: dostosowanie domu do animacji
         * @return void
         */
        customize: function()
        {

        },

        /**
         * Slider
         * @return [ DOMElement ]
         */
        getSlider: function()
        {
            return this.slider;
        },

        /**
         * Elementy animacji
         * @var [ DOMElement, ... ]
         */
        getElements: function()
        {
            return this.elements;
        },
        
        /**
         * Pobiera nawigację
         * @return [ DOMElement ]
         */
        getNav: function()
        {
            return this.nav;
        },
        
        /**
         * Bieżący widoczny element
         * @return [ DOMElement ]
         */
        getCurrentElement: function()
        {
            return this.currentElement;
        },
        
        /**
         * Ustawia bieżący element
         * @var [ DOMElement ] el
         */
        setCurrentElement: function(el)
        {
            this.currentElement = el;
        },
        
        /**
         * Ustawia index bieżącego elementu
         * @param int offset
         */
        setOffset: function(offset)
        {
            this.offset = offset;
            this.onChangeOffset(offset);
        },
        
        /**
         * Pobiera index bieżącego elementu
         * @return int
         */
        getOffset: function()
        {
            return this.offset;
        },
        
        /**
         * Zwraca ilość klatek
         * @return int
         */
        getCount: function()
        {
            return this.count;
        },

        /**
         * Preload grafiki:
         */
        preload: function()
        {
            var _this = this;

            // Rejestruje zdarzenie:
            this.getDom().bind('init', function() {
                _this.init();
            });

            this.getSlider().css({visibility: 'hidden'});
            this.getDom().append(this.renderPreloader());

            // Zbiera kolekcję elementów IMG:
            this.getElements().each(function() {
                var imgElement = _this.config.imgSchema($(this));
                if (typeof imgElement.get(0) == 'object')
                {
                    _this.images.push(imgElement.get(0));
                }
            });

            this.wait();
        },

        /**
         * Renderuje preloadera
         * @return [ DOMElement ]
         */
        renderPreloader: function()
        {
            if (typeof this.preloader == 'object')
            {
                return this.preloader;
            }

            this.preloader = $('<div class="ultimate-player-preload">'+this.config.preload.text+'</div>');
            if (this.config.preload.image)
            {
                this.preloader.empty().append('<img src="'+this.config.preload.image+'" alt="preloader" />');
            }

            this.preloader.css({
                width: this.config.preload.width,
                height: this.config.preload.height,
                left: Math.round((this.config.width / 2) - (this.config.preload.width / 2)),
                top: Math.round((this.config.height / 2) - (this.config.preload.height / 2)),
                lineHeight: this.config.preload.height + 'px'
            });

            return this.preloader;
        },

        /**
         * Czeka na załadowanie wszystkich obrazków a następnie triguje event: init
         * @return UltimatePlayer
         */
        wait: function()
        {
            var _this = this;
            
            if (!this.images.length)
            {
                this.dismountPreload();
                this.getDom().trigger('init');
                
                return this;
            }
            
            this.timerWait = window.setInterval(function() {
                var n = 0;

                for (var i in _this.images)
                {
                    if (_this.images[i].complete) n++;
                }

                if (n == _this.getCount())
                {
                    window.clearInterval(this.timerWait);
                    _this.dismountPreload();
                    _this.getDom().trigger('init');
                }
                else
                {
                    _this.updatePreload(n);
                }
            }, 500);

            return this;
        },

        /**
         * Aktualizacja preloadera (w przypadku gdyby chcieć zrobić progressbar)
         * @param int numLoaded
         */
        updatePreload: function(numLoaded)
        {
            // do nothing!
        },

        /**
         * Odmontowuje preloader
         * @return void
         */
        dismountPreload: function()
        {
            var _this = this;
            this.getSlider().css({visibility: 'visible'});
            this.preloader.fadeOut(400, function() {
                _this.preloader.remove();
                delete _this.preloader;
            });
        },

        /**
         * Renderuje triggery do ręcznego przewijania
         * @return [ DOMElement ]
         */
        renderNav: function()
        {
            if (this.nav)
            {
                return this.nav;
            }

            var _this = this;
            this.nav = $('<ul class="ultimate-player-nav" />');
            var width = (this.getCount() * (parseInt(this.config.navigation.width)+parseInt(this.config.navigation.margin))) + parseInt(this.config.navigation.margin);
            var offset = this.config.navigation.offset;
            var pos = 'left';

            switch (this.config.navigation.position)
            {
                case 'center':
                    offset = Math.round((this.config.width / 2) - (width / 2));
                    pos = 'left';
                    break;
                case 'left':
                    pos = 'left';
                    break;
                case 'right':
                    pos = 'right';
                    break;
            }

            var css = {
                width: width
            };
            css[pos] = offset;
            this.nav.css(css);

            this.getElements().each(function(i) {
                var el = $('<li />');
                el.css({
                    width: parseInt(_this.config.navigation.width),
                    height: parseInt(_this.config.navigation.height),
                    marginLeft: parseInt(_this.config.navigation.margin)
                });
                if (!i)
                {
                    el.addClass('current');
                }
                el.data('anim-index', i.toString());
                el.click(function() {
                    _this.onNavClick(el.data('anim-index'));
                    return false;
                });
                _this.nav.append(el);
            });

            return this.nav;
        },
        
        /**
         * Zaznacza bieżący element nawigajcji
         */
        setCurrentNaviElement: function()
        {
            this.getNav().children('.current').removeClass('current');
            this.getNav().children().eq(this.getOffset()).addClass('current');
        },

        /**
         * Zdarzenie reagujące na załadowanie wszystkich elementów
         */
        init: function()
        {
            this.loaded = true;
            
            // Ustawia bieżący element na ten z domyślnego offsetu (najwyższa klatka staje się widoczna)
            this.setCurrentElement(this.getElements().eq(this.getOffset()));
            
            // Wyrenderuj navigację, jeżeli skonfigurowano:
            if (typeof this.config.navigation == 'object')
            {
                this.dom.append(this.renderNav());
            }
            
            this.run();
        },
        
        /**
         * Kliknięto w element nawigacji:
         * @return void
         */
        onNavClick: function(index)
        {
            index = parseInt(index);
            
            if (this.getOffset() == index)
            {
                return ;
            }
                
            if (!isNaN(index))
            {
                this.setOffset(index);
            }
            else
            {
                throw new Error('"index" is not a number: ' + index);
            }
        },
        
        /**
         * Zdarzenie: nastąpiła zmiana indexu slajdu playera:
         * @param int offset
         */
        onChangeOffset: function()
        {
            this.animate();
            
            if (this.config.navigation)
            {
                this.setCurrentNaviElement();
            }
        },

        /**
         * Animacja do pozycji:
         * @param int pos
         */
        animate: function()
        {
            
        },
        
        /**
         * Inicjalizuje animację
         * @return void
         */
        run: function()
        {
            var _this = this;
            this.stopped = false;
            var offset = this.getOffset();
            
            switch (this.config.rotate)
            {
                case "circle":
                    this.timer = window.setInterval(function() {
                        if (_this.getOffset() + 1 >= _this.getCount())
                        {
                            offset = 0;
                        }
                        else
                        {
                            offset = _this.getOffset() + _this.direction;
                        }
                        
                        _this.setOffset(offset);
                    }, this.config.timeout);
                break;
                    
                case 'ping-pong':
                    this.timer = window.setInterval(function() {
                        if (_this.direction == 1)
                        {
                            if (_this.getOffset() + 1 >= _this.getCount())
                            {
                                _this.direction = -1;
                            }
                        }
                        else
                        {
                            if (_this.getOffset() -1 <= -1)
                            {
                                _this.direction = 1;
                            }
                        }
                        
                        offset = _this.getOffset() + _this.direction;
                        _this.setOffset(offset);
                    }, this.config.timeout);
                break;
            }
        },
        
        /**
         * Zatrzymanie timera
         * @return void
         */
        killTimer: function()
        {
            this.stopped = true;
            window.clearInterval(this.timer);
        },
        
        /**
         * Restart timera
         * @return void
         */
        resetTimer: function()
        {
            this.killTimer();
            this.run();
        }
    });

    $.fn.ultimatePlayer = function(config)
    {
        var _self = this;

        this.config = {
            timeout: 2000,
            preload: {
                image: false,
                text: 'Loading images...',
                width: 300,
                height: 100
            },
            navigation: {
                width: 10,
                height: 10,
                margin: 4,
                position: 'center',
                offset: 5
            },
            rotate: 'circle', // circle | ping-pong
            width: 703,
            height: 330,
            animation: {
                className: 'Fade',
                type: 'fadeIn',
                duration: 300
            },
            sliderSchema: function(dom) {return dom.children('ul:eq(0)');},
            imgSchema: function(liElement) {return liElement.find('img:eq(0)')}
        }
        
        // DEEPLY extend (like merge to this.config):
        $.extend(true, this.config, config || {});
        
        return this.each(function() {
            
            if (typeof UltimatePlayer[_self.config.animation.className] != 'function')
            {
                throw new Error('Nie znaleziono klasy animacji: ' + _self.config.animation.className);
            }
            
            var player = new UltimatePlayer[_self.config.animation.className]($(this), _self.config);
            
            if (typeof _self.config.preload == 'object')
            {
                player.preload();
            }
            else
            {
                player.init();
            }
        });
        
    };

})(jQuery);

