(function($) {

    $.fn.numericmask = function(allowDecimal, allowNegative) {

        return this.each
			(
				function() {
				    var valid = "1234567890";  // Characters that are valid, DIGITS only
				    if (allowDecimal) {
				        valid += "."; // add "." to valid inputs if "allowDecimal" is true
				    }
				    if (allowNegative) {
				        valid += "-";    // add "-" to valid inputs if "allowNegative" is true
				    }
				    /* event.keyCodes for keys such as Backspace, Delete, Tab, left+right arrows. Add more to this string in the format '<number>|'
				    for example to add keyCode 112, add '122|' to the end of the string so it becomes "|8|9|46|39|37|112|"     */
				    var otherKeys = "|8|9|46|39|37|";

				    $(this).keypress
						(
							function(event) {

							    var textInputString = $(this).val().toString();     //Get the current value of the input

							    var precision = $(this).attr("maxLength") ? $(this).attr("maxLength") : 0;  // Variable for the precision of the field (Total sum of DIGITS)
							    var scale = 0;  // Variable of the scale of the field, default to 0, will be set if allowDecimal is true (number of digits allowed after a ".")

							    /* Initialize precision and/or scale variables, depending on allowDecimal and allowNegative settings
							    All combinations of allowDecimal and allowNegative should be taken care of, assming the correct maxLength is given to the controls input
							    true, true == precision+2, true, false and false, true = precision+1, false, false = precision+0.
							    there should be +1 given to maxLength for each true value that is passed into numericmask for that controls input.  */
							    if (allowDecimal) {
							        precision -= 1; //subtract 1 from the maxLength to reserve space for the "." character
							        if ($(this).attr("scale")) {
							            scale = $(this).attr("scale"); // Get the scale for the decimal
							        }
							    }
							    if (allowNegative) {
							        precision -= 1; //subtract 1 from the maxLength to reserve space for the "-" character when entered before digits
							    }

							    // Get the string value of the input character
							    if (!event.charCode) {
							        input = String.fromCharCode(event.which);
							    }
							    else {
							        input = String.fromCharCode(event.charCode);
							    }
							    /* //debug input and if its valid etc
							    alert(input + " " + valid + " " + valid.indexOf(input)); */

							    //if the 'input' is not valid, dont allow input
							    if (valid.indexOf(input) != -1) {
							        // Detect if a selection has been made
							        if (getSelectedText($(this).get(0))) {
							            // Do behaviour is there is a selection
							            if (input == '-' || input == '.') {
							                //Do behaviour if there is a FULL selection
							                if (getSelectedText($(this).get(0)) == $(this).val()) {
							                    if (document.selection) {
							                        document.selection.clear();
							                    }
							                    $(this).val(input);
							                    event.preventDefault();
							                    //Do behaviour if there is a PARTIAL selection
							                } else {
							                    if (input == '-' || input == '.') {
							                        event.preventDefault();
							                    }
							                }
							            }
							        } else {
							            // Do behaviour if there isnt a selection

							            //if the input is a negative characer '-' carry out negative specific actions
							            if (input == '-') {
							                if (textInputString.indexOf(input) == -1) {
							                    $(this).val(input + textInputString);     //No existing minus character so add it before the existing value
							                }
							                else {
							                    $(this).val(textInputString.replace("-", ""));   //value already has a minus character so remove it
							                }
							                event.preventDefault();
							            }
							            //if the input is a decimal characer '.' carry out decimal specific actions
							            else if (input == '.') {
							                if (textInputString.indexOf(input) == -1) {
							                    $(this).val(textInputString + input);     //No existing decimal character so place one at the end of the current value
							                }
							                event.preventDefault();
							            }

							            /*  Split the inputs value into 2 strings val_array[0] = left of decimal and val_array[1] = right of decimal strings
							            If no decimal is found val_array[0] will be the only string returned from the .split() */
							            var val_array = textInputString.split(".");

							            //Check the value to the right of the decimal has a length within its scale length limit.
							            if ((textInputString.indexOf(".") != -1) && (getInputPosition($(this).get(0)) > textInputString.indexOf("."))) {
							                if ((val_array[1] != null) && !(val_array[1].length < scale)) {
							                    event.preventDefault();
							                }
							            }
							            //check the value to the left of the decimal (or the full value if there's no decimal) has a length within its (precision - scale) length limit
							            else {
							                if (!(val_array[0].replace("-", "").length < (precision - scale))) {
							                    event.preventDefault();
							                }
							            }
							        }
							    }
							    else {
							        // First make sure we're not going to block any essential keys (Enter = 13, add more if/when needed)
							        if (event.keyCode != 13) 
							        {
							            /*  input was invalid so prevent default unless it is a 'Special' key (delete, arrows, tab etc)
							            prevent default if we're in Internet Explorer anyway, 'special' keys do not fire the KeyPress event so will work regardless. */
							            if ($.browser.msie) {
							                event.preventDefault();
							            }
							            else {
							                // prevent default unless a keyCode (Special key - delete, arrows etc) defined in otherKeys has not been pressed
							                if ((otherKeys.indexOf("|" + event.keyCode + "|") == -1)) {
							                    event.preventDefault();
							                }
							            }
							        }
							    }
							}
						);
				    $(this).bind("blur", blur);
				    $(this).blur();
				});
    };

    function getSelectedText(textinput) {
        if (window.getSelection) {
            var len = textinput.value.length;
            var start = textinput.selectionStart;
            var end = textinput.selectionEnd;
            return textinput.value.substring(start, end);
        }
        else if (document.getSelection) {
            return document.getSelection();
        }
        else if (document.selection) {
            return document.selection.createRange().text; ;
        }
    }


    //Function for finding the position of the input cursor in an input field
    //Browser specific
    function getInputPosition(textinput) {
        // Mozilla/DOM 3.0
        if ('selectionStart' in textinput) {
            return textinput.selectionStart;
            // Explorer
        } else if (document.selection) {
            var r = document.selection.createRange();
            if (r == null) {
                return 0;
            }
            var re = textinput.createTextRange();
            var rc = re.duplicate();
            re.moveToBookmark(r.getBookmark());
            rc.setEndPoint('EndToStart', re);
            return rc.text.length;
        } else {
            return 0;
        }
    }

    function blur() {
        scale = $(this).attr("scale");
        var val_array = $(this).val().toString().split(".");
        if ($(this).val().indexOf(".") != -1) {
            //if it does have a ".", a full or partial decimal has been entered
            if (val_array[1].length < scale) {
                while (val_array[1].length < scale) {
                    val_array[1] += "0";
                }
            }
            else if (val_array[1].length > scale) {
                val_array[1] = val_array[1].substr(0, scale);
            }
            $(this).val(val_array[0] + "." + val_array[1]);
        }
        else {
            //if it doesnt have a ".", no decimal entered at all, so pad with <scale> amount of 0's
            padding = "";
            if ($(this).val().length > 0 && scale > 0) {
                $(this).val($(this).val() + ".");
                while (padding.length < scale) {
                    padding += "0";
                }
            }
            $(this).val($(this).val() + padding);
        }
    }

})(jQuery);

