/**
 * Base class for controls FloatEdit, IntegerEdit
 * @abstract
*/
Ext.define("Terrasoft.controls.NumberEdit", {
	extend: "Terrasoft.BaseEdit",

	alternateClassName: "Terrasoft.NumberEdit",

	/**
  * A string that contains a list of characters that can be entered from the keyboard
  * @protected
  * @type {String}
  */
	baseCharsRe: null,

	/**
  * Number entry pattern
  * @protected
  * @type {RegExp}
  */
	numberRe: null,

	/**
  * Template of separators of integer and fractional part
  * @protected
  * @type {RegExp}
  */
	decimalSeparatorsRe: null,

	/**
  * Indicates if the division of numbers of numbers is used
  * @type {Boolean}
  */
	useThousandSeparator: true,

	/**
  * Digit number separator
  * @type {Terrasoft.Resources.CultureSettings}
  */
	thousandSeparator: Terrasoft.Resources.CultureSettings.thousandSeparator,

	/**
  * The number of digits of a number without a separator
  * @type {Terrasoft.Resources.CultureSettings}
  */
	numberGroupSizes: Terrasoft.Resources.CultureSettings.numberGroupSizes,

	/**
  * @inheritdoc Terrasoft.controls.BaseEdit#init
  * @override
  */
	init: function () {
		this.callParent(arguments);
		var thousandSeparator = Ext.String.escapeRegex(this.thousandSeparator);
		this.thousandSeparatorRe = new RegExp(thousandSeparator, "g");
		this.displayNumberConfig = {
			decimalPrecision: this.decimalPrecision,
			decimalSeparator: this.decimalSeparator,
			useThousandSeparator: this.useThousandSeparator,
			thousandSeparator: this.thousandSeparator,
			numberGroupSizes: this.numberGroupSizes
		};
	},

	/**
  * Handler for focus element event.
  * After focus inner text formatted and align left.
  * @protected
  * @override
  */
	onFocus: function () {
		this.callParent(arguments);
		var el = this.getEl();
		if (el && el.dom && el.dom.value) {
			el.dom.select();
		}
		if (this.validationInfo.isValid === false) {
			return;
		}
		this.formatDomValue();
	},

	/**
  * Format value for dom element.
  * @private
  */
	formatDomValue: function () {
		var value = this.getTypedValue();
		var el = this.getEl();
		var domEl = el && el.dom;
		if (Ext.isEmpty(value) || !domEl) {
			return;
		}
		value = value.replace(this.thousandSeparatorRe, "");
		var numericValue = this.parseNumber(value);
		var config = Terrasoft.deepClone(this.displayNumberConfig);
		Ext.apply(config, {
			thousandSeparator: ""
		});
		domEl.value = Terrasoft.getFormattedNumberValue(numericValue, config);
	},

	/**
  * @inheritdoc Terrasoft.controls.BaseEdit#onEnterKeyPressed
  * @override
  */
	onEnterKeyPressed: function () {
		var value = this.getTypedValue();
		var numericValue = this.parseNumber(value);
		var hasChanges = this.changeValue(numericValue);
		this.fireEvent("enterkeypressed", this);
		if (!hasChanges) {
			this.fireEvent("editenterkeypressed", this);
		}
	},

	/**
  * The handler for the event when an element looses focus.
  * When the focus is received, the text inside the element is formatted and aligned to the right
  * @protected
  * @override
  */
	onBlur: function () {
		var el = this.getEl();
		var value = this.getTypedValue();
		var numericValue = this.parseNumber(value);
		el.dom.value = this.getFormattedNumberValue(numericValue);
		this.changeValue(numericValue);
		this.focused = false;
		this.fireEvent("blur", this);
		this.fireEvent("focusChanged", this);
	},

	/**
  * Initializes data for the template and updates the selectors
  * @override
  * @protected
  * @return {Object}
  */
	getTplData: function () {
		var tplData = this.callParent(arguments);
		var value = this.getTplValue();
		tplData.value = value;
		tplData.wrapClass.push("number-edit-align");
		tplData.editInputClass.push("number-edit-input-align");
		return tplData;
	},

	/**
  * Formats the value to display
  * @override
  * @protected
  * @return {String} formatted string
  */
	getTplValue: function () {
		var value = this.value;
		if (Ext.isEmpty(value)) {
			return "";
		}
		if (this.validationInfo.isValid === true) {
			this.value = this.parseNumber(value);
			return this.getFormattedNumberValue(value);
		}
	},

	/**
  * Handler for key press.
  * Prevents typing of prohibited symbols or values from keyboard that are not match the pattern numberRe.
  * The second parameter specifies the event processing mode.
  * @protected
  * @override
  * @param  {Event} e DOM event keypress.
  * @param  {String} type (optional) If param not set then processed both the integer, else param is
  * {@link Terrasoft.DataValueType.FLOAT} then both double.
  */
	onKeyPress: function (e, type) {
		this.callParent(arguments);
		if (this.readonly || !this.enabled) {
			return;
		}
		var isSpecialKey = Ext.isGecko && e.isSpecialKey();
		if (isSpecialKey) {
			return;
		}
		e.preventDefault();
		var keyUnicode = e.getKey();
		var key = String.fromCharCode(keyUnicode);
		var isDeprecated = this.baseCharsRe && !this.baseCharsRe.test(key);
		if (isDeprecated) {
			return;
		}
		var domEl = e.getTarget();
		var selectedTextLength = Terrasoft.utils.dom.getSelectedTextLength(domEl);
		if (type === Terrasoft.DataValueType.FLOAT && this.decimalSeparatorsRe.test(key)) {
			key = this.decimalSeparator;
		}
		var value = domEl.value;
		var caretPosition = Terrasoft.utils.dom.getCaretPosition(domEl);
		var valueBeforeCaret = "";
		var valueAfterCaret = "";
		if (Ext.isIE && !Ext.isIE11) {
			valueBeforeCaret = value.slice(0, caretPosition - selectedTextLength);
			valueAfterCaret = value.slice(caretPosition);
			caretPosition -= selectedTextLength;
		} else {
			valueBeforeCaret = value.slice(0, caretPosition);
			valueAfterCaret = value.slice(caretPosition + selectedTextLength);
		}
		var newValue = valueBeforeCaret + key + valueAfterCaret;
		isDeprecated = this.numberRe && !this.numberRe.test(newValue);
		if (isDeprecated) {
			return;
		} else {
			caretPosition += 1;
			domEl.value = newValue;
			Terrasoft.utils.dom.setCaretPosition(domEl, caretPosition);
		}
	},

	/**
  * Sets the value of the control
  * @param {Number/String} value - the value to set
  */
	setValue: function (value) {
		var numericValue = this.parseNumber(value);
		var isChanged = this.changeValue(numericValue);
		if (this.rendered && isChanged) {
			var domValue = this.focused === true ? value : this.getFormattedNumberValue(value);
			this.setDomValue(domValue);
		}
	},

	/**
  * Converts a string value to a number with the second parameter, if type is equal to Terrasoft.DataValueType.INTEGER
  * the method returns an integer,
  * if type is Terrasoft.DataValueType.FLOAT method will return a floating-point number.
  * If the value parameter is a number the function will return it without conversion.
  * @protected
  * @param  {String/Number} value The string you want to convert to a number
  * Terrasoft.DataValueType.INTEGER and Terrasoft.DataValueType.FLOAT
  * @return {Number} number after the conversion of the input string
  */
	parseNumber: function (value) {
		return Terrasoft.parseNumber(value, this.displayNumberConfig);
	},

	/**
  * The method formats the string / number according to the specified configuration object.
  * @protected
  * @param  {Number/String} value Number to format
  * @return {String} Formatted string
  */
	getFormattedNumberValue: function (value) {
		var config = Ext.apply({}, this.displayNumberConfig);
		return Terrasoft.getFormattedNumberValue(value, config);
	}

});