/*
 * jQuery UI Stepper
 *
 * Copyright (c) 2008 Ca Phun Ung <caphun at yelotofu dot com>
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://yelotofu.com/labs/jquery/UI/stepper
 *
 * Depends: 
 *	ui.core.js 
 *	jquery.mousewheel.js
 *
 */
jQuery.fn.uistepper = function() {
    jQuery.each(this, function() {
        var thisid = $(this).attr("id");
        var thisvalue = $(this).attr("value");
        if (thisvalue == null || thisvalue.length <= 0)
            thisvalue = 0;
        $(this).replaceWith("<div id=\"" + thisid + "Div\" class=\"ui-stepper\">"
                            + "<input id=\"" + thisid + "\" type=\"text\" size=\"2\" autocomplete=\"off\" name=\"" + $(this).attr("name") + "\" title=\"" + $(this).attr("title") + "\" value=\"" + $(this).attr("value") + "\" class=\"ui-stepper-textbox\" />"
                            + "<button type=\"image\" name=\"" + thisid + "ns_button_1_0\" value=\"1\" class=\"ui-stepper-plus\"></button>"
                            + "<button type=\"image\" name=\"" + thisid + "ns_button_2_0\" value=\"-1\" class=\"ui-stepper-minus\"></button>"
                        + "</div>");
        $("#" + thisid + "Div").stepper(
            {
                min: 0,
                max: 999,
                step: 1,
                start: thisvalue
            });
        return $("#" + thisid + "Div");
    });
    return this;
}

