"use strict";

function InputDecimal(elInput, nMaxDecimals)
{
	this._elInput = elInput;
	this.nMaxDecimals = nMaxDecimals;

	var _self = this;

	if(this._elInput)
	{
		if(this._elInput.getAttribute("InputDecimal") == "true")
			return;
		this._elInput.setAttribute("InputDecimal", "true");

		//this._elInput.setAttribute("type", "numeric"); // Force numpad keyboard on some mobile phones.
		//this._elInput.setAttribute("pattern", "\\d*"); // Force numpad keyboard on some mobile phones.


		var _onEventValidateDelayed = function()
		{
			setTimeout(function(){_self.colorizeInvalid();}, 50);
		};
		this._elInput.addEventListener("paste", _onEventValidateDelayed);
		this._elInput.addEventListener("cut", _onEventValidateDelayed);
		this._elInput.addEventListener("drop", _onEventValidateDelayed);
	
		this._elInput.addEventListener(
			"keyup",
			function()
			{
				_self.colorizeInvalid();
			}
		);
		this._elInput.addEventListener(
			"focus", 
			function(e)
			{
				if (_self.isValid())
				{
					if (parseInt(_self.toNumber() * Math.pow(10, _self.nMaxDecimals)) == 0 && _self._elInput.setSelectionRange)
						setTimeout(function (e) { _self._elInput.setSelectionRange(0, _self._elInput.value.length); }, 100);
				}
				else if (!_self.bAllowZero && _self._elInput.value.substr(0, 1) != "-" && parseFloat(_self._elInput.value) == 0.0000)
				{
					_self._elInput.value = "";
				}
			}
		);

		this._elInput.addEventListener(
			"change",
			function(e)
			{
				_self.format();
				_self.colorizeInvalid();
			}
		);

		this._elInput.addEventListener(
			"blur",
			function(e)
			{
				// if (_self._elInput.value.trim() == "")
				// {
				// 	var bAllowZeroSaved = _self.bAllowZero;
				// 	_self.bAllowZero = true;
				// 	_self.setFinancialNumber(0);
				// 	_self.bAllowZero = bAllowZeroSaved;

				// 	if (!_self.bAllowPositive && _self._elInput.value.substr(0, 1) != "-")
				// 	{
				// 		_self._elInput.value = "-" + _self._elInput.value;
				// 	}
				// }

				_self.format();
				_self.colorizeInvalid();

				if(_self._bTriggerOnChange)
				{
					if(_self._elInput.onchange)
						_self._elInput.onchange();
					_self._bTriggerOnChange=false;
				}
			}
		);

		this._elInput.addEventListener(
		"keydown",
		function(e)
		{
			if(!_self._elInput.setSelectionRange)
				return;
			
			var strCharacter;
			if(
				typeof InputDecimal.DECIMAL_SEPARATOR=="string"
				&& (
					(e.key && (e.key=="." || e.key==",") && e.key!=InputDecimal.DECIMAL_SEPARATOR)
					|| (e.char && (e.char=="." || e.char==",") && e.char!=InputDecimal.DECIMAL_SEPARATOR)
					|| (e.keyCode && ((e.keyCode==188 && InputDecimal.DECIMAL_SEPARATOR!=",") || (InputDecimal.DECIMAL_SEPARATOR=="," && (e.keyCode==190 || e.keyCode==110))))
				)
			)
				strCharacter=InputDecimal.DECIMAL_SEPARATOR;
			else if(
				(e.key && e.key=="-")
				|| (e.char && e.char=="-")
				
				//189 is not the minus sign on all keyboard layouts, 
				//yet this should do for most cases (as whatever character replaces it, it shouldn't have been pressed anyways)
				|| (e.keyCode && (e.keyCode==109 || e.keyCode==189)) 
			)
				strCharacter="-";
			else
				return;
			
			if(e.preventDefault) e.preventDefault();
			if(e.stop) e.stop();
			if(e.returnValue) e.returnValue=false;
			if(e.stopPropagation) e.stopPropagation();
			
			if(strCharacter==InputDecimal.DECIMAL_SEPARATOR)
			{
				var selectionStart=_self._elInput.selectionStart;
				_self._elInput.value=_self._elInput.value.substr(0, _self._elInput.selectionStart)+InputDecimal.DECIMAL_SEPARATOR+_self._elInput.value.substr(_self._elInput.selectionEnd);
				_self._elInput.setSelectionRange(selectionStart+1, selectionStart+1);
			}
			else if(strCharacter=="-")
			{
				var selectionStart=_self._elInput.selectionStart;
				var selectionEnd=_self._elInput.selectionEnd;
				var bWasNegative=_self._elInput.value.length>0 && _self._elInput.value.substr(0, 1)=="-";
				
				if(bWasNegative)
					_self._elInput.value=_self._elInput.value.substr(1);
				else
					_self._elInput.value="-"+_self._elInput.value;
				
				_self._elInput.setSelectionRange(selectionStart+(bWasNegative?-1:1), selectionEnd+(bWasNegative?-1:1));
				
				_self._bTriggerOnChange=true;
			}
		}
		);
		if(_self._elInput.value.trim() == "")
			_self._elInput.value = "0";
		
		_self.format();
		_self.colorizeInvalid();
	}
}

