/**
 * progressButton.js v1.0.0
 * http://www.codrops.com
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * Copyright 2013, Codrops
 * http://www.codrops.com
 */
 
;( function( window ) {

    'use strict';

    // https://gist.github.com/edankwan/4389601
    Modernizr.addTest('csstransformspreserve3d', function () {
        var prop = Modernizr.prefixed('transformStyle');
        var val = 'preserve-3d';
        var computedStyle;
        if(!prop) return false;

        prop = prop.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');

        Modernizr.testStyles('#modernizr{' + prop + ':' + val + ';}', function (el, rule) {
            computedStyle = window.getComputedStyle ? getComputedStyle(el, null).getPropertyValue(prop) : '';
        });

        return (computedStyle === val);
    });

    function extend( a, b ) {
        for( var key in b ) {
            if( b.hasOwnProperty( key ) ) {
                a[key] = b[key];
            }
        }
        return a;
    }

    // support
    var support = { transitions : Modernizr.csstransitions, transforms3d : Modernizr.csstransforms3d && Modernizr.csstransformspreserve3d },
        // transition end event name
        transEndEventNames = {
            'WebkitTransition': 'webkitTransitionEnd',
            'MozTransition': 'transitionend',
            'OTransition': 'oTransitionEnd',
            'msTransition': 'MSTransitionEnd',
            'transition': 'transitionend'
        },
        transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ];

    function ProgressButton( el, options ) {
        this.button = el;
        this.options = extend( {}, this.options );
        extend( this.options, options );
        this._init();
    }

    ProgressButton.prototype.options = {
        // time in ms that the status (success or error will be displayed)
        // during this time the button will be disabled
        statusTime : 1500
    };

    ProgressButton.prototype._init = function() {
        this._validate();
        // create structure
        this._create();
        // init events
        this._initEvents();
    };

    ProgressButton.prototype._validate = function() {
        // we will consider the fill/horizontal as default
        if( this.button.getAttribute( 'data-style' ) === null ) {
            this.button.setAttribute( 'data-style', 'fill' );
        }
        if( this.button.getAttribute( 'data-vertical' ) === null && this.button.getAttribute( 'data-horizontal' ) === null ) {
            this.button.setAttribute( 'data-horizontal', '' );
        }
        if( !support.transforms3d && this.button.getAttribute( 'data-perspective' ) !== null ) {
            this.button.removeAttribute( 'data-perspective' );
            this.button.setAttribute( 'data-style', 'fill' );
            this.button.removeAttribute( 'data-vertical' );
            this.button.setAttribute( 'data-horizontal', '' );
        }
    };

    ProgressButton.prototype._create = function() {
        var textEl = document.createElement( 'span' );
        textEl.className = 'content';
        textEl.id = 'button_content';
        textEl.innerHTML = this.button.innerHTML;
        var progressEl = document.createElement( 'span' );
        progressEl.className = 'progress';
        var progressInnerEl = document.createElement( 'span' );
        progressInnerEl.className = 'progress-inner';
        progressEl.appendChild( progressInnerEl );
        // clear content
        this.button.innerHTML = '';

        if( this.button.getAttribute( 'data-perspective' ) !== null ) {
            var progressWrapEl = document.createElement( 'span' );
            progressWrapEl.className = 'progress-wrap';
            progressWrapEl.appendChild( textEl );
            progressWrapEl.appendChild( progressEl );
            this.button.appendChild( progressWrapEl );
        }
        else {
            this.button.appendChild( textEl );
            this.button.appendChild( progressEl );
        }

        // the element that serves as the progress bar
        this.progress = progressInnerEl;

        // property to change on the progress element
        if( this.button.getAttribute( 'data-horizontal' ) !== null ) {
            this.progressProp = 'width';
        }
        else if( this.button.getAttribute( 'data-vertical' ) !== null ) {
            this.progressProp = 'height';
        }
        this._enable();
    };

    ProgressButton.prototype._setProgress = function( val ) {
        /* Speed controlled by CSS settings */
        // console.log('Val: ' +val);
        this.progress.style[ this.progressProp ] = 100 * val + '%';
    };

    ProgressButton.prototype._initEvents = function() {
        var self = this;
        this.button.addEventListener( 'click', function() {
            // disable the button
            self.button.setAttribute( 'disabled', '' );
            // add class state-loading to the button (applies a specific transform to the button depending which data-style is defined - defined in the stylesheets)
            classie.remove( self.progress, 'notransition' );
            classie.add( this, 'state-loading' );

            setTimeout( function() {
                if( typeof self.options.callback === 'function' ) {
                    self.options.callback( self );
                }
                else {
                    self._setProgress( 1 );
                    var onEndTransFn = function( ev ) {
                        if( support.transitions && ev.propertyName !== self.progressProp ) return;
                        this.removeEventListener( transEndEventName, onEndTransFn );
                        self._stop();
                    };

                    if( support.transitions ) {
                        self.progress.addEventListener( transEndEventName, onEndTransFn );
                    }
                    else {
                        onEndTransFn.call();
                    }

                }
            },
            self.button.getAttribute( 'data-style' ) === 'fill' ||
            self.button.getAttribute( 'data-style' ) === 'top-line' ||
            self.button.getAttribute( 'data-style' ) === 'lateral-lines' ? 0 : 200 ); // TODO: change timeout to transitionend event callback

        } );

    };

    ProgressButton.prototype._stop = function( status ) {
        var self = this;
        setTimeout( function() {
            // fade out progress bar
            self.progress.style.opacity = 0;
            var onEndTransFn = function( ev ) {
                if( support.transitions && ev.propertyName !== 'opacity' ) return;
                this.removeEventListener( transEndEventName, onEndTransFn );
                classie.add( self.progress, 'notransition' );
                self.progress.style[ self.progressProp ] = '0%';
                self.progress.style.opacity = 1;
            };

            if( support.transitions ) {
                self.progress.addEventListener( transEndEventName, onEndTransFn );
            }
            else {
                onEndTransFn.call();
            }


            // add class state-success to the button
            if( typeof status === 'number' ) {
                var statusClass = status >= 0 ? 'state-success' : 'state-error';
                classie.add( self.button, statusClass );
                // after options.statusTime remove status
                setTimeout( function() {
                    classie.remove( self.button, statusClass );
                    // self._enable();
                }, self.options.statusTime );
            }
            else {
                self._enable();
            }

            // remove class state-loading from the button
            classie.remove( self.button, 'state-loading' );
        }, 500 );
    };

    // enable button
    ProgressButton.prototype._enable = function() {
        this.button.removeAttribute( 'disabled' );
    };

    // add to global namespace
    window.ProgressButton = ProgressButton;

})( window );