/**

* Progress Bar wrapper.
* 
* @author Htmlstream 
* @version 1.0
* @requires appear.js (v1.0.3)
*
*/

;(function($){

'use strict';

$.HSCore.components.HSProgressBar = {

        /**
         * 
         * 
         * @var Object _baseConfig
         */
        _baseConfig : {
                bounds: -100,
                debounce: 10,
                time: 1000,
                fps: 60,
                rtl: false,
                direction: 'horizontal',
                useProgressElement: false,
                indicatorSelector: 'progress-bar-indicator',
                moveElementSelector: false,
                moveElementTo: 'currentPosition',
                onChange: function(value){},
                beforeUpdate: function(){},
                afterUpdate: function(){},
                onMoveElementChange: function(value){},
                beforeMoveElementUpdate: function(){},
                afterMoveElementUpdate: function(){}
        },

        /**
         * 
         * 
         * @var jQuery _pageCollection
         */
        _pageCollection : $(),

        /**
         * Initialization of Progress Bar wrapper.
         * 
         * @param String selector (optional)
         * @param Object config (optional)
         *
         * @return jQuery currentCollection - collection of initialized items.
         */
        init: function(selector, config){

                if(!(selector && $(selector).length)) return;

                this.extendHorizontalProgressBar();
                this.extendVerticalProgressBar();

                return this._initProgressBar(selector, config && $.isPlainObject(config) ? $.extend(true, {}, this._baseConfig, config) : this._baseConfig);

        },

        /**
         * 
         * Initialization of each Progress Bar of the page.
         *
         * @return undefined
         */
        _initProgressBar: function(selector, config) {

                var self = this,
                                currentCollection = $();

                appear({

                        bounds: config['bounds'],
                        debounce: config['debounce'],

                        init: function() {

                                $(selector).each(function(i, el) {

                                        var $this = $(el);

                                        if(config['direction'] === 'horizontal') {

                                                $this.data('ProgressBar', new self.HorizontalProgressBar($this, config));

                                        }
                                        else {

                                                $this.data('ProgressBar', new self.VerticalProgressBar($this, config));

                                        }

                                        currentCollection = currentCollection.add($this);
                                        self._pageCollection = self._pageCollection.add($this);

                                });

                        },

                        elements: function() {

                                return document.querySelectorAll(selector);

                        },

                        appear: function(el) {

                                // console.log( $(el).data('ProgressBar'), $(el).data('value') );

                                $(el).data('ProgressBar').update($(el).data('value'));

                        }

                });

                return currentCollection;

        },

        /**
         * Constructor Function of Horizontal Progress Bar
         * 
         * @param jQuery element
         * @param Object config
         *
         */
        HorizontalProgressBar: function(element, config) {

                this.element = element;
                this.indicator = this.element.find( config.indicatorSelector );

                this.config = config;
                this.moveElement = config['moveElementSelector'] ? element.parent().find(config['moveElementSelector']) : $();

                if(this.moveElement.length) {

                        if(config['rtl']) {
                                this.moveElement.css({
                                        'left': 'auto',
                                        'right': 0,
                                        'margin-right': this.moveElement.outerWidth() / -2
                                });
                        }
                        else {
                                this.moveElement.css({
                                        'left': 0,
                                        'margin-left': this.moveElement.outerWidth() / -2
                                });
                        }

                }

                if(this.config.useProgressElement) {
                        this.element.data( 'value', this.element.attr( 'value' ) );
                        this.element.attr('value', 0);
                }
                else {
                        this.element.data(
                                'value', 
                                this.indicator.length ? Math.round( this.indicator.outerWidth() / this.element.outerWidth() * 100 ) : 0
                        );
                        this.indicator.css('width', '0%');
                }

        },

        /**
         * Constructor Function of Vertical Progress Bar
         * 
         * @param jQuery element
         * @param Object config
         *
         */
        VerticalProgressBar: function(element, config) {

                this.element = element;
                this.config = config;
                this.indicator = element.find(config['indicatorSelector']);

                if(!this.indicator.length) return;

                element.data('value', parseInt(this.indicator.css('height'), 10) / this.indicator.parent().outerHeight() * 100);
                this.indicator.css('height', 0);

        },

        /**
         * Extends HorizontalProgressBar.
         *
         * @return undefined
         */
        extendHorizontalProgressBar: function() {

                /**
                 * Sets new value of the Progress Bar.
                 * 
                 * @param Number value
                 *
                 * @return undefined
                 */
                this.HorizontalProgressBar.prototype.update = function(value) {

                        var self = this;

                        if( this.config.useProgressElement ) {

                                var fps = (this.config['time'] / this.config['fps']),
                                                iterationValue = parseInt(value / fps, 10),
                                                counter = 0,
                                                self = this;

                                if(iterationValue == 0) iterationValue = 1;

                                this.config.beforeUpdate.call(this.element);
                                if(this.moveElement.length) this.config.beforeMoveElementUpdate.call(this.moveElement);

                                if(self.config.moveElementSelector && self.config['moveElementTo'] == 'end') {

                                        var mCounter = 0,
                                                        mIterationValue = parseInt(100 / fps, 10);

                                        if(mIterationValue == 0) mIterationValue = 1;

                                        var mCounterId = setInterval(function() {

                                                self.moveSubElement(mCounter+=mIterationValue);
                                                if(self.moveElement.length) self.config.onMoveElementChange.call(self.moveElement, mCounter+=mIterationValue);

                                                if(mCounter > 100) {
                                                        clearInterval(mCounterId);
                                                        self.moveSubElement(100);
                                                        if(self.moveElement.length) self.config.afterMoveElementUpdate.call(self.moveElement);
                                                }

                                        }, fps);

                                }

                                this.element.data('intervalId', setInterval(function(){

                                        var currentValue = counter += iterationValue;

                                        self.element.attr('value', currentValue);
                                        self.config.onChange.call(self.element, currentValue);

                                        if(self.config.moveElementSelector && self.config['moveElementTo'] == 'currentPosition') self.moveSubElement(currentValue);

                                        if(counter > value) {

                                                self.element.attr('value', value);
                                                if(self.config.moveElementSelector && self.config['moveElementTo'] == 'currentPosition') self.moveSubElement(value);
                                                clearInterval(self.element.data('intervalId'));
                                                self.config.afterUpdate.call(self.element);

                                        }

                                }, fps));
                        }
                        else {
                                if( this.indicator.length ) {
                                        this.indicator.stop().animate({
                                                'width': value + '%'
                                        }, {
                                                duration: self.config.time,
                                                complete: function() {
                                                        self.config.afterUpdate.call(self.element);
                                                }
                                        });
                                }
                        }

                };

                /**
                 * 
                 * 
                 * @param 
                 *
                 * @return 
                 */
                this.HorizontalProgressBar.prototype.moveSubElement = function(value, duration) {

                        if(!this.moveElement.length) return;

                        var self = this;

                        this.moveElement.css(this.config['rtl'] ? 'right' : 'left', value + '%');

                };

        },

        /**
         * Extends VerticalProgressBars.
         * 
         *
         * @return undefined
         */
        extendVerticalProgressBar: function() {

                /**
                 * Sets new value of the Progress Bar.
                 * 
                 * @param Number value
                 *
                 * @return undefined
                 */
                this.VerticalProgressBar.prototype.update = function(value) {

                        this.indicator.stop().animate({
                                height: value + '%'
                        });

                }

        },

        /**
         * Returns full collection of all initialized progress bars.
         * 
         *
         * @return jQuery _pageCollection
         */
        get: function() {

                return this._pageCollection;

        },

        /**
         * Returns API of the progress bar by index in collection.
         * 
         * @param Number index
         *
         * @return HorizontalProgressBar | VerticalProgressBar
         */
        getAPI: function(index) {

                if(this._pageCollection.eq(index).length) return this._pageCollection.eq(index).data('ProgressBar');

                return null;

        }

};

})(jQuery);