; (function($) {

    $.widget("ui.stepper", {
        plugins: {},

        ui: function(e) {
            return {
                instance: this,
                options: this.options,
                element: this.element
            };
        },

        keys: {
            BACK: 8,
            TAB: 9,
            LEFT: 37,
            UP: 38,
            RIGHT: 39,
            DOWN: 40,
            PGUP: 33,
            PGDN: 34,
            HOME: 36,
            END: 35,
            PERIOD: 190,
            MINUS: 109,
            NUMPAD_DECIMAL: 110,
            NUMPAD_SUBTRACT: 109
        },

        _init: function() {
            var self = this;
            this.element[0].value = this.options.start;
            this.element[0].textbox = $('input[type="text"]', this.element[0]);

            // check for decimals in step size
            if (this.options.step.toString().indexOf('.') != -1) {
                var s = this.options.step.toString();
                this.setData('decimals', s.slice(s.indexOf('.') + 1, s.length).length);
            }

            this.element.each(function() {
                var ns = $(this);
                var textbox = $('input[type="text"]', ns); // get the input textbox
                var bup = $('.ui-stepper-plus', ns); // plus button
                var bdn = $('.ui-stepper-minus', ns); // minus button

                self.element[0].value = self.value(textbox.val());

                if (textbox.length > 0) {
                    if (self.element[0].value == '' || isNaN(self.element[0].value)) {
                        textbox.val(self.format(self.options.start));
                        self.element[0].value = self.value(textbox.val());
                    }

                    // detect key presses and restrict to numeric values only
                    textbox
					.bind("keydown.stepper", function(e) {
					    if (!self.counter) self.counter = 1;
					    return self.keydown(e);
					})
					.bind("keyup.stepper", function(e) {
					    if (e.keyCode !== self.keys.BACK && e.keyCode !== self.keys.MINUS && e.keyCode !== self.keys.PERIOD) {
					        var val = self.value(this.value);
					        var dif = parseFloat(val) % parseFloat(self.options.step);
					        if (dif !== 0) {
					            val = parseFloat(val) + (parseFloat(self.options.step) - parseFloat(dif));
					        }
					        if (val < self.options.min) val = self.options.min;
					        if (val > self.options.max) val = self.options.max;
					        self.element[0].value = self.value(val);
					        this.value = self.format(val);
					    }
					    self.counter = 0;
					    self.propagate("change", e);
					})
                    // detect when textbox loses cursor focus
					.bind('blur', function(e) {
					    if (this.value < self.options.min) this.value = self.options.min;
					    if (this.value > self.options.max) this.value = self.options.max;
					    if (this.value === '') this.value = self.options.start;
					})
					.bind('mousewheel', function(e, delta) {
					    if (delta > 0)
					        self.spin(self.options.step);
					    else if (delta < 0)
					        self.spin(-self.options.step);
					    return false;
					})
					.attr('autocomplete', 'off') // turns off autocomplete in opera!
				;

                }

                // convert button type to button to prevent form submission onclick
                if (bup.attr('type') == 'submit' || bup.attr('type') == 'image') {
                    try {
                        bup.removeAttr('type');
                        bup.attr('type', 'button');
                    } catch (ex) {
                        // IE fix
                        bup.each(function() {
                            this.removeAttribute('type');
                            this.setAttribute('type', 'button');
                        });
                    }
                }
                //bup.click(function(){stepper(self.options.step);});
                bup
                /*.bind('mousedown', function(){
                self.mousedown(100, self.options.step);
                })
                .bind('mouseup', function(e){
                self.mouseup(e);
                })*/
				.bind('click', function(e) {
				    self.spin(self.options.step);
				})
				.bind('keyup', function(e) {
				    var keynum = (window.event ? event.keyCode : (e.which ? e.which : null));
				    switch (keynum) {
				        // (prev object) 
				        case self.keys.UP:
				        case self.keys.LEFT:
				            textbox.focus(); break;
				        // (next object) 
				        case self.keys.DOWN:
				        case self.keys.RIGHT:
				            bdn.focus(); break;
				    }
				})
			;

                // convert button type to button to prevent form submission onclick
                if (bdn.attr('type') == 'submit') {
                    try {
                        bdn.removeAttr('type');
                        bdn.attr('type', 'button');
                    } catch (e) {
                        // IE fix
                        bdn.each(function() {
                            this.removeAttribute('type');
                            this.setAttribute('type', 'button');
                        });
                    }
                }
                bdn
                /*.bind('mousedown' ,function(){
                self.mousedown(100, -self.options.step);
                })
                .bind('mouseup', function(e){
                self.mouseup(e);
                })*/
				.bind('click', function(e) {
				    self.spin(-self.options.step);
				})
				.bind('keyup', function(e) {
				    var keynum = (window.event ? event.keyCode : (e.which ? e.which : null));
				    switch (keynum) {
				        // (prev object) 
				        case self.keys.UP:
				        case self.keys.LEFT:
				            bup.focus();
				            break;
				        // (next object) 
				        case self.keys.DOWN:
				        case self.keys.RIGHT:
				            break;
				    }
				})
			;
            });
        },

        spin: function(val) {
            var textbox = this.element[0].textbox;
            if (textbox == undefined)
                return false;

            if (val == undefined || isNaN(val))
                val = 1;

            var textboxVal = this.value(textbox.val());
            textboxVal = parseFloat(textboxVal) + parseFloat(val);

            if (isNaN(textboxVal)) textboxVal = this.options.start;
            if (textboxVal < this.options.min) textboxVal = this.options.min;
            if (textboxVal > this.options.max) textboxVal = this.options.max;

            textbox.val(this.format(textboxVal));
            this.element[0].value = textboxVal;
        },

        number: function(num, dec) {
            return Math.round(parseFloat(num) * Math.pow(10, dec)) / Math.pow(10, dec);
        },

        currency: function(num) {
            var s = this.number(num, 2).toString();
            var dot = parseInt(s).toString().length + 1;
            s = s + ((s.indexOf('.') == -1) ? '.' : '') + '0000000001';
            s = s.substr(0, dot) + s.substr(dot, 2);
            return this.options.symbol + s;
        },

        value: function(val) {
            val = val.toString();
            return (this.options.format == 'currency') ? val.slice(this.options.symbol.length, val.length) : val;
        },

        format: function(val) {
            return (this.options.format == 'currency') ? this.currency(val) : this.number(val, this.options.decimals);
        },
        /*
        mousedown: function(i, val) {
        var self = this;
        i = i || 100;
        if(this.timer) window.clearInterval(this.timer);
        this.timer = window.setInterval(function() {
        self.spin(val);
        if(self.counter > 20) self.mousedown(20, val);
        }, i);
        },

	mouseup: function(e) {
        this.counter = 0;
        if(this.timer) 
        window.clearInterval(this.timer);
        this.propagate("change", e);
        },*/

        keydown: function(e) {
            if (this.upKey(e.keyCode)) this.spin(this.options.step);
            if (this.downKey(e.keyCode)) this.spin(-this.options.step);
            return this.allowedKey(e.keyCode);
        },

        upKey: function(key) {
            return (key === this.keys.UP || key === this.keys.PGUP) ? true : false;
        },

        downKey: function(key) {
            return (key === this.keys.DOWN || key === this.keys.PGDN) ? true : false;
        },

        allowedKey: function(key) {
            // add support for numeric keys 0-9
            if (key >= 96 && key <= 105) {
                key = 'NUMPAD';
            }

            switch (key) {
                case this.keys.TAB:
                case this.keys.BACK:
                case this.keys.LEFT:
                case this.keys.RIGHT:
                case this.keys.PERIOD:
                case this.keys.MINUS:
                case this.keys.NUMPAD_DECIMAL:
                case this.keys.NUMPAD_SUBTRACT:
                case 'NUMPAD':
                    return true;
                default:
                    return (/[0-9\-\.]/).test(String.fromCharCode(key));
            }
        },

        propagate: function(n, e) {
            $.ui.plugin.call(this, n, [e, this.ui()]);
            return this.element.triggerHandler(n == "step" ? n : "step" + n, [e, this.ui()], this.options[n]);
        }

    });

    $.ui.stepper.defaults = {
        min: 0,
        max: 10,
        step: 1,
        start: 0,
        decimals: 0,
        format: '',
        symbol: '$'
    };

})(jQuery);
