(function($, undefined) {

    /** @type {Number} Таймуат перед тем как циферки побегут по таймеру */
    var COUNT_INCREMENT_TIMEOUT = 400;

    /** @type {Number} Интервал беготни циферок */
    var COUNT_INCREMENT_INTERVAL = 120;

    /** @type {Number} Таймаут перед вызовом события обновления */
    var CHANGE_EVENT_FIRE_TIMEOUT = 250;

    var _counterInterval;
    var _counterTimeout;

    function init(jQueryObject, min, max, clearButton) {
        jQueryObject.attr({
            readonly : 'readonly'
        }).mousedown(_falseHandler);
        if (clearButton) {
            // Кнопка "крестик"
            $(document.createElement('span'))
                .addClass('z')
                .attr({ title : 'Убрать' })
                .insertAfter(jQueryObject)
                .click(clearHandler)

        }

        if (max > min) {
            /** mousedown handeler */
            function _d(e) {
                startCounter(this, min, max);
            };

            /** mouseup handler */
            function _u(e) {
                stopCounter(this);
            }


            // Стрелочка вверх
            $(document.createElement('span'))
                .addClass('u')
                .attr({ title : 'Увеличить количество' })
                .insertAfter(jQueryObject)
                .mousedown(_d)
                .mouseup(_u);

            // Стрелочка вниз
            $(document.createElement('span'))
                .addClass('d')
                .attr({ title : 'Уменьшить количество' })
                .insertAfter(jQueryObject)
                .mousedown(_d)
                .mouseup(_u);
        }
    }

    /**
     * Запустить счетчик
     * @params {Object} el DOM-элемент кнопки
     * @params {Number} min минимальное значение
     * @params {Number} max максимальное значение
     */
    function startCounter(el, min, max) {
        // Находим инпут
        var input = $(el).siblings('input').get(0);
        // Запоминаем значение
        input._zValue = input.value;
        // Определаем вверх или вниз
        var sign = (el.className == 'd') ?  '-1' : 1;

        // функция инкрементации
        var inFunc = function() {
            var v = parseInt(input.value) + 1 * sign;
            if ((v >= min) && (v <= max))
                input.value = v;
        }

        // сбросим старые таймеры (на всякий)
        clearTimers();

        // и запустим новые
        _counterTimeout = window.setTimeout(function() {
            _counterInterval = window.setInterval(inFunc, COUNT_INCREMENT_INTERVAL);
        }, COUNT_INCREMENT_TIMEOUT);

        inFunc();
    }

    /**
     * Остановить счетчик
     * @params {Object} el DOM-элемент кнопки
     */
    function stopCounter(el) {
        var input = $(el).siblings('input').get(0);
        // Если значение изменилось - то вызовем триггер
        if (input.value != input._zValue) {
            if (input._eventTimeout)
                window.clearTimeout(input._eventTimeout);
            input._eventTimeout = window.setTimeout(function() {
                $(input).trigger('change');
            }, CHANGE_EVENT_FIRE_TIMEOUT);
        }
        clearTimers();
    }

    /**
     * Сбросить таймеры
     */
    function clearTimers() {
        if (_counterTimeout)
            window.clearTimeout(_counterTimeout);
        if (_counterInterval)
            window.clearInterval(_counterInterval);
    }

    /**
     * Хэндлер сброса
     */
    function clearHandler() {
        var el = this;
        $(el).siblings('input').eq(0).trigger('clear');
    }

    function _falseHandler(e) {
        var el = this;
        window.setTimeout(function() { this.blur(); }, 1);
        return false;
    }

    $.fn.extend({
        inputArrowCounter : function(params) {
            if (!params)
                params = {};
            init(
                this,
                (params.minValue === undefined) ? 1 : params.minValue,
                (params.maxValue === undefined) ? 99 : params.maxValue,
                (params.clearButton === true)
            );
            return this;
        }
    });

})(jQuery);

