/*
 * jQuery.PsdCounter 
 *
 */

!(function (pContext, pDefinition) {
    if (typeof define == 'function' && typeof define.amd  == 'object') define(['jquery'], pDefinition);
    else pDefinition(pContext['$']);
}(this, function ($) {

    $.fn.counter = function(options) {

        options = options || {};

        var checkStop = function(data) {
            var stop = 0;
            var current = 0;
            $.each(data.parts, function(i, part) {
                stop += (stop * part.limit) + part.stop;
                current += (current * part.limit) + part.value;
            });
            return data.down ? stop >= current : stop <= current;
        };

        var tick = function() {
            var e = $(this);
            var data = e.data('counter');
            var i = data.parts.length - 1;
            while(i >= 0 ) {
                var part = data.parts[i];
                part.value += data.down ? -1 : 1;
                if (data.down && part.value < 0) {
                    part.value = part.limit;
                } else if (!data.down && part.value > part.limit) {
                    part.value = 0;
                } else {
                    break;
                }
                i--;
            }
            refresh(e, i);
            if (checkStop(data)) {
                clearInterval(data.intervalId);
                e.trigger("counterStop");
            }
        };

        var refresh = function(e, to) {
            var data = e.data('counter');
            var i = data.parts.length - 1;
            while (i >= to) {
                var part = data.parts[i];
                var digits = part.value + '';
                while (digits.length < part.padding) {
                    digits = '0' + digits;
                }
                $.each(split(digits, ''), function(j, digit) {
                    animate(e, i, j, digit);
                });
                i--;
            }
        };

        var animate = function(e, ipart, idigit, digit) {
            var edigit = $($(e.children('span.part').get(ipart)).find('span.digit').get(idigit));
            edigit.attr('class', 'digit digit' + digit +  ' digit' + edigit.text() + digit).text(digit);
        };

        
        var split = function(undef) {

            var nativeSplit = String.prototype.split,
                compliantExecNpcg = /()??/.exec("")[1] === undef,
                self;

            self = function (str, separator, limit) {
               
                if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
                    return nativeSplit.call(str, separator, limit);
                }
                var output = [],
                    flags = (separator.ignoreCase ? "i" : "") +
                        (separator.multiline  ? "m" : "") +
                        (separator.extended   ? "x" : "") + 
                        (separator.sticky     ? "y" : ""), 
                    lastLastIndex = 0,
                
                    separator = new RegExp(separator.source, flags + "g"),
                    separator2, match, lastIndex, lastLength;
                str += ""; 
                if (!compliantExecNpcg) {
                   
                    separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
                }
                
                limit = limit === undef ?
                    -1 >>> 0 : 
                    limit >>> 0; 
                while (match = separator.exec(str)) {
                    
                    lastIndex = match.index + match[0].length;
                    if (lastIndex > lastLastIndex) {
                        output.push(str.slice(lastLastIndex, match.index));
                        
                        if (!compliantExecNpcg && match.length > 1) {
                            match[0].replace(separator2, function () {
                                for (var i = 1; i < arguments.length - 2; i++) {
                                    if (arguments[i] === undef) {
                                        match[i] = undef;
                                    }
                                }
                            });
                        }
                        if (match.length > 1 && match.index < str.length) {
                            Array.prototype.push.apply(output, match.slice(1));
                        }
                        lastLength = match[0].length;
                        lastLastIndex = lastIndex;
                        if (output.length >= limit) {
                            break;
                        }
                    }
                    if (separator.lastIndex === match.index) {
                        separator.lastIndex++; 
                    }
                }
                if (lastLastIndex === str.length) {
                    if (lastLength || !separator.test("")) {
                        output.push("");
                    }
                } else {
                    output.push(str.slice(lastLastIndex));
                }
                return output.length > limit ? output.slice(0, limit) : output;
            };

            return self;

        }();

        return this.each(function() {
            var e = $(this);
            var data = e.data('counter') || {};
            data.interval = parseInt(options.interval || e.attr('ppInterval') || '1000', 10);
            data.down = ( options.direction || e.attr('ppDirection') || 'down') == 'down';
            data.parts = [];
            var initial = split(options.initial || e.text(), /([^0-9]+)/);
            var format = split(options.format || e.attr('ppFormat') || "23:59:59", /([^0-9]+)/);
            var stop =  options.stop || e.attr('ppStop');
            if (stop) {
                stop = split(stop, /([^0-9]+)/);
            }
            e.html('');
            $.each(format, function(index, value) {
                if (/^\d+$/.test(value)) {
                    var part = {};
                    part.index = index;
                    part.padding = (value + '').length;
                    part.limit = parseInt(value, 10);
                    part.value = parseInt(initial[initial.length - format.length + index] || 0, 10);
                    part.value = part.value > part.limit ? part.limit : part.value;
                    part.stop = parseInt(stop ? stop[stop.length - format.length + index] : (data.down ? 0 : part.limit), 10);
                    part.stop = part.stop > part.limit ? part.limit : part.stop;
                    part.stop = part.stop < 0 ? 0 : part.stop;
                    var epart = $('<span>').addClass('part').addClass('part' + index);
                    var digits = part.value + '';
                    while (digits.length < part.padding) {
                        digits = '0' + digits;
                    }
                    $.each(digits, function(i, digit) {
                        epart.append($('<span>').addClass('digit digit' + digit).text(digit));
                    });
                    e.append(epart);
                    data.parts.push(part);
                } else {
                    e.append($('<span>').addClass('separator').addClass('separator' + index).text(value));
                }
            });
            if (!checkStop(data)) {
                data.intervalId = setInterval($.proxy(tick, this), data.interval);
            } else {
                e.trigger("counterStop");
            }
            e.data('counter', data);
            return this;
        });
    };
}));
