Ext.define("IceCap.util.Handler", {

	singleton: true,

	config: {
		scaling: {
			colSize: 9.7,
			textSize: 16,
			defaultWidth: 18,
			defaultHeight: 24,
			lineHeight: 28
		},
		sessions: [],
		fixed: true,
		scaleSize: 14,
		marginValue: 4,
		scale: 1,
		serviceUrl: "/icecap/icecap.aspx",
		provider: null,
		measureItem: null,
		boldItem: null,
		normalWidth: 0,
		boldWidth: 0,
		changed: false,
		fontSizeValue: "14px",
		fieldRule: null,
		labelRule: null,
		windows: [],
		copyArea: null
	},

	FFW: {
		// FFW identification flag (0 - 1)
		// Bypass (2)
		// Dup or Field Mark Enable (3)
		//  Modified Data Tag (MDT) (4)
		// Field Shift/Edit Specification (5 - 7)
		// Auto Enter (8)
		// Field Exit Required (FER) (9)
		// Monocase (10)
		// Reserved (11)
		// Mandatory Enter (ME) (12)
		// Right Adjust/Mandatory Fill (MF) (13-15)
		IDENT_FLAG: (1 << 0),
		BYPASS: (1 << 1),
		DUP_OR_MARK: (1 << 2),
		MOD_DATA: (1 << 3),
		APLHA_SHIFT: (1 << 4),
		ALPHA_ONLY: (1 << 5),
		NUMERIC_SHIFT: (1 << 6),
		NUMERIC_ONLY: (1 << 7),
		KATAKANA_SHIFT: (1 << 8),
		DIGITS_ONLY: (1 << 9),
		IO_FEATURE: (1 << 10),
		SIGNED_NUMERIC: (1 << 11),
		AUTO_ENTER: (1 << 12),
		EXIT_REQ: (1 << 13),
		MONOCASE: (1 << 14),
		MAND_ENTER: (1 << 15),
		RA_NONE: (1 << 16),
		RA_ZEROFILL: (1 << 17),
		RA_BLANKFILL: (1 << 18),
		RA_FILL: (1 << 19),
		RA_RESERVED: (1 << 20),
		RA_MANDATORY: (1 << 21),
		RA_READONLY: (1 << 22)
	},

	typeMode: {
		OVERWRITE: 1,
		INSERT: 2,
		FOCUS: 3
	},

	requires: [
		"IceCap.state.local.Provider",
		"IceCap.state.session.Provider"
	],

	constructor: function(o_config) {

		var i_self = this;
		i_self.initConfig(o_config);

		if (!Ext.ClassManager.isCreated("IceCap.ux.container.GMapPanel")) {
			Ext.Loader.loadScriptsSync([
				"/icecap/app/ux-debug.js"
			]);
		}

		var i_provider = Ext.widget("icecap-state-local-provider", {});

		i_self.setProvider(i_provider);
		return this;
	},

	getPath: function(o_config) {

		var s_base = IceCap.util.Handler.getServiceUrl();
		var s_session = o_config.session;
		var s_activeTerminals = IceCap.util.Handler.getActiveTerminals();

		if (s_activeTerminals) {
			Ext.apply(o_config, {
				activeTerminals: s_activeTerminals
			});
		}

		return s_session + "" + s_base + "?" + Ext.urlEncode(o_config);
	},

	getX: function(n_col, n_scale) {

		n_scale = n_scale || 1;
		return Math.ceil(n_col * IceCap.util.Handler.getWidth(1, n_scale));
	},

	getY: function(n_lin, n_scale) {

		n_scale = n_scale || 1;
		return Math.ceil((n_lin -1) * IceCap.util.Handler.getHeight(1, n_scale));
	},

	toColAndLine: function(o_values, o_rules) {

		o_rules = o_rules || {
			fontScale: 1,
			lineScale: 1
		};

		var n_x = o_values.x;
		var n_y = o_values.y;

		var n_col = Math.ceil(n_x / IceCap.util.Handler.getWidth(1, o_rules.fontScale)) || 1;
		var n_lin = Math.ceil(n_y / IceCap.util.Handler.getHeight(1, o_rules.lineScale)) || 1;

		var o_position = Ext.apply({}, {
			col: n_col,
			lin: n_lin
		});

		return o_position;
	},

	getWidth: function (n_col, n_scale) {


		n_col = n_col || 1;
		n_scale = n_scale || 1;

		var i_self = this;
		var n_value = i_self.getColSize();
		
		n_value = n_value * n_scale;

		return n_value * n_col;
	},

	getHeight: function(n_lin, n_scale) {

		n_lin = n_lin || 1;
		n_scale = n_scale || 1;

		var i_self = this;
		var i_element = i_self.getMeasureItem();

		i_element.setHtml("W");

		var n_value = i_element.getHeight();

		n_value = n_value * n_scale;

		i_element.setHtml("");

		return n_value * n_lin;
	},

	getColSize: function(i_region) {

		var i_self = this;

		i_region = i_region || {};

		var n_value = i_self.getNormalWidth();

		if (i_region.isRegion) {

			var i_element = i_self.getMeasureItem();
			var i_elementBold = i_self.getBoldItem();

			var a_string = [];

			for (var i = 0; i < 100000; i++) {
				var s_value = "W";
				a_string.push(s_value);
			}

			var s_string = a_string.join("");
			var n_lenght = a_string.length;

			n_value = i_element.getTextWidth(s_string) / n_lenght;
			
			i_element.setStyle("font-size", "1em");
			i_element.setStyle("min-height", "22px");
			i_element.setStyle("line-height", "30px");

			i_elementBold.setStyle("font-size", "0.9286em");
			i_elementBold.setStyle("min-height", "22px");
			i_elementBold.setStyle("line-height", "30px");

			var n_width = i_region.width - 20;
			var n_height = i_region.height - 20;

			i_element.setHtml("W");

			var n_elementWidth = i_element.getWidth();

			var n_minWidth = n_elementWidth;

			i_element.setHtml("");

			if ((80 * n_minWidth) > n_width) {

				n_scale = Math.min(n_width / (80 * n_minWidth), (80 * n_minWidth) / n_width);
			}

			n_value = n_value * n_scale;

			i_self.setNormalWidth(n_value);

			n_value = i_elementBold.getTextWidth(s_string) / n_lenght;

			n_value = n_value * n_scale;

			i_self.setBoldWidth(n_value);

			n_value = i_self.getNormalWidth();
		}

		return n_value;
	},

	getBoldColSize: function() {

		var i_self = this;
		var n_value = Math.ceil(i_self.getBoldWidth());
		return n_value;
	},

	getLineHeight: function(b_true) {

		var i_self = this;
		var n_value;

		if (!b_true) {
			var i_element = i_self.getMeasureItem();

			i_element.setHtml("W");

			var n_value = i_element.getHeight();

			i_element.setHtml("");
		}
		else {
			var i_cssRule = i_self.getFieldRule();

			var o_style = i_cssRule.style;
			var s_minHeight = o_style.minHeight || "0px";
			n_value = parseFloat(s_minHeight.replace("px"));
		}

		return n_value;
	},

	getMargin: function() {
		return IceCap.util.Handler.getMarginValue();
	},

	getTextSize: function() {
		return IceCap.util.Handler.getDefaultWidth();
	},

	getDefaultWidth: function () {

		var i_self = this;
		var i_element = i_self.getMeasureItem();
		var n_value = i_element.getTextWidth("W");

		return n_value;
	},

	getDefaultHeight: function() {

		var i_self = this;
		var i_element = i_self.getMeasureItem();

		i_element.setHtml("W");

		var n_value = i_element.getHeight();

		i_element.setHtml("");
		return n_value;
	},

	getData: function(o_config, o_data, f_callback) {

		f_callback = f_callback || Ext.emptyFn;
		o_data = o_data || {};

		Ext.Ajax.request({
			url: IceCap.util.Handler.getPath(o_config),
			method: "POST",
			params: o_data,
			success: function(i_response, i_request) {

				var o_data = Ext.apply({}, {
					input: [],
					output: []
				});
				if (!Ext.String.startsWith(!i_response.responseText.toLowerCase(), "<html")) {

					Ext.USE_NATIVE_JSON = false; // DO THIS TO ALLOW THE PARSE OF FUNCTIONS

					o_data = Ext.decode(i_response.responseText, true) || Ext.apply({}, {
						input: [],
						output: []
					});

					//Ext.USE_NATIVE_JSON = true;
				}
				f_callback(o_data);
			},
			failure: function() {
				f_callback({
					input: [],
					output: []
				});
			}
		});
	},

	getNewSession: function(f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var s_activeTerminals = IceCap.util.Handler.getActiveTerminals();

		Ext.Ajax.request({
			url: IceCap.util.Handler.getServiceUrl() + "?activeTerminals=" + s_activeTerminals,
			method: "POST",
			success: function(i_response, i_request) {

				var o_data = Ext.decode(i_response.responseText, true) || Ext.apply({}, {
					success: false,
					session: ""
				});

				IceCap.util.Handler.addSession(o_data.session);

				f_callback(o_data);
			},
			failure: function(o_err) {

				var o_data = Ext.apply({}, {
					success: false,
					session: ""
				});
				f_callback(o_data);
			}
		});
	},

	useScale: function(n_scale) {

		var o_scale = IceCap.util.Scale.getFixed()[n_scale];

		if (o_scale) {
			IceCap.util.Handler.setScaling(o_scale);
		}
	},

	addSession: function(s_session) {

		var i_provider = IceCap.util.Handler.getProvider();

		var a_terminals = Ext.Array.from(i_provider.get("activeterminals"));
		var a_sessions = IceCap.util.Handler.getSessions() || [];

		var s_terminal = s_session.substring(s_session.length - 2);
		var n_terminal = parseFloat(s_terminal);

		if (isNaN(n_terminal)) {
			n_terminal = 0;
		}

		a_sessions.push(s_session);

		a_terminals.push(n_terminal);

		if (a_sessions.length != a_terminals.length) {

			a_terminals = [];

			Ext.Array.each(a_sessions, function(s_session) {

				var s_temp = s_session.substring(s_session.length - 2);
				var n_term = parseFloat(s_temp);

				if (isNaN(n_term)) {
					n_term = 0;
				}

				a_terminals.push(n_term);
			});
		}

		i_provider.set("activeterminals", a_terminals);


		IceCap.util.Handler.setSessions(a_sessions);
	},

	getActiveTerminals: function() {

		var i_provider = IceCap.util.Handler.getProvider();

		var a_terminals = Ext.Array.from(i_provider.get("activeterminals"));

		if (a_terminals.length === 0) {
			a_terminals.push(0);
		}

		return a_terminals.join(",");
	},

	removeSession: function(s_session) {

		var i_provider = IceCap.util.Handler.getProvider();

		var a_terminals = Ext.Array.from(i_provider.get("activeterminals"));

		var s_terminal = s_session.substring(s_session.length - 2);
		var n_terminal = parseFloat(s_terminal);

		if (isNaN(n_terminal)) {
			n_terminal = 0;
		}

		if (n_terminal) {
			Ext.Array.remove(a_terminals, n_terminal);
		}

		i_provider.set("activeterminals", a_terminals);

		var a_sessions = IceCap.util.Handler.getSessions() || [];

		Ext.Array.remove(a_sessions, s_session);

		IceCap.util.Handler.setSessions(a_sessions);
	},

	isSessionAlive: function(s_session, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		IceCap.util.Handler.addSession(s_session);

		Ext.Ajax.request({
			url: IceCap.util.Handler.getServiceUrl() + "?activeTerminals=" + IceCap.util.Handler.getActiveTerminals(),
			method: "POST",
			params: {
				isSessionAlive: s_session
			},
			success: function(i_response, i_request) {

				var o_result = Ext.decode(i_response.responseText, true) || Ext.apply({}, {
					success: false,
					message: ""
				});

				f_callback(o_result.success);
			},
			failure: function(o_err) {

				IceCap.util.Handler.removeSession(s_session);

				var o_result = Ext.apply({}, {
					success: false,
					session: ""
				});

				f_callback(o_result.success);
			}
		});
	},

	getScalingObject: function() {

		var b_fixed = IceCap.util.Handler.getFixed();
		var o_return = IceCap.util.Handler.getScaling();
		var n_scale = IceCap.util.Handler.getScaleSize();
		if (!b_fixed) {
			var o_free = IceCap.util.Scale.getFree()[n_scale];
			if (o_free) {
				o_return = o_free;
			}
		}

		return o_return;
	},

	createWindow: function(o_config) {

		var o_icecap = {
			func: o_config.func,
			initFunc: o_config.initFunc,
			responseCallBack: o_config.responseCallBack,
			requestCallBack: o_config.requestCallBack,
			theme: o_config.theme
		};

		var i_icecap = Ext.create("IceCap.view.Main", o_icecap);

		var i_window = Ext.widget("window", Ext.apply(o_config, {
			onEsc: Ext.emptyFn,
			items: [
				i_icecap
			]
		}));

		i_icecap.on({
			destroy: {
				fn: function () {
					if (!i_window.isDestroyed && !i_window.destroying) {
						i_window.close();
					}
				}
			}
		});

		return i_window;
	},

	createIndicators: function(s_hex16) {

		var i_self = this;

		// EXAMPLE
		// WE READ FROM LEFT TO RIGHT BITWISE
		// 0100 0011 0000 0110

		// 1 IN 16 BITS
		// RESULT 0000 0000 0000 0001

		// (1 << 15) SHIFT LEFT 15 BIT
		// RESULT 1000 0000 0000 0000

		var n_hex32 = 0;

		var n_hex16 = parseInt(s_hex16);

		if (!(n_hex16 & (1 << 15)) && (n_hex16 & (1 << 14))) {
			n_hex32 |= IceCap.util.Handler.FFW.IDENT_FLAG;
		}

		if (n_hex16 & (1 << 13) || (n_hex16 & (1 << 10 | 1 << 9 | 1 << 8) == (1 << 10 | 1 << 9))) {
			n_hex32 |= IceCap.util.Handler.FFW.BYPASS;
		}
		if (n_hex16 & (1 << 12)) {
			n_hex32 |= IceCap.util.Handler.FFW.DUP_OR_MARK;
		}
		if (n_hex16 & (1 << 11)) {
			n_hex32 |= IceCap.util.Handler.FFW.MOD_DATA;
		}

		n_hex32 |= i_self.ffw_spec(n_hex16);

		if (n_hex16 & (1 << 7)) {
			n_hex32 |= IceCap.util.Handler.FFW.AUTO_ENTER;
		}
		if (n_hex16 & (1 << 6)) {
			n_hex32 |= IceCap.util.Handler.FFW.EXIT_REQ;
		}
		if (n_hex16 & (1 << 5)) {
			n_hex32 |= IceCap.util.Handler.FFW.MONOCASE;
		}
		if (n_hex16 & (1 << 3)) {
			// n_hex32 |= IceCap.util.Handler.FFW.MAND_ENTER;
		}

		n_hex32 |= i_self.ffw_ra(n_hex16);

		return n_hex32;
	},

	ffw_spec: function(n_flag) {

		if (n_flag & (1 << 10) && n_flag & (1 << 9) && n_flag & (1 << 8)) {
			return IceCap.util.Handler.FFW.SIGNED_NUMERIC;
		}
		if (n_flag & (1 << 10) && n_flag & (1 << 9) && !(n_flag & (1 << 8))) {
			return IceCap.util.Handler.FFW.IO_FEATURE;
		}
		if (n_flag & (1 << 10) && !(n_flag & (1 << 9)) && n_flag & (1 << 8)) {
			return IceCap.util.Handler.FFW.DIGITS_ONLY;
		}
		if (n_flag & (1 << 10) && !(n_flag & (1 << 9)) && !(n_flag & (1 << 8))) {
			return IceCap.util.Handler.FFW.KATAKANA_SHIFT;
		}
		if (!(n_flag & (1 << 10)) && n_flag & (1 << 9) && n_flag & (1 << 8)) {
			return IceCap.util.Handler.FFW.NUMERIC_ONLY;
		}
		if (!(n_flag & (1 << 10)) && n_flag & (1 << 9) && !(n_flag & (1 << 8))) {
			return IceCap.util.Handler.FFW.NUMERIC_SHIFT;
		}
		if (!(n_flag & (1 << 10)) && !(n_flag & (1 << 9)) && n_flag & (1 << 8)) {
			return IceCap.util.Handler.FFW.ALPHA_ONLY;
		}

		return IceCap.util.Handler.FFW.APLHA_SHIFT;
	},

	ffw_ra: function(n_flag) {

		if (!(n_flag & (1 << 2)) && !(n_flag & (1 << 1)) && !(n_flag & (1 << 0))) {
			return IceCap.util.Handler.FFW.RA_NONE;
		}
		if ((n_flag & (1 << 2)) && !(n_flag & (1 << 1)) && (n_flag & (1 << 0))) {
			return IceCap.util.Handler.FFW.RA_ZEROFILL;
		}
		if ((n_flag & (1 << 2)) && (n_flag & (1 << 2)) && !(n_flag & (1 << 0))) {
			return IceCap.util.Handler.FFW.RA_BLANKFILL;
		}
		if ((n_flag & (1 << 2)) && (n_flag & (1 << 2)) && (n_flag & (1 << 0))) {
			return IceCap.util.Handler.FFW.RA_MANDATORY;
		}

		return IceCap.util.Handler.FFW.RA_RESERVED;
	},

	messageBox: function (o_config) {

		var i_self = this;

		o_config = o_config || {};

		Ext.applyIf(o_config, {
			message: "",
			icon: Ext.Msg.INFO,
			cancelFn: Ext.emptyFn,
			yesFn: Ext.emptyFn,
			noFn: Ext.emptyFn,
			yesText: "",
			noText: "",
			cancelText: "",
			title: "",
			closable: true
		});

		var s_msg = o_config.message || o_config.msg;
		var s_icon = o_config.icon;

		var s_yes = o_config.yesText;
		var f_yes = o_config.yesFn;

		var s_cancel = o_config.cancelText;
		var f_cancel = o_config.cancelFn;

		var f_close = o_config.cancelFn;

		var s_no = o_config.noText;
		var f_no = o_config.noFn;

		var s_title = o_config.title;

		var b_closable = o_config.closable;

		var b_first = true;

		var o_text = {};
		var s_default = "";

		if (s_yes) {
			o_text.yes = s_yes;
			s_default = "button-yes";
		}

		if (s_no) {
			o_text.no = s_no;
			if (!s_default) {
				s_default = "button-no";
			}
		}

		if (s_cancel) {
			o_text.cancel = s_cancel;
			if (!s_default) {
				s_default = "button-no";
			}
		}


		var i_msgBox = Ext.widget("window", {
			title: s_title,
			modal: true,
			draggable: false,
			ui: "icecap-message",
			layout: "fit",
			listeners: {
				destroy: {
					fn: function () {
						f_close();
					}
				}
			}
		});



		var a_items = [];

		if (o_text.cancel) {

			a_items.push({
				tabIndex: 2,
				xtype: "button",
				itemId: "button-cancel",
				text: o_text.cancel,
				minWidth: 80,
				handler: function (i_button) {
					f_cancel();
					i_msgBox.close();
				}
			});

			b_first = false;
		}

		if (o_text.no) {

			a_items.push({
				tabIndex: 1,
				xtype: "button",
				itemId: "button-no",
				text: o_text.no,
				minWidth: 80,
				handler: function (i_button) {

					f_no();
					i_msgBox.close();
				}
			});
		}

		if (a_items.length > 0) {

			a_items.unshift({
				xtype: "tbspacer",
				width: 8
			});

			a_items.push({
				xtype: "tbfill"
			});
		}



		if (o_text.yes) {

			a_items.push({
				tabIndex: 0,
				xtype: "button",
				text: o_text.yes,
				itemId: "button-yes",
				ui: "primary-button",
				minWidth: 80,
				handler: function (i_button) {

					f_yes();
					i_msgBox.close();
				}
			});
		}

		if (a_items.length > 1) {

			a_items.push({
				xtype: "tbspacer",
				width: 8
			});
		}

		var i_component = Ext.widget("component", {
			hidden: true,
			cls: Ext.baseCSSPrefix + "message-box-icon"
		});

		i_msgBox.add({
			xtype: "panel",
			minWidth: 300,
			layout: {
				type: "hbox",
				align: "stretch"
			},
			items: [
				i_component,
				{
					xtype: "container",
					flex: 1,
					html: s_msg
				}
			]
		});

		var s_cls = i_msgBox.messageIconCls;

		if (s_cls) {
			i_component.removeCls(s_cls);
		}

		if (s_icon) {
			//i_component.show();
			i_component.addCls(Ext.baseCSSPrefix + 'dlg-icon');
			i_component.addCls(i_msgBox.messageIconCls = s_icon);
		}
		else {
			i_component.removeCls(Ext.baseCSSPrefix + 'dlg-icon');
			//i_component.hide();
		}

		if (a_items.length > 0) {

			var i_toolbar = Ext.widget("toolbar", {
				ui: "footer",
				dock: "bottom",
				items: a_items,
				layout: a_items.length > 1 ? "hbox" : "center",
				listeners: {
					afterrender: {
						fn: function (i_toolbar) {

							if (s_default) {
								var i_button = i_toolbar.getComponent(s_default);

								if (i_button) {
									i_button.focus(false, 10);
								}
							}
						},
						buffer: 100
					}
				}
			});

			i_msgBox.addDocked(i_toolbar);
		}

		var a_bindings = i_self.getFKeys();

		i_msgBox.show();

		var i_keyMap = Ext.create("Ext.util.KeyMap", {
			target: i_msgBox.getEl(),
			binding: a_bindings
		});

		i_msgBox.mon(i_msgBox, "beforedestroy" , function(i_window) {
			i_keyMap.destroy();
		});

		return i_msgBox;
	},

	getInputFields: function(i_component) {

		var a_fields = i_component.queryBy(function (i_search) {
			var b_return = false;

			if (i_search.isXType("field") && !i_search.isXType("displayfield")) {
				b_return = i_search.inputEl && i_search.inputEl.isInputField() &&
				!i_search.hidden;
			}

			return b_return;
		})

		return a_fields;
	},

	getLabels: function (i_component) {

		var a_labels = i_component.queryBy(function (i_search) {
			var s_name = i_search.getEl().dom.className;

			return /icecap\-output.*/g.test(s_name.toLowerCase())
		});

		return a_labels;
	},

	getCopyValues: function (a_inputs, n_rows, n_cols, i_region, o_rules) {

		var a_copy = [];

		o_rules = o_rules || {
			fontScale: 1,
			lineScale: 1
		};

		i_region.x = i_region.x + 1;

		var o_selPosition = IceCap.util.Handler.toColAndLine(i_region, o_rules);

		if (o_selPosition.lin > 1) {
			o_selPosition.lin = o_selPosition.lin + 1;
		}

		if (o_rules.lineScale < 1) {
			o_selPosition.lin = o_selPosition.lin - 1;
		}

		o_selPosition.col = o_selPosition.col - 1;

		var a_start = Ext.Array.filter(a_inputs, function (i_search) {
			return i_region.intersect(i_search.getRegion(false, true));
		});

		for (var n_row = 0; n_row < n_rows; n_row++) {

			var a_rows = Ext.Array.filter(a_start, function (i_search) {
				return i_search.lin == (o_selPosition.lin) + n_row;
			});

			var s_result = "";

			var b_lines = false;

			var a_intersects = [];

			if (a_rows.length > 0) {

				Ext.Array.each(a_rows, function (i_item) {

					var i_box = i_item.getRegion(false, true);

					if (i_region.intersect(i_box)) {
						a_intersects.push(i_item);
					}
				});

				var n_width = Math.ceil(IceCap.util.Handler.getWidth(1, o_rules.fontScale));
				var n_height = Math.ceil(IceCap.util.Handler.getHeight(1, o_rules.lineScale));

				for (var n_col = 0; n_col < n_cols; n_col++) {

					var o_pos = {
						x: IceCap.util.Handler.getX(o_selPosition.col + n_col, o_rules.fontScale),
						y: IceCap.util.Handler.getY(o_selPosition.lin + n_row, o_rules.lineScale),
						width: n_width,
						height: n_height,
					};

					Ext.apply(o_pos, {
						left: o_pos.x,
						right: o_pos.x + o_pos.width,
						top: o_pos.y,
						bottom: o_pos.y + o_pos.height
					});

					var b_intersect = false;

					Ext.Array.each(a_intersects, function (i_item) {

						var i_box = i_item.getRegion(false, true);

						if (i_box.intersect(o_pos)) {
							b_intersect = true;
							return false;
						}
					});

					if (!b_intersect) {
						s_result = Ext.String.leftPad(s_result, s_result.length + 1);
					}
					else {
						n_col = n_cols;
					}
				}

				var n_x = 0;

				Ext.Array.each(a_rows, function (i_item, n_index) {

					var value = i_item.inputEl ? i_item.getValue() : i_item.el.dom.innerText;

					var i_box = i_item.getRegion(false, true);

					var a_lines = value.split("\n");

					if (a_lines.length > 1) {

						b_lines = true;

						Ext.Array.each(a_lines, function (s_line) {

							var a_split = s_line.split("");

							var s_single = "";

							Ext.Array.each(a_split, function (s_char, n_index) {

								var n_extra = Math.ceil(IceCap.util.Handler.getWidth(n_index, o_rules.fontScale));

								var o_charPos = {
									x: i_box.x + n_extra,
									y: i_box.y,
									width: n_width,
									height: n_height,
								};

								Ext.apply(o_charPos, {
									left: o_charPos.x,
									right: o_charPos.x + o_charPos.width,
									top: o_charPos.y,
									bottom: o_charPos.y + o_charPos.height
								});



								if (i_region.intersect(o_charPos)) {
									s_single += s_char;
								}
							});

							if (s_single.length < n_cols) {
								while (s_single.length != n_cols) {
									s_single = s_single + " ";
								}
							}

							a_copy.push(s_result + s_single);
						});

						s_result = "";

						n_row += a_lines.length - 1;

					}
					else {

						var a_split = value.split("");

						if (n_index) {
							if (n_x < i_item.col) {

								var n_cTemp = n_x;

								while (n_cTemp < i_item.col) {
									s_result += " ";
									n_cTemp++
								}
							}
						}

						var a_added = [];

						Ext.Array.each(a_split, function (s_char, n_index) {

							var n_extra = Math.round(IceCap.util.Handler.getWidth(n_index, o_rules.fontScale));

							var o_charPos = {
								x: i_box.x + n_extra,
								y: i_box.y,
								width: n_width,
								height: n_height,
							};

							Ext.apply(o_charPos, {
								left: o_charPos.x,
								right: o_charPos.x + o_charPos.width,
								top: o_charPos.y,
								bottom: o_charPos.y + o_charPos.height
							});


							if (i_region.intersect(o_charPos)) {
								s_result += s_char;
								a_added.push(s_char)
							}
						});

						n_x = i_item.col + a_added.length;
						var n_max = i_item.col + (i_item.maxLength || a_added.length);

						if (n_x < n_max) {

							var n_temp = n_x;

							while (n_temp < n_max) {
								s_result += " ";
								n_temp++
							}
							n_x = n_temp;
						}
					}
				});
			}
			else {
				s_result = Ext.String.leftPad(s_result, s_result.length + n_cols);
			}

			if (!b_lines && s_result.length < n_cols) {
				while (s_result.length != n_cols) {
					s_result = s_result + " ";
				}
			}

			if (!b_lines) {
				a_copy.push(s_result);
			}
		}

		return a_copy;
	},

	getFontSize: function(n_scale) {

		return "calc(0.9286em * " + n_scale + ")";
	},

	getCssRule: function() {

		var i_self = this;

		var i_fieldRule = i_self.getFieldRule();
		if (!i_fieldRule) {

			Ext.util.CSS.getRules();

			i_fieldRule = Ext.util.CSS.getRule(".x-form-text-icecap-field") || {
				style: {
					fontFamily: "Lucida Console, Andale Mono, monospace",
					fontSize: "14px",
					fontWeight: "400",
					lineHeight: "20px",
					minHeight: "22px"
				}
			};

			i_self.setFieldRule(i_fieldRule);
		}

		return i_fieldRule;
	},

	getLabelCssRule: function () {

		var i_self = this;

		var i_labelRule = i_self.getLabelRule();
		if (!i_labelRule) {

			Ext.util.CSS.getRules();

			i_labelRule = Ext.util.CSS.getRule(".x-form-display-field-icecap-display") || {
				style: {
					fontFamily: "Lucida Console, Andale Mono, monospace",
					fontSize: "14px",
					fontWeight: "400",
					minHeight: "24px",
					lineHeight: "30px",
					marginTop: "0px"
				}
			};

			i_self.setLabelRule(i_labelRule);
		}

		return i_labelRule;
	},

	getPasswordCssRule: function () {

		var i_self = this;

		var i_cssRule = Ext.util.CSS.getRule(".x-form-text-icecap-password-field") || {
			style: {
				fontFamily: "Lucida Console, Andale Mono, monospace",
				fontSize: "14px",
				fontWeight: "400",
				lineHeight: "20px",
				minHeight: "22px"
			}
		};

		return i_cssRule;
	},

	getTextAreaCssRule: function() {
		var i_self = this;

		var i_cssRule = Ext.util.CSS.getRule(".x-form-text-icecap-textarea-field") || {
			style: {
				fontFamily: "Lucida Console, Andale Mono, monospace",
				fontSize: "14px",
				fontWeight: "400",
				lineHeight: "20px",
				minHeight: "22px"
			}
		};

		return i_cssRule;
	},

	toWindow: function(i_item, b_comparing) {

		var i_self = this;

		var a_items = Ext.Array.from(i_item); 

		var a_windows = i_self.getWindows();

		Ext.Array.each(a_items, function(i_current) {

			i_current.setResizeMode(2);

			var i_active = i_current.getActiveWindow();

			if (i_active) {
				i_active.hide();
			}

			var i_window = Ext.widget("window", {
				layout: "fit",
				constrain: true,
				maximizable: true,
				onEsc: Ext.emptyFn,
				comparing: b_comparing,
				listeners: {
					afterrender: {
						fn: function (i_window) {

							var i_header = i_window.header;

							if (i_header) {

								var i_tabTool = Ext.widget("tool", {
									iconCls: "pf-navigate_minus",
									tooltip: "To tab",
									handler: function () {

										var i_panel = i_window.down("panel");

										if (i_panel) {

											i_panel.setTitle(i_window.title);

											var b_active = false;

											if (i_active && i_active.isVisible()) {
												i_active.hide();
												b_active = true;
											}

											IceCap.app.fireEvent("toTab", i_panel, b_active);

											i_window.close();
										}
									}
								});

								i_header.add(1, i_tabTool);
								i_current.show();

								if (i_active) {
									setTimeout(function() {
										if (i_active) {
											i_active.show();
											i_active.center();
										}
									}, 10);
								}
								else {
									i_current.focus(10);
								}
							}
						}
					},
					destroy: {
						fn: function(i_window) {

							var a_stored = IceCap.util.Handler.getWindows();
							Ext.Array.remove(a_stored, i_window);

							i_self.setWindows(a_stored);
						}
					}
				},
				items: [
					i_current
				]
			});

			i_window.setTitle(i_current.title);

			i_current.setTitle("");

			var i_topmost = Ext.WindowManager.topMost;

			if (i_topmost) {

				var a_xy = i_topmost.getXY();

				i_window.showAt(a_xy[0] + 100, a_xy[1] + 100);
			}
			else {
				i_window.show();
				i_window.center();
			}

			a_windows.push(i_window);
		})

		i_self.setWindows(a_windows);
	},

	createElements: function() {

		var i_self = this;
		var i_cssRule = i_self.getCssRule();

		var o_style = i_cssRule.style;
		var s_minHeight = o_style.minHeight || "0px";
		var n_minheight = parseFloat(s_minHeight.replace("px"));
		var s_lineHeight = (n_minheight + 8) + "px";

		var i_element = Ext.getBody().createChild({
			tag: "span",
			role: "presentation",
			cls: Ext.baseCSSPrefix + "textmetrics",
			style: {
				position: "absolute",
				left: "100px",
				top: "100px",
				"font-family": o_style.fontFamily,
				"line-height": s_lineHeight,
				"font-size": o_style.fontSize,
				"white-space": "pre",
				"font-weight": o_style.fontWeight
			}
		});

		var s_fontSize = o_style.fontSize || "14px";
		var n_fontSize = parseFloat(s_fontSize.replace("px"));

		var i_boldElement = Ext.getBody().createChild({
			tag: "span",
			role: "presentation",
			cls: Ext.baseCSSPrefix + "textmetrics",
			style: {
				position: "absolute",
				left: "-10000px",
				top: "-10000px",
				"font-family": o_style.fontFamily,
				"line-height": s_lineHeight,
				"font-size": n_fontSize - 1 + "px",
				"white-space": "pre",
				"font-weight": "bold"
			}
		});

		var a_svgs = Ext.getBody().dom.querySelectorAll("img[src='/system/shared/collection/flags/flags.svg']");

		if (a_svgs.length == 0) {

			Ext.getBody().createChild({
				tag: "img",
				role: "presentation",
				src: "/system/shared/collection/flags/flags.svg",
				style: {
					position: "absolute",
					left: "-10000px",
					top: "-10000px",
					visibility: "hidden"
				}
			});
		}

		i_self.setMeasureItem(i_element);
		i_self.setBoldItem(i_boldElement);

		var a_string = [];

		for (var i = 0; i < 100000; i++) {
			var s_value = "W";
			a_string.push(s_value);
		}

		var s_string = a_string.join("");
		var n_lenght = a_string.length;

		var n_normal = i_element.getTextWidth(s_string) / n_lenght;

		var n_bold = i_boldElement.getTextWidth(s_string) / n_lenght;

		i_self.setNormalWidth(n_normal);
		i_self.setBoldWidth(n_bold);
		i_self.setFontSizeValue(s_fontSize)
	},

	getFKeys: function () {

		var i_self = this;

		var a_keys = [
			{
				key: Ext.event.Event.F1,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F2,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F3,
				shift: false,
				alt: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F4,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F5,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F6,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F7,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F8,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F9,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F10,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F11,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F12,
				shift: false,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			}
		];

		a_keys = a_keys.concat(i_self.getFShiftKeys());

		return a_keys;
	},

	getFShiftKeys: function () {

		var i_self = this;

		var a_keys = [
			{
				key: Ext.event.Event.F1,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F2,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F3,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F4,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F5,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F6,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F7,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F8,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F9,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F10,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F11,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			},
			{
				key: Ext.event.Event.F12,
				shift: true,
				fn: function (n_key, i_event) {
					i_event.stopEvent();
				}
			}
		];

		return a_keys;
	},

	getRandomName: function() {

		var s_random = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);

		var s_name = Ext.id(null, s_random + "-");
		return s_name;

	},

	getTranslation: function(o_config, f_callback) {

		var i_self = this;
		var s_languages = o_config.languages.join(",");
		var s_textId = o_config.textID;

		f_callback = f_callback || Ext.emptyFn;

		Ext.Ajax.request({
			method: "POST",
			url: "/apiicecap/icecapXlate/icecapGetTranslation",
			jsonData: {
				icecaptextorginal_id: s_textId,
				languages: s_languages
			},
			success: function(i_response) {

				var o_data = Ext.decode(i_response.responseText, true) || Ext.apply({}, {});

				f_callback(o_data);
			}
		});
	},

	doUpsertTranslation: function(o_config, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		Ext.Ajax.request({
			method: "POST",
			url: "/apiicecap/icecapXlate/icecapUpsertTranslation",
			jsonData: o_config,
			success: function (i_response) {

				var o_data = Ext.decode(i_response.responseText, true) || Ext.apply({}, {});

				f_callback(o_data, o_config.translation);
			}
		});

	},

	calculateChange: function(i_panel, i_region) {

		var i_self = this;
		i_self.changeStyle(i_panel, i_region);
	},

	createStyleSheetRules() {

		var i_self = this;

		var s_id = Ext.id(null, "emulator-");
		var s_cssId = Ext.id(null, "-");

		var i_fRule = i_self.getCssRule();
		var i_lRule = i_self.getLabelCssRule();
		var i_pRule = i_self.getPasswordCssRule();
		var i_tRule = i_self.getTextAreaCssRule();

		var i_sheet = Ext.util.CSS.createStyleSheet(s_id);

		var s_fieldCss = "";
		var s_labelCss = "";
		var s_passCss = "";
		var s_textareaCss = "";

		var s_fieldName = ".x-form-text-icecap-field";
		var s_labelName = ".x-form-display-field-icecap-display";
		var s_passWordName = ".x-form-text-icecap-password-field";
		var s_textareaName = ".x-form-text-icecap-textarea-field";

		if (i_fRule.cssText) {
			s_fieldCss = i_fRule.cssText.substr(i_fRule.cssText.indexOf("{")).replace("{", "").replace("}", "");
			s_labelCss = i_lRule.cssText.substr(i_lRule.cssText.indexOf("{")).replace("{", "").replace("}", "");
			s_passCss = i_pRule.cssText.substr(i_pRule.cssText.indexOf("{")).replace("{", "").replace("}", "");
			s_textareaCss = i_tRule.cssText.substr(i_tRule.cssText.indexOf("{")).replace("{", "").replace("}", "");
		}
		else {
			s_fieldCss = [
				"font-family: Lucida Console, Andale Mono, monospace;",
				"font-size: 14px;",
				"font-weight: 400;",
				"line-height: 20px;",
				"min-height: 22px;"
			].join("\n");

			s_labelCss = [
				"font-family: Lucida Console, Andale Mono, monospace;",
				"font-size: 14px;",
				"font-weight: 400;",
				"line-height: 30px;",
				"min-height: 24px;"
			].join("\n");

			s_passCss = [
				"font-family: Lucida Console, Andale Mono, monospace;",
				"font-size: 14px;",
				"font-weight: 400;",
				"line-height: 20px;",
				"min-height: 22px;"
			].join("\n");

			s_textareaCss = [
				"font-family: Lucida Console, Andale Mono, monospace;",
				"font-size: 14px;",
				"font-weight: 400;",
				"line-height: 20px;",
				"min-height: 22px;"
			].join("\n");
		}

		Ext.util.CSS.createRule(i_sheet,  s_fieldName + s_cssId, s_fieldCss);

		Ext.util.CSS.createRule(i_sheet, s_labelName + s_cssId, s_labelCss);
		
		Ext.util.CSS.createRule(i_sheet, s_passWordName + s_cssId, s_passCss);

		Ext.util.CSS.createRule(i_sheet, s_textareaName + s_cssId, s_textareaCss);

		return {
			sheet: i_sheet,
			fieldCss: s_cssId,
			labelCss: s_cssId,
			password: s_cssId
		};
	},

	changeStyle: function(i_panel, i_region) {

		i_region = i_region || {};

		var i_self = this;
		var o_rules = i_panel.getCssRules();
		var i_sheet = o_rules.sheet;
		var o_inputData = i_panel.getInputData() || {};

		var i_element = i_self.getMeasureItem();
		var i_elementBold = i_self.getBoldItem();

		var a_string = [];

		for (var i = 0; i < 100000; i++) {
			var s_value = "W";
			a_string.push(s_value);
		}

		var s_string = a_string.join("");
		var n_lenght = a_string.length;

		var n_cols = o_inputData.width || 80;
		var n_lin = o_inputData.height || 24;

		if (i_region.isRegion) {

			var i_fieldRule = i_sheet.cssRules.item(0);
			var i_labelRule = i_sheet.cssRules.item(1);
			var i_passwordRule = i_sheet.cssRules.item(2);
			var i_textareaRule = i_sheet.cssRules.item(3);

			var i_fieldStyle = i_fieldRule.style;
			var i_labelStyle = i_labelRule.style;
			var i_passwordStyle = i_passwordRule.style;
			var i_textareaRule = i_textareaRule.style;
			
			var n_width = i_region.width;
			var n_height = i_region.height;

			i_element.setHtml("W");

			var n_elementWidth = i_element.getTextWidth(s_string) / n_lenght;

			var n_minheight = 24;
			var n_maxheight = 30;
			var n_minWidth = n_elementWidth;
			var n_lineHeight = 30;
			var n_fieldLineHeight = 20;
			var n_fontSize = 14;
			var n_scale = 1;
			var n_scaleLine = 1;
			var n_em = 1; // <-- this is compared to 14px;

			i_element.setHtml("");
			

			if ((n_cols * n_minWidth) > n_width) {

				n_scale = n_width / (n_cols * n_elementWidth);

				n_fontSize = Math.floor(n_fontSize * n_scale);
			}
			if ((n_lin * n_lineHeight) > n_height) {
				n_scaleLine = n_height / (n_lin * n_lineHeight);
			}

			if (n_scaleLine < 1) {

				n_minheight = Math.floor(n_minheight * n_scaleLine);
				n_lineHeight = Math.floor(n_lineHeight * n_scaleLine);
				n_maxheight = Math.floor(n_maxheight * n_scaleLine);
				n_fieldLineHeight = Math.floor(n_fieldLineHeight * n_scaleLine);
			}

			i_fieldStyle.fontSize = i_textareaRule.fontSize = i_labelStyle.fontSize = i_passwordStyle.fontSize = "calc(1em * " +  n_scale + ")";
			i_fieldStyle.minHeight = i_labelStyle.minHeight = i_passwordStyle.minHeight = n_minheight + "px";
			i_labelStyle.lineHeight = n_lineHeight + "px";
			i_fieldStyle.lineHeight = i_textareaRule.lineHeight = i_passwordStyle.lineHeight = n_fieldLineHeight + "px";


			if (n_scaleLine >= 1) {
				i_fieldStyle.maxHeight = i_labelStyle.maxHeight = i_passwordStyle.maxHeight = null;
			}
			else {
				i_fieldStyle.maxHeight = i_labelStyle.maxHeight = i_passwordStyle.maxHeight = n_maxheight + "px";
			}

			o_rules.fontScale = n_scale;
			o_rules.lineScale = n_scaleLine;
		}
	}

}, function() {

	IceCap.util.Handler.createElements();

	var i_self = this;

	var i_copyArea = Ext.widget("textarea", {
		renderTo: Ext.getBody(),
		width: "100%",
		style: {
			"top": "-9999px;",
			"left": "-100px;",
			"z-index": "10",
			"position": "absolute"
		},
		listeners: {
			afterrender: {
				fn: function (i_field) {

					i_field.hide();
				}
			}
		}
	});

	i_self.setCopyArea(i_copyArea);

});
