// kanu did that
(function( $ ) {
var INPTOPTS = 'InputOpts', NUMOPTS = 'NumberOpts', VAL = 'value', ACTIVE = 'active', KEYDOWN = 40, KEYUP = 38;
var FNC_COUNT = 0
var FOR_ELEMENT;
function NumberFromString(val,opts){
    if (typeof val != 'string') {return val};
    var opts = $.extend({},NumberInput.number_defaults,opts);
    var comma_seperator = opts.comma_seperator || '.';
    var kilo_seperator = opts.kilo_seperator || ',';
    val = val.split(kilo_seperator).join('').split(comma_seperator).join('.')
    return Number(val)
}
function NumberToString(val,opts){
    if (val == null) { return ''; };
    if (typeof val != 'number' || isNaN(val)) {return val};
    var opts = $.extend({},NumberInput.number_defaults,opts);
    var precision = opts.precision || 0;
    var comma_seperator = opts.comma_seperator || '.';
    var kilo_seperator = opts.kilo_seperator || '';
    // var valparts = val.toString().split('.');
    var valparts = val.toFixed(precision).split('.')
    var floor = valparts[0];
    var fract = valparts[1] || '';
    while (fract.length < precision){fract += '0';}

    if (kilo_seperator && floor.length > 3){
        var pattern = /(\d+)(\d{3}.*?)$/;
        while (r = pattern.exec(floor) ){ floor = r[1]+ kilo_seperator +r[2]};
    }

    return (precision <= 0)? floor : floor + comma_seperator + fract.substr(0,precision);
}

NumberInput = {
    defaults: {
        // use_steps : true,
        incr : 10,
        meta_modifier: 0.1,
        shift_modifier: 10,
        max_value : null,
        min_value : null
    },
    number_defaults : {
        comma_seperator : '.',
        kilo_seperator : ',',
        precision : 2
    },
    inputs : $(),
    set_defaults : function(opts){
        $.extend(this.defaults,opts);
        return this;
    },
    set_number_defaults : function(opts){
        $.extend(this.number_defaults,opts);
        return this;
    },
    destroy :function(){
      this.inputs = $();  
    },

    NumberToString : NumberToString,
    NumberFromString : NumberFromString
}

$.fn.NumberInput = function(opts){
    var opts = opts || {};
    var number_opts = opts.number || {}
    var input_opts = opts.input || {}

    this.each(function(){
        var self = $(this);
        var numopts = $.extend({},NumberInput.number_defaults,number_opts);
        self.data(NUMOPTS,numopts);
        self.data(INPTOPTS,$.extend({},NumberInput.defaults,opts));
        self.data(VAL,NumberFromString(self.val(),numopts));
        self.css('text-align','right')
        NumberInput.inputs = NumberInput.inputs.add(self)
    });
    this.not(':disabled').bind({
        focus: function(e){
            var self = $(this);
            self.data(ACTIVE,true)
            var val = self.data(VAL);
            if (isNaN(val) || val == null) {return} 
            else {
                var opts = $.extend({},self.data(NUMOPTS),{kilo_seperator:''});
                self.val(NumberToString(val,opts));
            };
        },
        blur: function(e){
            var self = $(this).unbind('mousemove.number');
            var val = self.data(VAL);
            if (isNaN(val)){self.addClass('error')} 
            else if (typeof val == 'number') {
                self.removeClass('error')
                self.val(NumberToString(val,self.data(NUMOPTS)));
            }
            else { self.removeClass('error')}
            self.data(ACTIVE,false)
        },
        change : function(e,val){
            var self = $(this);
            var val = (!val==undefined)? val : NumberFromString(self.val(),self.data(NUMOPTS));
            if (val != self.getnumber()) {
                 self.data(VAL,val);
                 self.trigger('changed.number');
            }
            return self;
        },
        keypress : function(e){
            switch (e.keyCode ){
                case KEYDOWN:
                    var incr = -1;
                    e.preventDefault()
                    break;
                case KEYUP :
                    incr = 1;
                    e.preventDefault()
                    break;
                default:
                    break;
            }
            if (incr) {
                var self = $(this);
                var numopts = self.data(NUMOPTS);
                var val = NumberFromString(self.val(),numopts);
                if (isNaN(val) || val == null ){return};
                
                var inptopts = self.data(INPTOPTS);
                
                if (e.metaKey){ incr = incr * inptopts.meta_modifier;}
                else if (e.shiftKey){ incr = incr * inptopts.shift_modifier; }
                val += (incr* inptopts.incr)/Math.pow(10,numopts.precision);
                self.setnumber(val).select();
            }
        },
        keyup : function(e){
            $(this).trigger('change');
        },
        keydown : function(e){
            // need to implement for safari, chrome and iE 
            // because cursor keys are not delivered by the keypress event
        }
    });
    return this;
}
$.fn.setnumber = function(val){
    var number;
    switch (typeof val) {
        case 'number' : 
            number = val;
            break;
        case 'string' : 
            number = NumberFromString(val,NumberFromString(val,NumberInput.number_defaults));
            break;
        case 'undefined' :
            number = null;
            break;
        default:
            number = (val == null)? null : NaN;
            break;
    }
    var changed = $();
    this.each(function(){
        var self = $(this);
        var opts = self.data(NUMOPTS);
        if (self.data(ACTIVE)){
            opts = $.extend({},opts,{kilo_seperator:''})
        }
        if (isNaN(number)) {
            if (self.data(VAL) != val){
                self.data(VAL,val);
                self.trigger('changed.number');
            }
        } else {
            if (self.data(VAL) != number){
                self.data(VAL,number);
                self.trigger('changed.number');
            }
        }
        self.val(NumberToString(number,opts))

    })
    return this
};
$.fn.getnumber = function(){
    return this.data(VAL);
};
$.fn.getnumber_fmt = function(opts){
    return NumberToString(this.getnumber(),$.extend({},this.data(NUMOPTS),opts));
};

$.NumberInput = NumberInput;
}( jQuery ) );