InputDecimal.prototype =
{
	/**
	 * @var Number
	 */
	nColorError: 0xff0000,
	
	
	/**
	 * @var HTMLInputElement
	 */
	_elInput: null,
	
	
	/**
	 * @var Number
	 */
	nMaxDecimals: 2,
	
	
	/**
	 * @var Boolean
	 */
	bAllowNegative: true,
	
	
	/**
	 * @var Boolean
	 */
	bAllowPositive: true,
	
	
	/**
	 * @var Boolean
	 */
	bAllowZero: true,
	
	
	/**
	 * @var Boolean
	 */
	_bTriggerOnChange: false,
	
	
	/**
	 * @var Number
	 */
	fMaxValue: Number.MAX_VALUE,

	
	/**
	 * @var Number
	 */
	fMinValue: Number.MIN_VALUE,


	/**
	 * @returns {HTMLInputElement}
	 */
	input: function()
	{
		return this._elInput;
	},
	
	
	isValid: function()
	{
		if((typeof this._elInput.value !== "string") || this._elInput.value.trim()==="")
			return false;

		var strValue = this._elInput.value.trim().replace(/[,]/g, ".").replace(/[\s]/g, "");
		
		//this will exclude exponential notation
		if(! ((/^[-]{0,1}[0-9.]{1,16}$/).test(strValue)) )
			return false;
		
		if(strValue == "")
			return false;
		
		if(strValue.substr(0, 1) == "-" && !this.bAllowNegative)
			return false;

		if (strValue.substr(0, 1) != "-" && !this.bAllowPositive)
			return false;

		if (strValue.substr(0, 1) != "-" && parseFloat(strValue) == 0.0000 && !this.bAllowZero)
			return false;
		if (strValue.substr(0, 1) == "-" && parseFloat(strValue.substr(1)) == 0.0000 && !this.bAllowZero)
			return false;
			
		if(strValue.split(".").length == 2)
		{
			var strInteger = strValue.split(".")[0];
			
			var strDecimals = strValue.split(".")[1];
			if(!strDecimals)
				strDecimals = "";
			
			while(strDecimals.length > 0 && strDecimals.substr(strDecimals.length - 1) == "0")
				strDecimals=strDecimals.substr(0, strDecimals.length - 1);
			
			if(strDecimals.length > this.nMaxDecimals || strInteger.length == 0 || (strInteger.length == 1 && strInteger == "-"))
				return false;
		}
		else if(strValue.split(".").length > 2)
			return false;
		
		
		if(strValue.split("-").length > 2)
			return false;
		if(strValue.split("-").length == 2 && strValue.substr(0, 1) != "-")
			return false;
		
		if(isNaN(parseFloat(strValue)))
			return false;
		
		if(parseFloat(strValue)>this.fMaxValue)
			return false;
		if(parseFloat(strValue)<this.fMinValue && this.fMinValue!=Number.MIN_VALUE)
			return false;
		
		return true;
	},
	
	toNumber: function(){
		if(!this.isValid())
			throw new Error("Value cannot be converted to Number because it does not pass validation (" + this._elInput.value + ").");
		
		return parseFloat(this._elInput.value.trim().replace(/[,]/g, ".").replace(/[\s]/g, ""));
	},
	
	toStringNumber: function()
	{
		if(!this.isValid())
			throw new Error("Value cannot be converted to StringNumber because it does not pass validation (" + this._elInput.value + ").");
		
		var strValue = this._elInput.value.trim().replace(/[,]/g, ".").replace(/[\s]/g, "");

		var strInteger = strValue.split(".")[0];
		
		var strDecimals = strValue.split(".")[1];
		if(!strDecimals)
			strDecimals = "";
		
		while(strDecimals.length > 0 && strDecimals.substr(strDecimals.length - 1) == "0")
			strDecimals = strDecimals.substr(0, strDecimals.length - 1);
		strDecimals = (strDecimals + new Array(this.nMaxDecimals+1).join("0")).substr(0, this.nMaxDecimals);
		
		if(this.nMaxDecimals)
			return strInteger + "." + strDecimals;
		return strInteger;
	},
	
	toFinancialNumber: function()
	{
		var strValue = this.toStringNumber().replace(/[.]/g, "");
		
		while(strValue.substr(0, 1) == "0" && strValue.length > 1)
			strValue = strValue.substr(1);
			
		return parseInt(strValue);
	},
	
	setFinancialNumber: function(nValue)
	{
		var strValue = parseInt(Math.round(nValue)).toString();
		
		var bNegative = false;
		if(strValue.substr(0, 1) == "-")
		{
			bNegative=true;
			strValue=strValue.substr(1);
		}
		
		if(strValue.length>this.nMaxDecimals)
			strValue=strValue.substr(0, strValue.length-this.nMaxDecimals)+"."+strValue.substr(strValue.length-this.nMaxDecimals);
		else
			strValue="0."+(new Array(this.nMaxDecimals-strValue.length+1).join("0")+strValue).substr(0, this.nMaxDecimals);
		
		if(bNegative)
			strValue="-"+strValue;
		this._elInput.value=strValue;
		
		this.format();
		this.colorizeInvalid();
	},
	
	format: function()
	{
		if(!this.isValid())
			return;
			
		var strValue = this._elInput.value.trim().replace(/[,]/g, ".").replace(/[\s]/g, "");
		
		if(strValue.split(".").length==2)
		{
			var strDecimals=strValue.split(".")[1];
			if(!strDecimals)
				strDecimals="";
			
			while(strDecimals.length>0 && strDecimals.substr(strDecimals.length-1)=="0")
				strDecimals=strDecimals.substr(0, strDecimals.length-1);
			strDecimals=(strDecimals+new Array(this.nMaxDecimals+1).join("0")).substr(0, this.nMaxDecimals);
			
			strValue=strValue.split(".")[0]+(this.nMaxDecimals==0?"":"."+strDecimals);
		}
		else
			strValue=strValue+"."+new Array(this.nMaxDecimals+1).join("0");
		if(strValue.substr(strValue.length-1)==".")
			strValue=strValue.substr(0, strValue.length-1);
			
		
		var bNegative=false;
		if(strValue.substr(0, 1)=="-")
		{
			bNegative=true;
			strValue=strValue.substr(1);
		}
		
		while(strValue.substr(0, 1)=="0" && strValue.split(".")[0].length>1)
			strValue=strValue.substr(1);
		
		if(bNegative)
			strValue="-"+strValue;
		
		if(typeof InputDecimal.DECIMAL_SEPARATOR=="string")
			if(InputDecimal.DECIMAL_SEPARATOR.length==1)
				strValue=strValue.replace(/[.]/g, InputDecimal.DECIMAL_SEPARATOR);
		
		this._elInput.value=strValue;
	},
	
	colorizeInvalid: function()
	{
		if(this.isValid())
			this._elInput.style.color="";
		else
			this._elInput.style.color="#"+this.nColorError.toString(16);
	}
};

InputDecimal.DECIMAL_SEPARATOR = ".";
