Ext.define("Portfolio.Router", {
	extend: "Ext.app.Controller",

	alternateClassName: [
		"Ext.ux.Router"
	],

	listen: {
		controller: {
			"*": {
				unmatchedroute: "onUnmatchedroute"
			}
		}
	},

	statics: {
		proxy: "/ip2-services/ip2dmdProxy.aspx",
		runDmdView: "/portfolio/ip2-run-dmd.js?entity={0}&dmd={1}&view={2}",
		runDmd: "/portfolio/ip2-run-dmd.js?entity={0}&dmd={1}",
		defaultDmd: "dmd/webshop.dmd",
		seourl: "/ip2-services/wshProxy.aspx",
		widget: "/wsh-widgets/",
		dynapp: "/portfolio/ip2-run-dynapp.js?lib={0}&file={1}"
	},

	routes: {

		"entity/:entity/:dmd": {
			action: "onEntityGrid",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		"dynapp/:lib/:file": {
			before: "onBeforeRoute",
			action: "onDynApp"
		},

		"widget/:src": {
			action: "onWidget",
			before: "onBeforeRoute",
			conditions: {
				":src": "(.+)"
			}
		},

		"dynapp-:lib-:file": {
			before: "onBeforeRoute",
			action: "onDynApp"
		},

		"widget-:src": {
			action: "onWidget",
			before: "onBeforeRoute",
			conditions: {
				":src": "(.+)"
			}
		},

		"widget-:entity-:token-:xpd-:dmd": {
			action: "onWidgetForm",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})",
				":token": "([0-9]+)",
				":xpd": "(.{1,30})",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		"entity-:entity": {
			action: "onEntityGrid",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})"
			}
		},

		"entity-:entity-:dmd": {
			action: "onEntityGrid",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		"entity-:entity-:token": {
			action: "onEntityForm",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})",
				":token": "([0-9]+)"
			}
		},

		"entity-:entity-:token-:dmd": {
			action: "onEntityForm",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})",
				":token": "([0-9]+)",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		"entity-:entity-:token-:tabindex-:dmd": {
			action: "onEntityFormTabIndex",
			before: "onBeforeRouteTabIndex",
			conditions: {
				":entity": "([\\w+]{1,})",
				":token": "([0-9]+)",
				":tabindex": "([0-9]+)",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		"entity-:entity-:view-:dmd": {
			action: "onEntityGridView",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})",
				":view": "([A-Za-z]+)",
				":dmd": "([\\w \\/.]+)"
			}
		},

		"entity-:entity-:view-:token-:dmd": {
			action: "onEntityViewForm",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})",
				":view": "([A-Za-z]+)",
				":token": "([0-9]+)",
				":dmd": "([\\w \\/.]+)"
			}
		},

		"entity-:entity-:view-:token-:tabindex-:dmd": {
			action: "onEntityViewFormTab",
			before: "onBeforeRoute",
			conditions: {
				":entity": "([\\w+]{1,})",
				":view": "([A-Za-z]+)",
				":token": "([0-9]+)",
				":tabindex": "([0-9]+)",
				":dmd": "([\\w \\/.]+)"
			}
		},

		":mode-widget-:src": {
			action: "onWidgetWindow",
			before: "onBeforeWindowRoute",
			conditions: {
				":mode": "([0-9]{1})",
				":src": "(.+)"
			}
		},

		":mode-entity-:entity": {
			action: "onEntityGridWindow",
			before: "onBeforeWindowRoute",
			conditions: {
				":mode": "([0-9]{1})",
				":entity": "([\\w+]{1,10})"
			}
		},

		":mode-entity-:entity-:dmd": {
			action: "onEntityGridWindow",
			before: "onBeforeWindowRoute",
			conditions: {
				":mode": "([0-9]{1})",
				":entity": "([\\w+]{1,})",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		":mode-entity-:entity-:view-:dmd": {
			action: "onEntityGridViewWindow",
			before: "onBeforeWindowRoute",
			conditions: {
				":mode": "([0-9]{1})",
				":entity": "([\\w+]{1,})",
				":view": "([A-Za-z]+)",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		":mode-entity-:entity-:token-:dmd": {
			action: "onEntityFormWindow",
			before: "onBeforeWindowRoute",
			conditions: {
				":mode": "([0-9]{1})",
				":entity": "([\\w+]{1,})",
				":token": "([0-9]+)",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		":mode-entity-:entity-:token-:tabindex-:dmd": {
			action: "onEntityFormTabIndexWindow",
			before: "onBeforeWindowRoute",
			conditions: {
				":mode": "([0-9]{1})",
				":entity": "([\\w+]{1,})",
				":token": "([0-9]+)",
				":tabindex": "([0-9]+)",
				":dmd": "([A-Za-z\\/._0-9]+)"
			}
		},

		":app-:paths-:config": {
			action: "onApplication",
			before: "onBeforeAppication",
			conditions: {
				":app": "(\\w+(?:\\.\\w+)*)",
				":paths": "([\\w%=.&]+)",
				":config": "([\\w%=.&]+)"
			}
		},

		":mode-:app-:paths-:config": {
			action: "onApplicationWindow",
			before: "onBeforeAppication",
			conditions: {
				":mode": "([0-9]{1})",
				":app": "(\\w+(?:\\.\\w+)*)",
				":paths": "([\\w%=.&]+)",
				":config": "([\\w%=.&]+)"
			}
		}
	},

	onBeforeAppication: function(n_mode, s_main, s_path, s_config, i_action) {

		if (s_config.resume) {
			i_action = s_config;
		}

		if (Portfolio.login.util.Handler.isLogedOn()) {
			i_action.resume();
		}
		else {

			i_action.stop(true);
		}

	},

	onApplication: function(s_main, s_path, s_config) {

		var o_paths = Ext.urlDecode(s_path);
		var o_appconfig = Ext.urlDecode(s_config);

		var o_config = Ext.apply({}, {
			enabled: true,
			disableCaching: true,
			paths: o_paths
		});

		Ext.Loader.setConfig(o_config);

		Portfolio.app.fireEvent("applicationAdd", s_main, o_appconfig, null);

		this.redirectTo("");
	},

	onApplicationWindow: function(n_mode, s_main, s_path, s_config) {

		var o_paths = Ext.urlDecode(s_path);
		var o_appconfig = Ext.urlDecode(s_config);

		var o_config = Ext.apply({}, {
			enabled: true,
			disableCaching: true,
			paths: o_paths
		});

		Ext.Loader.setConfig(o_config);

		var s_title = ip2.i18n(o_appconfig.title);
		delete o_appconfig.title;
		o_appconfig.closable = false;

		var i_application = Ext.create(s_main, o_appconfig);

		var o_size = ip2.getWindowSize();

		var i_window = Ext.widget("window", {
			title: s_title,
			layout: "fit",
			width: o_size.width * 0.9,
			height: o_size.height * 0.9,
			items: [
				i_application
			]
		});

		i_window.show();
	},

	onDynApp: function(s_lib, s_file) {

		var i_self = this;
		var o_statics = i_self.statics();

		var s_src = o_statics.dynapp.replace("{0}", s_lib).replace("{1}", s_file);

		var o_config = {
			text: s_src,
			title: s_src,
			url: s_src
		};

		o_config.url = s_src;

		Portfolio.app.fireEvent("startapplication", o_config);
	},

	onEntityGrid: function(s_entity, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		s_dmd = s_dmd || o_statics.defaultDmd;

		if (s_dmd != o_statics.defaultDmd) {
			s_dmd = s_dmd.replace(/\\/g, "/");
		}

		var o_dmd = ip2.resource.get(s_dmd);
		var o_entity;

		if (o_dmd && o_dmd.model) {
			s_entity = s_entity;

			o_entity = Ext.Array.findBy(o_dmd.model.entities, function(o_value) {
				return o_value.name.toUpperCase() == s_entity.toUpperCase();
			});

			if (o_entity) {

				var s_url = o_statics.runDmd.replace("{0}", s_entity).replace("{1}", s_dmd);

				var o_config = {
					text: ip2.i18n(o_entity.title),
					title: ip2.i18n(o_entity.title),
					url: s_url
				};

				Portfolio.app.fireEvent("startapplication", o_config);
			}
		}
	},

	onEntityGridView: function(s_entity, s_view, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		s_view = s_view || "portfolio";
		s_dmd = s_dmd || o_statics.defaultDmd;

		if (s_dmd != o_statics.defaultDmd) {
			s_dmd = s_dmd.replace(/\\/g, "/");
		}

		var o_dmd = ip2.resource.get(s_dmd);
		var o_entity;

		if (o_dmd && o_dmd.model) {
			s_entity = s_entity;

			o_entity = Ext.Array.findBy(o_dmd.model.entities, function(o_value) {
				return o_value.name.toUpperCase() == s_entity.toUpperCase();
			});

			if (o_entity) {

				var s_url = o_statics.runDmdView.replace("{0}", s_entity).replace("{1}", s_dmd).replace("{2}", s_view);

				var o_config = {
					text: ip2.i18n(o_entity.title),
					title: ip2.i18n(o_entity.title),
					url: s_url
				};

				Portfolio.app.fireEvent("startapplication", o_config);
			}
		}
	},

	onEntityForm: function(s_entity, s_token, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		s_dmd = s_dmd || o_statics.defaultDmd;
		s_entity = s_entity;

		var o_config = {
			dmd: s_dmd,
			entityName: s_entity,
			context: "form",
			uiName: "portfolio",
			activeTabIndex: 0,
			linkable: false,
			deletable: false
		};

		var i_model = ip2.model(o_config);
		var i_record = i_model.create();

		i_record.set(i_record.idProperty, s_token);

		var o_keys = {};
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		o_config.keys = o_keys;

		Portfolio.app.fireEvent("entityedit", o_config, "update");
	},

	onEntityFormTabIndex: function(s_entity, s_token, s_tabindex, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		s_dmd = s_dmd || o_statics.defaultDmd;
		s_entity = s_entity;

		var o_config = {
			dmd: s_dmd,
			entityName: s_entity,
			context: "form",
			uiName: "portfolio",
			activeTabIndex: parseFloat(s_tabindex)
		};

		var i_model = ip2.model(o_config);
		var i_record = i_model.create();

		i_record.set(i_record.idProperty, s_token);

		var o_keys = {};
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		o_config.keys = o_keys;

		Portfolio.app.fireEvent("entityedit", o_config, "update");
	},

	onEntityViewForm: function(s_entity, s_view, s_token, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		var o_config = {
			dmd: s_dmd,
			entityName: s_entity,
			context: "form",
			uiName: s_view || "portfolio",
			activeTabIndex: 0
		};

		var i_model = ip2.model(o_config);
		var i_record = i_model.create();

		i_record.set(i_record.idProperty, s_token);

		var o_keys = {};
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		o_config.keys = o_keys;

		Portfolio.app.fireEvent("entityedit", o_config, "update");
	},

	onEntityViewFormTab: function(s_entity, s_view, s_token, s_tabindex, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		var o_config = {
			dmd: s_dmd,
			entityName: s_entity,
			context: "form",
			uiName: s_view || "portfolio",
			activeTabIndex: parseFloat(s_tabindex) || 0
		};

		var i_model = ip2.model(o_config);
		var i_record = i_model.create();

		i_record.set(i_record.idProperty, s_token);

		var o_keys = {};
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		o_config.keys = o_keys;

		Portfolio.app.fireEvent("entityedit", o_config, "update");
	},

	onWidget: function(s_src) {

		var i_self = this;
		var o_statics = i_self.statics();

		var s_text = s_src.toLowerCase();

		var o_params = Ext.Object.fromQueryString(window.location.search);

		var o_config = {
			text: s_text,
			title: s_text,
			url: s_src,
			urlParams: o_params
		};

		if (s_src.indexOf("/") == -1) {
			s_src = o_statics.widget + s_src;
		}

		var a_split = s_src.split(".");

		var s_pop = a_split.pop();

		if (s_pop != "widget") {
			s_src = s_src + ".widget";
		}

		o_config.url = s_src;

		Portfolio.app.fireEvent("startapplication", o_config);
	},

	onWidgetForm: function(s_entity, s_token, s_xpd, s_dmd) {

		var i_self = this;
		var s_prop;
		var s_ID;
		var s_PARENTID;

		switch (s_entity) {
			case "WSHMNUET00":
				s_prop = "MNUPROP";
				s_PARENTID = "MNUPNTTKN";
				s_ID = "MNUMNUTKN";
				break;
			case "WSHFLDET00":
				s_prop = "FLDPROP";
				s_PARENTID = "FLDPNTTKN";
				s_ID = "FLDFLDTKN";
				break;
			case "WSHNAMET00":
				s_prop = "NAMPROP";
				s_PARENTID = "NAMPNTTKN";
				s_ID = "NAMNAMTKN";
				break;
			case "NAVMNUET00":
				s_prop = "MNUPROP";
				s_PARENTID = "MNUPNTTKN";
				s_ID = "MNUMNUTKN";
				break;
			case "NAVMNUET00":
				s_prop = "QSTPROP";
				s_PARENTID = "QSTPNTTKN";
				s_ID = "QSTQSTTKN";
				break;
		}

		var o_statics = i_self.statics();
		var o_xpd;

		var o_propertyNameMapping = {
			ID: s_ID,
			PARENTID: s_PARENTID,
			PROPERTIES: s_prop
		};

		s_dmd = s_dmd || o_statics.defaultDmd;
		s_entity = s_entity;

		if (s_xpd.indexOf(".") == -1) {
			s_xpd = s_xpd + ".xpd";
		}

		var o_config = {
			dmd: s_dmd,
			entityName: s_entity,
			context: "grid",
			uiName: "portfolio"
		};

		var i_model = ip2.model(o_config);
		var i_record = i_model.create();

		var o_key = {};
		o_key[i_record.idProperty] = s_token;

		var o_params = {
			action: "getRow",
			dmd: s_dmd || "dmd/webshop.dmd",
			model: s_entity,
			uiName: "",
			context: "",
			key: Ext.encode(o_key)
		};

		var s_params = ip2.param(o_params);

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx?" + s_params,
			success: function (o_response) {

				var o_result = Ext.decode(o_response.responseText, true) || {};
				var a_records = o_result.rows || [];

				if (a_records.length > 0) {
					i_record.set(a_records[0]);
					if (s_xpd) {
						o_xpd = ip2.resource.get(s_xpd);

						var o_flatten = ip2.xpd.flatten(o_xpd);

						o_xpd.flatten = o_flatten;

						var o_properties = Ext.decode(i_record.get(s_prop), true) || {};
						var o_collection = {};

						if (o_flatten.collections[o_properties[o_xpd.idProperty]]) {
							o_collection = o_flatten.collections[o_properties[o_xpd.idProperty]];
						}

						var i_window = Ext.widget("xpd.editor.window", {
							title: ip2.i18n({
								da: "Redigér",
								en: "Edit"
							}) + " - " +
								ip2.i18n(o_properties.TITLE) || ip2.i18n(o_properties.text) + " - " +
								i_record.get(i_record.idProperty),
							xpd: o_xpd,
							modal: true,
							propertyNameMapping: o_propertyNameMapping,
							record: i_record,
							action: "update",
							entity: s_entity,
							languageService: "",
							dmdFile: s_dmd || "dmd/webshop.dmd",
							preSave: function(a_modifed, f_callback) {
								f_callback();
							},
							doSave: function(i_record, i_node, s_value, f_callback) {

								var i_editor = this;

								i_self.onWidgetSave(o_params, i_record, i_editor, s_value, function() {
									f_callback(i_record);
								});
							}
						});

						i_window.show();
					}
				}
			}
		});
	},

	onWidgetSave: function(o_params, i_record, i_editor, s_value, f_callback) {

		var o_key = {};
		o_key[i_record.idProperty] = i_record.get(i_record.idProperty);

		var o_json = {};

		o_json[i_record.idProperty] = i_record.get(i_record.idProperty);
		o_json[i_editor.propertyNameMapping.PROPERTIES] = s_value;

		i_record.set(i_editor.propertyNameMapping.PROPERTIES, s_value);

		var s_params = ip2.param({
			action: "updateRow",
			dmd: o_params.dmd || "dmd/webshop.dmd",
			model: o_params.model,
			uiName: o_params.uiName,
			context: o_params.context
		});

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx?" + s_params + "&key= " + Ext.encode(o_key),
			jsonData: o_json,
			success: function () {
				f_callback();
			}
		});
	},

	onBeforeRoute: function(s_entity, s_token, s_xpd, s_dmd, n_window, action) {

		// TEST TO SEE WHAT IS THE ACTION OBJECT
		var i_action;
		if (s_token.resume) {
			i_action = s_token;
		}
		else if (s_xpd.resume) {
			i_action = s_xpd;
		}
		else if (s_dmd.resume) {
			i_action = s_dmd;
		}
		else if (n_window.resume) {
			i_action = n_window;
		}
		else {
			i_action = action;
		}
		if (Portfolio.login.util.Handler.isLogedOn()) {
			i_action.resume();
			this.redirectTo("");
		}
		else {
			i_action.stop(true);
		}

	},

	onBeforeRouteTabIndex: function(s_entity, s_token, s_tabindex, s_dmd, action) {

		// TEST TO SEE WHAT IS THE ACTION OBJECT
		var i_action;
		if (s_token.resume) {
			i_action = s_token;
		}
		else if (s_tabindex.resume) {
			i_action = s_tabindex;
		}
		else if (s_dmd.resume) {
			i_action = s_dmd;
		}
		else {
			i_action = action;
		}

		if (Portfolio.login.util.Handler.isLogedOn()) {
			i_action.resume();
			this.redirectTo("");
		}
		else {
			i_action.stop(true);
		}
	},

	onBeforeWindowRoute: function(n_window, s_entity, s_token, s_xpd, s_dmd, action) {

		// TEST TO SEE WHAT IS THE ACTION OBJECT
		var i_action;
		if (s_entity.resume) {
			i_action = s_entity;
		}
		if (s_token.resume) {
			i_action = s_token;
		}
		else if (s_xpd.resume) {
			i_action = s_xpd;
		}
		else if (s_dmd.resume) {
			i_action = s_dmd;
		}
		else if (n_window.resume) {
			i_action = n_window;
		}
		else {
			i_action = action;
		}

		if (Portfolio.login.util.Handler.isLogedOn()) {
			i_action.resume();
			this.redirectTo("");
		}
		else {
			i_action.stop(true);
		}
	},

	onWidgetWindow: function(n_mode, s_src) {

		s_src = s_src.toLowerCase();

		var i_self = this;
		var o_statics = i_self.statics();

		var o_config = {
			text: s_src,
			title: s_src,
			url: s_src,
			urlParams: Ext.Object.fromQueryString(ip2.qrystr())
		};

		if (s_src.indexOf("/") == -1) {
			s_src = o_statics.widget + s_src;
		}

		var a_split = s_src.split(".");

		var s_pop = a_split.pop();

		if (s_pop != "widget") {
			s_src = s_src + ".widget";
		}

		o_config.url = s_src;

		var o_size = ip2.getWindowSize();

		var i_widget = ip2.callWidget(o_config);

		var i_window = Ext.widget("window", {
			title: ip2.i18n(o_config.title),
			layout: "fit",
			width: o_size.width * 0.9,
			height: o_size.height * 0.9,
			listeners: {
				afterrender: {
					fn: function(i_window) {
						i_window.add(i_widget);
						i_widget.show();
					}
				}
			}
		});

		i_window.show();
	},

	onEntityGridWindow: function(n_window, s_entity, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		s_dmd = s_dmd || o_statics.defaultDmd;

		if (s_dmd != o_statics.defaultDmd) {
			s_dmd = s_dmd.replace(/\\/g, "/");
		}

		var o_dmd = ip2.resource.get(s_dmd);
		var o_entity;

		if (o_dmd && o_dmd.model) {
			s_entity = s_entity;

			o_entity = Ext.Array.findBy(o_dmd.model.entities, function(o_value) {
				return o_value.name.toUpperCase() == s_entity.toUpperCase();
			});

			if (o_entity) {

				var o_size = ip2.getWindowSize();

				var i_grid = Ext.widget("ip2pagingGrid", {
					text: ip2.i18n(o_entity.title),
					title: ip2.i18n(o_entity.title),
					dmd: {
						path: s_dmd,
						entityName: s_entity
					},
					uiName: "portfolio",
					transactiontype: s_entity
				});

				var i_window = Ext.widget("window", {
					title: ip2.i18n(o_entity.title),
					layout: "fit",
					items: [
						i_grid
					],
					width: o_size.width * 0.9,
					height: o_size.height * 0.9
				});

				i_window.show();
			}
		}
	},

	onEntityGridViewWindow: function(n_window, s_entity, s_view, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		s_dmd = s_dmd || o_statics.defaultDmd;

		if (s_dmd != o_statics.defaultDmd) {
			s_dmd = s_dmd.replace(/\\/g, "/");
		}

		var o_dmd = ip2.resource.get(s_dmd);
		var o_entity;

		if (o_dmd && o_dmd.model) {
			s_entity = s_entity;

			o_entity = Ext.Array.findBy(o_dmd.model.entities, function(o_value) {
				return o_value.name.toUpperCase() == s_entity.toUpperCase();
			});

			if (o_entity) {

				var o_size = ip2.getWindowSize();

				var i_grid = Ext.widget("ip2pagingGrid", {
					text: ip2.i18n(o_entity.title),
					title: ip2.i18n(o_entity.title),
					dmd: {
						path: s_dmd,
						entityName: s_entity
					},
					uiName: s_view,
					transactiontype: s_entity
				});

				var i_window = Ext.widget("window", {
					title: ip2.i18n(o_entity.title),
					layout: "fit",
					items: [
						i_grid
					],
					width: o_size.width * 0.9,
					height: o_size.height * 0.9
				});

				i_window.show();
			}
		}
	},

	onEntityFormWindow: function(n_window, s_entity, s_token, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		s_dmd = s_dmd || o_statics.defaultDmd;
		s_entity = s_entity;

		var o_config = {
			dmd: s_dmd,
			entityName: s_entity,
			context: "form",
			uiName: "portfolio",
			activeTabIndex: 0
		};

		var i_model = ip2.model(o_config);
		var i_record = i_model.create();

		i_record.set(i_record.idProperty, s_token);

		i_record.set(i_record.idProperty, s_token);

		var o_keys = {};
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		o_config.keys = o_keys;

		Portfolio.app.fireEvent("entityWindow", o_config, "update");
	},

	onEntityFormTabIndexWindow: function(n_window, s_entity, s_token, s_tabindex, s_dmd) {

		var i_self = this;
		var o_statics = i_self.statics();

		s_dmd = s_dmd || o_statics.defaultDmd;
		s_entity = s_entity;

		var o_config = {
			dmd: s_dmd,
			entityName: s_entity,
			context: "form",
			uiName: "portfolio",
			activeTabIndex: parseFloat(s_tabindex)
		};

		var i_model = ip2.model(o_config);
		var i_record = i_model.create();

		i_record.set(i_record.idProperty, s_token);

		var o_keys = {};
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		o_config.keys = o_keys;

		Portfolio.app.fireEvent("entityWindow", o_config, "update");
	},

	onUnmatchedroute: function(s_hash) {
		this.redirectTo("");
	}

}, function() {
	Portfolio.Router.instance = new Portfolio.Router();
});
Ext.define("Portfolio.dynapp.util.Service", {
	singleton: true,

	base: {
		url: "/ip2-services/ip2DynApp.aspx",
		name: "Portfolio.dynapp.model.Detail"
	},

	alternateClassName: [
		"Ext.dynapp.util.Service"
	],

	getPath: function(o_value) {

		var i_self = this;
		var s_url = Portfolio.dynapp.util.Service.base.url;

		o_value = o_value || {};

		var a_path = [s_url];

		if (o_value.hasOwnProperty("library")) {
			a_path.push(o_value.library);
		}

		if (o_value.hasOwnProperty("file")) {
			a_path.push(o_value.file);
		}

		a_path.push("json");

		var s_result = a_path.join(".");

		return s_result;
	},

	getModelName: function(o_value) {

		var i_self = this;
		var s_return = Portfolio.dynapp.util.Service.base.name;

		if (o_value.library && o_value.file) {
			s_return = [o_value.library, o_value.file].join("-");
		}

		return s_return;
	},

	getMeta: function(o_value, f_callback) {

		Ext.Ajax.request({
			url: Portfolio.dynapp.util.Service.getPath(o_value),
			jsonData: {
				action: "getMeta"
			},
			success: function (response, request) {
				var result;
				try {
					result = Ext.decode(response.responseText);
				}
				catch (err) {
					result = {
						fields: [],
						properties: {},
						srcPlugin: ""
					};
				}
				var o_result = {
					fields: result.fields || [],
					id: "_id_",
					properties: result.properties || {},
					srcPlugin: ""
				};
				if (o_result.properties.plugin) {
					if (!Ext.isObject(o_result.properties.plugin)) {
						o_result.srcPlugin = o_result.properties.plugin;
						eval("o_result.properties.plugin =" + o_result.properties.plugin);
					}
					else {
						o_result.srcPlugin = o_result.properties.plugin.src || "{}";
						eval("o_result.properties.plugin =" + o_result.srcPlugin);
					}
					if (!o_result.properties.plugin.permissions) {
						o_result.properties.plugin.permissions = Ext.apply({}, {
							create: true,
							read: true,
							update: true,
							"delete": true
						});
					}
					else {
						var o_permissions = o_result.properties.plugin.permissions;
						Ext.applyIf(o_permissions, {
							create: true,
							read: true,
							update: true,
							"delete": true
						});
					}
				}
				else {
					o_result.properties.plugin = Ext.apply({}, {
						permissions: {
							create: true,
							read: true,
							update: true,
							"delete": true
						}
					});
				}

				Ext.Array.each(o_result.fields, function(o_field) {
					if (o_field.type) {
						o_field.dataType = o_field.type;
						delete o_field.type;
					}
				});

				f_callback(o_result);
			},
			failure: function() {
				var o_metaData = {
					fields: [],
					id: "_id_",
					properties: {
						plugin: {
							permissions: {
								read: true,
								create: true,
								update: true,
								"delete": true
							}
						}
					}
				};
				f_callback(o_metaData);
			}
		});
	}
});
Ext.define("Portfolio.registry.util.Service", {

	singleton: true,

	base: {
		url: "/ip2-services/ip2Registry.aspx",
		name: "Portfolio.registry.model.Detail"
	},
	transaction: {
		url: "/ip2-services/ip2transaction.aspx"
	},

	config: {
		errorTpl: null
	},

	alternateClassName: [
		"Ext.registry.util.Service"
	],

	constructor: function(o_config) {

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

		var i_template = i_self.createErrorTemplate();
		i_self.setErrorTpl(i_template);
	},

	getPath: function(o_value) {

		var i_self = this;
		return Portfolio.registry.util.Service.transaction.url;
	},

	getTransactionUrl: function(o_options) {

		var i_self = this;
		var s_url = Portfolio.registry.util.Service.transaction.url;

		o_options = o_options || {};

		var a_path = [s_url];

		if (o_options.hasOwnProperty("library")) {
			a_path.push(o_options.library);
		}

		if (o_options.hasOwnProperty("file")) {
			a_path.push(o_options.file);
		}

		a_path.push("json");

		var s_result = a_path.join(".");

		return s_result;
	},

	getTransactionJson: function(o_options, s_type, a_records) {

		var o_json = {};

		var a_rows = [];

		Ext.Array.each(a_records, function(i_record) {
			a_rows.push(i_record.getData());
		});

		switch (s_type) {
			case "save":
			case "delete":
				Ext.apply(o_json, {
					rows: a_rows
				});
				break;
			default:
				break;
		}

		Ext.apply(o_json, {
			action: o_options.action,
			access: o_options.key
		});

		o_json[o_options.id] = o_options.idProperty;

		return o_json;
	},

	setDataAccess: function(o_options, s_type, a_records, f_callback) {

		var o_json = Portfolio.registry.util.Service.getTransactionJson(o_options, s_type, a_records);

		Ext.Ajax.request({
			url: Portfolio.registry.util.Service.getTransactionUrl(),
			jsonData: o_json,
			success: function (i_response, request) {

				var o_result = Ext.decode(i_response.responseText, true) || {};
				f_callback(o_result);
			},
			failure: function() {
				var o_result = {};
				f_callback(o_result);
			}
		});
	},

	getJsonData: function(o_value, s_type, o_record, o_store) {

		var o_json = {};
		var s_registry = "";
		var a_path = [];

		o_value = o_value || {};

		switch (s_type) {

			case "get":
				Ext.apply(o_json, {
					action: "ip2registry.getNode",
					key: o_record.key
				});
				break;
			case "set":
				Ext.apply(o_json, {
					action: "ip2registry.setValue",
					key: o_record.key,
					value: o_record.value,
					meta: o_record.meta
				});
				break;
			case "setDataStore":
				Ext.apply(o_json, {
					action: "ip2registry.setDatastoreValue",
					key: o_record.key,
					value: o_record.value,
					datastore: o_store
				});
				break;
			case "getDataStore":
				Ext.apply(o_json, {
					action: "ip2registry.getDataStoreNode",
					key: o_record.key,
					datastore: o_store
				});
				break;
			case "single":
				Ext.apply(o_json, {
					action: "ip2registry.setValue",
					key: o_record.key,
					value: o_record.value
				});
				break;
			case "delete":
				Ext.apply(o_json, {
					action: "ip2registry.deleteNode",
					key: o_record.key
				});
				break;
			case "copy":
				Ext.apply(o_json, {
					action: "ip2registry.copyNode",
					from: o_record.from,
					to: o_record.to
				});
				break;
			case "move":
				Ext.apply(o_json, {
					action: "ip2registry.moveNode",
					from: o_record.from,
					to: o_record.to
				});
				break;
		}

		if (o_value.hasOwnProperty("library")) {
			a_path.push(o_value.library);
		}

		if (o_value.hasOwnProperty("file")) {
			a_path.push(o_value.file);
		}

		Ext.apply(o_json, {
			registry: a_path.join("/")
		});

		return o_json;
	},

	getModelName: function(o_value) {

		var i_self = this;
		var s_return = Portfolio.registry.util.Service.base.name;

		if (o_value.library && o_value.file) {
			s_return = [o_value.library, o_value.file].join("-");
		}

		return s_return;
	},

	getEditor: function(o_options, o_field, o_store) {

		var i_self = this;
		var i_field;
		var o_meta = o_field.meta;
		var o_properties = o_meta.properties;
		var o_plugin = o_meta.plugin;
		var s_name = o_field.key.split(".").pop();
		var s_label = o_properties.title ? o_properties.title : s_name.charAt(0) + s_name.slice(1);

		var o_config = {
			name: o_field.key,
			value: o_field.value,
			defaultLanguage: ip2.getUser().get("USRLNG") || "en",
			languages: wsh.getLanguages("portfolio")
		};

		var s_type = "textfield";
		var s_metatype = "varchar";

		if (o_properties.type) {
			s_metatype = o_properties.type;
		}
		switch (s_metatype){
			case "string":
			case "char":
			case "varchar":
				if (o_properties.len >= 40) {
					s_type = "textarea";
				}
				o_config = Ext.apply(o_config, {
					maxLength: o_properties.len || 30
				});
				break;
			case "integer":
			case "int":
			case "decimal":
			case "dec":
			case "float":
			case "smallint":
			case "bigint":
			case "numeric":
				s_type = "numberfield";
				var n_precision = 0;
				if (o_properties.prec) {
					n_precision = o_properties.prec;
				}
				else {
					if (s_metatype != "int" || s_metatype != "integer") {
						n_precision = 2;
					}
				}
				o_config = Ext.apply(o_config, {
					decimalPrecision: n_precision,
					decimalSeparator: Ext.util.Format.decimalSeparator,
					maxLength: o_properties.len || 30
				});
				break;
			case "timestamp":
				s_type = "isotimestampfield";
				break;
			case "date":
				s_type = "datefield";
				o_config = Ext.apply(o_config, {
					format: "d-m-Y",
					submitFormat: "Y-m-d"
				});
				break;
			case "bool":
				s_type = "checkbox";
				break;
			default :
				o_config = Ext.apply(o_config, {
					maxLength: o_properties.len || 30
				});
				break;
		}

		var o_evaled;
		var f_validator;

		if (o_plugin.src) {
			try {
				eval("o_evaled = " + o_plugin.src);
			}
			catch (err) {
				console.log("eval error check plugin if its valid");
				o_evaled = {};
			}
			if (o_evaled.xtype) {
				if (o_evaled.xtype.indexOf("i18n") != -1) {
					var a_languages = o_config.languages;
					if (a_languages.indexOf(o_config.defaultLanguage) != 0) {
						var n_index = a_languages.indexOf(o_config.defaultLanguage);
						var s_value = a_languages.splice(n_index, 1)[0];
						a_languages.unshift(s_value);
					}
				}
				s_type = o_evaled.xtype;
			}
			if (o_evaled.validator) {
				f_validator = o_evaled.validator;
				delete o_evaled.validator;
			}
			Ext.apply(o_config, o_evaled);
		}

		i_field = Ext.widget(s_type, o_config);

		if (o_evaled && f_validator) {
			i_field.getErrors = (function(f_old) {
				return function(value) {
					value = i_field.getValue();
					var a_errors = f_old.apply(this, [value]) || [];

					var s_error = f_validator.call(this, i_self._form.getForm(), value) || "";

					if (s_error) {
						a_errors.push(s_error);
					}

					return a_errors;
				};
			})(i_field.getErrors);
		}
		i_field.suspendCheckChange++;
		i_field.setValue(o_field.value);
		i_field.resetOriginalValue();
		i_field.suspendCheckChange--;
		return i_field;
	},

	getChildNodes: function(o_options, o_record, o_store, f_callback) {

		var o_json = Portfolio.registry.util.Service.getJsonData(o_options, "get", o_record, o_store);

		Ext.Ajax.request({
			url: Portfolio.registry.util.Service.getPath(),
			jsonData: o_json,
			success: function (i_response, request) {

				var a_result = Ext.decode(i_response.responseText, true) || [];

				Ext.Array.each(a_result, function(o_record) {

					var o_meta = o_record.meta || {
						properties: {},
						plugin: {
							src: ""
						}
					};
					o_record.meta = o_meta;
					if (!o_meta.properties) {
						o_meta.properties = Ext.apply({}, o_meta);
					}
					if (!o_meta.plugin) {
						o_meta.plugin = {
							src: ""
						};
					}
				});

				f_callback(a_result);
			},
			failure: function() {
				var a_result = [];
				f_callback(a_result);
			}
		});
	},

	getNode: function(o_options, o_record, o_store, f_callback) {

		var s_methode = "";

		if (o_store) {
			s_methode = "getDataStore";
		}

		var o_json = Portfolio.registry.util.Service.getJsonData(o_options, s_methode, o_record, o_store);

		Ext.Ajax.request({
			url: Portfolio.registry.util.Service.getPath(),
			jsonData: o_json,
			success: function (i_response, request) {

				var o_result = Ext.decode(i_response.responseText, true) || {
					userowselection: true,
					filters: []
				}

				f_callback(o_result);
			},
			failure: function() {
				var o_result = {};
				f_callback(o_result);
			}
		});
	},

	doCopy: function(o_options, o_values, o_store, f_callback) {

		var o_json = Portfolio.registry.util.Service.getJsonData(o_options, "copy", o_values, o_store);

		Ext.Ajax.request({
			url: Portfolio.registry.util.Service.getPath(),
			jsonData: o_json,
			success: function (i_response, request) {

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

				if (!o_result.success) {

					ip2.messageBox({
						icon: Ext.MessageBox.ERROR,
						title: ip2.i18n({
							da: "Fejl",
							en: "Error"
						}),
						closable: true,
						message: Portfolio.registry.util.Service.getMessage(o_result),
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						}),
						yesFn: function() {
							f_callback(false);
						}
					});
				}
				else {
					f_callback(true);
				}
			},
			failure: function(i_response, request) {

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

				ip2.messageBox({
					icon: Ext.MessageBox.ERROR,
					title: ip2.i18n({
						da: "Fejl",
						en: "Error"
					}),
					closable: true,
					message: Portfolio.registry.util.Service.getMessage(o_result),
					yesText: ip2.i18n({
						da: "OK",
						en: "OK"
					}),
					yesFn: function() {
						f_callback(false);
					}
				});
			}
		});
	},

	doMove: function(o_options, o_values, o_store, f_callback) {

		var o_json = Portfolio.registry.util.Service.getJsonData(o_options, "move", o_values, o_store);

		Ext.Ajax.request({
			url: Portfolio.registry.util.Service.getPath(),
			jsonData: o_json,
			success: function (i_response, request) {

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

				if (!o_result.success) {

					ip2.messageBox({
						icon: Ext.MessageBox.ERROR,
						title: ip2.i18n({
							da: "Fejl",
							en: "Error"
						}),
						closable: true,
						message: Portfolio.registry.util.Service.getMessage(o_result),
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						}),
						yesFn: function() {
							f_callback(false);
						}
					});
				}
				else {
					f_callback(true);
				}
			},
			failure: function(i_response, request) {

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

				ip2.messageBox({
					icon: Ext.MessageBox.ERROR,
					title: ip2.i18n({
						da: "Fejl",
						en: "Error"
					}),
					closable: true,
					message: Portfolio.registry.util.Service.getMessage(o_result),
					yesText: ip2.i18n({
						da: "OK",
						en: "OK"
					}),
					yesFn: function() {
						f_callback(false);
					}
				});
			}
		});
	},

	setValue: function(o_options, o_value, o_store, f_callback) {

		var o_record = o_value;
		var s_methode = "set";

		if (o_store) {
			s_methode = "setDataStore";
		}

		var o_json = Portfolio.registry.util.Service.getJsonData(o_options, s_methode, o_record, o_store);

		Ext.Ajax.request({
			url: Portfolio.registry.util.Service.getPath(),
			jsonData: o_json,
			success: function (i_response, request) {

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

				if (!o_result.success) {

					ip2.messageBox({
						icon: Ext.MessageBox.ERROR,
						title: ip2.i18n({
							da: "Fejl",
							en: "Error"
						}),
						closable: true,
						message: Portfolio.registry.util.Service.getMessage(o_result),
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						})
					});
				}
				else {
					f_callback(o_record);
				}
			},
			failure: function(i_response, request) {

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

				ip2.messageBox({
					icon: Ext.MessageBox.ERROR,
					title: ip2.i18n({
						da: "Fejl",
						en: "Error"
					}),
					closable: true,
					message: Portfolio.registry.util.Service.getMessage(o_result),
					yesText: ip2.i18n({
						da: "OK",
						en: "OK"
					})
				});
			}
		});
	},

	setSingleValue: function(o_options, s_key, value, o_store, f_callback) {

		var s_methode = "single";
		if (o_store) {
			s_methode = "setDataStore";
		}

		var o_json = Portfolio.registry.util.Service.getJsonData(o_options, s_methode, {
			key: s_key,
			value: value
		}, o_store);

		Ext.Ajax.request({
			url: Portfolio.registry.util.Service.getPath(),
			jsonData: o_json,
			success: function (i_response, request) {

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

				if (!o_result.success) {

					ip2.messageBox({
						icon: Ext.MessageBox.ERROR,
						title: ip2.i18n({
							da: "Fejl",
							en: "Error"
						}),
						closable: true,
						message: Portfolio.registry.util.Service.getMessage(o_result),
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						})
					});
					f_callback();
				}
				else {
					f_callback();
				}
			},
			failure: function(i_response, request) {

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

				ip2.messageBox({
					icon: Ext.MessageBox.ERROR,
					title: ip2.i18n({
						da: "Fejl",
						en: "Error"
					}),
					closable: true,
					message: Portfolio.registry.util.Service.getMessage(o_result),
					yesText: ip2.i18n({
						da: "OK",
						en: "OK"
					})
				});
			}
		});
	},

	deleteEntry: function(o_options, o_record, o_store, f_callback) {

		var o_json = Portfolio.registry.util.Service.getJsonData(o_options, "delete", o_record, o_store);

		Ext.Ajax.request({
			url: Portfolio.registry.util.Service.getPath(),
			jsonData: o_json,
			success: function (i_response, request) {

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

				if (!o_result.success) {

					ip2.messageBox({
						icon: Ext.MessageBox.ERROR,
						title: ip2.i18n({
							da: "Fejl",
							en: "Error"
						}),
						closable: true,
						message: Portfolio.registry.util.Service.getMessage(o_result),
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						})
					});
				}
				else {
					f_callback();
				}
			},
			failure: function(i_response, request) {

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

				ip2.messageBox({
					icon: Ext.MessageBox.ERROR,
					title: ip2.i18n({
						da: "Fejl",
						en: "Error"
					}),
					closable: true,
					message: Portfolio.registry.util.Service.getMessage(o_result),
					yesText: ip2.i18n({
						da: "OK",
						en: "OK"
					})
				});
			}
		});
	},

	getMessage: function(o_values) {

		var i_self = this;

		var i_template = i_self.getErrorTpl();

		return i_template.apply(o_values);
	},

	createErrorTemplate: function() {

		var i_template = Ext.create("Ext.XTemplate",
			"<div>",
				"<h4>" + ip2.i18n({
					da: "Beskrivelse",
					en: "Description"
				}) + "</h2>",
				"<span>{description}</span>",
				"<h4>" + ip2.i18n({
					da: "Besked",
					en: "Message"
				}) + "</h2>",
				"<span>{message}</span>",
				"<span>{msg}</span>",
			"</div>"
		);

		i_template.compile();

		return i_template;
	}
});
Ext.define("Portfolio.util.Xpd", {

	singleton: true,

	alternateClassName: [
		"ip2.xpd"
	],

	requires: [
		"Portfolio.util.Handler"
	],

	ALLOWED_CHILDS: 1,
	ALLOWED_PARENTS: 2,
	ALL_PROPERTIES_KEY: "all",
	XPD_DEFAULTLANGUAGE: "en",

	DEFAULT_KEY: "__default__",

	privates: {
		cf: function(s_name, o_properties, o_data, a_filter) {

			a_filter = a_filter || [];

			Ext.Object.each(o_properties.filter, function(o_value, s_key) {

				if (!Ext.isObject(o_value)) {
					var s_value = o_value;

					o_value = {
						value: s_value
					};
				}

				//var o_filter = Ext.Object.merge({
				var o_filter = Ext.apply({
					value: o_data[s_key],
					property: o_properties.databasebind
				}, o_value);

				if (o_properties.as) {
					o_filter.as = o_properties.as;
				}

				var value = o_filter.value;

				if (Ext.isString(value)) {
					o_filter.value = ip2.microTemplate(value, o_data);
				}

				// Map out the value to the s_key o.value -> o.where etc.
				o_filter[s_key] = o_filter.value;
				delete o_filter.value;

				if (!i_self.hasFilter(a_filter, o_filter) && o_filter[s_key]) {
					a_filter.push(o_filter);
				}
			});

			return a_filter;
		},

		hasFilter: function (a_filter, o_filter) {

			var b_found = false;

			var s_filter = Ext.encode(o_filter);

			Ext.Array.each(a_filter, function(o_value) {

				var s_current = Ext.encode(o_value);

				if (s_current == s_filter) {
					b_found = true;
					return false;
				}
			});

			return b_found;
		}
	},

	createFilter: function(o_collection, o_data, a_filter) {

		var i_self = this;

		a_filter = a_filter || [];
		o_data = o_data || {};

		Ext.Object.each(o_collection.properties, function (o_property, s_key) {

			var a_result = i_self.cf(s_key, o_property, o_data, a_filter);

			Ext.Array.each(a_result, function (o_value) {
				if (!i_self.hasFilter(a_filter, o_value)) {
					a_filter.push(o_value);
				}
			});
		});

		return a_filter;
	},

	translate: function(xpd, value, lang) {

		var i_self = this;

		value = value || "";

		var defaultLanguage;

		if (xpd.defaultLanguage) {
			defaultLanguage = xpd.defaultLanguage;
		}

		if (!lang) {
			lang = ip2.session.getLanguage();
		}

		lang = lang || defaultLanguage || i_self.XPD_DEFAULTLANGUAGE;

		var languages = xpd.language;
		var chkValue = value.toLowerCase();
		var ret;

		if (!languages[lang]) {
			lang = "en";
		}

		if (!languages[lang]) {
			lang = "da";
		}

		if (languages && languages[lang]) {
			ret = languages[lang].text[chkValue] !== undefined ? languages[lang].text[chkValue] : value;
		} // TODO: This only checks if the wanted language exists, check for fallback to the default language for possible other value here!
		else {
			ret = value;
		}

		return ret;
	},

	flattenLayout: function(collections, xpdLayout) {

		var i_self = this;

		var defaultsId = i_self.DEFAULT_KEY;

		// First prepare the layout object - add default values
		Ext.Object.each(xpdLayout, function(context, contextKey) {

			var defaults = context[defaultsId] || {};

			// Itereate over the context for the layout object
			Ext.Object.each(context, function(layout, propertyId) {

				if (propertyId != defaultsId) {

					// Extend the layout for this collection id
					context[propertyId] = Ext.Object.merge({}, defaults, layout);
				}
			});
		});

		if (!Ext.Object.isEmpty(xpdLayout)) {

			// Go through the flattened collections and extend layout on to
			Ext.Object.each(collections, function(collection) {

				var properties = collection.properties;

				Ext.Object.each(properties, function(field, name) {

					field.layout = field.layout || {};

					Ext.Object.each(xpdLayout, function(context, contextKey) {

						var defaults = context[name] || (context[defaultsId] || {});

						if (!field.layout[contextKey]) {
							field.layout[contextKey] = defaults;
						}
						else {
							field.layout[contextKey] = Ext.Object.merge({}, defaults, field.layout[contextKey]);
						}
					});
				});
			});
		}

		return xpdLayout;
	},

	flatten: function(xpd, against, includeName) {

		var i_self = this;

		// Which property will we be flatten against defaults to id:
		against = against || "id";

		// Make sure includeName have to be set to `true to include the name when returning:
		includeName = (includeName === true);

		if (xpd.hasOwnProperty("against")) {
			if (xpd.against === against) {
				return xpd;
			}
			else {
				throw new Error(".flatten: The given XPD is flattened, but not against: " + against + ", but rather: " + xpd.against);
			}
		}
		else {

			// deepClone the xpd we are getting. This way we are allowed to modify each collection.
			xpd = Ext.apply({}, xpd);

			var collections = i_self.flattenItems({
				// map out collections and properties to our fake xpd collection
				collections: xpd.collections,
				properties: xpd.properties,
				layout: xpd.uilayout,
				widgets: xpd.widgets
			}, against, includeName);

			var all = {};
			Ext.Object.each(collections, function(coll) {
				Ext.Object.each(coll.properties, function(prop, name) {
					all[name] = prop;
				});
			});
			collections[i_self.ALL_PROPERTIES_KEY] = all;

			// Process the xpd.layout object - sanitize first
			xpd.layout = xpd.layout || {};

			var layout = i_self.flattenLayout(collections, xpd.layout);

			// Return an object to the user:
			return {
				// What have the xpd been flatten against?
				against: against,

				// Did we include the name ({name: ...})?
				includeName: includeName,

				// Map the idProperty from the xpd object.
				idProperty: xpd.idProperty,

				// Map out the path if any is specified
				path: xpd.path || xpd._path,

				// Map the language from the xpd object.
				language: xpd.language,

				// Map out the propertyRulesPath if any is specified
				propertyRulesPath: xpd.propertyRulesPath,

				// Map out the groups if any is specified // TODO: Have another .xpd that holds the groups!!
				groups: xpd.groups,

				// Iterate each collection and its children.
				// Start with a fake xpd collection:
				collections: collections,

				// Layout object - added by Igor
				layout: layout,

				// Filter so we can filter the collection if needed
				filter: xpd.filter || "",

				// CID map if we need to place a cid to an inner properties
				cidMap: xpd.cidMap || {},

				// convert to pre convert properties in data before collection initialization
				convert: xpd.convert || undefined
			};
		}
	},

	flattenItems: function(parent, against, includeName) {

		var i_self = this;
		// We return an object like this:
		// { 1: {properties}, 2: {properties} }
		var o_result = {};
		

		if (parent.hasOwnProperty("collections")) {

			var o_clone = Ext.clone(parent.collections);

			Ext.Object.each(o_clone, function(key, child) {

				var o_copy = Ext.clone(child);
				// Copy all parents properties to the child, if it doesn"t allready have them.
				o_copy.properties = o_copy.properties ? Ext.clone(o_copy.properties) : {};

				// ip2.defaults(o_copy.properties, parent.properties);
				var child_properties = Ext.clone(o_copy.properties);
				var child_widgets = o_copy.widgets ? Ext.clone(o_copy.widgets) : [];
				var child_layouts = o_copy.layout ? Ext.clone(o_copy.layout) : {};
				var parent_properties = parent.properties ? Ext.clone(parent.properties) : {};
				var parent_widgets = parent.widgets ? Ext.clone(parent.widgets) : [];
				var parent_layouts = parent.layout ? Ext.clone(parent.layout) : {};

				Ext.Object.each(parent_properties, function(s_key, parent_value) {

					if (!child_properties.hasOwnProperty(s_key)) {
						child_properties[s_key] = Ext.clone(parent_value);
					}
					else {
						Ext.applyIf(child_properties[s_key], parent_value);
					}
					
				});

				if (o_copy.$delete) {
					Ext.Array.each(o_copy.$delete, function(s_key) {
						delete child_properties[s_key];
					});
				}

				Ext.apply(o_copy.properties, child_properties);

				if (Ext.isArray(parent_widgets) && Ext.isArray(child_widgets)) {

					Ext.Array.each(parent_widgets, function(o_parent) {

						var b_found = false;

						Ext.Array.each(child_widgets, function(o_child) {

							if (o_parent.name == o_child.name) {
								b_found = true;
							}
							if (b_found) {
								return true;
							}
						});

						if (!b_found) {
							child_widgets.push(o_parent);
						}
					});
				}

				o_copy.widgets = child_widgets;
				
				Ext.Object.each(parent_layouts, function(s_layout, value) {

					if (!child_layouts.hasOwnProperty(s_layout)) {

						child_layouts[s_layout] = Ext.clone(value);
					}
				});

				o_copy.layout = child_layouts;

				// Does the child have any collections itself then iterate through them

				if (o_copy.hasOwnProperty("collections")) {

					var o_collections = i_self.flattenItems(o_copy, against, includeName);
					Ext.Object.merge(o_result, o_collections);
				}

				// Do we have to include the name?
				if (includeName) {
					o_copy.name = key;
				}

				// push our child to the return object
				// If against is name we will have to use the key from the collection iteration:
				if (against === "name") {
					o_result[key] = o_copy;
				}
				else {
					o_result[o_copy[against]] = o_copy;
				}
			});
		}

		return o_result;
	},

	processGroups: function(xpd, data, dynamicNS) {

		var i_self = this;

		var DEFAULT_TITLE = "untitled group";

		if (xpd.hasOwnProperty("against")) {
			xpd = i_self.flatten(xpd);
		}
		else if (xpd.against !== "id") {
			throw new Error(".processGroups: Can only handle xpd flattened agaist collection id (.id)");
		}

		data = data || {};

		var o_collection = xpd.collections[data[xpd.idProperty]] || {
			properties: xpd.collections.all
		};

		var ret = {};

		if (o_collection) {

			var o_properties = o_collection.properties || {};
			var o_xpdGroups = xpd.groups || {};

			Ext.Object.each(data, function(attr, key) {

				if (!o_properties[key]) {
					return;
				}

				var o_property = o_properties[key];
				var a_groups = o_property.groups;

				Ext.Object.each(a_groups, function(s_group) {

					if (o_xpdGroups[s_group].renderIn && o_xpdGroups[s_group].renderIn.webshop) {
						if (!ret[s_group]) {
							ret[s_group] = {
								title: (o_xpdGroups[s_group] || {}).title || DEFAULT_TITLE,
								properties: {}
							};
						}

						var value = attr || "";

						if (o_property["enum"] && dynamicNS) {
							value = dynamicNS.getEnumValue(attr + "-text");
							if (value < "") {
								value = dynamicNS.getEnumValue(attr);
							}
						}

						ret[s_group].properties[key] = {
							title: i_self.translate(xpd, o_property.title),
							value: String(value),
							name: key
						};
					}
				});
			});
		}

		return ret;
	},

	allowedChilds: function(xpd, xpdCollection) {

		var i_self = this;

		if (xpd.hasOwnProperty("against")) {
			xpd = i_self.flatten(xpd);
		}
		else if (xpd.against !== "id") {
			throw new Error(".allowedChilds: Can only handle xpd flattened agaist collection id (.id)");
		}

		var collectionId = typeof xpdCollection == "number" ? xpdCollection : xpdCollection.id;

		return i_self.allowedRelations(xpd, collectionId, i_self.ALLOWED_CHILDS);
	},

	allowedParents: function(xpd, xpdCollection) {

		var i_self = this;

		if (xpd.hasOwnProperty("against")) {
			xpd = i_self.flatten(xpd);
		}
		else if (xpd.against !== "id") {
			throw new Error(".allowedParents: Can only handle xpd flattened agaist collection id (.id)");
		}

		var collectionId = typeof xpdCollection == "number" ? xpdCollection : xpdCollection.id;

		return i_self.allowedRelations(xpd, collectionId, i_self.ALLOWED_PARENTS);
	},

	allowedRelation: function(xpdFlatten, collectionId, type) {

		var i_self = this;

		var allowed = {};
		var xpdColl = xpdFlatten.collections[collectionId];

		Ext.Object.each(xpdFlatten.collections, function(coll, key) {
			if (key == i_self.ALL_PROPERTIES_KEY) {
				return;
			}

			if (type == i_self.ALLOWED_PARENTS) {
				if (coll.allowedchilds) {
					Ext.Array.each(coll.allowedchilds, function(id) {
						if (xpdColl.id == id) {
							allowed[coll.id] = coll;
						}
					});
				}
				else {
					allowed[coll.id] = coll;
				}
			}
			else {
				if (coll.allowedparents) {
					Ext.Array.each(coll.allowedparents, function(id) {
						if (xpdColl.id == id) {
							allowed[coll.id] = coll;
						}
					});
				}
				else {
					allowed[coll.id] = coll;
				}
			}
		});

		var ret;

		if (type == i_self.ALLOWED_PARENTS) {
			if (xpdColl.allowedparents) {
				ret = Ext.Array.map(xpdColl.allowedparents, function(id) {
					return allowed[id];
				});
			}
		}
		else {
			if (xpdColl.allowedchilds) {
				ret = Ext.Array.map(xpdColl.allowedchilds, function(id) {
					return allowed[id];
				});
			}
		}

		if (!ret) {
			ret = [];
			Ext.Object.each(allowed, function(coll) {
				ret.push(coll);
			});
		}

		return ret;
	},

	fixDatabasebind: function(str) {

		var r_split = /[^ ,]+/g;
		var r_preparse = /([^, (]+)\(([^)]+)\)/g;

		return (str.join ? str.join(',') : str).replace(r_preparse, function(_, a, b) {
			return a + '.' + (b.match(r_split) || []).join(',' + a + '.');
		}).match(r_split) || [];
	},

	getCollectionByKey: function (o_xpd, value, s_key) {

		var i_self = this;

		s_key = s_key || "name";

		var o_found = null;

		Ext.Object.each(o_xpd.collections, function (o_col) {
			if (o_col[s_key] == value) {
				o_found = o_col;
				return false;
			}
		});

		return o_found;
	}
});
Ext.define("Portfolio.util.Wsh", {

	singleton: true,

	alternateClassName: [
		"wsh",
		"wsh.i18n"
	],

	config: {
		primaryLanguage: null,
		enumValues: null,
		context: "portfolio",
		stored: {}
	},

	requires: [
		"Portfolio.util.Handler"
	],

	constructor: function(o_config) {

		var i_self = this;

		i_self.initConfig(o_config);
	},

	reload: function (s_context) {

		var i_self = this;

		s_context = s_context || i_self.getContext();

		var o_response = ip2.getEvaled({
			url: "/portfolio/cms/getLanguages?payload={\"module\":\""+ s_context +"\"}",
			class: "wshlangauges-evaled"
		});

		if (!o_response || (Ext.isObject(o_response) && !o_response.success)) {
			o_response = ip2.getEvaled("/wsh-services/wshGetLanguages.aspx");
		}

		var a_languages = [];

		if (Ext.isObject(o_response)) {
			a_languages = Ext.Array.from(o_response.languages);
		}

		if (Ext.isArray(o_response)) {
			a_languages = o_response;
		}


		a_languages = a_languages.filter(function (value) {
			return value;
		});

		var o_ns = ip2.resource.get("adm.ns");
		i_self.setEnumValues(o_ns.enums.languages.values);

		i_self.setLanguages(a_languages, s_context);
	},

	getLanguages: function(s_context) {

		var i_self = this;
		var o_stored = i_self.getStored();

		if (!s_context) {
			s_context = i_self.getContext();
		}

		if (!o_stored.hasOwnProperty(s_context)) {
			i_self.reload(s_context);
		}
		var value = o_stored[s_context] ||  [];
		return value;
	},

	setLanguages: function(value, s_context) {

		var i_self = this;
		s_context = s_context || i_self.getContext();
		var o_stored = i_self.getStored();
		o_stored[s_context] = value;
	},

	getAll: function (b_reload) {

		var i_self = this;

		var a_languages = i_self.getLanguages();

		if (!a_languages || b_reload) {
			i_self.reload();
			a_languages = i_self.getLanguages();
		}

		return a_languages;
	},

	getPrimary: function () {

		var i_user = ip2.getUser();
		return i_user.get("USRLNG");
	},

	getEnum: function (s_value, s_lang) {

		var i_self = this;

		var o_enumValues = i_self.getEnumValues();
		var s_enumValue = "";

		var o_enum = o_enumValues[s_value];

		if (!s_lang) {
			s_enumValue = ip2.i18n(o_enum);
		}
		else {
			s_enumValue = o_enum[s_lang];
		}

		return s_enumValue;
	}

}, function() {
	var i_self = this;
	i_self.reload();
});
Ext.define("Ext.ux.Notification", {

	singleton: true,

	config: {
		notification: []
	},

	constructor: function (o_config) {
		var i_self = this;

		i_self.initConfig(o_config);

		return i_self;
	},

	getDefaultOffset: function () {
		var defaultOffset = [-10, -10];
		if (!Ext.isIE9m) {
			if (Ext.getBody().getHeight() > Ext.Element.getViewportHeight()) {
				defaultOffset[0] = -10 - Ext.getScrollbarSize().width;
			}
			if (Ext.getBody().getWidth() > Ext.Element.getViewportWidth()) {
				defaultOffset[1] = -10 - Ext.getScrollbarSize().height;
			}
		}
		return defaultOffset;
	},
	notify: function (title, msg) {
		if (Ext.isString(title)) {
			Ext.ux.Notification.show({
				title: title,
				html: msg || ""
			});
		} else {
			Ext.ux.Notification.show(title);
		}
	},
	show: function (config) {
		if (config && (config.items || config.dockedItems)) {
			var resources = [];
			if (config.items && config.items['x.res']) {
				if (config.items['x.res'].ns) {
					Ext.ns.apply(Ext, config.items['x.res'].ns);
				}
				if (config.items['x.res'].res) {
					resources = config.items['x.res'].res;
				}
				config.items = config.items.config;
			}
			if (config.dockedItems && config.dockedItems['x.res']) {
				if (config.dockedItems['x.res'].ns) {
					Ext.ns.apply(Ext, config.dockedItems['x.res'].ns);
				}
				if (config.dockedItems['x.res'].res) {
					resources = Ext.Array.push(resources, config.dockedItems['x.res'].res);
				}
				config.dockedItems = config.dockedItems.config;
			}
			if (resources.length > 0) {
				Ext.ux.ResourceMgr.load(resources, Ext.Function.bind(this.show, this, [config]));
				return;
			} else {
				if (Ext.isString(config.items)) {
					config.items = Ext.decode(config.items);
				}
				if (Ext.isString(config.dockedItems)) {
					config.dockedItems = Ext.decode(config.dockedItems);
				}
			}
		}
		config = config || {};
		var removeHeight = (Ext.isDefined(config.height) && !config.height) || (config.bodyStyle && config.bodyStyle.match(/height\s*:\s*auto/g));
		config = Ext.applyIf(config, {
			width: 200,
			height: 100,
			autoHide: true,
			plain: false,
			resizable: false,
			draggable: false,
			alignToCfg: {
				el: document,
				position: "br-br",
				offset: this.getDefaultOffset()
			},
			showMode: "grid",
			closeVisible: false,
			bringToFront: false,
			focusOnToFront: false,
			pinEvent: "none",
			hideDelay: 2500,
			shadow: false,
			showPin: false,
			pinned: false,
			showFx: {
				fxName: "slideIn",
				args: ["b", {}]
			},
			hideFx: {
				fxName: "slideOut",
				args: ["b", {}]
			},
			focus: Ext.emptyFn,
			stopHiding: function () {
				if (this.tools && this.tools.close && this.tools.close.show) {
					this.tools.close.show();
				}
				this.pinned = true;
				if (this.autoHide) {
					this.hideTask.cancel();
				}
			},
			isStandardAlign: function () {
				return this.alignToCfg.el == document && this.alignToCfg.position == "br-br";
			},
			getStatndardAlign: function () {
				var w = [];
				for (var i = 0; i < Ext.ux.Notification.getNotification().length; i++) {
					var window = Ext.ux.Notification.getNotification()[i];
					if (window.isStandardAlign()) {
						w.push(window);
					}
				}
				return w;
			},
			getOffset: function () {
				var offset = [],
					predefinedOffset = this.alignToCfg.offset || Ext.ux.Notification.getDefaultOffset();
				offset.push(predefinedOffset[0]);
				offset.push(predefinedOffset[1]);
				if (this.showMode == "grid" && this.isStandardAlign()) {
					var saw = this.getStatndardAlign(),
						height = this.getSize().height - offset[1],
						width = this.getSize().width - offset[0],
						yPos = Ext.fly(this.alignToCfg.el).getViewSize().height - height,
						xPos = Ext.fly(this.alignToCfg.el).getViewSize().width - width,
						found = false,
						isIntersect = function (tBox, box) {
							tBox.x2 = tBox.x + tBox.width;
							tBox.y2 = tBox.y + tBox.height;
							box.x2 = box.x + box.width;
							box.y2 = box.y + box.height;
							if ((tBox.x2 - box.x) <= 0 || (box.x2 - tBox.x) <= 0) {
								return false;
							}
							if ((tBox.y2 - box.y) <= 0 || (box.y2 - tBox.y) <= 0) {
								return false;
							}
							return true;
						};

					if (saw.length > 0) {
						yPos = saw[0].getBox().top;
					}

					while (xPos >= 0 && !found) {

						while (yPos > 0 && !found) {

							var intersect = false;

							Ext.Array.each(saw, function (i_window) {
								var box = i_window.getBox();
								if (box.width === 0 && box.height === 0) {
									box = window._defaultBox;
								}
								if (isIntersect({
									x: xPos,
									y: yPos,
									width: width,
									height: height
								}, box)) {
									intersect = true;
								}
							});

							found = !intersect;

							if (!found) {
								yPos -= height;
							}
						}

						if (!found) {
							yPos = Ext.fly(this.alignToCfg.el).getViewSize().height - height;
							xPos -= width;
						}
					}
					if (found) {
						this._defaultBox = {
							x: xPos,
							y: yPos,
							width: width,
							height: height
						};
						offset[0] = offset[0] + ((xPos + width) - Ext.fly(this.alignToCfg.el).getViewSize().width);
						offset[1] = offset[1] + ((yPos + height) - Ext.fly(this.alignToCfg.el).getViewSize().height);
					}
				}
				return offset;
			},
			afterShow: function () {
				var offset = this.getOffset(), listeners;
				Ext.ux.Notification.getNotification().push(this);
				this._showing = true;
				this.alignOffset = offset;
				this.el.alignTo(this.alignToCfg.el || document, this.alignToCfg.position || "br-br", offset);
				this.el.setDisplayed(this.showFx.fxName == "frame" || this.showFx.fxName == "highlight");
				this.el[this.showFx.fxName].apply(this.el, this.showFx.args);
				listeners = {
					beforeanimate: this.beforeAnimate,
					afteranimate: this._afterShow,
					scope: this
				};
				if (this.showFx.fxName == "fadeIn") {
					delete listeners.beforeanimate;
					this.el.setOpacity(0, false);
				}
				Ext.fx.Manager.getFxQueue(this.el.dom.id || Ext.id(this.el.dom))[0].on(listeners);
			},
			beforeAnimate: function () {
				this.el.setDisplayed(true);
				if (this.bringToFront) {
					this.toFront();
				}
			},
			_afterShow: function () {
				this._showing = false;
				if (this._closed) {
					this.destroy();
					return;
				}
				this.toFront();
				if (this.shadow) {
					this.el.enableShadow(true);
				}
				this.onShowComplete();
			},
			onHide: function () {
				if (this._closed) {
					return;
				}
				if (Ext.isArray(this.hideFx.args) && this.hideFx.args.length > 0) {
					this.hideFx.args[this.hideFx.args.length - 1] = Ext.apply(this.hideFx.args[this.hideFx.args.length - 1], {
						listeners: {
							afteranimate: this._hide,
							scope: this
						}
					});
				} else {
					this.hideFx.args = [{
						listeners: {
							afteranimate: this._hide,
							scope: this
						}
					}];
				}
				this.el[this.hideFx.fxName].apply(this.el, this.hideFx.args);
			},
			_hide: function () {
				this.hidden = true;
				this.el.hide();
				this.afterHide();
				this.fireEvent('close', this);
				this.destroy();
			}
		});
		if (removeHeight) {
			delete config.height;
		}
		config.cls = config.cls || "";
		config.cls += " x-notification";
		if (config.closeVisible) {
			for (var i = Ext.ux.Notification.getNotification().length - 1; i >= 0; i--) {
				Ext.ux.Notification.getNotification()[i]._closed = true;
				if (!Ext.ux.Notification.getNotification()[i]._showing) {
					Ext.ux.Notification.getNotification()[i].destroy();
				}
			}
			Ext.ux.Notification.setNotification([]);
		}
		var w = new Ext.window.Window(config),
			mOver = function (e, t) {
				if (!this.pinned) {
					this.hideTask.cancel();
					this.delayed = true;
				}
			},
			mOut = function (e, t) {
				if (!this.pinned) {
					this.hideTask.delay(this.hideDelay);
					this.delayed = false;
				}
			};
		w.on("render", function () {
			if (this.autoHide) {
				this.el.on("mouseover", mOver, this);
				this.el.on("mouseout", mOut, this);
				if (this.header && this.tools.close && !this.forceCloseTool) {
					this.tools.close.hide();
				}
			}
			if (this.contentEl) {
				Ext.fly(this.contentEl).removeCls("x-hide-offsets");
			}
		}, w);
		w.afterRender = Ext.Function.createSequence(w.afterRender, function () {
			if (this.showPin) {
				this.pin = function (e, toolEl, owner, tool) {
					this.tools.unpin.hide();
					this.tools.pin.show();
					this.hideTask.cancel();
					this.pinned = true;
				}
					;
				this.unpin = function (e, toolEl, owner, tool) {
					this.tools.pin.hide();
					this.tools.unpin.show();
					this.hide();
					this.pinned = false;
				}
					;
				this.addTool({
					type: "unpin",
					itemId: "unpin",
					handler: this.pin,
					hidden: this.pinned,
					hideMode: "display",
					scope: this
				});
				this.addTool({
					type: "pin",
					itemId: "pin",
					handler: this.unpin,
					hidden: !this.pinned,
					hideMode: "display",
					scope: this
				});
			}
		});
		w.focus = Ext.emptyFn;
		w.afterShow = Ext.Function.createSequence(w.afterShow, function () {
			if (this.pinEvent !== "none") {
				this.el.on(this.pinEvent, this.stopHiding, this);
				this.on(this.pinEvent, this.stopHiding, this);
			}
			if (this.autoHide && !this.delayed && !this.pinned) {
				this.hideTask.delay(this.hideDelay);
			}
		});
		w.on("beforedestroy", function () {
			for (var i = 0; i < Ext.ux.Notification.getNotification().length; i++) {
				if (Ext.ux.Notification.getNotification()[i].id == this.id) {
					Ext.ux.Notification.getNotification().splice(i, 1);
					break;
				}
			}
			if (this.contentEl) {
				var ce = Ext.get(this.contentEl)
					, el = Ext.ux.ResourceMgr.getAspForm() || Ext.getBody();
				ce.addCls("x-hidden");
				el = el.dom;
				el.appendChild(ce.dom);
			}
			if (this.initialConfig.id) {
				window[this.initialConfig.id] = undefined;
			}
		}, w);
		if (config.autoHide) {
			w.hideTask = new Ext.util.DelayedTask(w.hide, w);
		}
		w.on("beforehide", function () {
			this.el.disableShadow();
		}, w);
		w.show();
		return w;
	}
}, function() {
	Ext.onReady(function () {
		Ext.MessageBox.notify = Ext.ux.Notification.notify;
	});
});
/**
 * Base class from Ext.ux.TabReorderer.
 */
Ext.define('Ext.ux.BoxReorderer', {

	mixins: {
		observable: 'Ext.util.Observable'
	},

	alias: "plugin.boxreorder",

	/**
	 * @cfg {String} itemSelector
	 * A {@link Ext.DomQuery DomQuery} selector which identifies the encapsulating elements of child
	 * Components which participate in reordering.
	 */
	itemSelector: '.x-box-item',

	/**
	 * @cfg {Mixed} animate
	 * If truthy, child reordering is animated so that moved boxes slide smoothly into position.
	 * If this option is numeric, it is used as the animation duration in milliseconds.
	 */
	animate: 100,

	/**
	 * @event StartDrag
	 * Fires when dragging of a child Component begins.
	 * @param {Ext.ux.BoxReorderer} this
	 * @param {Ext.container.Container} container The owning Container
	 * @param {Ext.Component} dragCmp The Component being dragged
	 * @param {Number} idx The start index of the Component being dragged.
	 */

	/**
	 * @event Drag
	 * Fires during dragging of a child Component.
	 * @param {Ext.ux.BoxReorderer} this
	 * @param {Ext.container.Container} container The owning Container
	 * @param {Ext.Component} dragCmp The Component being dragged
	 * @param {Number} startIdx The index position from which the Component was initially dragged.
	 * @param {Number} idx The current closest index to which the Component would drop.
	 */

	/**
	 * @event ChangeIndex
	 * Fires when dragging of a child Component causes its drop index to change.
	 * @param {Ext.ux.BoxReorderer} this
	 * @param {Ext.container.Container} container The owning Container
	 * @param {Ext.Component} dragCmp The Component being dragged
	 * @param {Number} startIdx The index position from which the Component was initially dragged.
	 * @param {Number} idx The current closest index to which the Component would drop.
	 */

	/**
	 * @event Drop
	 * Fires when a child Component is dropped at a new index position.
	 * @param {Ext.ux.BoxReorderer} this
	 * @param {Ext.container.Container} container The owning Container
	 * @param {Ext.Component} dragCmp The Component being dropped
	 * @param {Number} startIdx The index position from which the Component was initially dragged.
	 * @param {Number} idx The index at which the Component is being dropped.
	 */

	constructor: function() {
		this.mixins.observable.constructor.apply(this, arguments);
	},

	init: function(container) {
		var me = this;

		me.container = container;

		// Set our animatePolicy to animate the start position (ie x for HBox, y for VBox)
		me.animatePolicy = {};
		me.animatePolicy[container.getLayout().names.x] = true;



		// Initialize the DD on first layout, when the innerCt has been created.
		me.container.on({
			scope: me,
			boxready: me.onBoxReady,
			beforedestroy: me.onContainerDestroy
		});
	},

	/**
	 * @private Clear up on Container destroy
	 */
	onContainerDestroy: function() {
		var dd = this.dd;
		if (dd) {
			dd.unreg();
			this.dd = null;
		}
	},

	onBoxReady: function() {
		var me = this,
			layout = me.container.getLayout(),
			names = layout.names,
			dd;

		// Create a DD instance. Poke the handlers in.
		// TODO: Ext5's DD classes should apply config to themselves.
		// TODO: Ext5's DD classes should not use init internally because it collides with use as a plugin
		// TODO: Ext5's DD classes should be Observable.
		// TODO: When all the above are trus, this plugin should extend the DD class.
		dd = me.dd = new Ext.dd.DD(layout.innerCt, me.container.id + '-reorderer');
		Ext.apply(dd, {
			animate: me.animate,
			reorderer: me,
			container: me.container,
			getDragCmp: me.getDragCmp,
			clickValidator: Ext.Function.createInterceptor(dd.clickValidator, me.clickValidator, me, false),
			onMouseDown: me.onMouseDown,
			startDrag: me.startDrag,
			onDrag: me.onDrag,
			endDrag: me.endDrag,
			getNewIndex: me.getNewIndex,
			doSwap: me.doSwap,
			findReorderable: me.findReorderable
		});

		// Decide which dimension we are measuring, and which measurement metric defines
		// the *start* of the box depending upon orientation.
		dd.dim = names.width;
		dd.startAttr = names.beforeX;
		dd.endAttr = names.afterX;
	},

	getDragCmp: function(e) {
		return this.container.getChildByElement(e.getTarget(this.itemSelector, 10));
	},

	// check if the clicked component is reorderable
	clickValidator: function(e) {
		var cmp = this.getDragCmp(e);

		// If cmp is null, this expression MUST be coerced to boolean so that createInterceptor is able to test it against false
		return !!(cmp && cmp.reorderable !== false);
	},

	onMouseDown: function(e) {
		var me = this,
			container = me.container,
			containerBox,
			cmpEl,
			cmpBox;

		// Ascertain which child Component is being mousedowned
		me.dragCmp = me.getDragCmp(e);
		if (me.dragCmp) {
			cmpEl = me.dragCmp.getEl();
			me.startIndex = me.curIndex = container.items.indexOf(me.dragCmp);

			// Start position of dragged Component
			cmpBox = cmpEl.getBox();

			// Last tracked start position
			me.lastPos = cmpBox[me.startAttr];

			// Calculate constraints depending upon orientation
			// Calculate offset from mouse to dragEl position
			containerBox = container.el.getBox();
			if (me.dim === 'width') {
				me.minX = containerBox.left;
				me.maxX = containerBox.right - cmpBox.width;
				me.minY = me.maxY = cmpBox.top;
				me.deltaX = e.getX() - cmpBox.left;
			} else {
				me.minY = containerBox.top;
				me.maxY = containerBox.bottom - cmpBox.height;
				me.minX = me.maxX = cmpBox.left;
				me.deltaY = e.getY() - cmpBox.top;
			}
			me.constrainY = me.constrainX = true;
		}
	},

	startDrag: function() {
		var me = this,
			dragCmp = me.dragCmp;

		if (dragCmp) {
			// For the entire duration of dragging the *Element*, defeat any positioning and animation of the dragged *Component*
			dragCmp.setPosition = Ext.emptyFn;
			dragCmp.animate = false;

			// Animate the BoxLayout just for the duration of the drag operation.
			if (me.animate) {
				me.container.getLayout().animatePolicy = me.reorderer.animatePolicy;
			}
			// We drag the Component element
			me.dragElId = dragCmp.getEl().id;
			me.reorderer.fireEvent('StartDrag', me, me.container, dragCmp, me.curIndex);
			// Suspend events, and set the disabled flag so that the mousedown and mouseup events
			// that are going to take place do not cause any other UI interaction.
			dragCmp.suspendEvents();
			dragCmp.disabled = true;
			dragCmp.el.setStyle('zIndex', 100);
		} else {
			me.dragElId = null;
		}
	},

	/**
	 * @private
	 * Find next or previous reorderable component index.
	 * @param {Number} newIndex The initial drop index.
	 * @return {Number} The index of the reorderable component.
	 */
	findReorderable: function(newIndex) {
		var me = this,
			items = me.container.items,
			newItem;

		if (items.getAt(newIndex).reorderable === false) {
			newItem = items.getAt(newIndex);
			if (newIndex > me.startIndex) {
				 while(newItem && newItem.reorderable === false) {
					newIndex++;
					newItem = items.getAt(newIndex);
				}
			} else {
				while(newItem && newItem.reorderable === false) {
					newIndex--;
					newItem = items.getAt(newIndex);
				}
			}
		}

		newIndex = Math.min(Math.max(newIndex, 0), items.getCount() - 1);

		if (items.getAt(newIndex).reorderable === false) {
			return -1;
		}
		return newIndex;
	},

	/**
	 * @private
	 * Swap 2 components.
	 * @param {Number} newIndex The initial drop index.
	 */
	doSwap: function(newIndex) {
		var me = this,
			items = me.container.items,
			container = me.container,
			wasRoot = me.container._isLayoutRoot,
			orig, dest, tmpIndex;

		newIndex = me.findReorderable(newIndex);

		if (newIndex === -1) {
			return;
		}

		me.reorderer.fireEvent('ChangeIndex', me, container, me.dragCmp, me.startIndex, newIndex);
		orig = items.getAt(me.curIndex);
		dest = items.getAt(newIndex);
		items.remove(orig);
		tmpIndex = Math.min(Math.max(newIndex, 0), items.getCount() - 1);
		items.insert(tmpIndex, orig);
		items.remove(dest);
		items.insert(me.curIndex, dest);

		// Make the Box Container the topmost layout participant during the layout.
		container._isLayoutRoot = true;
		container.updateLayout();
		container._isLayoutRoot = wasRoot;
		me.curIndex = newIndex;
	},

	onDrag: function(e) {
		var me = this,
			newIndex;

		newIndex = me.getNewIndex(e.getPoint());
		if ((newIndex !== undefined)) {
			me.reorderer.fireEvent('Drag', me, me.container, me.dragCmp, me.startIndex, me.curIndex);
			me.doSwap(newIndex);
		}

	},

	endDrag: function(e) {
		if (e) {
			e.stopEvent();
		}
		var me = this,
			layout = me.container.getLayout(),
			temp;

		if (me.dragCmp && !me.reorderer.removeOnDrop(e.target.offsetParent, me.dragCmp)) {
			delete me.dragElId;

			// Reinstate the Component's positioning method after mouseup, and allow the layout system to animate it.
			delete me.dragCmp.setPosition;
			me.dragCmp.animate = true;

			// Ensure the lastBox is correct for the animation system to restore to when it creates the "from" animation frame
			me.dragCmp.lastBox[layout.names.x] = me.dragCmp.getPosition(true)[layout.names.widthIndex];

			// Make the Box Container the topmost layout participant during the layout.
			me.container._isLayoutRoot = true;
			me.container.updateLayout();
			me.container._isLayoutRoot = undefined;

			// Attempt to hook into the afteranimate event of the drag Component to call the cleanup
			temp = Ext.fx.Manager.getFxQueue(me.dragCmp.el.id)[0];
			if (temp) {
				temp.on({
					afteranimate: me.reorderer.afterBoxReflow,
					scope: me
				});
			}
			// If not animated, clean up after the mouseup has happened so that we don't click the thing being dragged
			else {
				Ext.Function.defer(me.reorderer.afterBoxReflow, 1, me);
			}

			if (me.animate) {
				delete layout.animatePolicy;
			}
			me.reorderer.fireEvent('drop', me, me.container, me.dragCmp, me.startIndex, me.curIndex);
		}
	},

	// THIS IS FOR HANDLING DROP IF WE SHOULD REMOVE THEM
	removeOnDrop: function() {
		return false;
	},

	/**
	 * @private
	 * Called after the boxes have been reflowed after the drop.
	 * Re-enabled the dragged Component.
	 */
	afterBoxReflow: function() {
		var me = this;
		me.dragCmp.el.setStyle('zIndex', '');
		me.dragCmp.disabled = false;
		me.dragCmp.resumeEvents();
	},

	/**
	 * @private
	 * Calculate drop index based upon the dragEl's position.
	 */
	getNewIndex: function(pointerPos) {
		var me = this,
			dragEl = me.getDragEl(),
			dragBox = Ext.fly(dragEl).getBox(),
			targetEl,
			targetBox,
			targetMidpoint,
			i = 0,
			it = me.container.items.items,
			ln = it.length,
			lastPos = me.lastPos;

		me.lastPos = dragBox[me.startAttr];

		for (; i < ln; i++) {
			targetEl = it[i].getEl();

			// Only look for a drop point if this found item is an item according to our selector
			if (targetEl.is(me.reorderer.itemSelector)) {
				targetBox = targetEl.getBox();
				targetMidpoint = targetBox[me.startAttr] + (targetBox[me.dim] >> 1);
				if (i < me.curIndex) {
					if ((dragBox[me.startAttr] < lastPos) && (dragBox[me.startAttr] < (targetMidpoint - 5))) {
						return i;
					}
				} else if (i > me.curIndex) {
					if ((dragBox[me.startAttr] > lastPos) && (dragBox[me.endAttr] > (targetMidpoint + 5))) {
						return i;
					}
				}
			}
		}
	}
});
/**
 * This plugin allow you to reorder tabs of a TabPanel.
 */
Ext.define('Ext.ux.TabReorderer', {

	extend: 'Ext.ux.BoxReorderer',
	alias: 'plugin.tabreorderer',

	itemSelector: '.' + Ext.baseCSSPrefix + 'tab',

	init: function(tabPanel) {
		var me = this;

		me.callParent([tabPanel.getTabBar()]);

		// Ensure reorderable property is copied into dynamically added tabs
		tabPanel.onAdd = Ext.Function.createSequence(tabPanel.onAdd, me.onAdd);
	},

	onBoxReady: function() {
		var tabs,
			len,
			i = 0,
			tab;

		this.callParent(arguments);

		// Copy reorderable property from card into tab
		for (tabs = this.container.items.items, len = tabs.length; i < len; i++) {
			tab = tabs[i];
			if (tab.card) {
				tab.reorderable = tab.card.reorderable;
			}
		}
	},

	onAdd: function(card, index) {
		card.tab.reorderable = card.reorderable;
	},

	afterBoxReflow: function() {
		var me = this;

		// Cannot use callParent, this is not called in the scope of this plugin, but that of its Ext.dd.DD object
		Ext.ux.BoxReorderer.prototype.afterBoxReflow.apply(me, arguments);

		// Move the associated card to match the tab order
		if (me.dragCmp) {
			me.container.tabPanel.setActiveTab(me.dragCmp.card);
			me.container.tabPanel.move(me.dragCmp.card, me.curIndex);
		}
	}
});
/**
 * Plugin for adding a close context menu to tabs. Note that the menu respects
 * the closable configuration on the tab. As such, commands like remove others
 * and remove all will not remove items that are not closable.
 */
Ext.define("Ext.ux.TabCloseMenu", {
	extend: "Ext.plugin.Abstract",

	alias: "plugin.tabclosemenu",

	mixins: {
		observable: "Ext.util.Observable"
	},

	/**
	 * @cfg {String} closeTabText
	 * The text for closing the current tab.
	 */
	closeTabText: "Close Tab",

	/**
	 * @cfg {Boolean} showCloseOthers
	 * Indicates whether to show the "Close Others" option.
	 */
	showCloseOthers: true,

	/**
	 * @cfg {String} closeOthersTabsText
	 * The text for closing all tabs except the current one.
	 */
	closeOthersTabsText: "Close Other Tabs",

	/**
	 * @cfg {Boolean} showCloseAll
	 * Indicates whether to show the "Close All" option.
	 */
	showCloseAll: true,

	/**
	 * @cfg {String} closeAllTabsText
	 * The text for closing all tabs.
	 */
	closeAllTabsText: "Close All Tabs",

	/**
	 * @cfg {Array} extraItemsHead
	 * An array of additional context menu items to add to the front of the context menu.
	 */
	extraItemsHead: null,

	/**
	 * @cfg {Array} extraItemsTail
	 * An array of additional context menu items to add to the end of the context menu.
	 */
	extraItemsTail: null,

	//public
	constructor: function (config) {
		this.callParent([config]);
		this.mixins.observable.constructor.call(this, config);
	},

	init: function(tabpanel) {
		this.tabPanel = tabpanel;
		this.tabBar = tabpanel.down("tabbar");

		this.mon(this.tabPanel, {
			scope: this,
			afterlayout: this.onAfterLayout,
			single: true
		});
	},

	onAfterLayout: function() {
		this.mon(this.tabBar.el, {
			scope: this,
			contextmenu: this.onContextMenu,
			delegate: ".x-tab"
		});
	},

	destroy: function() {
		this.callParent();
		Ext.destroy(this.menu);
	},

	// private
	onContextMenu : function(event, target) {
		var me = this,
			menu = me.createMenu(),
			disableAll = true,
			disableOthers = true,
			tab = me.tabBar.getChildByElement(target),
			index = me.tabBar.items.indexOf(tab);

		me.item = me.tabPanel.getComponent(index);
		menu.child("#close").setDisabled(!me.item.closable);

		if (me.showCloseAll || me.showCloseOthers) {
			me.tabPanel.items.each(function(item) {
				if (item.closable) {
					disableAll = false;
					if (item !== me.item) {
						disableOthers = false;
						return false;
					}
				}
				return true;
			});

			if (me.showCloseAll) {
				menu.child("#closeAll").setDisabled(disableAll);
			}

			if (me.showCloseOthers) {
				menu.child("#closeOthers").setDisabled(disableOthers);
			}

			if (me.tabBar.items.length == 1) {
				menu.child("#compare").setDisabled(true);
			}
			else {
				menu.child("#compare").setDisabled(false);
			}
		}

		event.preventDefault();
		me.fireEvent("beforemenu", menu, me.item, me);

		menu.showAt(event.getXY());
	},

	createMenu: function() {
		var me = this;

		if (!me.menu) {

			var items = [{
				itemId: "close",
				text: me.closeTabText,
				scope: me,
				handler: me.onClose
			}];

			items.push({
				itemId: "toWindow",
				text: "To window",
				scope: me,
				handler: me.toWindow
			});

			items.push({
				xtype: "menuitem",
				itemId: "compare",
				text: "Compare",
				scope: me,
				menu: {
					listeners: {
						beforeshow: {
							fn: function(i_menu) {

								i_menu.removeAll(true);

								var a_tabs = me.tabPanel.items.getRange();

								var a_items = [];

								Ext.Array.each(a_tabs, function(i_tab) {


									if (i_tab != me.item) {

										var s_title = i_tab.title;

										var o_item = {
											xtype: "menuitem",
											text: s_title,
											tab: i_tab,
											handler: function (i_item) {
												Portfolio.app.fireEvent("compare", me.item, i_tab);
											}
										};

										a_items.push(o_item);
									}
								});

								i_menu.add(a_items);
							}
						}
					}
				}
			});

			if (me.showCloseAll || me.showCloseOthers) {
				items.push("-");
			}

			if (me.showCloseOthers) {
				items.push({
					itemId: "closeOthers",
					text: me.closeOthersTabsText,
					scope: me,
					handler: me.onCloseOthers
				});
			}

			if (me.showCloseAll) {
				items.push({
					itemId: "closeAll",
					text: me.closeAllTabsText,
					scope: me,
					handler: me.onCloseAll
				});
			}

			if (me.extraItemsHead) {
				items = me.extraItemsHead.concat(items);
			}

			if (me.extraItemsTail) {
				items = items.concat(me.extraItemsTail);
			}

			me.menu = Ext.create("Ext.menu.Menu", {
				items: items,
				listeners: {
					hide: me.onHideMenu,
					scope: me
				}
			});
		}

		return me.menu;
	},

	onHideMenu: function () {
		var me = this;
		me.fireEvent("aftermenu", me.menu, me);
	},

	onClose: function() {
		this.tabPanel.remove(this.item);
	},

	onCloseOthers: function() {
		this.doClose(true);
	},

	onCloseAll: function() {
		this.doClose(false);
	},

	doClose: function(excludeActive) {
		var items = [];

		this.tabPanel.items.each(function(item) {
			if (item.closable) {
				if (!excludeActive || item !== this.item) {
					items.push(item);
				}
			}
		}, this);

		Ext.suspendLayouts();
		Ext.Array.each(items, function(item) {
			this.tabPanel.remove(item);
		}, this);
		Ext.resumeLayouts(true);
	},

	toWindow: function () {

		var i_self = this;
		var i_item = i_self.item;

		Portfolio.app.fireEvent("toWindow", i_item);
	}
});

Ext.define('Ext.ux.plugin.data.Tracker', {

	alias: ['plugin.datatracker', 'plugin.DataTracker'],

	extend: 'Ext.AbstractPlugin',

	statics: {
		datatracks: {
			items: [],
			getTrack: function(filterFn) {

				var tracks = Ext.ux.plugin.data.Tracker.datatracks,
					items = tracks.items,
					response = [];

				Ext.Array.each(items, function(track) {
					Ext.Array.each(track, function(trackItem) {
						if (Ext.isFunction(filterFn)) {
							if (filterFn.call(tracks, trackItem))
								response.push(trackItem);
						}
						else {
							response.push(trackItem);
						}
					});
				});

				return response;
			}
		}
	},

	/**
	 * @private
	 *
	 */
	_dataTrack: null,

	/**
	 * @private
	 *
	 */
	_dataParent: null,

	init: function(component) {

		var plugin = this;

		plugin.pluginId = 'datatracker';

		plugin.initDataTracker(component);

		// Make sure this is rendered
		//component.on('afterrender', plugin.initDataTracker, plugin, {single:true});
	},

	initDataTracker: function(component) {

		var plugin = this,
			configParent,
			parent;

		component._isDataTrackerReady = false;

		// TODO: Remove dataParent - conflict on automatic getters and setters in initalConfig!!
		parent = component.initialConfig.dataParent;

		if (component.initialConfig.trackerParent)
			parent = component.initialConfig.trackerParent;

		if (parent) {
			plugin._dataParent = parent;
		}

		// Apply getter methods for the component
		Ext.apply(component, {
			getDataTrack: function (filterFn) {

				var self = this,
					dataParent;

				dataParent = self.getDataParent();

				function DataTracks() {

					this.length = 0;

					this.items = [];

					if (dataParent) this.initialize(dataParent);
				}

				DataTracks.prototype = {

					initialize: function(item) {

						var self = this,
							parentItem;

						self.items.push(item);

						self[self.length] = item;

						self.length++;

						if (Ext.isFunction(item.getParent)) {

							parentItem = item.getParent();

							if (parentItem)
								self.initialize(parentItem);
						}
					},

					each: function(fn, scope) {

						scope = scope || this;

						var self = this,
							items = self.items,
							i = 0,
							len = items.length;

						for (; i < len; i++) {

							var item = items[i];

							fn.call(scope, item, i, items);
						}

						return self;
					},

					some: function(fn, scope) {

						scope = scope || this;

						var self = this,
							items = self.items,
							i = 0,
							len = items.length;

						for (; i < len; i++) {

							var item = items[i];

							if (fn.call(scope, item, i, items)) return true;
						}

						return false;
					},

					findBy: function (f_handler) {

						var m_return = null;

						this.each(function (i_item) {

							var m_temp = f_handler.apply(this, arguments);

							if (m_temp) {

								m_return = i_item;

								return false;
							}
						});

						return m_return;
					},

					getKeys: function() {

						var self = this,
							keys = {};

						self.each(function(item) {

							var parentKeys = item.getKeys();

							if (parentKeys) {

								parentKeys = Ext.decode(parentKeys);

								Ext.Object.merge(keys, parentKeys);
							}
						});

						return keys;
					},

					getKeyNames: function() {

						var self = this,
							namesArray = [],
							names;

						self.each(function(item) {

							var keys = item.getKeys(),
								prop;

							if (keys) {

								keys = Ext.decode(keys);

								for (prop in keys) {

									namesArray.push(prop);
								}
							}
						});

						// Remove doublets from array
						names = Ext.Array.filter(namesArray, function(item, index) {

							return Ext.Array.indexOf(namesArray, item) == index;
						});

						return names;
					},

					getKeyValues: function() {

						var self = this,
							valuesArray = [],
							values;

						self.each(function(item) {

							var keys = item.getKeys(),
								prop;

							if (keys) {

								keys = Ext.decode(keys);

								for (prop in keys) {

									valuesArray.push(keys[prop]);
								}
							}
						});

						// Remove doublets from array
						values = Ext.Array.filter(valuesArray, function(item, index) {

							return Ext.Array.indexOf(valuesArray, item) == index;
						});

						return values;
					},

					filter: function() {

						var self = this;
					},

					toJson: function() {

						var self = this;
					}
				};

				return new DataTracks();
			},
			getDataParent: function () {

				var self = this,
					plugin = self.getPlugin('datatracker'),
					parent = plugin.getDataParent(),
					response = null;

				if (!parent)
					return response;

				response = {
					self: parent,
					children: [],
					getParent: function() {
						return null;
					},
					getStore: function() {
						return null;
					},
					getModel: function() {
						return null;
					},
					getRecord: function() {
						return null;
					},
					getKeys: function() {
						return null;
					}
				};

				// Look for record getting method or other means of getting a record/records
				// Apply method getRecord to response object
				if (parent.getRecord || parent.record) {

					if (Ext.isFunction(parent.getRecord)) {
						response.getRecord = function() {
							return parent.getRecord.call(parent);
						};
					}
					else if (parent.record) {
						response.getRecord = function() {
							return parent.record;
						};
					}
				}

				// Look for a store getting method or other means of getting a store
				// Apply method getStore to response object
				if (parent.getStore || parent.store) {

					if (Ext.isFunction(parent.getStore)) {
						response.getStore = function() {
							return parent.getStore.call(parent);
						};
					}
					else if (parent.store) {
						response.getStore = function() {
							return parent.store;
						};
					}
				}

				// Look for a model getting method or other means of getting a model
				// Apply method getModel to response object
				if (parent.getModel || parent.model) {

					if (Ext.isFunction(parent.getModel)) {
						response.getModel = function() {
							return parent.getModel.call(parent);
						};
					}
					else if (parent.model) {
						response.getModel = function() {
							return parent.model;
						};
					}
				}

				if (parent.getKeys || parent.keys) {

					if (Ext.isFunction(parent.getKeys)) {
						response.getKeys = function() {
							return parent.getKeys.call(parent);
						};
					}
					else if (parent.model) {
						response.getKeys = function() {
							return parent.keys;
						};
					}
				}

				if (Ext.isFunction(parent.getDataParent)) {
					response.getParent = function() {
						return parent.getDataParent.call(parent);
					};
				}

				return response;
			},
			getDataChildren: function (filterFn) {

				var self = this,
					plugin = self.getPlugin('datatracker'),
					roottrack = plugin.getRootTrack(),
					response = [];

				return response;
			},
			setDataParent: function (parent) {

				var self = this;

				plugin.setDataParent(parent);

				return self;
			},
			getDataRoot: function () {

				var self = this,
					dataTrack = self.getDataTrack(),
					root;

				dataTrack.some(function (track) {

					if (!track.getParent()) {
						root = track;
					}
					return true;
				});
			}
		});

		component._isDataTrackerReady = true;

		component.fireEvent('datatrackerinit', component, plugin);
	},

	// Only handles ID for now!
	_queryDataParent: function(request) {

		var response;

		// Determine type of request

		// Is this an Ext component?
		// TODO: Do some actual checking if it is an Ext component
		if (Ext.isObject(request))
			response = request;

		// This is a string, treat is as a query
		if (Ext.isString(request)) {
			response = Ext.getCmp(request);
		}

		return response;
	},

	getDataParent: function() {

		return this._queryDataParent(this._dataParent);
	},

	getDataTrack: function() {

		return this._dataTrack;
	},

	getRootTrack: function() {

		return Ext.ux.plugin.data.Tracker.datatracks;
	},

	setDataParent: function(parent) {

		var plugin = this,
			_dataParent;

		_dataParent = plugin._queryDataParent(parent);

		plugin._dataParent = _dataParent;

		return plugin;
	}
});
Ext.define('Ext.ux.util.ComponentController', {
	
	statics: {
		uppercaseFirst: function (str) {
			s = str + ''; //str.toLowerCase();
			return s.replace(/\b./g, function(m) {
				return m.toUpperCase();
			});
		}
	},

	initComponentController: function () {

		var i_cmp = this;

		i_cmp.__children = {};

		i_cmp.initReferences();

		return i_cmp;
	},

	initReferences: function () {

		var i_cmp = this,
			a_refs = i_cmp.refs;

		if (a_refs && a_refs.length) {
			Ext.Array.each(a_refs, function (o_ref) {

				var s_ref = o_ref.ref,
					s_method = 'get' + Ext.ux.util.ComponentController.uppercaseFirst(s_ref),
					s_selector = o_ref.selector;

				// Check if method getter already exists
				if (i_cmp[s_method]) {
					throw new Error('Method ' + s_method + ' already exists on ', i_cmp.$className);
				}
				else {
					i_cmp[s_method] = function () {

						var i_found;

						// Check if we have already found and stored the reference
						if (i_cmp.__children[s_ref]) {
							i_found = i_cmp.__children[s_ref];
						}

						// We have not, attempt to query and store it
						else {
							i_found = i_cmp.down(s_selector);
							if (i_found) i_cmp.__children[s_ref] = i_found;
						}

						return i_found;
					};
				}
			});
		}
	},

	control: function (o_control) {

		var i_cmp = this;

		Ext.Object.each(o_control, function (s_ref, o_listeners) {

			// Look for a referenced child and set the scope
			var i_child = i_cmp['get' + Ext.ux.util.ComponentController.uppercaseFirst(s_ref)](),
				i_scope = o_listeners.scope || i_cmp;

			// If a child was found - set the control for listeners
			if (i_child && Ext.isFunction(i_child.on)) {
				
				// Add the component controller and a getter to the child
				i_child.__componentController = i_cmp;
				i_child.getComponentController = function () {
					return this.__componentController;
				};

				// Pipe the event through to the controller if child was found
				// and event managment was present
				Ext.Object.each(o_listeners, function (s_key, f_action) {
					if (s_key != 'scope') {
						i_child.on(s_key, f_action, i_scope);
					}
				});
			}
		});

		return i_cmp;
	}
});

/**
 * @class Ext.ux.util.Dependencies
 * <p>[introduction here]
 * Example usage:</p>
 * <pre><code>
// [explanation here]
Ext.define('My.random.Class', {
	extend: ['Ext.panel.Panel'],
	mixins: {
		dependencies: 'Ext.ux.mixins.Dependencies'
    },
    initComponent: function() {

		this.callParent();

		this.initDependencies();
    }
});

// [explanation here]
var p = Ext.create('My.random.Class', {
	border: false,
	dependencies: [
		[
			'scripts/jquery.js',
			'styles/mystyle.css'
		],
		[
			'plugins/jquery.plugin.js'
		]
	],
	items: [{
		title: 'Some sub panel',
		width: 300,
		autoHeight: true,
		html: 'Some content'
	}],
	listeners: {
		'dependenciesinit': {
			fn: function(self) {
				console.log($, jQuery);
			}
		}
	}
});
</code></pre>
 */

Ext.define('Ext.ux.util.Dependencies', {

	statics: {
		_loaded: {}
	},

	/**
	 * @private
	 */
	_dependenciesStack: null,

	/**
	 * @private
	 */
	_dependenciesLoaded: null,

	/**
	 * @private
	 */
	_dependenciesRqsCnt: 0,

	/**
	 * @private
	 */
	_dependenciesPrevious: null,

	_dependenciesInitialized: false,

	/**
	 * Performs initialization of this mixin. Component classes using this mixin should call this method
	 * during their own initialization.
	 */
	initDependencies: function(scope, callback) {

		scope = scope || this;
		callback = callback || Ext.emptyFn;

		if (scope._dependenciesInitialized)
			return false;

		var me = scope,
			dependencies = me.dependencies || null,
			autoLoad = me.autoLoadDependencies || true;

		/**
		 * @private
		 */
		scope._dependenciesStack = [];

		/**
		 * @private
		 */
		scope._dependenciesLoaded = [];

		me._dependenciesInitialized = true;

		if (dependencies && autoLoad) {

			me.loadDependencies(dependencies, function() {

				me.fireEvent('dependenciesinit', me, me, me._dependenciesLoaded); // deprecate this event call

				me.fireEvent('dependencyinit', me, me._dependenciesLoaded);

				if (Ext.isFunction(callback)) {
					callback.call(me, me);
				}
			});
		}
	},

	/**
	     * [explanation here]
	     * @param {Array/String} src The dependencies to load, can be an array of strings, a string (one source file), an array of arrays (for nested dependencies)
	     * @param {Function} value2 Callback function
	     * @chainable
	     */
	loadDependencies: function(src, callback) {

		callback = callback || Ext.emptyFn;

		var me = this,
			stackEntry,
			i = 0;

		src = me._filterDependencies(src);

		stackEntry = {
			inProcess: 0,
			callback: callback,
			previous: me._dependenciesPrevious
		};

		if (src instanceof Array) {
			for (; i < src.length; i++) {
				if (!src[i]) src.splice(i, 1);
			}

			if (src[0] instanceof Array) {

				var s1 = src[0],
					s2 = src.slice(1);

				me.loadDependencies(s1, function () {

					if (s2.length === 0) {
						if (callback) callback.call();
					}

					else {
						me.loadDependencies(s2, function () {
							if (callback) callback.call();
						});
					}
				});

				return;
			}

			if (src.length) {

				me._dependenciesPushStack(stackEntry, src.length);

				for (i = 0; i < src.length; i++) {

					if (src[i]) {
						if (!me.isSourceLoaded(src[i])) {
							me.addLoadedSource(src[i]);
						}
						me._dependenciesLoadResource(src[i], stackEntry);
					}
				}
			}
			else {

				callback.call();
			}
		}

		else if (src) {

			// TODO: Check out all changes in this else if statement

			// START OF ADDED (force loading into the array loader part for easier check if already loaded)
			var a = [];
			a.push(src);
			me.loadDependencies(a);

			// END OF ADDED

			/* START OF REMOVED

				me._dependenciesPushStack(stackEntry, 1);
				me._dependenciesLoadResource(src, stackEntry);

			END OF REMOVED */
		}

		else {

			me.fireEvent('dependenciesloaded', me); // deprecate this call

			me._dependenciesReady = true;

			if (callback) callback.call();
		}

		return me;
	},

	/**
	 * @private
	 */
	_filterDependencies: function(m_dependencies) {

		var i_this = this,
			a_proxy = [],
			a_dependencies;

		if (!Ext.isArray(m_dependencies)) {
			a_proxy.push(m_dependencies);
			a_dependencies = i_this._filterDependencies(a_proxy);
		}
		else {
			a_dependencies = m_dependencies;
		}

		Ext.Array.each(a_dependencies, function(m_dependency, n_index) {

			if (Ext.isArray(m_dependency)) {
				m_dependency = i_this._filterDependencies(m_dependency);
			}
			else {

				// only allow js and css files to be cached like this!
				var a_split = m_dependency.split('.'),
					s_type = a_split[a_split.length - 1];

				if (s_type == 'js' || s_type == 'css') {

					if (i_this.isSourceLoaded(m_dependency)) {
						a_dependencies.splice(n_index, 1);
					}
				}
			}
		});

		return a_dependencies;
	},

	/**
	 * @private
	 */
	_dependenciesDoCallback: function(req) {

		var me = this;

		req.done = true;

		me._dependenciesRqsCnt--;

		// Handle memory leak in IE
		req.elm.onload = req.elm.onreadystatechange = null;

		if (req.head && req.elm.parentNode) {
			// You can't go and remove the item from the DOM structure if it's not loaded
			// You can have unexpected behaivor.
			// req.head.removeChild(req.elm);
		}

		// decement all previous requirements levels, This need to be seperate since callback can start increment
		for (var se = req.stackEntry; se; se = se.previous) {
			se.inProcess--;
		}

		for (se = req.stackEntry; se; se = se.previous) {

			if (se.callback	&& se.inProcess === 0) {

				var cb = se.callback;
				se.callback = null;
				cb.call();

				if (me._dependenciesRqsCnt === 0) {

					me._dependenciesStack = [];
					me.previous = null;
				}
			}
		}
	},

	/**
	 * @private
	 */
	_dependenciesLoadResource: function(src, stackEntry) {

		var me = this,
			req;

		req = {
			src: src,
			stackEntry: stackEntry,
			elm: {},
			head: document.getElementsByTagName("head")[0] || document.documentElement,
			done: false
		};

		me._dependenciesRqsCnt++;

		if (me._dependenciesLoaded[src]) {
			me._dependenciesDoCallback(req);
			return;
		}

		me._dependenciesLoaded[src] = true;

		var a_extension = src.split('.'),
			s_extension = a_extension[a_extension.length - 1]

		if (s_extension == 'css') {

			req.elm = document.createElement('link');
			req.elm.rel = 'stylesheet';
			req.elm.type = 'text/css';
			req.elm.href = src;

			(function() {
				// Load css file, scope is make for not population parent score with
				// img
				var img = document.createElement("img");

				img.style.position = "absolute";
				img.style.top = '-1000px';
				img.style.left = '-1000px';

				img.onerror = img.onload = function() {

					img.parentNode.removeChild(img);
					me._dependenciesDoCallback(req);
				};

				document.body.appendChild(img);

				img.src = src;
			})();
		}

		else if (s_extension == 'js') {

			req.elm = document.createElement('script');
			req.elm.type = 'text/javascript';
			req.elm.src = src;

			// This is for IE
			req.elm.onreadystatechange = function () {
				if ((this.readyState !== "loaded" && this.readyState !== "complete") || (req.done)) {
					return;
				}
				me._dependenciesDoCallback(req);
			};

			req.elm.onload = function () {
				me._dependenciesDoCallback(req);
			};
		}
		else {

			Ext.require(src, function () {
				me._dependenciesDoCallback(req);
			});

			return;
		}

		// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
		// This arises when a base node is used (#2709 and #4378).
		//req.head.insertBefore( req.elm, req.head.firstChild );

		// AND: The new item needs to be the last item in the DOM structure.
		// Else you may cause unespected problems in browser.
		req.head.appendChild(req.elm);

		return;
	},

	/**
	 * @private
	 */
	_dependenciesPushStack: function(stackEntry, len) {

		var me = this;

		for (var se = stackEntry; se; se = se.previous) {

			se.inProcess += len;
		}

		me._dependenciesStack.push(stackEntry);
		me._dependenciesPrevious = stackEntry;
	},

	addLoadedSource: function(s_src) {

		Ext.ux.util.Dependencies._loaded[s_src.toLowerCase()] = true;
	},

	isSourceLoaded: function(s_src) {

		return Ext.ux.util.Dependencies._loaded[s_src.toLowerCase()] ? true : false;
	},

	isDependencyReady: function() {

		var me = this,
			isReady;

		isReady = this._dependenciesRqsCnt === 0;

		return isReady;
	},

	isDependencyInit: function() {

		return this._dependenciesInitialized;
	}
});
Ext.define('Ext.ux.util.KeyMapping', {

	initKeyMapping: function () {

		var i_cmp = this;

		i_cmp.on('afterrender', function () {

			var i_view = i_cmp.getView && i_cmp.getView() ? i_cmp.getView() : null;

			if (i_view) {
				i_view.on('itemkeydown', function itemkeydown(i_self, i_record, o_item, n_index, e, eOpts) {
					
					var s_key = e.browserEvent.keyIdentifier,
						s_method;

					s_key = i_cmp._normalizeKeyMapping(s_key);
					
					s_method = ['on', s_key, 'Key'].join(''); // Deprecate this!
					i_cmp.fireEvent(s_method, i_cmp, i_record, o_item, n_index, e, eOpts); // Deprecate this!
					i_cmp[s_method] && i_cmp[s_method].apply(i_cmp, arguments); // Deprecate this!

					s_method = [s_key, 'Key'].join('');
					i_cmp.fireEvent(s_method, i_cmp, i_record, o_item, n_index, e, eOpts);
					i_cmp[s_method] && i_cmp[s_method].apply(i_cmp, arguments);
				});
			}
			else {
				i_cmp.getEl().on('keydown', function keydown(e, i_htmlNode, eOpts) {
					
					var s_key = e.browserEvent.keyIdentifier,
						s_method;

					s_key = i_cmp._normalizeKeyMapping(s_key);
					
					s_method = ['on', s_key, 'Key'].join(''); // Deprecate this!
					i_cmp[s_method] && i_cmp[s_method].apply(i_cmp, arguments); // Deprecate this!
					// Deprecate this!
					if (i_cmp.fireEvent(s_method, i_cmp, e, i_htmlNode, eOpts) === false) {
						return false;
					}

					s_method = [s_key, 'Key'].join('');
					i_cmp[s_method] && i_cmp[s_method].apply(i_cmp, arguments);
					if (i_cmp.fireEvent(s_method, i_cmp, e, i_htmlNode, eOpts) === false) {
						return false;
					}
				});
			}
		}, i_cmp, { single: true });

		return i_cmp;
	},
	_normalizeKeyMapping: function (s_key) {

		switch (s_key) {
			case 'U+007F':
				s_key = 'Delete';
			break;

			case 'U+004B':
				s_key = 'Plus';
			break;
			
			case 'U+004D':
				s_key = 'Minus';
			break;

			case 'U+0009':
				s_key = 'Tab';
			break;

			default:
			break;
		}

		return s_key;
	}

});
Ext.define("Ext.ux.util.ace.Editor", {

	mixins: [
		"Ext.mixin.Mashup"
	],

	requiredScripts: [
		"/portfolio/app/ux/util/ace/src/ace.js"
	],

	editorOptions: [
		"selectionStyle",
		"highlightActiveLine",
		"highlightSelectedWord",
		"readOnly",
		"cursorStyle",
		"mergeUndoDeltas",
		"behavioursEnabled",
		"wrapBehavioursEnabled",
		"autoScrollEditorIntoView",

		"hScrollBarAlwaysVisible",
		"vScrollBarAlwaysVisible",
		"highlightGutterLine",
		"animatedScroll",
		"showInvisibles",
		"showPrintMargin",
		"printMarginColumn",
		"printMargin",
		"fadeFoldWidgets",
		"showFoldWidgets",
		"showLineNumbers",
		"showGutter",
		"displayIndentGuides",
		"fontSize",
		"fontFamily",
		"maxLines",
		"minLines",
		"scrollPastEnd",
		"fixedWidthGutter",
		"theme",

		"scrollSpeed",
		"dragDelay",
		"dragEnabled",
		"focusTimout",
		"tooltipFollowsMouse",

		"firstLineNumber",
		"overwrite",
		"newLineMode",
		"useWorker",
		"useSoftTabs",
		"tabSize",
		"wrap",
		"foldStyle",
		"mode"
	],
	editorOptionsPrefixes: {
		"theme": "ace/theme/",
		"mode": "ace/mode/"
	},

	// Editor options
	selectionStyle: "line",//"line"|"text"
	highlightActiveLine: true,
	highlightSelectedWord: true,
	readOnly: false,
	cursorStyle: "ace", //"ace"|"slim"|"smooth"|"wide"
	mergeUndoDeltas: false, //false true "always"
	behavioursEnabled: false,
	wrapBehavioursEnabled: true,

	// autoScrollEditorIntoView: , // this is needed if editor is inside scrollable page

	// Renderer options
	hScrollBarAlwaysVisible: false,
	vScrollBarAlwaysVisible: false,
	highlightGutterLine: true,
	animatedScroll: false,
	showInvisibles: false,
	showPrintMargin: true,
	printMarginColumn: 80,
	printMargin: 80,
	fadeFoldWidgets: false,
	showFoldWidgets: true,
	showLineNumbers: true,
	showGutter: true,
	displayIndentGuides: true,
	fontSize: 12, //number or css font-size string
	// fontFamily: '', //css
	// maxLines: ,
	// minLines: false,
	scrollPastEnd: 0,

	// fixedWidthGutter: false,
	theme: "textmate", //path to a theme textmate|

	// Mousehandler options
	scrollSpeed: 2, //number
	dragDelay: 0, //number
	dragEnabled: true,
	focusTimout: 0, // number
	tooltipFollowsMouse: true,

	// Session options
	firstLineNumber: 1, //number
	overwrite: false,
	newLineMode: "auto", // auto|?
	useWorker: true,
	useSoftTabs: true,
	tabSize: 4, //number
	wrap: false,

	// foldStyle: true,
	mode: "text", //path to a mode text|json|

	// Properties
	_editor: null,
	onAceLoaded: Ext.EmptyFn,

	initAce: function () {

		var i_cmp = this;
		i_cmp.fireEvent("aceloaded", i_cmp, window.ace);
	},

	initEditor: function (s_id) {

		var i_cmp = this;
		var i_editor;
		var i_ace = window.ace;

		i_editor = i_ace.edit(s_id);
		i_cmp._editor = i_editor;

		i_cmp.initEditorOptions();

		i_cmp.on({
			resize: {
				fn: function() {
					setTimeout(function () {
						i_cmp.getEditor().resize();
					}, 100);
				}
			},
			activate: {
				fn: function() {
					i_cmp.getEditor().focus();
				}
			},
			focus: {
				fn: function () {
					i_cmp.getEditor().focus();
				}
			}
		});

		var value = i_cmp.getValue();
		if (Ext.isObject(value)) {
			value = JSON.stringify(value, null, "\t");
		}
		if (Ext.isArray(value)) {
			value = value.join("\n");
		}

		if (!Ext.isDefined(value)) {
			value = "";
		}

		i_cmp.setEditorValue(value);

		i_editor.session.on("change", function() {
			i_cmp.fireEvent("editorchange", i_cmp, i_editor, i_cmp.getEditorValue());
		});
		i_editor.session.on("changeAnnotation", function() {
			i_cmp.fireEvent("editorvalidate", i_cmp);
		});

		i_cmp.fireEvent("editorready", i_cmp, i_editor);

		return i_editor;
	},

	initEditorOptions: function () {

		var i_cmp = this;
		var a_pick = i_cmp.editorOptions;
		var o_options = {};
		var o_config = i_cmp.initialConfig;

		Ext.Array.each(a_pick, function(s_key) {
			if (o_config.hasOwnProperty(s_key)) {
				o_options[s_key] = o_config[s_key];
			}
		});

		// Run the options through the prefix map
		var o_pf = i_cmp.editorOptionsPrefixes;
		Ext.Object.each(o_options, function (s_key, value) {
			if (o_pf[s_key]) {
				o_options[s_key] = o_pf[s_key] + value;
			}
		});

		i_cmp.setEditorOptions(o_options);
	},
	setEditorOptions: function (o_options) {

		var i_cmp = this;
		var i_editor = i_cmp.getEditor();

		if (i_editor) {
			i_editor.setOptions(o_options);
		}
	},
	isEditorValid: function () {

		var i_cmp = this;
		var i_session = i_cmp.doSession();
		var b_valid = true;

		if (i_session) {

			var a_list = i_session.getAnnotations();

			Ext.Array.some(a_list, function (o_annotation) {

				if (o_annotation.type == "error") {
					b_valid = false;
					return true;
				}
			});
		}

		return b_valid;
	},

	getEditorErrors: function () {

		var i_cmp = this;
		var i_session = i_cmp.doSession();
		var a_errors = [];

		if (i_session) {

			var a_list = i_session.getAnnotations();

			Ext.Array.each(a_list, function (o_annotation) {

				if (o_annotation.type == "error") {
					a_errors.push([
						o_annotation.text,
						"on line",
						o_annotation.row++,
						"column",
						o_annotation.column
					].join(" "));
				}
			});
		}

		return a_errors;
	},

	/**
	 * This method returns the editor object created by AceEditor used by this UX
	 */
	getEditor: function() {

		return this._editor;
	},

	getEditorId: function() {

		return this.editorId;
	},

	/**
	 * This method returns the current session of the editor
	 */
	doSession: function() {

		var i_cmp = this;
		var i_editor = i_cmp._editor;
		var i_session;

		if (i_editor) {
			i_session = i_editor.getSession();
		}

		return i_session;
	},

	/**
	 * This handler gets the value of the editor, by value is meant the text/code/script
	 */
	getEditorValue: function() {

		var i_cmp = this;
		var i_session;
		var i_editor = i_cmp.getEditor();
		var value;

		if (i_editor) {
			i_session = i_editor.getSession();
		}

		if (i_session) {
			value = i_session.getValue();
		}

		return value;
	},

	/**
	 * This handler sets the value of the editor, by value is meant the text/code/script
	 * @param {string} value The value/code to insert into the editor
	 */
	setEditorValue: function(value) {

		var i_cmp = this;
		var i_editor = i_cmp._editor;
		var i_session;
		if (i_editor) {
			i_session = i_editor.getSession();
		}

		if (i_session) {
			i_session.setValue(value);
		}

		return this;
	},

	gotoLine: function(line) {
		this.getEditor().gotoLine(line);
		return this;
	},

	/**
	 * This handler undoes the last change in the editor and returns the editor object for chainability
	 */
	undo: function() {
		this.getEditor().undo();
		return this;
	},

	/**
	 * This handler redoes the last undone change in the editor and returns the editor object for chainability
	 */
	redo: function() {
		this.getEditor().redo();
		return this;
	},

	/**
	 * This handler replaces the next occurence of "toReplace" with "replaceWith"
	 * @param {string} toReplace The string to look for and replace
	 * @param {string} replaceWith The string to replace found occurence of "toReplace" with
	 * @returns this
	 */
	replace: function(toReplace, replaceWith) {
		var editor = this.getEditor();

		editor.find(toReplace);
		editor.replace(replaceWith);

		return this;
	},

	/**
	 * This handler replaces all found occurences of "toReplace" with "replaceWith"
	 * @param {string} toReplace
	 * @param {string} replaceWith
	 * @returns this
	 */
	replaceAll: function(toReplace, replaceWith) {
		var editor = this.getEditor();

		editor.find(toReplace);
		editor.replaceAll(replaceWith);

		return this;
	}
});
/**
 * A plugin that provides the ability to visually indicate to the user that a node is disabled.
 * 
 * Notes:
 * - Compatible with Ext 4.x
 * - If the view already defines a getRowClass function, the original function will be called before this plugin.
 * 
        var tree = Ext.create('Ext.tree.Panel',{
            plugins: [{
                ptype: 'nodedisabled'
            }]   
            ...
        });
 * 
 * @class Ext.ux.plugin.tree.NodeDisabled
 * @extends Ext.AbstractPlugin
 * @author Phil Crawford
 * @license Licensed under the terms of the Open Source <a href="http://www.gnu.org/licenses/lgpl.html">LGPL 3.0 license</a>.  Commercial use is permitted to the extent that the code/component(s) do NOT become part of another Open Source or Commercially licensed development library or toolkit without explicit permission.
 * @version 0.2 (August 10, 2011)
 * @constructor
 * @param {Object} config 
 */
Ext.define('Ext.ux.plugin.tree.NodeDisabled', {
	alias: 'plugin.nodedisabled',extend: 'Ext.AbstractPlugin'
    
	//configurables
	/**
	     * @cfg {String} disabledCls
	     * The CSS class applied when the {@link Ext.data.Model} of the node has a 'disabled' field with a true value.
	     */
	,disabledCls: 'ip2-tree-node-disabled'
	/**
	     * @cfg {Boolean} preventSelection 
	     * True to prevent selection of a node that is disabled. Default true.
	     */
	,preventSelection: true
    
	//properties
    
	/**
	     * @private
	     * @param {Ext.tree.Panel} tree
	     */
	,init: function(tree) {
		var me = this,view = tree.getView(),origFn,origScope;
        
		me.callParent(arguments);
        
		origFn = view.getRowClass;
		if (origFn) {
			origScope = view.scope || me;
			Ext.apply(view, {
				getRowClass: function() {
					var v1,v2;
					v1 = origFn.apply(origScope, arguments) || '';
					v2 = me.getRowClass.apply(me, arguments) || '';
					return (v1 && v2) ? v1 + ' ' + v2 : v1 + v2;
				},onCheckboxChange: me.onCheckboxChange
			});
		}
		else {
			Ext.apply(view, {
				getRowClass: Ext.Function.bind(me.getRowClass, me),onCheckboxChange: me.onCheckboxChange
			});
		}            
        
		if (me.preventSelection) {
			tree.getSelectionModel().on('beforeselect', me.onBeforeNodeSelect, me);
		}
		if (me.preventCheckChange) {
			view.on('checkchange', me.onCheckChange, me);
		}
	} // eof init

	/**
	     * Returns a properly typed result.
	     * @return {Ext.tree.Panel}
	     */
	,getCmp: function() {
		return this.callParent(arguments);
	} //eof getCmp 
    
	/**
	     * @private
	     * @param {Ext.data.Model} record
	     * @param {Number} index
	     * @param {Object} rowParams
	     * @param {Ext.data.Store} ds
	     * @return {String}
	     */
	,getRowClass: function(record, index, rowParams, ds) {
		return record.get('disabled') ? this.disabledCls : '';
	}//eof getRowClass
    
	/**
	     * @private
	     * @param {Ext.selection.TreeModel} sm
	     * @param {Ext.data.Model} node
	     * @return {Boolean}
	     */
	,onBeforeNodeSelect: function(sm, node) {
		if (node.get('disabled')) {
			return false;
		}
	}//eof onBeforeNodeSelect
    
	/**
	     * @OVERRIDES {@link Ext.tree.View#onCheckboxChange}
	     * @private
	     * @param {Ext.EventObject} e
	     * @param {Object} target
	     */
	,onCheckboxChange: function(e, t) {
		var item = e.getTarget(this.getItemSelector(), this.getTargetEl()),
		record, value;
            
		if (item) {
			record = this.getRecord(item);
			if (record.get('disabled')) {
				return;
			}
            
			value = !record.get('checked');
			record.set('checked', value);
			this.fireEvent('checkchange', record, value);
		}
	}//eof onCheckboxChange

});//eo class

Ext.define("Ext.ux.plugin.UploadDD", {

	alias: ["plugin.uploadDD"],

	extend: "Ext.AbstractPlugin",

	statics: {
		mime: {
			"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
			"application/vnd.openxmlformats-officedocument.spreadsheetml.template": "xltx",
			"application/vnd.openxmlformats-officedocument.presentationml.template": "potx",
			"application/vnd.openxmlformats-officedocument.presentationml.slideshow": "ppsx",
			"application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
			"application/vnd.openxmlformats-officedocument.presentationml.slide": "sldx",
			"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
			"application/vnd.openxmlformats-officedocument.wordprocessingml.template": "dotx",
			"application/vnd.ms-excel.addin.macroEnabled.12": "xlam",
			"application/vnd.ms-excel.sheet.binary.macroEnabled.12": "xlsb",
			"application/envoy": "evy",
			"application/fractals": "fif",
			"application/futuresplash": "spl",
			"application/hta": "hta",
			"application/internet-property-stream": "acx",
			"application/mac-binhex40": "hqx",
			"application/msword": "doc",
			"application/msword": "dot",
			"application/oda": "oda",
			"application/olescript": "axs",
			"application/pdf": "pdf",
			"application/pics-rules": "prf",
			"application/pkcs10": "p10",
			"application/pkix-crl": "crl",
			"application/postscript": "ai",
			"application/postscript": "eps",
			"application/postscript": "ps",
			"application/rtf": "rtf",
			"application/set-payment-initiation": "setpay",
			"application/set-registration-initiation": "setreg",
			"application/vnd.ms-excel": "xla",
			"application/vnd.ms-excel": "xlc",
			"application/vnd.ms-excel": "xlm",
			"application/vnd.ms-excel": "xls",
			"application/vnd.ms-excel": "xlt",
			"application/vnd.ms-excel": "xlw",
			"application/vnd.ms-outlook": "msg",
			"application/vnd.ms-pkicertstore": "sst",
			"application/vnd.ms-pkiseccat": "cat",
			"application/vnd.ms-pkistl": "stl",
			"application/vnd.ms-powerpoint": "pot",
			"application/vnd.ms-powerpoint": "pps",
			"application/vnd.ms-powerpoint": "ppt",
			"application/vnd.ms-project": "mpp",
			"application/vnd.ms-works": "wcm",
			"application/vnd.ms-works": "wdb",
			"application/vnd.ms-works": "wks",
			"application/vnd.ms-works": "wps",
			"application/winhlp": "hlp",
			"application/x-bcpio": "bcpio",
			"application/x-cdf": "cdf",
			"application/x-compress": "z",
			"application/x-compressed": "tgz",
			"application/x-cpio": "cpio",
			"application/x-csh": "csh",
			"application/x-director": "dcr",
			"application/x-director": "dir",
			"application/x-director": "dxr",
			"application/x-dvi": "dvi",
			"application/x-gtar": "gtar",
			"application/x-gzip": "gz",
			"application/x-hdf": "hdf",
			"application/x-internet-signup": "ins",
			"application/x-internet-signup": "isp",
			"application/x-iphone": "iii",
			"application/x-javascript": "js",
			"application/x-latex": "latex",
			"application/x-msaccess": "mdb",
			"application/x-mscardfile": "crd",
			"application/x-msclip": "clp",
			"application/x-msdownload": "dll",
			"application/x-msmediaview": "m13",
			"application/x-msmediaview": "m14",
			"application/x-msmediaview": "mvb",
			"application/x-msmetafile": "wmf",
			"application/x-msmoney": "mny",
			"application/x-mspublisher": "pub",
			"application/x-msschedule": "scd",
			"application/x-msterminal": "trm",
			"application/x-mswrite": "wri",
			"application/x-netcdf": "cdf",
			"application/x-netcdf": "nc",
			"application/x-perfmon": "pma",
			"application/x-perfmon": "pmc",
			"application/x-perfmon": "pml",
			"application/x-perfmon": "pmr",
			"application/x-perfmon": "pmw",
			"application/x-pkcs12": "p12",
			"application/x-pkcs12": "pfx",
			"application/x-pkcs7-certificates": "p7b",
			"application/x-pkcs7-certificates": "spc",
			"application/x-pkcs7-certreqresp": "p7r",
			"application/x-pkcs7-mime": "p7c",
			"application/x-pkcs7-mime": "p7m",
			"application/x-pkcs7-signature": "p7s",
			"application/x-sh": "sh",
			"application/x-shar": "shar",
			"application/x-shockwave-flash": "swf",
			"application/x-stuffit": "sit",
			"application/x-sv4cpio": "sv4cpio",
			"application/x-sv4crc": "sv4crc",
			"application/x-tar": "tar",
			"application/x-tcl": "tcl",
			"application/x-tex": "tex",
			"application/x-texinfo": "texi",
			"application/x-texinfo": "texinfo",
			"application/x-troff": "roff",
			"application/x-troff": "t",
			"application/x-troff": "tr",
			"application/x-troff-man": "man",
			"application/x-troff-me": "me",
			"application/x-troff-ms": "ms",
			"application/x-ustar": "ustar",
			"application/x-wais-source": "src",
			"application/x-x509-ca-cert": "cer",
			"application/x-x509-ca-cert": "crt",
			"application/x-x509-ca-cert": "der",
			"application/ynd.ms-pkipko": "pko",
			"application/zip": "zip",
			"application/acad": "dwg",
			"application/step": "stp",
			"image/pjpeg": "jpeg",
			"image/jpeg": "jpeg",
			"image/jpg": "jpg",
			"image/png": "png",
			"image/gif": "gif",
			"image/tiff": "tiff",
			"image/x-tiff": "tiff"
		},
		mimeToExtension: function (s_mime) {
			return Ext.ux.plugin.UploadDD.mime[s_mime];
		},
		extensionToMime: function (s_extension) {
			var s_mime;
			Ext.Object.each(Ext.ux.plugin.UploadDD.mime, function (s_key, s_name) {
				if (s_name == s_extension) {
					s_mime = s_key;
				}
			});
			return s_mime;
		},
		cancelEvent: function (o_event) {

			o_event = o_event || window.event;

			if (o_event.preventDefault) {
				o_event.preventDefault();
			}

			if (o_event.stopPropagation) {
				o_event.stopPropagation();
			}

			return false;
		},
		addEventHandler: function (obj, evt, handler) {

			if (obj.addEventListener) {
				// W3C method
				obj.addEventListener(evt, handler, false);
			}
			else if (obj.attachEvent) {
				// IE method.
				obj.attachEvent("on" + evt, handler);
			}
			else {
				// Old school method.
				obj["on" + evt] = handler;
			}
		}
	},

	/**
	 * @cfg {Array} [extensions=null]
	 * Array of extensions allowed to drop. If null then all extensions are allowed
	 */
	extensions: null,

	/**
	 * @private {Boolean} enableDrop
	 * False to disallow the View from accepting drop gestures.
	 */
	enableDrop: true,

	pluginId: "uploadDD",

	baseCls: "x-ux-plugin-uploadDD",
	failureCls: "x-ux-plugin-uploadDD-error",
	successCls: "x-ux-plugin-uploadDD-over",
	dragging: 0,

	_filePreviewMap: null,

	init: function(i_component) {

		var i_plugin = this;
		var i_el = i_component.getEl();

		i_plugin.component = i_component;

		i_component.addCls(i_plugin.baseCls);

		if (i_el && i_el.dom && i_el.query("table")[0]) {
			i_plugin.initUploadDD(i_el.query("table")[0]);
		}
		else {
			i_component.on("afterrender", function (i_self) {
				i_plugin.initUploadDD(i_self.getEl().query("table")[0]);
			}, i_component, { single: true });
		}

		return i_plugin;
	},

	initUploadDD: function(i_dropNode) {

		var i_plugin = this;
		var i_component = i_plugin.component;
		var i_class = Ext.ux.plugin.UploadDD;
		var i_global = Ext.global;

		if (i_global.FileReader) {

			// Prevent drops on body
			i_class.addEventHandler(document.body, "dragenter", function(o_event) {
				i_plugin.onBodyEnter(o_event);
			});

			i_class.addEventHandler(document.body, "dragleave", function(o_event) {
				i_plugin.onBodyLeave(o_event);
			});

			i_class.addEventHandler(document.body, "dragover", Ext.ux.plugin.UploadDD.cancelEvent);
			i_class.addEventHandler(document.body, "drop", function(o_event) {
				i_plugin.cancelDropEvent(o_event);
			});

			// Tells the browser that we *can* drop on this target
			i_class.addEventHandler(i_dropNode, "dragover", Ext.ux.plugin.UploadDD.cancelEvent);

			i_class.addEventHandler(i_dropNode, "dragenter", function (o_event) {
				i_plugin.onDragEnter(o_event);
			});

			i_class.addEventHandler(i_dropNode, "dragleave", function (o_event) {
				i_plugin.onDragLeave(o_event);
			});

			i_class.addEventHandler(i_dropNode, "drop", function (o_event) {
				i_plugin.onDragDrop(o_event);
			});
		}

		// Hide this component since no DnD upload is possible
		// TODO: Give component a chance to do this instead - plugins don"t decide, they tell!
		else {
			i_component.hide();
		}
	},

	cancelDropEvent: function(o_event) {
		var i_plugin = this;
		var i_component = i_plugin.component;
		o_event = o_event || window.event;

		if (o_event.preventDefault) {
			o_event.preventDefault();
		}

		if (o_event.stopPropagation) {
			o_event.stopPropagation();
		}
		i_plugin.dragging = 0;
		i_component.fireEvent("bodydragleave", i_component, o_event);

		return false;
	},

	onBodyEnter: function(o_event) {
		var i_plugin = this;
		var i_component = i_plugin.component;
		i_plugin.dragging++;
		o_event.dataTransfer.dropEffect = "copy";
		i_component.fireEvent("bodydragenter", i_component, o_event);
	},

	onBodyLeave: function(o_event) {
		var i_plugin = this;
		var i_component = i_plugin.component;
		i_plugin.dragging--;
		if (i_plugin.dragging === 0) {
			i_component.fireEvent("bodydragleave", i_component, o_event);
		}
	},

	onDragEnter: function (o_event) {

		var i_plugin = this;
		var i_component = i_plugin.component;
		var i_transfer = o_event.dataTransfer;
		var b_allow = true;

		//Ext.ux.plugin.UploadDD.cancelEvent(o_event);

		// Extensions overloading, in case it is a comma seperated string
		// we strip whitespaces and split on comma
		var a_extensions = i_plugin.extensions;

		if (ip2.isString(a_extensions)) {
			a_extensions = a_extensions.replace(" ", "");
			a_extensions = a_extensions.split(",");
		}

		if (a_extensions[0] != "*") {
			ip2.each(i_transfer.items, function (o_item) {
				if (!ip2.isNumber(o_item)) {
					var s_extension = i_plugin.getRewriter().mimeToExtension(o_item.type);
					b_allow = (Ext.Array.indexOf(a_extensions, s_extension) > -1);
				}
			});
		}

		if (!b_allow) {
			i_component.addCls(i_plugin.failureCls);
			i_plugin.enableDrop = false;
		}
		else {
			i_component.addCls(i_plugin.successCls);
			i_plugin.enableDrop = true;
		}

		i_component.fireEvent("dragenter", i_component, o_event);
	},

	onDragLeave: function (o_event) {

		var i_plugin = this;
		var i_component = i_plugin.component;

		//Ext.ux.plugin.UploadDD.cancelEvent(o_event);

		i_component.removeCls(i_plugin.successCls);
		i_component.removeCls(i_plugin.failureCls);

		i_component.fireEvent("dragleave", i_component, o_event);
	},

	onDragDrop: function (o_event) {

		var i_plugin = this;
		var i_component = i_plugin.component;

		// get window.event if e argument missing (in IE)
		o_event = o_event || Ext.global.event;

		//Ext.ux.plugin.UploadDD.cancelEvent(o_event);

		// TODO ADD BEFORE DROP HANDLER
		if (i_plugin.enableDrop) {

			var i_transfer = o_event.dataTransfer;
			var i_files = i_transfer.files || [];

			var a_result = i_files;

			if (Ext.isIE) {

				var a_files = [];

				for (var i = 0; i < i_files.length; i++) {
					var i_file = i_files.item(i);
					a_files.push(i_file);
				}

				a_result = a_files;
			}

			var b_beforedrop = i_component.fireEvent("beforedrop", i_component, a_result, o_event);

			if (b_beforedrop !== false) {
				i_component.fireEvent("drop", i_component, a_result);
			}
		}

		i_component.removeCls(i_plugin.failureCls);
		i_component.removeCls(i_plugin.successCls);

		return false;
	},

	getExtensions: function () {

		return this.extensions;
	},
	setExtensions: function (a_extensions) {

		this.extensions = a_extensions;
		return this;
	},

	getRewriter: function () {

		var i_plugin = this;
		var s_class = i_plugin.$className;
		var i_global = Ext.global;

		return ip2.getProperty(s_class, i_global);
	}
});
Ext.define("Portfolio.angular.Component", {

	xtype: "angular-component",

	extend: "Ext.Component",

	alias: [
		"widget.angular.component"
	],

	config: {
		rootTag: "app-root",
		appPath: "",
		baseHref: "/",
		mode: "dev"
	},

	renderTpl: [
		"<div id={id}-root data-ref=rootEl>",
		"</div>"
	],

	childEls: [
		{
			name: "rootEl",
			itemId: "root"
		}
	],

	alternateClassName: [
		"Ext.ux.angular.Component"
	],

	listeners: {
		afterrender: {
			fn: function(i_component) {

				var i_self = this;

				var i_root = i_self.rootEl;
				var i_domElement = i_root.dom;

				if (i_domElement.attachShadow) {

					var i_shadowRoot = i_domElement.attachShadow({
						mode: "open"
					});

					var s_mode = i_self.getMode() || "dev";

					var a_files = [
						i_self.getAppPath() + "/runtime.js"
					];

					if (!window.hasOwnProperty("Zone")) {
						a_files.push(i_self.getAppPath() + "/polyfills.js");
					}

					if (s_mode.toLowerCase() == "dev") {
						a_files.push(i_self.getAppPath() + "/vendor.js");
					}

					a_files.push(i_self.getAppPath() + "/main.js");

					var n_counter = a_files.length;

					var i_template = Ext.create("Ext.XTemplate",
						"<{rootTag} id={id}-root>",
							"<base id={id}-base href={baseHref}></base>",
						"</{rootTag}>"
					);

					var i_appRoot = Ext.DomHelper.createDom(i_template.apply({
						rootTag: i_self.getRootTag(),
						baseHref: i_self.getBaseHref(),
						id: Ext.id()
					}));

					var i_tag;

					if (s_mode === "dev") {

						i_tag = document.createElement("script");

						i_tag.setAttribute("type", "text/javascript");
						i_tag.async = false;
						i_tag.src = i_self.getAppPath() + "/styles.js";
					}
					else {

						i_tag = document.createElement("link");

						i_tag.setAttribute("rel", "stylesheet");
						i_tag.href = i_self.getAppPath() + "/styles.css";
					}

					i_shadowRoot.appendChild(i_tag);

					Ext.Array.each(a_files, function(s_path) {

						var i_script = document.createElement("script");

						i_script.setAttribute("type", "text/javascript");
						i_script.async = false;
						i_script.src = s_path;

						i_script.onload = function() {
							n_counter--;
							if (n_counter === 0) {

								i_shadowRoot.appendChild(i_appRoot);
							}
						};

						i_appRoot.appendChild(i_script);
					});

					i_root.appendChild(i_appRoot);
				}
				else {
					i_root.setText("This browser does not support shadow dom");
				}
			}
		}
	}
});
/**
 * @class Ext.ux.form.JsonForm
 * Extends the regular {@link Ext.form.Panel form(panel)} in regards to how values can be gotten.
 * The courtesy method "getValues" of the {@link Ext.form.Panel form(panel)} itself is overwritten, where as the {@link Ext.form.Basic form}
 * of the {@link Ext.form.Panel form(panel)} is untouched.
 * The getValues method delivers a JSON like object structure of all underlying forms and or other components that has
 * a getValues method as well as, all deep nested "form orphan" fields flat in the root of the returned object.
 * When looking for underlying forms and other elements with getValues method, this component does not look further into that
 * found component, but relies on its delivered content.
 * @extends Ext.form.Panel
 * 
 */

Ext.define('Ext.ux.form.JsonForm', {
	
	extend: 'Ext.form.Panel',

	alias: ['widget.jsonform'],

	initComponent: function() {

		this.callParent(arguments);
		
		this.initConfig(this.initialConfig);

		return this;
	},

	/** 
	 * @method buildChildrenArrays
	 * @private
	 */
	buildChildrenArrays: function(component, arrays) {

		arrays || (arrays = {
			fields: [],
			forms: []
		});

		var form = this,
			doItems = (component.items && component.items.each),
			doDocked = (component.dockedItems && component.dockedItems.each);

		// Does this component have a items mixedcollection?
		if (doItems) {
			form.buildChildrenIterator(component, component.items, arrays);
		}

		// Does this component have a dockedItems mixedcollection?
		else if (doDocked) {
			form.buildChildrenIterator(component, component.dockedItems, arrays);
		}

		return arrays;
	},

	/** 
	 * @method buildChildrenIterator
	 * @private
	 */
	buildChildrenIterator: function (component, collection, arrays) {

		var form = this;

		collection.each(function(item) {

			// Check if item is a form field and add to fields array
			if (item.isFormField) {
				arrays.fields.push(item);
			}

			// Item is something else, examine in depth for getValues method
			else {

				// Item has a getValues method
				// Add item to the forms array and break out of this branch iteration
				if (item.getValues && typeof item.getValues === 'function') {
					arrays.forms.push(item);
				}

				// Maybe item has a getForm method?
				// Get form and add it to the forms array and break out
				else if (item.getForm && typeof item.getForm === 'function') {
					arrays.forms.push(item);
				}

				// Neither was true - keep on iterating down
				else {
					form.buildChildrenArrays(item, arrays);
				}
			}
		});
	},

	/** 
	 * @method getChildrenArrayValues
	 * @private
	 * @return {Object} values
	 */
	getChildrenArrayValues: function(arrays, dirtyOnly, includeEmptyText, useDataValues) {

		arrays || (arrays = {
			fields: [],
			forms: []
		});

		var fields = arrays.fields,
			forms = arrays.forms,
			values = {},
			isArray = Ext.isArray,
			data, val, bucket, name,
			i = 0;

		// Iterate over fields and add to root value object
		for (; i < fields.length; i++) {
			
			var field = fields[i];

			// Add option of forcing the field to be dirty via dirty property
			var forceDirty = field.dirty,
				isDirty = forceDirty === true ? forceDirty : field.isDirty();

			// Borrowed from the getValues method of Ext.form.Basic
			if (!dirtyOnly || isDirty) {
				
				data = field[useDataValues ? 'getModelData' : 'getSubmitData'](includeEmptyText);

				if (Ext.isObject(data)) {
					
					for (name in data) {
						
						if (data.hasOwnProperty(name)) {
							
							val = data[name];

							if (includeEmptyText && val === '') {
								val = field.emptyText || '';
							}

							if (values.hasOwnProperty(name)) {
								bucket = values[name];

								if (!isArray(bucket)) {
									bucket = values[name] = [bucket];
								}

								if (isArray(val)) {
									values[name] = values[name] = bucket.concat(val);
								}
								else {
									bucket.push(val);
								}
							}

							else {
								values[name] = val;
							}
						}
					}
				}
			}
		}

		// Iterate over forms and add value from each forms own getValues method and add to values
		for (i = 0; i < forms.length; i++) {

			var form = forms[i],
				formIsDirty = form.getForm().isDirty();

			// Send along arguments from own getValues call, apart from asString since we want
			// to control that in the end
			if (!dirtyOnly || formIsDirty) {

				var value = form.getValues(false, dirtyOnly, includeEmptyText, useDataValues);

				if (Ext.Object.getSize(value)) {
					values[form.name] = value;
				}
			}
		}

		return values;
	},

	/**
	 * @method getValues
	 * Overwritten courtesy method that generates the tree structured value object
	 * @param {Boolean} [asString=false] If true, will return the key/value collection as a single
	 * URL-encoded param string.
	 * @param {Boolean} [dirtyOnly=false] If true, only fields that are dirty will be included in the result.
	 * @param {Boolean} [includeEmptyText=false]] If true, the configured emptyText of empty fields will be used.
	 * @return {String/Object}
	 */
	getValues: function(asString, dirtyOnly, includeEmptyText, useDataValues) {

		var form = this,
			arrays,
			values;

		// Build the fields and forms arrays object
		arrays = form.buildChildrenArrays(form);

		// Build the values object
		values = form.getChildrenArrayValues(arrays, dirtyOnly, includeEmptyText, useDataValues);

		// User asked for a query string - give it to him/her
		if (asString) {
			values = JSON.stringify(values);
		}

		return values;
	},

	setChildrenArrayValues: function(arrays, values) {

		var field,
			form,
			i = 0;

		// Iterate the fields
		// TODO: I have a problem here in regards to shared names and array type values!!
		for (; i < arrays.fields.length; i++) {
			field = arrays.fields[i];
			field.setValue(values[field.name]);
		}

		// Iterate the "forms"
		// TODO: Have the same problem still ofc as mention above for fields
		for (i = 0; arrays.forms.length; i++) {
			form = arrays.forms[i];
			form.setValues(values[form.name]);
		}

		return this;
	},

	setValues: function(values) {

		var form = this,
			arrays;

		arrays = form.buildChildrenArrays(form);

		form.setChildrenArrayValues(arrays, values);

		return form;
	}
});

Ext.define('Ext.ux.form.field.plugin.InputMask', {
	extend: 'Ext.AbstractPlugin',
	alias: 'plugin.inputmask',

	mixins: {
		observable: 'Ext.util.Observable'
	},

	constructor: function(cfg, settings) {
		var me = this;

		var config = {
			pasteEventName: (Ext.isIE ? 'paste' : 'input'),
			iPhone: (window.orientation != undefined),
			mask: {
				definitions: {
					'c': "[\.,]",

					'9': "[0-9]",
					'a': "[A-Za-z]",
					'*': "[A-Za-z0-9]"
				},
				dataName: "rawMaskFn"
			},
			format: cfg.format,
			settings: settings || {}
		};

		me.callParent([config]);
		me.mixins.observable.constructor.call(me);
	},

	jqmap: function(array, callback) {
		var result = [];
		Ext.each(array, function(item, index) {
			var intermediate = callback(index, item);
			if (intermediate) {
				if (Ext.isArray(intermediate)) {
					for (var i = 0; i < intermediate.length; i += 1) {
						this.push(intermediate[i]);
					}
				}
				else {
					this.push(intermediate);
				}
			}
		}, result);
		return result;
	},

	init: function(field) {
		var me = this;
		me.field = field;
		field.enableKeyEvents = true;

		var mask = me.format;

		if (!mask && this.length > 0) {
			var input = this[0];
			return input[field.mask.dataName]();
		}
		me.settings = Ext.applyIf(me.settings, {
			placeholder: "_",
			completed: null
		});

		me.defs = me.mask.definitions;
		me.tests = [];
		me.partialPosition = mask.length;
		me.firstNonMaskPos = null;

		Ext.each(mask.split(""), function(c, i) {
			if (c == '?') {
				me.format.length--;
				me.partialPosition = i;
			}
			else if (me.defs[c]) {
				me.tests.push(new RegExp(me.defs[c]));
				if (me.firstNonMaskPos == null)
				me.firstNonMaskPos = me.tests.length - 1;
			}
			else {
				me.tests.push(null);
			}
		});

		me.fireEvent("unmask");

		var input = me.field;

		me.buffer = me.jqmap(mask.split(""), function(i, c) {
			if (c != '?') {
				return me.defs[c] ? me.settings.placeholder : c;
			}
		});
		me.focusText = input.getRawValue();

		input[me.mask.dataName] = function() {
			return me.jqmap(buffer, function(i, c) {
				return tests[i] && c != settings.placeholder ? c : null;
			}).join('');
		};

		if (!input.readOnly) {

			input.on('unmask', function() {
				this.un('.mask');
				this[plugin.mask.dataName] = undefined;
			}, input, { single: true });

			input.on('focus', me.onFocus, me);

			input.on('blur', function(f) {
				me.checkVal();
				if (f.getRawValue() != me.focusText) {
					f.fireEvent('change', f.getRawValue(), me.focusText);

					//was f.change();
				}
			});

			input.on('keydown', function(f, e) {
				if (me.keydownEvent(f, e) == false) {
					e.preventDefault();
				}
			}, me);
			input.on('keypress', function(f, e) {
				if (me.keypressEvent(f, e) == false) {
					e.preventDefault();
				}
			}, me);

			input.on('render', function(f) {
				var el = input.inputEl || this.el.down('input');

				el && el.on(me.pasteEventName, function() {
					setTimeout(function() {
						input.caret(me.checkVal(true));
					}, 0);
				});
			}, undefined, { single: true });
		}

		me.checkVal(); //Perform initial check for existing values

		input.caret = me.caret;

		me.oriGet = Ext.Function.bind(field.getValue, field);

		Ext.apply(field, {
			getValue: function(v) {
				val = me.prepareValueToExternalWorld();
				return val;
			},
			setValue: function(v) {
				me.field.setRawValue('');
				me.clearBuffer(0, me.format.length);
				me.prepareValueToInternalWorld(v);
			}
		});
	},

	caret: function(begin, end) {
		if (this.length == 0) return;
		var el = Ext.get(this.inputId) || this.el.down('input');
		if (typeof begin == 'number') {
			end = (typeof end == 'number') ? end : begin;
			if (el.dom.setSelectionRange) {
				el.dom.setSelectionRange(begin, end);
			}
			else if (el.dom.createTextRange) {
				var range = el.dom.createTextRange();
				range.collapse(true);
				range.moveEnd('character', end);
				range.moveStart('character', begin);
				range.select();
			}
			return this;
		}
		else {
			if (el.dom.setSelectionRange) {
				begin = el.dom.selectionStart;
				end = el.dom.selectionEnd;
			}
			else if (document.selection && document.selection.createRange) {
				var range = document.selection.createRange();
				begin = 0 - range.duplicate().moveStart('character', -100000);
				end = begin + range.text.length;
			}
			return { begin: begin, end: end };
		}
	},

	unmask: function() {
		return this.fireEvent("unmask");
	},

	/*===============================================*/

	onFocus: function(f) {
		var me = this;

		me.focusText = f.getRawValue();
		var pos = me.checkVal();
		me.writeBuffer();
		var moveCaret = function() {
			if (pos == me.format.length)
			f.caret(0, pos);
			else
			f.caret(pos);
		};
		(Ext.isIE ? moveCaret : function() {
			setTimeout(moveCaret, 0)
		})();
	},

	/*===============================================*/

	seekNext: function(pos) {
		var me = this;

		while (++pos <= me.format.length && !me.tests[pos]);
		return pos;
	},
	seekPrev: function(pos) {
		var me = this;

		while (--pos >= 0 && !me.tests[pos]);
		return pos;
	},

	shiftL: function(begin, end) {
		var me = this;
		if (begin < 0)
		return;
		for (var i = begin, j = me.seekNext(end); i < me.format.length; i++) {
			if (me.tests[i]) {
				if (j < me.format.length && me.tests[i].test(me.buffer[j])) {
					me.buffer[i] = me.buffer[j];
					me.buffer[j] = me.settings.placeholder;
				}
				else
								break;
				j = me.seekNext(j);
			}
		}
		me.writeBuffer();
		me.field.caret(Math.max(me.firstNonMaskPos, begin));
	},

	shiftR: function(pos) {
		var me = this;

		for (var i = pos, c = me.settings.placeholder; i < me.format.length; i++) {
			if (me.tests[i]) {
				var j = me.seekNext(i);
				var t = me.buffer[i];
				me.buffer[i] = c;
				if (j < me.format.length && me.tests[j].test(t))
				c = t;
				else
				break;
			}
		}
	},

	keydownEvent: function(f, e) {
		var me = this;

		var k = e.getKey();

		//backspace, delete, and escape get special treatment
		if (k == 8 || k == 46 || (me.iPhone && k == 127)) {
			var pos = me.field.caret(),
									begin = pos.begin,
									end = pos.end;

			if (end - begin == 0) {
				begin = k != 46 ? me.seekPrev(begin) : (end = me.seekNext(begin - 1));
				end = k == 46 ? me.seekNext(end) : end;
			}
			me.clearBuffer(begin, end);
			me.shiftL(begin, end - 1);

			return false;
		}
		else if (k == 27) {
			//escape
			me.field.setRawValue(me.focusText);
			me.field.caret(0, me.checkVal());
			return false;
		}
	},

	keypressEvent: function(f, e) {
		var me = this;

		if (e.charCode == 0) {
			return true;
		}

		var k = e.getCharCode(),
							pos = me.field.caret();
		if (e.ctrlKey || e.altKey || e.metaKey || k < 32) {
			//Ignore
			return true;
		}
		else if (k) {
			if (pos.end - pos.begin != 0) {
				me.clearBuffer(pos.begin, pos.end);
				me.shiftL(pos.begin, pos.end - 1);
			}

			var p = me.seekNext(pos.begin - 1);
			if (p < me.format.length) {
				var c = String.fromCharCode(k);
				if (me.tests[p].test(c)) {
					me.shiftR(p);
					me.buffer[p] = c;
					me.writeBuffer();
					var next = me.seekNext(p);
					me.field.caret(next);
					if (me.settings.completed && next >= me.format.length)
					me.settings.completed.call(f);
				}
			}
			return false;
		}
	},

	clearBuffer: function(start, end) {
		var me = this;

		for (var i = start; i < end && i < me.format.length; i++) {
			if (me.tests[i])
			me.buffer[i] = me.settings.placeholder;
		}
	},

	writeBuffer: function() {
		var me = this;
		return me.field.setRawValue(me.buffer.join(''));
	},

	checkVal: function(allow) {
		var me = this;
		var input = me.field;

		//try to place characters where they belong
		var test = input.getRawValue();
		var lastMatch = -1;
		for (var i = 0, pos = 0; i < me.format.length; i++) {
			if (me.tests[i]) {
				me.buffer[i] = me.settings.placeholder;
				while (pos++ < test.length) {
					var c = test.charAt(pos - 1);
					if (me.tests[i].test(c)) {
						me.buffer[i] = c;
						lastMatch = i;
						break;
					}
				}
				if (pos > test.length)
				break;
			}
			else if (me.buffer[i] == test.charAt(pos) && i != me.partialPosition) {
				pos++;
				lastMatch = i;
			}
		}
		if (!allow && lastMatch + 1 < me.partialPosition) {
			input.setRawValue('');
			me.clearBuffer(0, me.format.length);
		}
		else if (allow || lastMatch + 1 >= me.partialPosition) {
			me.writeBuffer();
			if (!allow) input.setRawValue(input.getRawValue().substring(0, lastMatch + 1));
		}
		return (me.partialPosition ? i : me.firstNonMaskPos);
	},

	prepareValueToExternalWorld: function() {
		var me = this;

		var result = [], valid = true;
		for (var i = 0; i < me.tests.length; i += 1) {
			if (me.tests[i] != null) {
				result.push(me.buffer[i]);
			}
		}
		return Ext.Array.indexOf(result, me.settings.placeholder) == -1 ? result.join('') : '';
	},

	prepareValueToInternalWorld: function(val) {
		var me = this;

		var p = -1;
		if (val != null) {
			Ext.each(String(val).split(''), function(c) {
				p = me.seekNext(p);
				if (me.tests[p].test(c)) {
					me.buffer[p] = c;
				}
			});
		}
		me.writeBuffer();
	}
});
Ext.define('Ext.ux.form.field.plugin.SuffixLabel', {

	alias: ['plugin.suffixlabel'],

	extend: 'Ext.AbstractPlugin',

	statics: {
		textAttr: (function () {

			// first time initialization of closure
			var span = document.createElement('span');
			span.style.position = 'absolute';
			span.style.visibility = 'hidden';
			span.style.height = 'auto';
			span.style.width = 'auto';
			var s = document.getElementsByTagName('body')[0].appendChild(span);

			return {
				pixWidth: function(t, cn) {
					span.className = cn;
					span.innerHTML = t;
					return span.clientWidth;
				}
			};
		})(),
		fn: {
			setWidth: function (n_width) {

				var i_component = this,
					i_suffixCmp = i_component.getSuffixLabel();

				i_suffixCmp.setWidth(n_width);

				i_component.syncSuffixLabel();

				return i_component;
			},
			hide: function () {

				this.getSuffixLabel().hide();

				return this;
			},
			show: function () {

				this.getSuffixLabel().show();

				return this;
			},
			getSuffixLabel: function () {

				var i_component = this,
					i_suffixCmp = Ext.getCmp('suffixlabel-' + i_component.id);

				return i_suffixCmp;
			},
			getSuffixLabelText: function () {

				return this.suffixLabelText;
			},
			setSuffixLabelText: function (s_label) {

				var i_component = this,
					i_suffixCmp = i_component.getSuffixLabel(),
					i_label = i_suffixCmp.down('[name=labeltext]');

				i_component.suffixLabelText = s_label;

				i_label.update(s_label);

				i_component.syncSuffixLabel();

				return i_component;
			},
			syncSuffixLabel: function () {

				var i_component = this,
					s_label = i_component.getSuffixLabelText(),
					i_suffixCmp = i_component.getSuffixLabel(),
					i_field = i_suffixCmp.down('[name=fieldcontainer]'),
					i_label = i_suffixCmp.down('[name=labelcontainer]'),
					n_fullWidth = i_suffixCmp.getWidth(),
					n_labelWidth = Ext.ux.form.field.plugin.SuffixLabel.textAttr.pixWidth(s_label, 'x-panel-body') + 8,
					n_fieldWidth,
					n_fieldHeight = i_field.getHeight() - 3;

				// If we have a fixed suffix width set - then we use that one!
				if (i_component.suffixWidth) {
					n_labelWidth = i_component.suffixWidth + 15;
				}

				n_fieldWidth = n_fullWidth - n_labelWidth;

				if (i_component.suffixHeight) {
					n_fieldHeight = i_component.suffixHeight;
				}

				// Remember the margin of the label
				i_field.setWidth(n_fieldWidth);
				i_label.setWidth(n_labelWidth);
				i_label.setHeight(n_fieldHeight);
				i_component.setSize(n_fieldWidth);				
			}
		}
	},

	constructor: function(o_settings) {
			
		var i_plugin = this,
			i_component = o_settings.cmp,
			s_label = o_settings.label,
			s_type = o_settings.type || 'text';

		i_plugin.label = s_label;
		i_plugin.type = s_type;
	},

	init: function (i_component) {

		var i_plugin = this,
			s_label = i_plugin.label,
			s_type = i_plugin.type;

		i_plugin.pluginId = 'suffixlabel';

		Ext.Object.merge(i_component, Ext.ux.form.field.plugin.SuffixLabel.fn);

		i_plugin.initField(i_component, s_label, s_type);
	},

	buildField: function (i_component, s_label, s_type) {

		var i_plugin = this,
			i_parent = i_component.up(),
			i_wrapper,
			n_index = i_parent.items.indexOf(i_component);

		var a_extend = ['layout', 'anchor', 'width', 'minWidth'];

		var s_padding = s_type == 'text' ? '3px 0 0 5px' : '0 0 0 15px';

		i_component.suffixType = s_type;

		i_wrapper = {
			xtype: 'fieldcontainer',
			id: 'suffixlabel-' + i_component.id,
			listeners: {
				'afterrender': {
					fn: function () {

						var i_suffixLabel = i_component.getSuffixLabel(),
							i_label = i_suffixLabel.down('[name=labeltext]');

						Ext.apply(i_component, {
							minWidth: 0
						});

						i_label.addClass('x-form-item-label-suffix');

						i_component.setSuffixLabelText(s_label);
					},
					single: true
				},
				'resize': {
					fn: function () {
						i_component.syncSuffixLabel();
					}
				}
			},
			items: [
				{
					xtype: 'panel',
					layout: 'hbox',
					align: 'stretch',
					border: false,
					anchor: '100%',
					defaults: {
						border: false,
						layout: 'anchor',
						xtype: 'panel'
					},
					items: [
						{
							name: 'fieldcontainer'
						},
						{
							name: 'labelcontainer',
							items: [
								{
									name: 'labeltext',
									border: false,
									padding: s_padding
								}
							]
						}
					]
				}
			]
		};

		Ext.Array.each(a_extend, function(s_prop) {

			var o_config = i_component.initialConfig;

			if (o_config[s_prop]) {
				i_wrapper[s_prop] = o_config[s_prop];
			}
		});

		i_wrapper = i_parent.insert(n_index, i_wrapper);

		i_wrapper.down('[name=fieldcontainer]').add(i_component);

		return i_plugin;
	},

	initField: function (i_component, s_label, s_type) {

		var i_plugin = this,
			i_parent = i_component.up();

		if (!i_parent) {
			i_component.on({
				'afterrender': {
					fn: function (i_self) {
						i_plugin.buildField(i_self, s_label, s_type);
					},
					single: true
				}
			});
		}
		else {
			i_plugin.buildField(i_component, s_label, s_type);
		}

		return i_plugin;
	}
});

Ext.define('Ext.ux.form.field.plugin.Unique', {
	extend: 'Ext.AbstractPlugin',
	alias: ['plugin.uniquevalidation'],

	_isValid: true,
	_ajaxReq: null,
	asJson: false,

	init: function (i_cmp) {

		var i_plugin = this;

		i_plugin.validateValue = Ext.Function.createBuffered(i_plugin.validateValue, 250);

		if (Ext.isObject(i_plugin.errorMessage)) {
			i_plugin.errorMessage = ip2.i18n(i_plugin.errorMessage);
		}

		i_plugin.id = 'Unique';
		i_plugin.component = i_cmp;

		i_cmp.getErrors = (function(f_old) {
			return function(value) {
				var a_errors = f_old.apply(this, arguments) || [];

				if (!i_plugin._isValid) {
					a_errors.push(i_plugin.errorMessage);
				}

				return a_errors;
			};
		})(i_cmp.getErrors);

		i_cmp.validate = (function(f_old) {
			return function() {

				i_plugin.validateValue(i_cmp.getValue(), function() {
					f_old.call(i_cmp);
				});

				return i_plugin._isValid;
			};
		})(i_cmp.validate);
	},
	getDataParent: function(i_parent) {

		while (i_parent && !i_parent.dataParent) {
			i_parent = i_parent.up();
		}

		return i_parent.dataParent;
	},
	getDataLanguage: function (i_parent) {

		while (i_parent && !i_parent.language) {
			i_parent = i_parent.up();
		}

		if (i_parent) {
			return i_parent.language ? i_parent.language : 'da';
		}
		else {
			return 'da';
		}
	},
	parseHandler: function(resp) {
		var o_resp = Ext.decode(resp);

		return o_resp.success;
	},

	validateValue: function(value, f_callback) {

		var i_plugin = this;
		var i_cmp = i_plugin.component;
		var o_params = {};

		if (i_cmp) {
			if (ip2.isEqual(i_cmp.originalValue, value)) {
				i_plugin._isValid = true;
				i_plugin._ajaxReq = null;
				f_callback(true);
				return;
			}
	
			if (i_plugin._ajaxReq) {
				Ext.Ajax.abort(i_plugin._ajaxReq);
			}
	
			Ext.Object.each(i_plugin.extraParams, function(key, val) {
				o_params[key] = Ext.isFunction(val) ? val.call(i_plugin.component, value) : val;
			});
	
			if (i_plugin.valueKey) {
				if (ip2.isStringedObject(value)) {
					value = JSON.parse(value);
				}
				o_params[i_plugin.valueKey] = value;
			}
	
			var s_language = i_plugin.getDataLanguage(i_cmp);
	
			if (s_language) {
				o_params.language = s_language;
			}
	
			if (i_plugin.asJson) {
				i_plugin._ajaxReq = Ext.Ajax.request({
					url: i_plugin.serviceUrl,
					jsonData: o_params,
					success: function (o_resp) {
						
						if (i_plugin.parseHandler) {
							var b_valid = i_plugin.parseHandler.call(i_plugin.component, o_resp.responseText);
	
							i_plugin._isValid = b_valid;
							i_plugin._ajaxReq = null;
							f_callback(b_valid);
						}
						
					}
				});
			}
			else {
				i_plugin._ajaxReq = Ext.Ajax.request({
					url: i_plugin.serviceUrl,
					params: o_params,
					success: function (o_resp) {

						if (i_plugin.parseHandler) {

							var b_valid = i_plugin.parseHandler.call(i_plugin.component, o_resp.responseText);
							i_plugin._isValid = b_valid;
							i_plugin._ajaxReq = null;
							f_callback(b_valid);
						}
						
					}
				});
			}
		}

		
	}
});
Ext.define('Ext.ux.form.field.QuickCombo', {
	extend: 'Ext.form.field.ComboBox',
	alias: 'widget.quickcombo',

	/**
	     * @cfg {Array} data
	     * The data to put in the quickcombo
	     */
	data: null,

	/**
	     * @cfg {Array} fields
	     * The fields the store uses for data
	     */
	fields: null,

	initComponent: function () {

		var i_cmp = this;
		var i_store = i_cmp.createStore();

		Ext.apply(i_cmp, {
			store: i_store
		});

		//i_cmp.valueField = i_cmp.intitialConfig.valueField || i_cmp.fields[0];
		//i_cmp.displayField = i_cmp.intitialConfig.displayField || i_cmp.fields[1];

		i_cmp.callParent(arguments);

		return i_cmp;
	},

	createStore: function () {

		var i_cmp = this,
		a_field = i_cmp.fields || [],
		a_data = i_cmp.data || [],
		i_store;

		i_store = Ext.create('Ext.data.Store', {
			fields: a_field,
			data: a_data
		});

		return i_store;
	}
});
Ext.define('Ext.ux.form.field.AutoTimeStamp', {
	
	extend: 'Ext.form.field.Text',

	alias: ['widget.autotimestampfield'],

	hidden: true,

	enforceRecordValue: true,

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		return i_cmp;
	},
	
	addLeadingZero: function (n_val) {

		var s_val = String(n_val);

		if (s_val.length == 1) {
			s_val = '0' + s_val;
		}

		return s_val;
	},
	
	getValue: function () {

		var i_cmp = this;
		var i_timestamp = new Date();

		var s_date = [
			i_timestamp.getFullYear(),
			i_cmp.addLeadingZero(i_timestamp.getMonth() + 1),
			i_cmp.addLeadingZero(i_timestamp.getDate())
		].join('-');

		var s_time = [
			i_cmp.addLeadingZero(i_timestamp.getHours()),
			i_cmp.addLeadingZero(i_timestamp.getMinutes()),
			i_cmp.addLeadingZero(i_timestamp.getSeconds()),
			i_timestamp.getMilliseconds() + '000'
		].join('.');

		return [s_date, s_time].join('-');
	},
	
	getSubmitValue: function () {

		return this.getValue();
	},

	setValue: function () {

		var i_cmp = this;
		var s_value = i_cmp.getValue();

		return i_cmp.callParent([s_value]);
	},
	
	isDirty: function () {

		return false;
	}
});

Ext.define("Ext.ux.themed.Button", {

	extend: "Ext.button.Button",

	alias: [
		"widget.themedbutton"
	],

	config: {
		iconActive: "icon icon-init ",
		iconHover: "icon icon-over ",
		iconDisable: "icon icon-disabled ",
		iconClass: ""
	},

	listeners: {
		menushow: {
			fn: function (i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconActive();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		menuhide: {
			fn: function (i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconActive();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		mouseover: {
			fn: function (i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconHover();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		mouseout: {
			fn: function (i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconActive();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		enable: {
			fn: function(i_self) {
				i_self.setIconCls(i_self.getIconActive() + i_self.getIconClass());
			}
		},
		disable: {
			fn: function(i_self) {
				i_self.setIconCls(i_self.getIconDisable() + i_self.getIconClass());
			}
		}
	},

	initComponent: function() {

		var i_self = this;
		var o_config = i_self.initialConfig;
		var s_iconCls = o_config.iconCls || o_config.icon || "";

		if (Ext.String.startsWith(s_iconCls, "icon-")) {
			s_iconCls = "icon " + s_iconCls.toLowerCase();
		}
		else {
			s_iconCls = "icon icon-" + s_iconCls.toLowerCase();
		}

		i_self.setIconClass(s_iconCls.toLowerCase());

		s_iconCls = s_iconCls ? i_self.getIconActive() + i_self.getIconClass() : i_self.getIconActive();

		i_self.iconCls = s_iconCls;

		i_self.callParent();

		return i_self;
	}
});
Ext.define("Ext.ux.themed.MenuItem", {

	extend: "Ext.menu.Item",

	alias: "widget.themedmenuitem",

	config: {
		iconActive: "icon icon-init ",
		iconHover: "icon icon-over ",
		iconDisable: "icon icon-disabled ",
		iconClass: "",
	},

	listeners: {
		activate: {
			fn: function(i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconHover();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		deactivate: {
			fn: function(i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconActive();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		enable: {
			fn: function(i_self) {
				i_self.setIconCls(i_self.getIconActive() + i_self.getIconClass());
			}
		},
		disable: {
			fn: function(i_self) {
				i_self.setIconCls(i_self.getIconDisable() + i_self.getIconClass());
			}
		}
	},

	initComponent: function() {

		var i_self = this;
		var s_iconCls = i_self.iconCls || "";

		if (Ext.String.startsWith(s_iconCls, "icon-")) {
			s_iconCls = "icon " + s_iconCls.toLowerCase();
		}
		else {
			s_iconCls = "icon icon-" + s_iconCls.toLowerCase();
		}

		i_self.setIconClass(s_iconCls.toLowerCase());

		s_iconCls = s_iconCls ? i_self.getIconActive() + i_self.getIconClass() : i_self.getIconActive();

		i_self.iconCls = s_iconCls;

		i_self.callParent();

		return i_self;
	}
});
Ext.define('Ext.ux.themed.ActionColumn', {

	requires: [
		'Ext.grid.column.Action'
	],

	extend: 'Ext.grid.column.Action',
	
	alias: ['widget.themedactioncolumn'],
	
	constructor: function (o_config) {

		var i_cmp = this,
			s_icon = o_config.iconCls || o_config.icon || '',
			s_iconCls = 'icon icon-' + s_icon.toLowerCase();

		o_config.iconCls = s_iconCls;
		o_config.items = o_config.items || i_cmp.items || [{}];
		o_config.icon = null;
		o_config.width = o_config.width || 25;

		i_cmp.callParent([o_config]);

		return i_cmp;
	},

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent();

		return i_cmp;
	}
});

Ext.define("Ext.ux.themed.SplitButton", {

	extend: "Ext.button.Split",

	alias: [
		"widget.themedsplitbutton"
	],

	config: {
		iconActive: "icon icon-init ",
		iconHover: "icon icon-over ",
		iconDisable: "icon icon-disabled ",
		iconClass: "",
	},

	listeners: {
		menushow: {
			fn: function (i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconActive();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		menuhide: {
			fn: function (i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconActive();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		mouseover: {
			fn: function (i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconHover();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		mouseout: {
			fn: function (i_self) {
				var s_iconCls = i_self.isDisabled() ? i_self.getIconDisable() : i_self.getIconActive();
				i_self.setIconCls(s_iconCls + i_self.getIconClass());
			}
		},
		enable: {
			fn: function(i_self) {
				i_self.setIconCls(i_self.getIconActive() + i_self.getIconClass());
			}
		},
		disable: {
			fn: function(i_self) {
				i_self.setIconCls(i_self.getIconDisable() + i_self.getIconClass());
			}
		}
	},

	initComponent: function() {

		var i_self = this;
		var o_config = i_self.initialConfig;
		var s_iconCls = o_config.iconCls || o_config.icon || "";

		if (Ext.String.startsWith(s_iconCls, "icon-")) {
			s_iconCls = "icon " + s_iconCls.toLowerCase();
		}
		else {
			s_iconCls = "icon icon-" + s_iconCls.toLowerCase();
		}

		i_self.setIconClass(s_iconCls.toLowerCase());

		s_iconCls = s_iconCls ? i_self.getIconActive() + i_self.getIconClass() : i_self.getIconActive();

		i_self.iconCls = s_iconCls;

		i_self.callParent();

		return i_self;
	}
});
Ext.define("Ext.ux.themed.FAB", {

	extend: "Ext.ux.themed.Button",

	alias: [
		"widget.ux-fab",
		"widget.themedfab"
	],

	floating: true,

	height: 50,
	width: 50,

	iconCls: "pf-plus",

	style: {
		"background-color": "red",
		"border-radius": "50%",
		"border": "1px solid #eef0f1",
		"margin": "0px"
	},

	config: {
		alignment: "br-br",
		offX: 0,
		offY: 0,
		color: "red",
		borderColor: "#eef0f1"
	},

	shadow: false,

	requires: [
		"Ext.ux.themed.Button"
	],

	listeners: {
		afterrender: {
			fn: function() {

				var i_self = this;

				var i_parent = i_self.floatParent;
				var s_color = i_self.getColor();

				var a_offset =[
					i_self.getOffX(),
					i_self.getOffY()
				];

				if (i_parent && i_parent.getEl()) {
					i_self.alignTo(i_parent.getEl(), i_self.getAlignment(), a_offset);
					i_self.toFront(false);
				}
				else {
					i_parent.on({
						afterrender: {
							fn: function(i_parent) {
								i_self.alignTo(i_parent.getEl(), i_self.getAlignment(), a_offset);
								i_self.toFront(false);
							},
							buffer: 10
						}
					});
				}

				if (s_color) {
					i_self.setStyle("background-color", s_color);
				}
			},
			single: true
		},
		added: {
			fn: function(i_button) {

				var i_self = this;

				var i_parent = i_self.ownerCt;

				if (i_parent) {

					i_parent.on({
						resize: {
							fn: function(i_parent) {

								var a_offset =[
									i_self.getOffX(),
									i_self.getOffY()
								];

								i_self.alignTo(i_parent.getEl(), i_self.getAlignment(), a_offset);
								i_self.toFront(false);
							}
						},
						move: {
							fn: function(i_parent) {

								var a_offset =[
									i_self.getOffX(),
									i_self.getOffY()
								];

								i_self.alignTo(i_parent.getEl(), i_self.getAlignment(), a_offset);
								i_self.toFront(false);
							},
							buffer: 10
						}
					});
				}

				i_self.show();
			}
		}
	},

	updateColor: function(value) {

		var i_self = this;
		i_self.setStyle("background-color", value);
	},

	updateBorderColor: function(value) {

		var i_self = this;
		i_self.setStyle("border-color", value);
	},

	updateAlignment: function(value) {

		var i_self = this;

		var i_parent = i_self.floatParent;

		if (i_parent) {
			var a_offset =[
				i_self.getOffX(),
				i_self.getOffY()
			];

			i_self.alignTo(i_parent.getEl(), i_self.getAlignment(), a_offset);
			i_self.toFront(false);
		}
	},

	updateOffX: function(value) {

		var i_self = this;

		var i_parent = i_self.floatParent;

		if (i_parent) {

			var a_offset =[
				value,
				i_self.getOffY()
			];

			i_self.alignTo(i_parent.getEl(), i_self.getAlignment(), a_offset);
		}
	},

	updateOffY: function(value) {

		var i_self = this;

		var i_parent = i_self.floatParent;

		if (i_parent) {

			var a_offset = [
				i_self.getOffX(),
				value
			];

			i_self.alignTo(i_parent.getEl(), i_self.getAlignment(), a_offset);
		}
	}
});

/**
 * @class Ext.ux.xpd.I18nField
 * Base class that all group components of the XPD component uses
 * @extends Ext.tab.Panel
 */

Ext.define("Ext.ux.xpd.I18nField", {

	extend: "Ext.form.FieldContainer",

	alias: [
		"widget.i18nxpdeditorfield"
	],

	mixins: {
		field: "Ext.form.field.Field"
	},

	cls: "x-ux-form-xpdlanguagepanel",

	tabPosition: "bottom",

	xpd: "",

	dataParent: null,

	defaultLanguage: "en",

	languages: null,

	value: "",

	layout: "fit",

	languageControllers: null,
	tabPanel: null,

	initComponent: function() {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;

		var o_xpd = ip2.resource.get(i_cmp.xpd, true);

		Ext.apply(i_cmp, {
			languageControllers: {},
			value: o_config.value || i_cmp.value,
			languages: o_config.languages,
			defaultLanguage: o_config.defaultLanguage || i_cmp.defaultLanguage,
			xpdCollection: o_xpd,
			items: [
				{
					xtype: "tabpanel",
					itemId: "tabPanel",
					tabPosition: i_cmp.tabPosition,
					autoScroll: true,
					layout: "fit"
				}
			]
		});

		// Sort languages so defaultLanguage is first
		var a_languages = [];
		a_languages.push(i_cmp.defaultLanguage);
		Ext.Array.each(i_cmp.languages, function (s_lang) {
			if (s_lang != i_cmp.defaultLanguage) {
				a_languages.push(s_lang);
			}
		});
		i_cmp.languages = a_languages;

		i_cmp.callParent(arguments);

		i_cmp.initLanguageControllers();

		i_cmp.initField();

		return i_cmp;
	},

	initLanguageControllers: function () {

		var i_cmp = this;
		var a_languages = i_cmp.languages;
		var i_tabPanel = i_cmp.down("#tabPanel");

		Ext.Array.each(a_languages, function (s_language) {

			var o_controller = i_cmp.createLanguageController(s_language);
			var i_controller = i_tabPanel.add(o_controller);

			i_controller.syncTabIcon();

			i_cmp.languageControllers[s_language] = i_controller;
		});
	},

	createLanguageController: function (s_lang) {

		var i_cmp = this;
		var i_controller;
		var s_lockId = "xpdlock";
		var s_fieldId = "xpdfield";

		var a_languages = i_cmp.languages;

		var s_primaryLanguage = i_cmp.defaultLanguage;
		var s_currentLanguage = s_lang;

		var s_primaryLanguageTitle = wsh.i18n.getEnum(s_primaryLanguage);
		var s_currentLanguageTitle = wsh.i18n.getEnum(s_currentLanguage);

		i_controller = Ext.widget("panel", {
			title: s_currentLanguageTitle,
			autoScroll: true,
			cls: "x-ux-form-xpdlanguagepanel-form",
			bodyPadding: 20,

			language: s_currentLanguage,
			itemId: s_currentLanguage,

			layout: "anchor",

			lockId: s_lockId,
			fieldId: s_fieldId,

			isLocked: true,
			isMaster: (s_currentLanguage == s_primaryLanguage),

			value: null,

			listeners: {
				"afterrender": {
					fn: function (i_self) {
						i_self.setIconCls("ip2-icon-data-unknown");
					},
					single: true
				}
			},
			items: [
				{
					xtype: "container",
					itemId: s_lockId,
					layout: {
						type: "vbox",
						align: "center",
						pack: "center"
					},
					height: "100%",
					width: "100%",
					items: [
						{
							xtype: "fieldset",
							title: ip2.i18n({
								da: "Aktiver " + s_currentLanguageTitle.toLowerCase(),
								en: "Activate " + s_currentLanguageTitle.toLowerCase()
							}),
							width: 500,
							padding: "20 30",
							layout: "anchor",
							items: [
								{
									xtype: "quickcombo",
									itemId: "language",
									valueField: "value",
									displayField: "title",
									fields: ["title", "value"],
									editable: false,
									forceSelection: true,
									anchor: "100%",
									margin: "0 0 10px 0",
									isFormField: false,
									data: (function () {

										var a_languages = i_cmp.languages;
										var a_data = [];

										Ext.Array.each(a_languages, function (s_value) {
											if (s_value != s_currentLanguage) {
												var s_title = wsh.i18n.getEnum(s_value);
												a_data.push({
													title: s_title,
													value: s_value
												});
											}
										});

										a_data.push({
											title: ip2.i18n({
												da: "Uden indhold",
												en: "Without content"
											}),
											value: 0
										});

										return a_data;
									})(),
									labelWidth: 160,
									fieldLabel: ip2.i18n({
										da: "Kopier indhold fra",
										en: "Copy content from"
									}),
									labelAlign: "top",
									listeners: {
										afterrender: {
											fn: function (i_self) {
												var s_value = i_cmp.defaultLanguage;
												i_self.setValue(s_value);
											}
										},
										change: {
											fn: function (i_self, s_lang) {

												if (i_controller) {
													var i_button = i_controller.down("#data");
													i_button.language = s_lang;
												}
											}
										}
									}
								},
								{
									xtype: "button",
									itemId: "data",
									language: s_primaryLanguage,
									width: 120,
									style: "float: right;",
									text: ip2.i18n({
										da: "Aktiver",
										en: "Activate"
									}),
									handler: function () {

										var i_self = this;
										var s_lang = i_self.language;
										var i_controller = i_self.up("#" + s_currentLanguage);
										var i_master = i_cmp.down("#" + s_lang);

										if (!i_master) {
											i_controller.unlockField();
										}
										else {
											var o_value = i_master.getValue();

											if (!o_value) {

												var s_languageTitle = wsh.i18n.getEnum(s_lang);
												ip2.messageBox({
													message: ip2.i18n({
														da: "Der er ingen værdier at hente fra " + s_languageTitle,
														en: "No values to copy from " + s_languageTitle
													})
												});
											}
											else {
												i_controller.unlockField(o_value, true);
											}
										}
									}
								}
							]
						}
					]
				}
			],
			getField: function () {

				var i_self = this,
					s_id = i_self.fieldId;

				return i_self.down("#" + s_id);
			},
			getLock: function () {

				var i_self = this,
					s_id = i_self.lockId;

				return i_self.down("#" + s_id);
			},
			lockField: function () {

				var i_self = this,
					i_field = i_self.getField();
				i_lock = i_self.getLock();

				// Kill the xpd field if present
				if (i_field) {
					i_field.destroy();
				}

				i_lock.show();

				i_self.isLocked = true;

				i_self.syncTabIcon();
			},
			unlockField: function (o_value, b_dirty) {

				var i_self = this;
				var s_language = i_self.language;

				o_value = o_value || i_self.value;

				if (!o_value) {
					o_value = (function () {

						var o_return = {};
						var s_idProperty = i_cmp.xpdCollection.idProperty;
						var s_language = i_cmp.defaultLanguage;
						var o_value = Ext.decode(i_cmp.value);

						o_return[s_idProperty] = o_value[s_language][s_idProperty];

						return o_return;
					})();
				}

				var s_value = Ext.encode(o_value);

				var i_field = i_self.getField(),
					i_lock = i_self.getLock();

				if (!i_field) {

					var s_xpd = i_cmp.xpd;
					var i_dataParent = i_cmp.dataParent;

					i_field = i_self.add({
						xtype: "xpdfield",
						itemId: i_self.fieldId,
						xpd: s_xpd,
						environment: "editor",
						dataParent: i_dataParent,
						language: i_self.language,
						//language: ip2.session.getLanguage(),
						isFormField: false,
						value: b_dirty ? "" : s_value,
						anchor: "100%",
						listeners: {
							"dirtychange": function (i_field, b_dirty) {
								i_self.syncTabIcon();
								i_cmp.checkChange();
							},
							"validitychange": function (i_field, b_valid) {
								i_self.syncTabIcon();
								i_cmp.checkChange();
							}
						}
					});
				}
				else {
					i_field.setValue(s_value);
					i_field.resetOriginalValue();
				}

				if (b_dirty) {
					i_field.setValue(s_value);
				}

				i_lock.hide();
				i_field.show();

				i_self.isLocked = false;

				i_self.syncTabIcon();
			},
			isValid: function () {

				var i_self = this,
					i_field = i_self.getField(),
					b_locked = i_self.isLocked;

				return b_locked ? true : i_field.isValid();
			},
			isDirty: function () {

				var i_self = this;
				var i_field = i_self.getField();
				var b_locked = i_self.isLocked;

				return b_locked ? false : i_field.isDirty();
			},
			syncTabIcon: function () {

				var i_self = this,
					i_tab = i_self.tab,
					b_locked = i_self.isLocked;

				if (!i_tab.getEl()) {
					i_self.on({
						"afterrender": {
							fn: function (i_self) {
								i_self.syncTabIcon();
							},
							single: true,
							scope: i_self
						}
					});
				}

				if (b_locked) {
					i_tab.setIconCls("ip2-icon-data-lock");
				}
				else {

					if (!i_self.isValid()) {
						i_self.tab.setIconCls("flatiu icon-data-error");
					}
					else if (i_self.isDirty()) {
						i_self.tab.setIconCls("flatiu icon-data-new");
					}
					else {
						i_self.tab.setIconCls("");
					}
				}
			},
			getDataValue: function () {

				var i_self = this,
					o_value = i_self.getValue(),
					o_dataValue = null;

				if (o_value) {
					o_dataValue = {};
					o_dataValue[i_self.itemId] = o_value;
				}

				return o_dataValue;
			},
			getValue: function () {

				var i_self = this,
					i_field = i_self.getField(),
					o_value = null,
					s_value;

				if (i_field) {
					s_value = i_field.getValue();
				}

				if (s_value) {
					o_value = Ext.decode(s_value);
				}

				return o_value;
			},
			setValue: function (o_value) {

				var i_self = this,
					i_field = i_self.getField();

				i_self.value = o_value;

				if (!i_field) {

					if (o_value) {
						i_self.unlockField(o_value);
					}
				}
				else {
					if (o_value) {
						var s_value = Ext.encode(o_value);
						i_field.setValue(s_value);
					}
					else {
						i_self.lockField();
					}
				}

				return i_self;
			},
			resetOriginalValue: function () {

				var i_self = this,
					i_field = i_self.getField();

				if (i_field) {
					i_field.resetOriginalValue();
				}
			}
		});

		return i_controller;
	},

	getValue: function () {

		var i_cmp = this;
		var o_languageControllers = i_cmp.languageControllers;
		var o_values = {};

		Ext.Object.each(o_languageControllers, function (s_language, i_wrapper) {

			var o_value = i_wrapper.getValue();

			if (o_value) {
				o_values[s_language] = o_value;
			}
		});

		var s_value = "";

		if (Ext.Object.getSize(o_values)) {
			s_value = Ext.encode(o_values);
		}

		return s_value;
	},
	setValue: function (value) {

		var i_cmp = this,
			o_controllers = i_cmp.languageControllers,
			o_values;

		o_values = value ? Ext.decode(value) : {};

		Ext.Object.each(o_controllers, function (s_language, i_wrapper) {
			i_wrapper.setValue(o_values[s_language]);
		});

		return i_cmp.mixins.field.setValue.call(i_cmp, value);
	},
	resetOriginalValue: function () {

		var i_cmp = this,
			o_controllers = i_cmp.languageControllers;

		Ext.Object.each(o_controllers, function (s_language, i_wrapper) {
			i_wrapper.resetOriginalValue();
		});

		return i_cmp.mixins.field.resetOriginalValue.call(i_cmp);
	},
	isDirty: function() {

		var i_cmp = this,
			b_dirty = false,
			o_controllers = i_cmp.languageControllers;

		Ext.Object.each(o_controllers, function (s_language, i_wrapper) {
			if (i_wrapper.isDirty()) {
				b_dirty = true;
				return false;
			}
		});

		return b_dirty;
	},
	isValid: function () {

		var i_cmp = this,
			b_valid = true,
			o_controllers = i_cmp.languageControllers;

		Ext.Object.each(o_controllers, function (s_language, i_wrapper) {
			if (!i_wrapper.isValid()) {
				b_valid = false;
				return false;
			}
		});

		return b_valid;
	}
});
Ext.define("Ext.ux.call2action.GeneralPanel", {
	extend: "Ext.form.Panel",

	alias: [
		"widget.ip2Call2ActionGeneralPanel"
	],

	border: false,

	bodyPadding: 10,

	layout: "anchor",

	initComponent: function() {

		var i_self = this;
		i_self.callParent();

		var o_data = i_self.config.data;
		i_self.data = o_data;

		var o_xpd = ip2.resource.get("call2action.xpd", true);

		if (o_xpd && Ext.Object.getKeys(o_xpd.collections).length > 1) {

			var a_fields = Ext.ux.xpd.Handler.getFieldsWithValues(o_xpd, 1, o_data);

			i_self.add(a_fields);
		}
	},

	/* ----------------------------------------------------------------------------------------------------
	    Validate and save form
	   ---------------------------------------------------------------------------------------------------- */
	doSave: function(o_options) {

		var i_self = this;
		var o_data = i_self.getData();
		var i_form = i_self.getForm();
		var b_formValid = i_form.isValid();

		var f_success = o_options.success || Ext.emptyFn;
		var f_faliure  = o_options.failure || Ext.emptyFn;

		if (b_formValid) {

			var o_values = i_form.getFieldValues();

			Ext.apply(o_data, o_values);

			f_success();
		}
		else {
			var a_errors = [{
				panel: "general"
			}];
			f_faliure(i_self, a_errors);
		}
	},

	getValue: function() {

		var i_self = this;
		return i_self.getData();
	}

});
Ext.define("Ext.ux.call2action.UrlPanel", {

	extend: "Ext.form.Panel",

	alias: [
		"widget.ip2Call2ActionUrlPanel"
	],

	border: false,

	bodyPadding: 10,

	defaults: {
		xtype: "textfield",
		labelAlign: "left",
		labelWidth: 120
	},

	layout: {
		type: "anchor"
	},

	config: {
		choises: null
	},

	initComponent: function() {

		var i_self = this;
		var o_data = i_self.config.data;

		i_self.data = o_data;

		i_self.callParent();

		if (!o_data.link) {
			o_data.link = {};
		}

		i_self.add(i_self.createItems());
	},

	createItems: function() {

		var i_self = this;
		var o_data = i_self.getData();
		var a_items = [];

		var i_heading = Ext.widget("textfield", {
			fieldLabel: ip2.i18n({
				da: "Overskrift",
				en: "Headline"
			}),
			name: "title",
			allowBlank: true,
			anchor: "100%",
			value: o_data.link.title || "",
			listeners: {
				change: {
					fn: function(field) {
						if (i_self.isEmpty()) {
							i_self.fireEvent("isempty");
						}
					},
					buffer: 100
				}
			}
		});

		var i_urlField = Ext.widget("textfield", {
			fieldLabel: ip2.i18n({
				da: "URL",
				en: "URL"
			}),
			name: "url",
			allowBlank: true,
			anchor: "100%",
			value: o_data.link.url || "",
			listeners: {
				change: {
					fn: function(field) {
						if (i_self.isEmpty()) {
							i_self.fireEvent("isempty");
						}
					},
					buffer: 100
				}
			}
		});

		var i_choiseGroup = Ext.widget("radiogroup", {
			fieldLabel: ip2.i18n({
				da: "Link type",
				en: "Link type"
			}),
			columns: 3,
			vertical: true,
			width: 400,
			items: [
				{
					boxLabel: "URL",
					name: "linktype",
					inputValue: "url",
					checked: o_data.link.linktype == "url" ? true : false,
					readOnly: false,
					onBoxClick: function() {

						if (!i_self.disabled && !i_self.readOnly) {
							var b_check = true;
							if (this.checked) {
								b_check = false;
							}
							this.setValue(b_check);
						}
					}
				},
				{
					boxLabel: "Video",
					name: "linktype",
					inputValue: "video",
					checked: o_data.link.linktype == "video" ? true : false,
					readOnly: false,
					onBoxClick: function() {

						if (!i_self.disabled && !i_self.readOnly) {
							var b_check = true;
							if (this.checked) {
								b_check = false;
							}
							this.setValue(b_check);
						}
					}
				},
				{
					boxLabel: ip2.i18n({
						da: "Billede",
						en: "Image"
					}),
					name: "linktype",
					inputValue: "image",
					checked: o_data.link.linktype == "image" ? true : false,
					readOnly: false,
					onBoxClick: function() {

						if (!i_self.disabled && !i_self.readOnly) {
							var b_check = true;
							if (this.checked) {
								b_check = false;
							}
							this.setValue(b_check);
						}
					}
				}
			]
		});

		a_items.push(i_heading);
		a_items.push(i_urlField);
		a_items.push(i_choiseGroup);

		i_self.setChoises(i_choiseGroup);

		return a_items;
	},

	/* ----------------------------------------------------------------------------------------------------
		Is valid
	   ---------------------------------------------------------------------------------------------------- */
	isValid: function() {

		var i_self = this;

		var b_valid = true;
		var i_form = i_self.getForm();

		var i_title = i_form.findField("title");
		var i_url = i_form.findField("url");

		var s_title = i_title.getValue();
		var s_url = i_url.getValue();

		if (Ext.isEmpty(s_title) && !Ext.isEmpty(s_url)) {
			i_title.markInvalid(i_title.blankText);
			b_valid = false;
		}
		else if (!Ext.isEmpty(s_title) && Ext.isEmpty(s_url)) {
			i_url.markInvalid(i_url.blankText);
			b_valid = false;
		}

		return b_valid;
	},

	/* ----------------------------------------------------------------------------------------------------
		Is empty
	   ---------------------------------------------------------------------------------------------------- */
	isEmpty: function() {

		var i_self = this;

		var b_empty = true;
		var i_form = i_self.getForm();

		var i_title = i_form.findField("title");
		var i_url = i_form.findField("url");

		var s_title = i_title.getValue();
		var s_url = i_url.getValue();

		if (!Ext.isEmpty(s_url) || !Ext.isEmpty(s_title)) {
			b_empty = false;
		}

		i_self.isValid();

		return b_empty;
	},

	/* ----------------------------------------------------------------------------------------------------
		Validate and save form
	   ---------------------------------------------------------------------------------------------------- */
	getValue: function() {

		var i_self = this;

		var o_value = {
			type: "url"
		};

		var i_form = i_self.getForm();

		if (i_self.isValid()) {

			var o_values = i_form.getFieldValues();
			Ext.apply(o_value, o_values);
		}

		return o_value;
	},

	enable: function() {

		var i_self = this;
		i_self.callParent();

		var i_choiseGroup = i_self.getChoises();

		var a_items = i_choiseGroup.getBoxes();

		Ext.Array.each(a_items, function(i_field) {
			if (i_field.getMaskTarget() || i_field.getEl()) {
				i_field.unmask();
			}
		});
	}

});
Ext.define("Ext.ux.call2action.PagingToolbar", {

	extend: "Ext.toolbar.Paging",

	config: {
		filterField: null,
		store: null
	},

	initComponent: function() {

		var i_self = this;

		i_self.callParent();
	},

	getPagingItems: function() {

		var i_self = this;
		var i_store = i_self.getStore();

		var a_items = i_self.callParent();

		var i_filterField = Ext.create("Ext.form.field.Text", {
			width: 300,
			enableKeyEvents: true,
			itemId: "filterField",
			name: "filterField",
			listeners: {
				keydown: function(fld, e) {
					if (e.getKey() == e.ENTER) {
						i_store.load();
					}
				}
			}
		});

		a_items.push(i_filterField);

		i_self.setFilterField(i_filterField);

		return a_items;
	}
});
Ext.define("Ext.ux.call2action.EntityGrid", {

	extend: "Ext.grid.Panel",

	alias: ["widget.ip2Call2ActionEntityGrid"],

	border: false,

	multiSelect: false,

	config: {
		dmd: {},
		viewReady: false,
		dmdInfo: {},
		pagingBar: null
	},

	initComponent: function() {

		var i_self = this;

		var o_dmdConfig = i_self.getDmd();

		// create model and store
		var i_model = ip2.model({
			dmd: o_dmdConfig.dmd,
			entityName: o_dmdConfig.entity,
			uiName: (o_dmdConfig.ui) ? o_dmdConfig.ui : "portfolio"
		});

		var i_protoModel = i_model.prototype;

		var o_dmdInfo = ip2.dmd.getInfo({
			dmd: o_dmdConfig.dmd,
			entity: o_dmdConfig.entity,
			view: o_dmdConfig.ui || "portfolio",
			context: "grid"
		});

		var i_proxy = ip2.getProxyByEntity({
			dmd: o_dmdConfig.dmd,
			entity: o_dmdConfig.entity,
			view: o_dmdConfig.ui || "portfolio",
			context: "grid"
		});

		var o_extraParams = i_proxy.getExtraParams();

		Ext.apply(o_extraParams, {
			action: "getRows",
			context: "grid",
			uiName: o_dmdConfig.ui || "portfolio",
			dmdFile: ip2.resource.getFullPath(o_dmdConfig.dmd)
		});

		var i_store = Ext.create("Ext.data.Store", {
			model: i_model,
			remoteSort: true,
			autoSync: false,
			proxy: i_proxy,
			pageSize: 14,
			listeners: {
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_toolbar = i_self.getPagingBar();

						var s_search = i_toolbar.filterField.getValue();
						var i_proxy = i_store.getProxy();

						var o_extraParams = i_proxy.getExtraParams();

						if (s_search) {
							o_extraParams.search = s_search;
						}
						else {
							delete o_extraParams.search;
						}

						//store.proxy.extraParams.search = i_self.tb.filterField.getValue();

						if (o_dmdConfig.filter) {
							Ext.apply(i_proxy.extraParams, {
								filter: (Ext.isString(o_dmdConfig.filter)) ? o_dmdConfig.filter : Ext.encode(o_dmdConfig.filter)
							});
						}
						else {
							if (o_extraParams.filter) {
								delete o_extraParams.filter;
							}
						}
						if (o_dmdConfig.union && o_dmdConfig.union.length > 0) {
							Ext.apply(i_proxy.extraParams, {
								union: (Ext.isString(o_dmdConfig.union)) ? o_dmdConfig.union : Ext.encode(o_dmdConfig.union)
							});
						}
						else {
							if (o_extraParams.union) {
								delete o_extraParams.union;
							}
						}
					}
				},
				load: {
					fn: function(i_store, a_records) {

						if (o_dmdConfig.union && o_dmdConfig.union.length > 0) {

							var union = (Ext.isString(o_dmdConfig.union)) ? Ext.decode(o_dmdConfig.union) : o_dmdConfig.union;
							var s_prop = union[0].property;
							var n_token = union[0].value;

							Ext.Array.each(a_records, function(i_record) {
								if (i_record.get(s_prop) == n_token) {
									i_self.selModel.select(i_record, false);
								}
							});
						}
					}
				}
			}
		});

		var i_selModel = Ext.create("Ext.selection.CheckboxModel", {
			mode: "SINGLE",
			allowDeselect: true
		});

		var o_columns = i_protoModel.columns;
		var a_columns = o_dmdConfig.columns;
		var o_uiTypes = ip2.getUiTypes();

		var a_uiColumns = [];

		Ext.Array.each(o_columns, function (o_definition, s_key) {

			var o_found;
			var b_isDefined = false;

			Ext.Array.each(a_columns, function (o_col) {
				if (o_col.dataIndex == s_key) {
					o_found = o_col;
					b_isDefined = true;
					return false;
				}
			});

			if (!b_isDefined) {

				var s_uiType = o_definition.uitype || o_definition.uiType;
				var o_uiType = o_uiTypes[s_uiType];

				// Prep the config object from the definition
				var o_config = Ext.apply({}, o_definition.column);

				if (o_config.xpd) {

					var o_xpdInfo = ip2.getFieldXpdInfo(s_key, o_dmdInfo.entity, o_config);

					if (o_xpdInfo) {
						ip2.applyFieldXpdInfo(o_config, o_xpdInfo);
					}
				}

				var o_column = Ext.apply({}, o_config);

				// Could have a renderer applied from uiTypes
				if (o_uiType && o_uiType.grid && o_uiType.grid.renderer) {
					o_column.renderer = o_uiType.grid.renderer;
				}

				o_column.header = o_config.header || ip2.i18n(o_definition.title) || ip2.i18n(o_definition.header) || ip2.i18n({
					da: "Beskrivelse",
					en: "Description"
				});

				Ext.apply(o_column, o_found);

				a_uiColumns.push(o_column);
			}
		});

		i_self.columns = a_uiColumns;

		var i_toolbar = Ext.create("Ext.ux.call2action.PagingToolbar", {
			wrapper: i_self,
			dock: "top",
			store: i_store,
			displayInfo: true
		});

		var o_listeners = i_self.listeners = i_self.listeners || {};

		Ext.apply(o_listeners, {
			afterrender: {
				fn: function(i_self) {
					var i_selectionModel = i_self.getSelectionModel();
					if (i_selectionModel.mode == "SINGLE") {
						i_selectionModel.allowDeselect = true;
					}
				}
			},
			deselectAll: {
				fn: function() {
					i_self.selModel.deselectAll();
				}
			},
			viewready: {
				fn: function(view) {

					i_self.setViewReady(true);
					i_self.wrapper.fireEvent("childviewready");
				}
			}
		});

		i_self.store = i_store;

		i_self.selModel = i_selModel;

		i_self.callParent(arguments);

		i_self.addDocked(i_toolbar);
		i_self.setPagingBar(i_toolbar);

		i_store.load({
			params: {
				start: 0
			}
		});
	}
});
Ext.define('Ext.ux.call2action.SitePanel', {

	extend: 'Ext.panel.Panel',

	alias: 'widget.ip2Call2ActionSitePanel',

	layout: 'accordion',

	split: true,

	border: false,

	initComponent: function() {
		var me = this;

		//me.height = 344; // TODO

		if (!me.data.website) {
			me.data.website = {
				type: '',
				token: 0
			};
		}

		me.childExpanded = false;

		me.stackGrid = Ext.create('Ext.ux.call2action.EntityGrid', {
			wrapper: me,
			itemId: 'stackgrid',
			dmd: {
				dmd: 'webshop.dmd',
				entity: 'WSHPAGET00',
				ui: 'portfolio',
				columns: ['PLGPROP_TITLE', 'PLGPROP__CID__'],
				filter: '[{"property":"PLGPROP__CID__", "value":"13"}]',
				union: (me.data.website.type == 'stack') ? '[{"property":"PAGPAGTKN", "value":"' + me.data.website.token + '"}]' : ''
			},
			title: ip2.i18n({
				da: 'Stakke',
				en: 'Stacks'
			}),
			listeners: {
				selectionchange: function(sm, records) {
					if (records.length > 0) {
						me.data.website.type = 'stack';
						me.data.website.token = records[0].data.PAGPAGTKN;

						me.productGrid.fireEvent('deselectAll');
						me.pagesGrid.fireEvent('deselectAll');

						me.fireEvent('dataactive');
					}
					else {
						me.fireEvent('datadeactive');
					}
				}
			}
		});

		me.productGrid = Ext.create('Ext.ux.call2action.EntityGrid', {
			wrapper: me,
			itemId: 'productgrid',
			dmd: {
				dmd: 'webshop.dmd',
				entity: 'WSHITMET00',
				ui: 'portfolio',
				columns: ['ILGPROP_ITEMNUMBER', 'ILGPROP_TITLE'],
				union: (me.data.website.type == 'product') ? '[{"property":"ITMITMTKN", "value":"' + me.data.website.token + '"}]' : ''
			},
			title: ip2.i18n({
				da: 'Produkter',
				en: 'Products'
			}),
			listeners: {
				selectionchange: function(sm, records) {
					if (records.length > 0) {
						me.data.website.type = 'product';
						me.data.website.token = records[0].data.ITMITMTKN;

						me.stackGrid.fireEvent('deselectAll');
						me.pagesGrid.fireEvent('deselectAll');

						me.fireEvent('dataactive');
					}
					else {
						me.fireEvent('datadeactive');
					}
				}
			}
		});

		me.pagesGrid = Ext.create('Ext.ux.call2action.EntityGrid', {
			wrapper: me,
			itemId: 'pagesgrid',
			dmd: {
				dmd: 'webshop.dmd',
				entity: 'WSHPAGET00',
				ui: 'portfolio',
				columns: ['PLGPROP_TITLE', 'PLGPROP__CID__'],
				filter: '[{"property":"PLGPROP__CID__", "value":"11"}]',
				union: (me.data.website.type == 'page') ? '[{"property":"PAGPAGTKN", "value":"' + me.data.website.token + '"}]' : ''
			},
			title: ip2.i18n({
				da: 'Sider',
				en: 'Pages'
			}),
			listeners: {
				selectionchange: function(sm, records) {
					if (records.length > 0) {
						me.data.website.type = 'page';
						me.data.website.token = records[0].data.PAGPAGTKN;

						me.stackGrid.fireEvent('deselectAll');
						me.productGrid.fireEvent('deselectAll');

						me.fireEvent('dataactive');
					}
					else {
						me.fireEvent('datadeactive');
					}
				}
			}
		});

		me.items = [
		me.stackGrid,
		me.productGrid,
		me.pagesGrid
		];

		me.listeners = me.listeners || {};
		Ext.apply(me.listeners, {
			childviewready: function(panel) {
				if (!me.childExpanded) {
					var item;
					switch (me.data.website.type) {
						case 'stack':
							item = me.getComponent('stackgrid');
							break;
						case 'product':
							item = me.getComponent('productgrid');
							break;
						case 'page':
							item = me.getComponent('pagesgrid');
							break;
					}
					if (item) {
						var expand = new Ext.util.DelayedTask(function() {
							item.expand();
							me.childExpanded = true;
						});
						expand.delay(200);
					}
				}
			}
		});

		me.callParent();
	},

	/* ----------------------------------------------------------------------------------------------------
	    Validate and save form
	   ---------------------------------------------------------------------------------------------------- */
	doSave: function(args) {
		var me = this;

		if (Ext.isFunction(args.success)) {
			args.success.call()
		}
	}

});
Ext.define("Portfolio.ux.container.Iframe", {

	xtype: "portfolio-ux-container-iframe",

	alternateClassName: [
		"Ext.ux.container.Iframe"
	],

	extend: "Ext.panel.Panel",

	alias: [
		"widget.containeriframe",
		"widget.webcontainer"
	],

	config: {
		iframe: null,
		iframeId: "",
		src: ""
	},

	listeners: {
		afterrender: {
			fn: function(i_container) {

				var i_self = this;

				var i_iframe = i_self.getIframe();
				var s_url = i_self.getSrc();

				if (i_iframe.getEl()) {
					i_iframe.el.dom.src = s_url;
				}
			},
			single: true
		}
	},

	initComponent: function () {

		var i_self = this;

		i_self.callParent();
		var s_id = Ext.id(null, "iframe-");

		var i_component = Ext.widget("component", {
			id: s_id,
			xtype: "component",
			autoEl: {
				tag: "iframe",
				style: "height: 100%; width: 100%; border: none;"
			},
			listeners: {
				load: {
					element: "el",
					fn: function () {

						i_self.setLoading(false);

						var i_iframe = i_self.getIframe();
						var s_url = i_self.getSrc();

						var temp = document.createElement("a");

						temp.href = s_url;

						if (window.location.origin != temp.origin) {
							i_iframe.el.dom.contentWindow.postMessage(Ext.encode({
								id: i_self.getIframeId(),
								originated: window.location.origin
							}), temp.origin);
						}
					}
				},
				render: {
					fn: function () {
						i_self.setLoading(true);
					}
				}
			}
		});

		i_self.setIframe(i_component);
		i_self.setIframeId(s_id);

		i_self.add(i_component);

		i_self.initPostMessage();
	},

	updateSrc: function(s_url) {

		var i_self = this;

		if (i_self.rendered) {

			var i_iframe = i_self.getIframe();

			if (i_iframe.getEl()) {
				i_iframe.el.dom.src = s_url;
			}
		}
	},

	initPostMessage: function() {

		var i_self = this;

		Ext.getWin().on({
			message: {
				fn: function(i_event) {

					var i_browserEvent = i_event.browserEvent;

					var o_data = Ext.decode(i_browserEvent.data) || {};
					var i_frame = i_self.getIframe();

					if (i_frame && (o_data.id == i_self.getIframeId() || i_frame.id == o_data.id) ) {
						if (o_data.close) {
							i_self.close();
						}
						else {
							if (o_data.event) {
								i_self.fireEvent(o_data.event, i_self, o_data);
							}
						}
					}
				}
			}
		});
	}
});

Ext.define("Ext.ux.container.Widget", {

	alias: [
		"widget.ux.container.widget",
		"widget.widgetcontainer"
	],

	extend: "Ext.form.Panel",
	layout: "fit",

	config: {
		params: null,
		src: null,
		widget: true,
		attr: null
	},

	initComponent: function () {

		var i_widget = this;

		i_widget.title = ip2.i18n(i_widget.title);
		i_widget.callParent();

		var o_params = Ext.apply({}, {
			owner: i_widget,
			url: i_widget.getSrc(),
			params: i_widget.getParams(),
			config: null,
			attr: {}
		});

		i_widget.on({
			added: {
				fn: function(i_panel) {
					setTimeout(function() {
						i_widget.handleLoad(o_params);
					}, 10);
				}
			},
			close: {
				fn: function (i_self) {

					var i_component = i_self.down();
					if (i_component) {
						if (Ext.isFunction(i_component.onClose)) {
							i_component.onClose(i_component, i_self);
						}
					}
				}
			}
		});

		return i_widget;
	},

	handleLoad: function (o_params) {

		var i_widget = this;
		var m_source = i_widget.getSrc();

		if (Ext.isObject(m_source)) {
			i_widget.componentReady(o_params, m_source);
		}

		if (Ext.isString(m_source)) {

			var s_split = m_source.split(".");
			var s_extension = s_split[s_split.length - 1];

			if (s_extension === "js" || s_extension === "widget") {

				i_widget.ajaxLoad(o_params);
			}
			else {
				i_widget.iFrameLoad(o_params);
			}
		}

		return i_widget;
	},

	iFrameLoad: function (o_params) {

		var i_widget = this;
		var s_url = o_params.url;

		var o_config = {
			xtype: "webcontainer",
			src: s_url
		};

		i_widget.componentReady(o_params, o_config);

		return i_widget;
	},

	ajaxLoad: function (o_params) {

		var i_widget = this;

		if (!o_params.attr) {
			o_params.attr = {};
		}

		var o_config = ip2.getEvaled({
			url: o_params.url
		});

		var o_clone = Ext.clone(o_config);

		Ext.applyIf(o_clone, {
			xtype: "panel",
			attr: o_params.attr
		});

		i_widget.componentReady(o_params, o_clone);
	},

	componentReady: function (o_params, o_cmp) {

		var i_widget = this;
		var i_owner = o_params.owner;

		if (i_owner && i_owner.dataParent) {
			Ext.apply(o_cmp, {
				entity: i_owner.dataParent.entity
			});
		}

		if (o_params.callback) {
			o_params.callback.call(i_widget, o_cmp, o_params.attr, resp);
			return;
		}

		// No owner container was sent along, we make a window as container

		var i_component = Ext.widget(o_cmp.xtype, o_cmp);
		var i_child = i_owner.add(i_component);

		if (Ext.isFunction(i_child.onInitialize)) {
			i_child.onInitialize(i_child, i_owner);
		}
		if (Ext.isFunction(i_widget.onInitialize)) {
			i_widget.onInitialize(i_child, i_owner);
		}

		// ON OPEN
		if (Ext.isFunction(i_child.onOpen)) {
			i_child.onOpen(i_child, i_owner);
		}
		if (Ext.isFunction(i_widget.onOpen)) {
			i_widget.onOpen(i_child, i_owner);
		}

		// ON LOAD
		if (Ext.isFunction(i_child.onLoad)) {
			i_child.onLoad(i_child, i_owner);
		}
		if (Ext.isFunction(i_widget.onLoad)) {
			i_widget.onLoad(i_child, i_owner);
		}

		// ON READY
		if (Ext.isFunction(i_child.onReady)) {
			i_child.onReady(i_child, i_owner);
		}
		if (Ext.isFunction(i_widget.onReady)) {
			i_widget.onReady(i_child, i_owner);
		}

		if (Ext.isFunction(i_child.expand)) {
			i_child.expand();
		}

		i_widget.fireEvent("ready", i_widget);

		var i_widgetCmp = i_widget.getWidgetComponent();

		if (i_widgetCmp) {
			i_widget.mon(i_widgetCmp, "afterlayout", i_widget.doLoaded, i_widget);
		}
	},

	doLoaded: function() {

		var i_widget = this;
		var i_widgetCmp = i_widget.getWidgetComponent();
		var a_fields = i_widgetCmp.query("field");
		var a_tree = i_widgetCmp.query("treepanel");
		var a_grid = i_widgetCmp.query("gridpanel");

		if (a_fields.length > 0 || a_tree.length > 0) {

			i_widget.fireEvent("loaded", i_widget);
			i_widget.mun(i_widgetCmp, "afterlayout", i_widget.doLoaded, i_widget);

			if (i_widget.readOnly) {

				Ext.Array.each(a_fields, function(i_field) {
					if (i_field.setReadOnly) {
						setTimeout(function() {
							i_field.setReadOnly(true);
						}, 1);
					}
				});

				Ext.Array.each(a_tree, function(i_tree) {
					i_tree.disable();
				});

				Ext.Array.each(a_grid, function(i_grid) {
					i_grid.disable();
				});
			}
		}
	},

	getWidgetComponent: function () {

		return this.items.items[0];
	},

	getWidgetCmp: function () {

		return this.getWidgetComponent();
	}
});
Ext.define("Ext.ux.container.Ip2Widget", {

	extend: "Ext.ux.container.Widget",

	alias: [
		"widget.ip2widget",
		"widget.ip2widgetcontainer"
	],

	config: {
		i18nValues: {},
		modified: {},
		language: "en",
		languageChange: false,
		attr: {},
		context: "portfolio"
	},

	trackResetOnLoad: true,

	requires: [
		"Ext.ux.plugin.data.Tracker"
	],

	initComponent: function() {

		var i_self = this;

		var i_user = ip2.getUser();

		var s_language = i_user ? i_user.get("USRLNG") : "en";
		var a_languages = wsh.getLanguages(i_self.getContext());

		i_self.setLanguage(s_language);

		var i_tracker = Ext.create("Ext.ux.plugin.data.Tracker");

		var a_plugins = Ext.Array.from(i_self.plugins);

		a_plugins.push(i_tracker);

		i_self.plugins = a_plugins;

		var o_modified = i_self.getModified();

		Ext.Array.each(a_languages, function(s_language) {
			o_modified[s_language] = [];
		});

		i_self.setModified(o_modified);

		i_self.on({
			loaded: {
				fn: function(i_widget) {

					var i_form = i_self.getForm();
					var i_widgetCmp = i_self.getWidgetCmp();
					var a_languages = wsh.getLanguages(i_self.getContext());

					var o_i18nValue = i_self.getI18nValues();

					if (i_widgetCmp && i_widgetCmp.isDirty && i_form) {

						var a_fields = i_widgetCmp.query("field");
						var a_trees = i_widgetCmp.query("treepanel");

						Ext.Array.each(a_fields, function(i_field) {

							i_field.inWidget = true;

							if (i_field.isFormField) {

								if (i_field.i18n) {

									var s_value = i_field.value;
									var o_value = {};
									var o_fieldvalue = null;
									var regex = new RegExp("/n","g");

									if (ip2.isStringedObject(s_value)) {
										o_fieldvalue = Ext.decode(s_value);
									}

									if (o_fieldvalue) {

										Ext.Array.each(a_languages, function(s_lang) {

											var value = o_fieldvalue[s_lang];

											o_value[s_lang] = !Ext.isEmpty(value, false) ? value : "";

											value = o_value[s_lang];

											if (Ext.isString(value)) {
												value = value.replace(regex, "\n");
												o_value[s_lang] = value;
											}
										});
									}
									else {

										Ext.Array.each(a_languages, function(s_lang) {
											o_value[s_lang] = "";
										});
									}

									o_i18nValue[i_field.name] = o_value;

									var value = o_value[i_self.getLanguage()];

									i_field.suspendCheckChange++;
									i_field.isReseting = true;
									i_field.setValue(value);
									i_field.resetOriginalValue();
									i_field.fireEvent("change", i_field, value);
									i_field.isReseting = false;
									i_field.suspendCheckChange--;

									i_field.on({
										change: {
											fn: function(i_field, value) {

												if (!i_self.getLanguageChange()) {

													var b_dirty = i_field.isDirty();
													var b_valid = i_field.isValid ? i_field.isValid() : true;
													var b_found = false;
													var o_modified = i_self.getModified();
													var s_language = i_self.getLanguage();

													Ext.Array.each(o_modified[s_language], function(o_field) {

														if (o_field.name == i_field.name) {

															o_field.dirty = b_dirty;
															o_field.valid = b_valid;
															o_field.value = value;
															b_found = true;

															if (b_found && i_field.isReseting) {
																o_field.originalValue = i_field.originalValue;
															}
															return false;
														}
													});

													if (!b_found) {

														var o_field = {
															name: i_field.name,
															valid: b_valid,
															dirty: b_dirty,
															value: value,
															originalValue: i_field.originalValue
														};

														o_modified[s_language].push(o_field);
													}
												}
											}
										}
									});
								}
							}
						});

						Ext.Array.each(a_trees, function(i_tree) {

							i_tree.inWidget = true;

							var i_store = i_tree.getStore();

							i_store.on({
								update: {
									fn: function(store, i_record, operation, a_modified) {

										var b_valid = i_widgetCmp.isValid ? i_widgetCmp.isValid() : true;

										if (!b_valid) {
											i_self.fireEvent("validitychange", i_self, b_valid);
										}
										else {
											var b_dirty = i_widgetCmp.isDirty();
											i_self.fireEvent("dirtychange", i_self, b_dirty);
										}
									}
								},
								datachanged: {
									fn: function(store, i_record, operation, a_modified) {

										var b_valid = i_widgetCmp.isValid ? i_widgetCmp.isValid() : true;

										if (!b_valid) {
											i_self.fireEvent("validitychange", i_self, b_valid);
										}
										else {
											var b_dirty = i_widgetCmp.isDirty();
											i_self.fireEvent("dirtychange", i_self, b_dirty);
										}
									}
								}
							});
						});
					}
				}
			},
			dirtychange: {
				fn: function(i_form, b_dirty) {

					var i_widgetCmp = i_self.getWidgetCmp();

					if (i_self.title && i_widgetCmp && i_widgetCmp.isDirty) {

						if (i_form.getForm || i_form.isValid) {

							var b_valid = true;

							if (i_form.getForm) {
								b_valid = i_form.getForm().isValid();
							}
							else if (i_form.isValid) {
								b_valid = i_form.isValid();
							}

							if (b_valid) {

								if (b_dirty) {
									i_self.setIconCls("flatui icon-data-new");
								}
								else {
									i_self.setIconCls("");
								}
							}
						}
						else {

							if (b_dirty) {
								i_self.setIconCls("flatui icon-data-new");
							}
							else {
								i_self.setIconCls("");
							}
						}
					}
				}
			},
			validitychange: {
				fn: function(i_form, b_valid) {

					if (i_self.title) {
						if (!b_valid) {
							i_self.setIconCls("flatui icon-data-error");
						}
						else {
							var b_dirty = i_self.isDirty();
							i_self.fireEvent("dirtychange", i_self, b_dirty);
						}
					}
				}
			}
		});

		// widgets are not to be considered fields or forms in any respect for parents who may
		// be gathering data - they live their own lives

		if (i_self.title) {
			i_self.iconCls = "";
		}

		i_self.callParent(arguments);

		var i_form = i_self.getForm();

		i_form.wasValid = true;

		i_self.enableBubble([
			"dirtychange",
			"validitychange"
		]);

		var o_attr = i_self.getAttr();

		if (o_attr.url) {
			i_self.addDocked(i_self.createLinkBar());
		}

		return i_self;
	},

	createLinkBar: function() {

		var i_self = this;

		var a_items = [
			{
				xtype: "tbfill"
			},
			{
				xtype: "button",
				iconCls: "pf-link",
				itemId: "button-link",
				handler: function(i_button) {

					var o_attr = i_self.getAttr();

					if (!Ext.Object.isEmpty(o_attr)) {

						var o_attr = o_attr;
						var s_widget = o_attr.url;
						var s_name = s_widget.split(".").shift();

						var i_window = Ext.widget("link.window", {
							model: {
								widget: {
									name: s_name
								}
							}
						});

						i_window.show();
					}
				}
			}
		];

		var i_toolbar = Ext.widget("toolbar", {
			dock: "bottom",
			items: a_items,
			itemId: "linkbar"
		});

		return i_toolbar;
	},

	changeLanguage: function(s_lang) {

		var i_self = this;
		i_self.setLanguageChange(true);

		var i_form = i_self.getForm();
		var a_fields = i_form.getFields().items;
		var o_i18nValue = i_self.getI18nValues();
		var o_newvalues = {};
		var s_language = i_self.getLanguage();
		var o_modified = i_self.getModified();

		Ext.Array.each(a_fields, function(i_field) {

			if (i_field.i18n) {
				o_i18nValue[i_field.name][s_language] = i_field.getValue();
			}
		});

		Ext.Array.each(a_fields, function(i_field) {

			if (i_field.i18n) {
				o_i18nValue[i_field.name] = o_i18nValue[i_field.name] || {};
				o_newvalues[i_field.name] = o_i18nValue[i_field.name][s_lang] || "";
			}
		});

		if (i_form) {
			i_form.setValues(o_newvalues);
		}
		else {

			Ext.Array.each(a_fields, function(i_field) {

				Ext.Object.each(o_newvalues, function(s_key, value) {

					if (i_field.name == s_key) {

						i_field.suspendCheckChange++;
						i_field.setValue(value);
						i_field.resetOriginalValue();
						i_field.suspendCheckChange--;
					}
				});
			});
		}

		var a_modified = Ext.Array.from(o_modified[s_lang]);

		Ext.Array.each(a_modified, function(o_field) {

			Ext.Array.each(a_fields, function(i_field) {

				if (i_field.name == o_field.name) {

					var value = i_field.getValue();
					var valueOld = o_field.originalValue;

					i_field.suspendCheckChange++;
					i_field.setValue(valueOld);
					i_field.resetOriginalValue();
					i_field.wasDirty = o_field.dirty;
					i_field.setValue(value);
					i_field.suspendCheckChange--;
				}
			});
		});

		i_self.setLanguageChange(false);
		i_self.setLanguage(s_lang);
	},

	_aftersave: function(f_callback) {

		var i_self = this;
		var i_form = i_self.getForm();
		var a_fields = i_form.getFields().items;
		var a_languages = wsh.getLanguages(i_self.getContext());
		var o_i18nValue = i_self.getI18nValues();
		var s_language = i_self.getLanguage();

		f_callback = f_callback || Ext.emptyFn;

		Ext.Array.each(a_fields, function(i_field) {

			if (i_field.i18n) {

				var value = o_i18nValue[i_field.name][s_language];

				i_field.suspendCheckChange++;
				i_field.setValue(value);
				i_field.suspendCheckChange--;
			}

			i_field.resetOriginalValue();
		});

		var o_modified = {};

		Ext.Array.each(a_languages, function(s_language) {
			o_modified[s_language] = [];
		});

		i_self.setModified(o_modified);

		f_callback.call(i_self);
	},

	_doSave: function() {

		var i_self = this;
		var i_form = i_self.getForm();
		var a_fields = i_form.getFields().items;

		var o_i18nValue = i_self.getI18nValues();
		var s_language = i_self.getLanguage();

		Ext.Array.each(a_fields, function(i_field) {

			if (i_field.i18n) {

				o_i18nValue[i_field.name][s_language] = i_field.getValue();

				var o_value = o_i18nValue[i_field.name];
				var s_value = JSON.stringify(o_value);

				i_field.setValue(s_value);
			}
		});
	},

	doSave: function (f_callback) {

		var i_self = this;
		var i_widget = i_self.getWidgetComponent();

		f_callback = f_callback || Ext.emptyFn;

		i_self._doSave();

		if (i_widget.doSave) {
			i_widget.doSave(function() {
				i_self._aftersave(f_callback);
			});
		}
		else {
			f_callback.call(i_self);
		}
	},

	doPreSave: function(i_record, f_callback) {

		var i_self = this;
		var i_widget = i_self.getWidgetComponent();

		f_callback = f_callback || Ext.emptyFn;

		if (i_widget.doPreSave) {
			i_widget.doPreSave(i_record, function(i_record) {
				f_callback(i_record);
			});
		}
		else {
			f_callback(i_record);
		}
	}
});
Ext.define("Ext.ux.container.Icecap", {
	extend: "Ext.panel.Panel",
	alias: ["widget.icecap"],
	loadComplete: false,
	cmd: "",
	cfg: "",
	initCmd: "",
	config: {
		iframe: null,
		iframeId: ""
	},
	icecapclose: false,
	initComponent: function () {

		var i_self = this;
		i_self.callParent();

		var s_url = "";

		var a_parts = [];

		a_parts.push("func=" + i_self.cmd);

		if (i_self.cfg) {
			a_parts.push("config=" + i_self.cfg);
		}

		if (i_self.initCmd) {
			a_parts.push("initFunc=" + i_self.initCmd);
		}

		s_url = "/icecap/icecap.aspx?" + a_parts.join("&");

		var i_component = Ext.widget("component", {
			id: "icecap-frame-" + i_self.id,
			xtype: "component",
			autoEl: {
				tag: "iframe",
				style: "height: 100%; width: 100%; border: none;",
				src: s_url
			},
			listeners: {
				load: {
					element: "el",
					fn: function () {

						var i_widget = i_self.up("ip2widget");

						var i_frame = Ext.getCmp(i_self.getIframeId());
						if (i_frame.hidden) {
							i_frame.setVisible(true);
						}
						if (i_widget) {
							i_widget.ownerCt.unmask();
						}
						else {
							i_self.setLoading(false);
						}

						i_self.loadComplete = true;
						i_self.setIframe(i_frame);
						try {
							var i_content = i_frame.el.dom.contentWindow;
							i_content.widget = i_self;
							i_content.ip2 = ip2 || {};
						}
						catch (err) {}
					}
				},
				render: function () {
					var i_widget = i_self.up("ip2widget");
					if (i_widget) {
						if (i_widget.ownerCt) {
							if (!i_widget.ownerCt.hidden) {
								i_widget.ownerCt.mask(ip2.i18n({
									en: "Loading...",
									da: "Indlæser..."
								}));
							}
						}
					}
					else {
						i_self.setLoading(ip2.i18n({
							en: "Loading...",
							da: "Indlæser..."
						}));
					}
				}
			}
		});

		i_self.on({
			added: {
				fn: function() {
					var i_owner = i_self.up().up();
					if (i_owner) {
						i_owner.addListener("hide", function () {
							i_self.unmask();
						}, i_owner);
						i_owner.addListener("show", function () {
							if (!i_self.loadComplete) {
								var i_widget = i_self.up("ip2widget");
								if (i_widget) {
									i_widget.ownerCt.mask(ip2.i18n({
										en: "Loading...",
										da: "Indlæser..."
									}));
								}
							}
						}, i_owner);
					}
				}
			},
			"panel-removeTab": {
				fn: function() {
					this.close();
				}
			}
		});

		i_self.on({
			beforeclose: {
				fn: function(i_panel) {
					if (!i_self.icecapclose) {

						var i_iframe = i_self.getIframe() || Ext.getCmp(i_self.getIframeId());

						i_iframe.el.dom.contentWindow.postMessage("icecap-close", "*");
						return false;
					}
					else {
						return true;
					}
				}
			}
		});

		i_self._iframe = i_component;
		i_self.setIframeId("icecap-frame-" + i_self.id);

		i_self.add(i_component);
	}
});
/**
 * @class Ext.ux.data.PagingMemoryProxy
 * @extends Ext.data.proxy.Memory
 * <p>Paging Memory Proxy, allows to use paging grid with in memory dataset</p>
 */
Ext.define('Ext.ux.data.PagingMemoryProxy', {
	extend: 'Ext.data.proxy.Memory',
	alias: 'proxy.pagingmemory',
	alternateClassName: 'Ext.data.PagingMemoryProxy',

	read: function(operation, callback, scope) {
		var reader = this.getReader(),
		result = reader.read(reader.rawData),
		sorters, filters, sorterFn, records;

		scope = scope || this;

		var o_operation_scope = operation.getScope();
		var i_filters = o_operation_scope.filters || {
			items: []
		};

		// filtering
		filters = i_filters.items || [];
		if (filters.length > 0) {
			//at this point we have an array of  Ext.util.Filter objects to filter with,
			//so here we construct a function that combines these filters by ANDing them together
			records = [];

			Ext.each(result.records, function(record) {
				var isMatch = true,
				length = filters.length,
				i;

				for (i = 0; i < length; i++) {
					var filter = filters[i],
					fn = filter.getFilterFn(),
					scope = filter.scope;

					isMatch = isMatch && fn.call(scope, record);
				}
				if (isMatch) {
					records.push(record);
				}
			}, this);

			result.records = records;
			result.totalRecords = result.total = records.length;
		}

		// sorting
		sorters = o_operation_scope.sorters.items || [];
		if (sorters.length > 0) {
			//construct an amalgamated sorter function which combines all of the Sorters passed
			sorterFn = function(r1, r2) {
				var result = sorters[0].sort(r1, r2),
				length = sorters.length,
				i;

				//if we have more than one sorter, OR any additional sorter functions together
				for (i = 1; i < length; i++) {
					result = result || sorters[i].sort.call(this, r1, r2);
				}

				return result;
			};

			result.records.sort(sorterFn);
		}

		// paging (use undefined cause start can also be 0 (thus false))
		if (operation.getStart() !== undefined && operation.getLimit() !== undefined) {
			result.records = result.records.slice(operation.getStart(), operation.getStart() + operation.getLimit());
			result.count = result.records.length;
		}

		Ext.apply(operation, {
			_resultSet: result
		});

		operation.setSuccessful(true);

		Ext.Function.defer(function () {
			Ext.callback(callback, scope, [operation]);
		}, 10);
	}
});
Ext.ns('Ext.ux.folderorganizer');
Ext.ux.folderorganizer.Alert = function(cfg) {
	cfg = cfg || {};

	Ext.applyIf(cfg, {
		buttons: Ext.Msg.OK,
		icon: Ext.Msg.WARNING
	});

	Ext.MessageBox.show(cfg);
}
/**
 * @class Ext.ux.folderorganizer.Button
 *
 * @extend Ext.button.Button
 *
 * Icon only button
 *
 * <p>Usage:</p>
 * <pre><code>
    {
        xtype: 'ip2Button',
        handler: function() {
            alert('You clicked the button!')
        }
    }
 * </code></pre>
 *
 */

Ext.define('Ext.ux.folderorganizer.Button', {
	extend: 'Ext.button.Button',
	alias: ['widget.ip2button', 'widget.ip2Button'],
	minWidth: 75,
	initComponent: function() {
		var button = this;

		if (button.keyMap) {
			if (button.keyMap.primary) {
				// add "ip2-default" class
				button.renderTpl =
				'<em id="{id}-btnWrap" class="{splitCls}">' +
				'<tpl if="href">' +
				'<a id="{id}-btnEl" href="{href}" target="{target}"<tpl if="tabIndex"> tabIndex="{tabIndex}"</tpl> role="link">' +
				'<span id="{id}-btnInnerEl" class="{baseCls}-inner">' +
				'{text}' +
				'</span>' +
				'<span id="{id}-btnIconEl" class="{baseCls}-icon"></span>' +
				'</a>' +
				'</tpl>' +
				'<tpl if="!href">' +
				'<button id="{id}-btnEl" type="{type}" hidefocus="true"' +
				'<tpl if="tabIndex"> tabIndex="{tabIndex}"</tpl> role="button" autocomplete="off">' +
				'<span id="{id}-btnInnerEl" class="{baseCls}-inner ip2-default" style="{innerSpanStyle}">' +
				'{text}' +
				'</span>' +
				'<span id="{id}-btnIconEl" class="{baseCls}-icon {iconCls}">&#160;</span>' +
				'</button>' +
				'</tpl>' +
				'</em>';
			}
			if (button.keyMap.bindTo && button.keyMap.key) {
				var bindTo = button.keyMap.bindTo,
				listeners = bindTo.listeners || {};
				bindTo.listeners = Ext.apply(listeners, {
					afterrender: function() {
						button.setKeyMap(bindTo);
					}
				});

				// save key mapping for this key in the bindto commponent.
				if (!bindTo.ip2Buttons) bindTo.ip2Buttons = [];
				bindTo.ip2Buttons.push(button);
			}
		}

		button.callParent();
	},
	setKeyMap: function(bindTo) {
		var buttons = [];

		for (var i = 0; i < bindTo.ip2Buttons.length; i++) {
			var button = bindTo.ip2Buttons[i],
			keyMap = button.keyMap;
			buttons.push({
				key: keyMap.key,
				alt: (typeof keyMap.alt === "undefined") ? false : keyMap.alt,
				ctrl: (typeof keyMap.ctrl === "undefined") ? false : keyMap.ctrl,
				shift: (typeof keyMap.shift === "undefined") ? false : keyMap.shift,
				fn: function() {
					this.handler.call(this);
				},
				scope: button,
				defaultEventAction: 'preventDefault'
			});
		}

		var i_keymap = Ext.create("Ext.util.KeyMap", {
			target: button,
			binding: buttons
		});
	}
});

Ext.define('Ext.ux.folderorganizer.ItemRelationSelector', {
	extend: 'Ext.tree.Panel',
	alias: ['widget.itemRelationSelector'],
	useArrows: true,
	rootVisible: false,
	multiSelect: true,
	singleExpand: false,
	hideHeaders: true,
	columns: [{
		xtype: 'treecolumn',
		dataIndex: 'GROUP',
		flex: 1
	}],
	layout: 'fit',
	autoScroll: true,
	initComponent: function() {
		var me = this;

		me.clearSelection();

		// family tree store
		if (!Ext.ClassManager.isCreated('familyTree')) {
			Ext.define('familyTree', {
				extend: 'Ext.data.Model',
				fields: [
					{ name: 'ID', type: 'string' },
					{ name: 'KEY', type: 'string' },
					{ name: 'GROUP', type: 'string' },
					{ name: 'leaf', type: 'boolean' },
					{ name: 'allowDrag', type: 'boolean' },
					{ name: 'allowDrop', type: 'boolean' },
					{ name: 'allowEdit', type: 'boolean' },
					{ name: 'allowRemove', type: 'boolean' },
					{ name: 'iconCls', type: 'string' }
				],
				idProperty: 'ID',
				proxy: {
					type: 'ajax',
					url: me.proxy,
					extraParams: {
						action: 'familyTreeStore',
						parentOnly: true,
						checkbox: true,
						displayRootNode: false
					}
				}
			});
		}

		me.store = Ext.create('Ext.data.TreeStore', {
			model: 'familyTree',
			clearOnLoad: false,
			autoLoad: true,
			listeners: {
				beforeload: {
					fn: function(store, operation) {
						var node = operation.node;
						var i_proxy = store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();
						var s_node = node.get("ID");
						if (s_node == "root") {
							s_node = s_node + ".0";
						}
						Ext.apply(o_extraParams, {
							node: s_node
						});
						delete operation.node;
					}
				}
			}
		});

		me.listeners = {
			checkchange: function(node, newValue) {
				var family = node.data.KEY;
				if (me.checkedItems.family.indexOf(family) > -1) {
					var pos = me.checkedItems.family.indexOf(family);
					me.checkedItems.ID.splice(pos, 1);
					me.checkedItems.family.splice(pos, 1);
				}
				if (me.uncheckedItems.family.indexOf(family) > -1) {
					var pos = me.uncheckedItems.family.indexOf(family);
					me.uncheckedItems.ID.splice(pos, 1);
					me.uncheckedItems.family.splice(pos, 1);
				}
				if (newValue) {
					// new checked
					if (!me.multiSelect) {
						me.singleSelection();
					}
					me.checkedItems.family.push(family);
				}
				else {
					// existing unchecked
					me.uncheckedItems.family.push(family);
				};
			}
		};

		me.callParent(arguments);

		if (Ext.isFunction(me.wrapper.getDataParent)) {

			me.record = me.wrapper.getDataParent().getRecord();

			if (me.record) {
				me.onParentLoad();
			}
			else {
				// wait for data parent store loaded

				var store = me.wrapper.getDataParent().getStore();

				store.on('load', function(store, records) {
					if (Ext.isArray(records)) {
						me.record = records[0];
						me.onParentLoad();
					}
				});
			}
		}

		me.enableBubble("dirtychange");

		return me;
	},

	/**
	 * @method on parent load
	 *
	 */
	onParentLoad: function() {
		var me = this;

		me.clearSelection();

		me.getData(me.getExisting);
	},

	/**
	 * @method Get Existing: set checkbox as checked for already existing relation
	 *
	 */
	getExisting: function(records) {

		var me = this;

		me.existing = {
			ID: [],
			family: []
		};

		if (!records) {
			return;
		}

		// create unique array with parents
		var parentFamily = [];
		for (var i = 0; i < records.length; i++) {
			var data = records[i].data;
			var parents = data.parents.split('.');

			for (var p = 0; p < parents.length; p++) {
				if (parentFamily.indexOf(parents[p]) == -1) {
					parentFamily.push(parents[p]);
				}
			}
		}

		// expand all parents and set check mark when expanding is finished
		me.expandParent({
			parents: parentFamily,
			index: 0,
			records: records,
			success: function(records) {
				for (var i = 0; i < records.length; i++) {
					var data = records[i].data;
					me.setCheck(data.family, true, data.ID);
					me.existing.family.push(data.family);
				}
			}
		});
	},

	/**
	 * @method expand parent
	 *
	 */
	expandParent: function(args) {
		var me = this;

		if (args.index >= args.parents.length) {
			var task = new Ext.util.DelayedTask(function() {
			Ext.callback(args.success, me, [args.records]);
		});
			task.delay(500);
			return false;
		}

		var node = me.store.getNodeById('fami.' + args.parents[args.index]);
		if (node && !node.isExpanded()) {
			node.expand(false, function() {
				args.index = args.index + 1;
				var task = new Ext.util.DelayedTask(function() {
					me.expandParent(args);
				});
				task.delay((args.index >= args.parents.length) ? 0 : 500);
			}, me);
		}
		else {
			args.index = args.index + 1;
			me.expandParent(args);
		}
	},

	/**
	 * @method set uncheck for already check (single selection)
	 *
	 */
	singleSelection: function() {

		var me = this;

		for (var i = 0; i < me.existing.family.length; i++) {
			me.setCheck(me.existing.family[i], false);
		}
		me.existing.family = [];

		for (var i = 0; i < me.checkedItems.family.length; i++) {
			me.setCheck(me.checkedItems.family[i], false);
		}
		me.checkedItems.family = [];
	},

	/**
	 * @method set check or uncheck
	 *
	 */
	setCheck: function(family, checked, ID) {

		var node = this.store.getNodeById('fami.' + family);

		if (node) {
			node.set('checked', checked);
			if (ID) {
				node.set('relID', ID);
			}
		}
	},

	/**
	 * @method doSave
	 *
	 */
	doSave: function() {

		var me = this;

		var key = {
			product: me.getKeyValue()
		};

		// checked
		for (var i = 0; i < me.checkedItems.family.length; i++) {
			var data = me.getFamilyNode(me.checkedItems.family[i]);
			key.ID = data.relID;
			key.family = me.checkedItems.family[i];
			var node = me.store.getNodeById('fami.' + key.family);
			me.doUpdate('update', key, node);
		}

		// unchecked
		if (me.multiSelect || me.checkedItems.family.length == 0) {
			for (var i = 0; i < me.uncheckedItems.family.length; i++) {
				var data = me.getFamilyNode(me.uncheckedItems.family[i]);
				key.ID = data.relID;
				key.family = me.uncheckedItems.family[i];
				var node = me.store.getNodeById('fami.' + key.family);
				me.doUpdate('remove', key, node);
			}
		}

		me.existing.family = me.checkedItems.family;
		me.clearSelection();

		me.fireEvent('savecomplete', me, true);
	},

	/**
	 * @method doUpdate (empty function). Make you own function :-)
	 *
	 */
	doUpdate: function() {
	},

	/**
	 * @method doDelete (empty function). Make you own function :-)
	 *
	 */
	doDelete: function() {
		var me = this;

		var key = {
			product: me.getKeyValue()
		};

		// existing
		for (var i = 0; i < me.existing.family.length; i++) {
			var data = me.getFamilyNode(me.existing.family[i]);
			key.ID = data.relID;
			key.family = me.existing.family[i];
			me.setCheck(key.family, false, 0);
			me.doUpdate('remove', key);
		}

		// checked
		for (var i = 0; i < me.checkedItems.family.length; i++) {
			var data = me.getFamilyNode(me.checkedItems.family[i]);
			key.ID = data.relID;
			key.family = me.checkedItems.family[i];
			me.setCheck(key.family, false, 0);
			me.doUpdate('remove', key);
		}
	},

	/**
	 * @method get data for this product
	 *
	 */
	getData: function(cb) {
		var me = this;

		// get existing item data and load the records into writer store
		if (!Ext.ClassManager.isCreated('data')) {
			Ext.define('data', {
				extend: 'Ext.data.Model',
				fields: [
					{ name: 'ID', type: 'string' },
					{ name: 'family', type: 'int' },
					{ name: 'parents', type: 'string' }
				],
				idProperty: 'family',
				proxy: {
					type: 'ajax',
					url: me.proxy + '?action=' + me.getAction + '&item=' + me.getKeyValue(),
					reader: {
						type: 'json',
						rootProperty: 'rows'
					}
				}
			});
		}
		Ext.create('Ext.data.Store', {
			model: 'data',
			autoLoad: true,
			listeners: {
				load: function(store, records) {
					Ext.callback(cb, me, [records]);
				}
			}
		});
	},

	/**
	 * @method getKeyValue
	 *
	 */
	getKeyValue: function() {

		var me = this;

		return (me.record) ? me.record.data.ITMITMTKN : '';
	},

	/**
	 * @method get family node data
	 *
	 */
	getFamilyNode: function(family) {
		var node = this.store.getNodeById('fami.' + family);
		return node.data;
	},

	/**
	 * @method clean up selection
	 *
	 */
	clearSelection: function() {
		this.checkedItems = {
			ID: [],
			family: []
		};
		this.uncheckedItems = {
			ID: [],
			family: []
		};
	},

	resetDirty: function() {

		var i_self = this;
		var i_store = i_self.getStore();
		var a_nodes = i_store.getData().items;

		ip2.each(a_nodes, function(i_node) {
			i_node.oldChecked = i_node.get("checked");
			i_node.dirty = false;
		});

		i_self.fireEvent("dirtychange", i_self, false);
	},

	isDirty: function() {

		var i_self = this;
		var i_store = i_self.getStore();
		var a_nodes = i_store.getData().items;
		var b_dirty = false;

		ip2.each(a_nodes, function(i_node) {
			if (i_node.dirty) {
				b_dirty = true;
			}
		});

		return b_dirty;
	}
});
Ext.define('Ext.ux.folderorganizer.MultiChoice', {
	extend: 'Ext.window.Window',
	alias: ['widget.ip2MsgMultiChoice', 'widget.ip2msgMultiChoice', 'widget.ip2msgmultichoice'],
	bodyStyle: 'background-color: white;',
	width: 500,
	initComponent: function () {
		var me = this;

		me.items = [];

		windowHeight = 0;

		// Guide line
		if (me.guideLine && me.guideLine.length > 0) {
			windowHeight += 58;
			me.items.push(
				Ext.create('Ext.form.field.Display', {
					hideLabel: true,
					value: me.guideLine,
					padding: '12 20 12 20'
				})        	
			)
		}

		// Question grid
		if (me.questions && me.questions.length > 0) {
			windowHeight += 40 + (me.questions.length * 26);

			var store = Ext.create('Ext.data.Store', {
				fields: ['answer', 'question', 'icon'],
				proxy: {
					type: 'memory',
					reader: {
						type: 'json'
					}
				}
			});

			store.loadData(me.questions);

			var iconRenderer = function(value, meta, record) {
				return '<img src="' + value + '"/>'
			}

			me.items.push(
		        Ext.create('Ext.grid.Panel', {
			hideHeaders: true,
			store: store,
			border: false,
			padding: '0 20 12 20',
			columns: [
			{ dataIndex: 'icon', renderer: iconRenderer, width: 30 },
			{ dataIndex: 'question', flex: 1 }
			],
			viewConfig: {
				getRowClass: function(record, rowIndex, rowParams, store) {
					return 'ip2-grid-row-XL';
				}
			},
			listeners: {
				itemclick: function(view, record) {
					if (Ext.isFunction(me.handler)) {
						me.handler.call(me, record.data.answer);	
					}
					me.hide();
				}
			}                   
		        })
	       	)
		}

		me.height = windowHeight;

		me.callParent();
	}    
});
Ext.define("Ext.ux.folderorganizer.PagingToolbar", {
	extend: "Ext.toolbar.Paging",
	initComponent: function() {
		var me = this;

		me.callParent(arguments);

		// Hack to prevent the number field in pagination from
		// showing up as dirty in serialization contexts
		var i_inputItem = me.down("#inputItem");

		if (i_inputItem) {
			i_inputItem.isFormField = false;
		}

		return me;
	},
	getPagingItems: function() {
		var me = this;

		var items = me.callParent();

		if (Ext.isArray(me.extraButtons)) {
			Ext.Array.each(me.extraButtons, function(button) {
				switch (button) {
					case "add":
						items.push(
              Ext.create("Ext.button.Button", {
	text: me.getI18N("add"),
	tooltip: me.getI18N("addTips").toString(),
	iconCls: "ip2-icon-add",
	handler: function() {
		me.ownerCt.addRow();
	}
              })
            );
						break;
					case "remove":
						items.push(
              Ext.create("Ext.button.Button", {
	text: me.getI18N("remove"),
	tooltip: me.getI18N("removeTips").toString(),
	iconCls: "ip2-icon-remove",
	handler: function() {
		me.ownerCt.removeRow();
	}
              })
            );
						break;
					case "refresh":
						items.push(
              Ext.create("Ext.button.Button", {
	text: me.getI18N("refresh"),
	tooltip: me.getI18N("refreshTips").toString(),
	iconCls: "ip2-icon-refresh",
	handler: function() {
		me.ownerCt.refresh();
	}
              })
            );
						break;
				}
			});
		}

		if (me.displayFilterField) {
			me.filterField = Ext.create("Ext.form.field.Text", {
				width: 300,
				enableKeyEvents: true,
				name: me.namePrefix + ".filterField",
				isFormField: false,
				listeners: {
					scope: me,
					keydown: function(fld, e) {
						me.onPagingKeyDown(fld, e);
						me.child("#inputItem").setValue(1);
						if (e.getKey() == e.ENTER) {
							me.ownerCt.store.load({
								params: {
									start: 0
								}
							});
						}
					},
					blur: me.onPagingBlur
				}
			});
			items.push(me.filterField);
		}

		return items;
	},
	getI18N: function(key) {
		return (ip2.folderorganizer) ? ip2.folderorganizer.getTextValue(key) : key;
	}
});
Ext.define('Ext.ux.folderorganizer.PropertyGrid', {
	extend: 'Ext.grid.property.Grid',
	sortableColumns: false,
	border: '0 0 0 1',
	initComponent: function() {
		var me = this;

		me.setProperties();

		me.dockedItems = [{
			xtype: 'toolbar',
			dock: 'bottom',
			items: [{
				xtype: 'tbfill' 
			},{
				xtype: 'button',
				text: me.getI18N('save'),
				handler: function(button) {
					var propertygrid = button.up('propertygrid');

					propertyGrid.wrapper.fireEvent('propertychange', propertygrid.record, propertygrid.action, propertygrid.parentRecord);

					if (propertygrid) propertygrid.hide();
				} 
			},{
				xtype: 'button',
				text: me.getI18N('cancel'),
				handler: function(button) {
					var propertygrid = button.up('propertygrid');
					if (propertygrid) propertygrid.hide();
				} 
			}]
		}];

		me.listeners = {
			propertychange: function(source, recordId, value) {
				if (me.record) {
					me.record.set(recordId, value);
				}
			}
		}
    
		me.callParent();
	},
	display: function(action, record, parentRecord) {
		var me = this;

		me.action = action;
		me.record = record;
		me.parentRecord = parentRecord || null;

		me.setPropertyValue(record);

		me.show();

		me.editingPlugin.startEditByPosition({ row: 0, column: 0 });    
	},
	setProperties: function() {
		var me = this;
    
		me.source = {},
		me.propertyNames = {},
		me.customEditors = {};

		if (me.fields) {
			// Use fields with title property
			for (var i = 0; i < me.fields.length; i++) {
				if (me.fields[i].title) {
					me.addPropertyField(me.fields[i]);
				}
			}

			// if source still empty, use all fields
			if (Ext.isEmpty(me.source)) {
				for (var i = 0; i < fields.length; i++) {
					me.addPropertyField(fields[i]);
				}
			}
		}
	},
	addPropertyField: function(field) {
		if (field.groupColumn) return;

		var me = this;

		if (field.type.type == 'int') {
			me.customEditors[field.name] = 'numberfield';
		}
		else {
			me.customEditors[field.name] = 'textfield';
		}

		me.source[field.name] = me.getDefaultValue(field.name);

		me.propertyNames[field.name] = (field.title) ? field.title : field.name;
	},
	setPropertyValue: function(record) {
		var me = this;

		me.suspendEvents();
    
		var properties = {};
		for (var key in me.source) {
			properties[key] = (record) ? record.data[key] : me.getDefaultValue(key);
		};

		me.setSource(properties);

		me.resumeEvents();
	},
	getDefaultValue: function(fieldName) {
		switch (this.customEditors[fieldName]) {
			case 'numberfield':
				return 0;
				break;
			default:
				return '';
				break;
		}
	},
	getI18N: function(key) {
		return ip2.folderorganizer.getTextValue(key);
	}
});
﻿Ext.define('Ext.ux.folderorganizer.FolderPropertyGrid', {
	extend: 'Ext.grid.Panel',
	alias: ['widget.folderorganizerFolderPropertyGrid'],
	border: false,
	height: 144,
	collapsible: true,
	titleCollapse: true,
	autoScoll: true,
	initComponent: function() {
		var me = this;

		me.uiName = 'organizer';
		me.language = ip2.session.getLanguage();

		me.model = ip2.model({
			dmd: me.wrapper.dmdPath,
			entityName: 'WSHITMET00',
			dataLibrary: me.wrapper.folder.dataLibrary || ''
		});
		me.entity = me.wrapper.entity;
		me.dmdName = me.wrapper.dmdPath.split(".").shift();
		var i_proxy = me.model.getProxy();
		i_proxy.url = me.wrapper.folder.proxy;
		me.model.owner = {
			id: me.itemId,
			xtype: me.xtype
		};
		Ext.apply(i_proxy.extraParams, {
			action: me.action
		});
		me.store = Ext.create('Ext.data.Store', {
			model: me.model,
			listeners: {
				beforeload: function(store) {
					var i_proxy = store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();
					o_extraParams.action = me.action;
					o_extraParams.folder;
					var selectedTreeNode = me.wrapper.treegrid.getSelectionModel().selected.items[0];
					if (selectedTreeNode) {
						o_extraParams.folder = selectedTreeNode.data.ID;
					}
				},
				load: function(store, records) {
					store.productKeys = [];

					for (var i = 0; i < records.length; i++) {
						store.productKeys.push(records[i].data.ITMITMTKN);
					}
				}
			}
		});

		me.columns = me.buildGridColumns();
		var b_dragAndDrop = ip2.isAccessible("app." + me.dmdName + ".data." + me.entity + ".update");

		me.viewConfig = {
			plugins: {
				ptype: 'gridviewdragdrop',
				ddGroup: 'organizerItems',
				enableDrag: b_dragAndDrop,
				enableDrop: b_dragAndDrop,
				appendOnly: false,
				onViewRender: function(view) {
					var dnd = this;

					if (dnd.enableDrag) {
						dnd.dragZone = Ext.create('Ext.view.DragZone', {
							view: view,
							name: me.itemId,
							ddGroup: dnd.dragGroup || dnd.ddGroup,
							dragText: dnd.dragText,
							isPreventDrag: function(e, record, item, index) {
								return (record.data.IRLRELTYP == 'cat' && me.getTreeNodeType() == 'itm') ? true : false;
							}
						});
					}

					if (dnd.enableDrop) {
						dnd.dropZone = Ext.create('Ext.grid.ViewDropZone', {
							view: view,
							ddGroup: dnd.dropGroup || dnd.ddGroup,
							onNodeOver: function(node, dragZone, e, data) {
								var s_entity = me.wrapper.treegrid.entity;
								var dnd = this;
								var view = dnd.view;
								var draggingRecords = data.records;
								var i_proto = Ext.dd.DropZone.prototype;
								var s_allowed = i_proto.dropAllowed;

								draggingRecords[0].allowDrop = true;

								if (!Ext.Array.contains(data.records, dnd.view.getRecord(node))) {
									dnd.positionIndicator(node, data, e);
								}

								// if related product - then drop after 'cat' relationtype is not allowed
								if (me.itemId == 'relatedPropertyGrid') {
									var pos = dnd.getPosition(e, node);
									var overRecord = view.getRecord(node);

									if (!Ext.Array.contains(draggingRecords, overRecord) &&
									pos == 'after' && !dnd.containsRecordAtOffset(draggingRecords, overRecord, 1)
									) {
										if (overRecord.data.IRLRELTYP == 'cat' && me.getTreeNodeType() == 'itm') {
											draggingRecords[0].allowDrop = false;
											return false;
										}
									}
								}

								// Tree node ?
								if (!me.isDropAllow(draggingRecords[0])) {
									draggingRecords[0].allowDrop = false;
									s_allowed = i_proto.dropNotAllowed;
								}

								return s_allowed;
							},
							onContainerOver: function(dd, e, data) {
								var dnd = this;
								var view = dnd.view;
								var count = view.store.getCount();
								var draggingRecords = data.records;
								var i_proto = Ext.dd.DropZone.prototype;
								var s_allowed = i_proto.dropAllowed;

								draggingRecords[0].allowDrop = true;

								if (dnd.overRecord && dnd.overRecord.data && dnd.overRecord.data.IRLRELTYP == 'cat' && me.getTreeNodeType() == 'itm') {
									draggingRecords[0].allowDrop = false;
									return false;
								}

								me.getFamilyStatus(draggingRecords[0]);
								if (count) {
									dnd.positionIndicator(view.getNode(count - 1), data, e);
								}
								else {
									delete dnd.overRecord;
									delete dnd.currentPosition;
									dnd.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, 0);
									dnd.valid = true;
								}
								if (!me.isDropAllow(draggingRecords[0])) {
									draggingRecords[0].allowDrop = false;
									s_allowed = i_proto.dropNotAllowed;
								}

								return s_allowed;
							},
							onNodeEnter: function(node, dragZone, e, data) {
								var dnd = this;

								me.getFamilyStatus(data.records[0]);
							},
							onNodeDrop: function(node, dragZone, e, data) {
								var me = this;
								var dropped = false;
								processDrop = function () {
										me.invalidateDrop();
										me.handleNodeDrop(data, me.overRecord, me.currentPosition);
										dropped = true;
										me.fireViewEvent('drop', node, data, me.overRecord, me.currentPosition);
									},
									performOperation = false;

								performOperation = me.fireViewEvent('beforedrop', node, data, me.overRecord, me.currentPosition, processDrop);
								if (performOperation !== false) {

									if (!dropped) {
										processDrop();
									}
								}

								return performOperation;
							}
						});
					}
				}
			},
			listeners: {
				beforedrop: function(node, data, targetRecord, dropPosition, dropFunction, eOpts) {
					var draggingRecord = data.records[0];
					if (ip2.isAccessible("app." + me.dmdName + ".data." + me.entity + ".delete")) {
						if (!draggingRecord.allowDrop) {
							return false;
						}

						data.sequence = me.calculateSequence(data, targetRecord, dropPosition);
						if (me.isReSequence(draggingRecord)) {
							data.copy = false;
						}
						else {
							data.copy = true;
						}
					}
					else {
						return false;
					}
				},
				drop: function(node, data, targetRecord, dropPosition, eOpts) {
					var draggingRecord = data.records[0];
					if (!data.copy) {
						me.reSequence(draggingRecord, data.sequence);
					}
					else {
						var treeNode = (data.view && data.view.xtype == 'treeview') ? true : false;
						me.createRow(draggingRecord, treeNode, data.sequence, dropPosition);
					}
				}
			},
			getRowClass: function (record, index) {
				if (record.get('PHANTOM') == '1') {
					return 'disabled-row';
				}
			}
		};
		me.callParent();
	},

	/* ----------------------------------------------------------------------------------------------------
		Get family status
	   ---------------------------------------------------------------------------------------------------- */
	getFamilyStatus: function(record) {
		record.familyStatus = 'member';
	},

	/* ----------------------------------------------------------------------------------------------------
		Is drop allow ?
	   ---------------------------------------------------------------------------------------------------- */
	isDropAllow: function(record) {
		var me = this;
		var isTreeNode = me.wrapper.treegrid.isTreeNodeDrag(record);
		var selectedTreeNodes = me.wrapper.treegrid.getView().getSelectedNodes();

		// drag and drop within folder property grid (re-sequence)
		if (me.isReSequence(record)) {
			return true;
		}

		if (isTreeNode) {
			var properties = Ext.decode(record.data.PROPERTIES);
			record.data.ITMITMTKN = parseInt(properties.itemnumber);
		}

		if (Ext.Array.contains(me.store.productKeys, record.data.ITMITMTKN)) {
			return false;
		}

		if (me.store.model.owner.id == 'familyPropertyGrid') {
			// check if target product is a single
			if (me.store.getCount() == 1) {
				return true;
			}

			// check if source product is a single
			if (record.data.ITMIFMTKN > 0 && record.familyStatus == 'member') {
				return false;
			}
		}

		if (me.dependcy && me.dependcy.store && me.dependcy.store.productKeys) {
			if (Ext.Array.contains(me.dependcy.store.productKeys, record.data.ITMITMTKN)) {
				return false;
			}
		}

		return true;
	},

	/* ----------------------------------------------------------------------------------------------------
		Re-sequence: Do the job server-side
	   ---------------------------------------------------------------------------------------------------- */
	reSequence: function(node, sequence) {
		var me = this;

		node.data.SEQUENCE = sequence;

		if (node.store.model.owner.id == 'familyPropertyGrid') {
			action = 'updateProductFamilySequence';
		}
		else {
			action = 'updateProductRelationSequence';
		}

		Ext.Ajax.request({
			url: me.model.proxy.url,
			params: {
				action: action,
				itemToken: node.data.ITMITMTKN,
				relToken: node.data.IRLIRLTKN,
				sequence: sequence
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
		Re-sequence: Calculate new sequence
	   ---------------------------------------------------------------------------------------------------- */
	calculateSequence: function(data, targetRecord, position) {
		var me = this;

		var afterSeq;
		var beforeSeq;
		var nextSibling;
		var previousSibling;
		var position = position || 'before';

		if (targetRecord === undefined) {
			targetRecord = me.store.first();
		}

		switch (position) {
			case 'after':
				afterSeq = targetRecord.data.SEQUENCE;
				nextSibling = me.store.getAt(me.store.indexOf(targetRecord) + 1);
				if (nextSibling && nextSibling.data.IRLTYP != 'cat') {
					beforeSeq = nextSibling.data.SEQUENCE;
				}
				else {
					beforeSeq = afterSeq + 20;
				}
				break;
			case 'before':
				previousSibling = me.store.getAt(me.store.indexOf(targetRecord) - 1);
				if (previousSibling) {
					afterSeq = previousSibling.data.SEQUENCE;
				}
				else {
					afterSeq = 0;
				}
				beforeSeq = (targetRecord) ? targetRecord.data.SEQUENCE : 20;
				break;
		}
		var sequence = parseFloat(afterSeq + ((beforeSeq - afterSeq) / 2));

		return sequence;
	},

	/* ----------------------------------------------------------------------------------------------------
		is drag and drop with same container (re-sequence)
	   ---------------------------------------------------------------------------------------------------- */
	isReSequence: function(record) {
		if (record.store.model == undefined) {
			return false;
		}
		else if (record.store.model.owner && record.store.model.owner.id == this.itemId) {
			return true;
		}
		return false;
	},

	/* ----------------------------------------------------------------------------------------------------
		Build grid column base on data model
	   ---------------------------------------------------------------------------------------------------- */
	buildGridColumns: function() {

		var me = this;
		var gridColumns = [];
		var uiColumns = me.store.model.prototype.entity.ui.grids[me.uiName].columns;
		var o_dmd = ip2.resource.baseConfig.dmd;
		var o_webshop = o_dmd.webshop;
		var o_model = o_webshop.model;
		var a_entities = o_model.entities;
		var dmdModel = Ext.Array.findBy(a_entities, function(o_value) {
				return o_value.name == "WSHITMET00";
			});

		for (var i = 0; i < uiColumns.length; i++) {
			var column = {};

			Ext.apply(column, uiColumns[i]);

			column.dataIndex = column.name;
			if (!column.width) {
				column.flex = 1;
			}

			if (!column.title) {
				if (dmdModel.columns[column.name]) {
					column.title = dmdModel.columns[column.name].title;
				}
			}

			if (Ext.isObject(column.title)) {
				column.title = column.title[me.language];
			}

			column.header = column.title;

			if (column.uitype) {
				if (ip2.uitypes[column.uitype] && ip2.uitypes[column.uitype].grid && ip2.uitypes[column.uitype].grid.renderer) {
					column.renderer = ip2.uitypes[column.uitype].grid.renderer;
				}
			}

			gridColumns.push(column);
		}

		// add icon columns
		var s_entity = me.entity;
		var column = {
			xtype: 'actioncolumn',
			width: 26,
			entity: s_entity,
			items: [{
				itemId: 'remove',
				text: me.getI18N('remove'),
				tooltip: me.getI18N('removeTips').toString(),
				handler: function(grid, rowIndex, colIndex) {
					var record = grid.getStore().getAt(rowIndex);
					me.removeRow(record);
				},
				getClass: function(value, metadata, record) {
					var i_column = this;
					if (ip2.isAccessible("app." + me.dmdName + ".data." + i_column.entity + ".delete")) {
						if (record.get('PHANTOM') == '1') {
							return 'icon icon-delete x-hidden-display';
						}
						else {
							return "icon icon-delete x-grid-center-icon";
						}
					}
					else {
						return 'icon icon-delete x-hidden-display';
					}
				}
			}]
		};
		gridColumns.push(column);

		return gridColumns;
	},

	/* ----------------------------------------------------------------------------------------------------
		Create row
	   ---------------------------------------------------------------------------------------------------- */
	createRow: function(record, isTreeNode, sequence, dropPosition) {

		var me = this;
		var action;

		if (me.itemId == 'familyPropertyGrid') {
			action = 'addProductInFamily';
		}
		else {
			action = 'addProductInRelation';
		}

		// Override TreeNode by loading a data record
		if (isTreeNode) {
			var properties = Ext.decode(record.data.PROPERTIES);
			var payload = {
				action: 'getRow',
				key: '{ITMITMTKN:' + properties.itemnumber + '}',
				model: 'WSHITMET00',
				context: 'grid',
				uiName: me.wrapper.content.uiName,
				dmdFile: 'webshop.dmd',
				action: 'getRow'
			};
			var result = ip2.sajax.request({
				url: '/ip2-services/ip2dmdProxy.aspx?' + $.param(payload),
				method: 'GET',
				asJson: true
			});
			var index = me.store.indexOf(record);

			me.store.remove(record);

			me.store.insert(index, result.rows[0]);
			record = me.store.getAt(index);

			// reset treenode selection
			var node = me.wrapper.treegrid.store.getNodeById(me.selectedFolderToken);
			me.wrapper.treegrid.getSelectionModel().select(node);
		}

		Ext.Ajax.request({
			url: me.model.proxy.url,
			params: {
				action: action,
				folderToken: me.selectedFolderToken,
				familyToken: record.data.ITMIFMTKN,
				itemToken: record.data.ITMITMTKN,
				dropPosition: dropPosition,
				sequence: sequence
			},
			success: function(response, request) {
				var result = Ext.decode(response.responseText);
				for (var rowInx = 0; rowInx < result.rows.length; rowInx++) {
					var record = me.store.findRecord('ITMITMTKN', result.rows[rowInx].ITMITMTKN);
					for (var key in result.rows[rowInx]) {
						record.set(key, result.rows[rowInx][key]);
					}
					me.store.productKeys.push(result.rows[rowInx].ITMITMTKN);
				}

				me.folderPropertyAdded(record);
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
		Remvoe row
	   ---------------------------------------------------------------------------------------------------- */
	removeRow: function(record) {
		var me = this;
		var action;
		var token;
		var itemToken;

		if (record.data.IRLRELTYP) {
			action = 'removeProductInRelation';
			token = record.data.IRLIRLTKN;
			itemToken = record.data.ITMITMTKN;
		}
		else {
			action = 'removeProductInFamily';
			token = record.data.ITMIFMTKN;
			itemToken = record.data.ITMITMTKN;
		}

		Ext.Ajax.request({
			url: me.model.proxy.url,
			params: {
				action: action,
				token: token,
				itemToken: itemToken
			},
			record: record,
			success: function(response, request) {
				var index = me.store.productKeys.indexOf(request.record.data.ITMITMTKN);
				if (index > -1) {
					me.store.productKeys.splice(index, 1);
				}
				me.store.remove(request.record);

				me.folderPropertyRemoved(request.record.data);
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
		get tree node type
	   ---------------------------------------------------------------------------------------------------- */
	getTreeNodeType: function() {
		var me = this;

		var node = me.wrapper.treegrid.store.getNodeById(me.selectedFolderToken);
		return (node.data.cid == 3) ? 'itm' : 'cat';
	},

	/* ----------------------------------------------------------------------------------------------------
		Call after Folder Property added (Can be override by owner)
	   ---------------------------------------------------------------------------------------------------- */
	folderPropertyAdded: function(data) {
	},

	/* ----------------------------------------------------------------------------------------------------
		Call after Folder Property removed (Can be override by owner)
	   ---------------------------------------------------------------------------------------------------- */
	folderPropertyRemoved: function(data) {
	},

	/* ----------------------------------------------------------------------------------------------------
		Get i18n text by language (Can be override by owner)
	   ---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return ip2.folderorganizer.getTextValue(key);
	}

});
﻿Ext.define('Ext.ux.folderorganizer.FolderProductLocation', {
	extend: 'Ext.grid.Panel',
	alias: ['widget.folderorganizerFolderProductLocation'],
	border: false,
	autoScoll: true,
	viewConfig: {
		loadMask: true
	},
	hideHeaders: true,
	initComponent: function() {
		var me = this;

		me.radioButtonClicked = false;

		var modelName = 'folderProductLocationModel';

		if (!Ext.ClassManager.isCreated(modelName)) {
			Ext.define(modelName, {
				extend: 'Ext.data.Model',
				proxy: {
					type: 'ajax',
					url: me.wrapper.proxy,
					reader: {
						type: 'json',
						rootProperty: 'rows',
						totalProperty: 'totalRows'
					},
					extraParams: {
						action: 'getProductCatalogLocation'
					}
				}
			});
		}

		me.columns = [
		{ xtype: 'rownumberer' },
		{ header: ip2.i18n(me.getI18N('primary')), dataIndex: 'PRILOC', width: 24,
                renderer: function(value, meta, record, rowIndex, colIndex, store) {
	var html = me.createPrimaryLocationRadioButton(value, record, store.getCount());

	return html;
                }
            },
            { header: ip2.i18n(me.getI18N('breadcrumb')), dataIndex: 'TITLE', flex: 1 }
        ];

		me.store = Ext.create('Ext.data.Store', {
			model: modelName,
			autoLoad: true,
			remoteSort: false
		});

		me.listeners = me.listeners || {};
		Ext.apply(me.listeners, {
			itemclick: function(view, record, item, index, e) {
				if (!me.radioButtonClicked) {
					var a_split = record.data.BREADCRUMB.split(',');
					if (!a_split[0] == "") {
						var i_selected = me.wrapper.treegrid.getSelectionModel().getSelection()[0];
						me.wrapper.treegrid.expandTreeToNode(a_split, i_selected, 'PROPERTIES', 'itemnumber');
					}
				}
				me.radioButtonClicked = false;
			}
		});

		me.callParent();
	},

	/* ----------------------------------------------------------------------------------------------------
	    Create primary location radio button
	   ---------------------------------------------------------------------------------------------------- */
	createPrimaryLocationRadioButton: function(value, record, count) {
		var me = this;

		if (count < 2) {
			return '';
		}

		var id = [
		'primaryLocation',
		record.internalId,
		ip2.unique()
		].join('-');
		var checked = value ? 'CHECKED' : '';
		var html = new Ext.XTemplate('',
		'<table ',
		'class="x-ux-gallery-cell" ',
		'style="text-align: center; ',
		'width: 100%;"',
		'>',
		'<tr>',
		'<td valign="middle">',
		'<input ',
		'id="' + id + '" ',
		'type="radio" ',
		'class="primaryLocation" ',
		'name="primaryLocation" ',
		'value="' + record.data.FLDFLDTKN + '" ',
		checked,
		'/>',
		'</td>',
		'</tr>',
		'</table>',
		'').html;

		setTimeout(function () {
			var el = Ext.get(id);

			if (el) {
				el.on('change', function (e, rb) {
					me.radioButtonClicked = true;
					Ext.Ajax.request({
						url: me.wrapper.proxy,
						params: {
							action: 'setProductCatalogLocation',
							folderToken: rb.value
						}
					});
				});
			}
		}, 4);

		return html;
	},

	/* ----------------------------------------------------------------------------------------------------
	    Get i18n text by language
	   ---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return ip2.folderorganizer.getTextValue(key);
	}

});
﻿Ext.define("Ext.ux.folderorganizer.SearchField", {
	extend: "Ext.form.field.Text",
	hideLabel: true,
	width: 180,
	enableKeyEvents: true,
	isFormField: false,
	triggers: {
		clear: {
			cls: "x-form-clear-trigger",
			scope: "this",
			hidden: true,
			handler: "onTrigger1Click"
		},
		search: {
			cls: "x-form-search-trigger",
			scope: "this",
			handler: "onTrigger2Click"
		}
	},
	initComponent: function() {
		var me = this;

		me.emptyText = me.getI18N("searchText");

		me.listeners = me.listeners || {};
		Ext.apply(me.listeners, {
			keydown: function(fld, e) {
				if (e.getKey() == e.ENTER) {
					var value = me.getValue();
					if (value.length == 0) {
						me.onTrigger1Click();
					}
					else if (value.length < 3) {
						me.markInvalid(me.getI18N("min3characters"));
					}
					else {
						me.onTrigger2Click();
					}
				}
			}
		});

		me.callParent();
	},

	/* ----------------------------------------------------------------------------------------------------
	        Clear search field and refresh tree
	     ---------------------------------------------------------------------------------------------------- */
	onTrigger1Click: function() {
		var me = this;

		me.setValue("");
		me.wrapper.treegrid.searchValue = "";

		me.wrapper.treegrid.refresh(true);
		me.getTrigger("clear").hide();
	},

	/* ----------------------------------------------------------------------------------------------------
	        Submit Search
	     ---------------------------------------------------------------------------------------------------- */
	onTrigger2Click: function() {
		var me = this;
		var value = me.getValue().trim();

		if (value.length < 3) {
			me.markInvalid(me.getI18N("min3characters"));
		}
		else {
			me.getTrigger("clear").show();
			me.wrapper.treegrid.searchValue = value;
			me.wrapper.treegrid.search(value);
		}
	},

	/* ----------------------------------------------------------------------------------------------------
	        I18N translation
	     ---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return ip2.folderorganizer.getTextValue(key);
	}
});
Ext.define("Ext.ux.folderorganizer.Toolbar", {
	extend: "Ext.toolbar.Toolbar",

	border: false,
	listeners: {
		afterrender: {
			fn: function() {
				this.keyMapping();
			}
		},
		nodeselection: {
			fn: function(node) {
				this.setButtonsStatus(node);
			}
		}
	},
	initComponent: function() {

		var me = this;
		var i_wrapper = me.wrapper;

		me.allowAdd = ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + me.wrapper.entity + ".create");
		me.allowEdit = (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + me.wrapper.entity + ".update") ||
						ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + me.wrapper.entity + ".read"));
		me.allowRemove = ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + me.wrapper.entity + ".delete");

		me.xpd = me.wrapper.xpd;

		me.items = [];
		if (Ext.isArray(me.wrapper.folder.buttons)) {
			Ext.Array.each(me.wrapper.folder.buttons, function(button) {
				switch (button) {
				case "add":
					var cfg = {
						xtype: "button",
						itemId: "add",
						text: me.getI18N("add"),
						iconCls: "pf-add",
						disabled: false
					};

					var menuCids = [];
					var buttonCount = 0;
					var addCollection;
					var traverseAllowedChilds = function(allowedchilds, menuCids) {
						for (var i = 0; i < allowedchilds.length; i++) {
							if (menuCids.indexOf(allowedchilds[i]) == -1) {
								menuCids.push(allowedchilds[i]);
								var collection = me.xpd.flatten.collections[allowedchilds[i]];
								traverseAllowedChilds(collection.allowedchilds, menuCids);
							}
						}
					};
					var collection = me.xpd.flatten.collections[me.wrapper.folder.cid];
					if (collection && collection.allowedchilds) {
						traverseAllowedChilds(collection.allowedchilds, menuCids);
					}
					else {
						for (var index in me.xpd.flatten.collections) {
							if (index != "all") {
								menuCids.push(index);
							}
						}
					}

					//if (me.xpd && me.wrapper.cid.length != 1) {
					if (me.xpd && me.wrapper.folder.multiAddChoice) {
						var a_items = [];
						for (var index in menuCids) {
							var collection = me.xpd.flatten.collections[menuCids[index]];
							var showAddButton = (Ext.isBoolean(collection.showAddButton)) ? collection.showAddButton : true;
							if (me.allowCreation(collection) && showAddButton) {

								var s_cls = collection.iconCls ? collection.iconCls.split("-").pop() : "pf-add";

								if (s_cls == "gear") {
									s_cls = "gearwheel";
								}

								if (s_cls != "pf-add") {
									s_cls = [
										"pf",
										s_cls
									].join("-");
								}

								var i_menu = Ext.widget("menuitem", {
									text: ip2.xpd.translate(me.xpd, collection.title),
									itemId: "add" + collection.id,
									collection: collection,
									iconCls: s_cls,
									handler: function(menu) {
										me.wrapper.treegrid.addRow(menu.collection);
									}
								});
								a_items.push(i_menu);

								buttonCount++;
								addCollection = collection;
							}
						};
						if (buttonCount == 1) {
							Ext.apply(cfg, {
								handler: function() {
									me.wrapper.treegrid.addRow(addCollection);
								}
							});
						}
						else {
							Ext.apply(cfg, {
								menu: Ext.widget("menu", {
									items: a_items
								})
							});
						}
					}
					else {
						buttonCount++;
						if (me.wrapper.folder.childCid) {
							Ext.apply(cfg, {
								handler: function() {
									me.wrapper.treegrid.addRow(me.xpd.flatten.collections[me.wrapper.folder.childCid]);
								}
							});
						}
						else {
							Ext.apply(cfg, {
								handler: function() {
									me.wrapper.treegrid.addRow();
								}
							});
						}
					}

					if (buttonCount == 1) {
						me.items.push(
							Ext.widget("button", cfg)
						);
					}
					else {
						me.items.push(
							Ext.widget("splitbutton", cfg)
						);
					}
					break;
				case "edit":
					me.items.push(
						{
							xtype: "button",
							itemId: "edit",
							text: me.getI18N("update"),
							iconCls: "pf-edit",
							disabled: true,
							handler: function () {
								me.wrapper.treegrid.updateRow();
							}
						}
					);
					break;
				case "remove":
					me.items.push(
						{
							xtype: "button",
							itemId: "remove",
							text: me.getI18N("remove"),
							iconCls: "pf-navigate_cross",
							disabled: true,
							handler: function () {
								me.wrapper.treegrid.removeRow();
							}
						}
					);
					break;
				case "refresh":
					me.items.push(
						{
							xtype: "button",
							itemId: "refresh",
							text: me.getI18N("refresh"),
							iconCls: "pf-refresh",
							handler: function () {
								me.wrapper.treegrid.refresh();
							}
						}
					);
					break;
				case "deselect":
					me.items.push(
						{
							xtype: "button",
							itemId: "deselect",
							text: me.getI18N("deselect"),
							iconCls: "pf-deselect",
							handler: function () {
								me.wrapper.treegrid.deselect();
							}
						}
					);
					break;
				}
			});
		}

		if (me.wrapper.displayFilterField) {
			me.items.push(
				Ext.create("Ext.ux.folderorganizer.SearchField", {
					itemId: "search",
					wrapper: me.wrapper
				})
			);
		}

		me.callParent();
	},
	/* ----------------------------------------------------------------------------------------------------
			Setup key mapping
		 ---------------------------------------------------------------------------------------------------- */
	keyMapping: function() {

		var i_self = this;

		var i_keyMap = Ext.create("Ext.util.KeyMap", {
			target: i_self.getEl(),
			binding: [
				{
					key: "a",
					ctrl: true,
					fn: function() {
						var addButton = i_self.getComponent("add");
						if (addButton.menu) {
							addButton.showMenu();
						}
						else {
							i_self.addRow();
						}
					}
				},
				{
					key: "e",
					ctrl: true,
					fn: function() {
						i_self.updateRow();
					}
				}
			]
		});

		return i_keyMap;
	},

	/* ----------------------------------------------------------------------------------------------------
			The checkbox for a node is changed
		 ---------------------------------------------------------------------------------------------------- */
	setButtonsStatus: function(node) {
		var me = this;

		var parentCollection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(me, node);

		me.wrapper.treegrid.node = node;

		// disable all buttons
		Ext.Array.each(me.items.items, function(button) {
			if (button.itemId != "refresh" && button.itemId != "deselect" && button.itemId != "search") {
				button.disable();
			}
		});

		if (me.isAddAllow(node)) {
			var addButton = me.getComponent("add");
			addButton.enable();
		}
		if (me.allowAdd && me.wrapper.folder.cid.length == 1) {
			var addButton = me.getComponent("add");
			addButton.enable();
		}

		// edit allow, if node allows it
		if (me.allowEdit) {
			if (node.data.allowEdit) {

				var button = me.getComponent("edit");
				if (button) {
					if (parentCollection) {
						button.enable();
					}
					else {
						button.enable();
					}
				}
			}
		}

		// remove is allow. if node allows it
		if (node.get("allowRemove")) {
			if (node && !node.isRoot()) {
				var button = me.getComponent("remove");
				if (button) {
					if (parentCollection) {
						button.enable();
					}
					else {
						button.enable();
					}
				}
			}
		}

		if (!parentCollection) {
			return;
		}

		// add is allow, if any children collection not having a entity property
		if (Ext.isArray(parentCollection.allowedchilds) && parentCollection.allowedchilds.length > 0) {
			for (var i = 0; i < parentCollection.allowedchilds.length; i++) {
				var collection = me.xpd.flatten.collections[parentCollection.allowedchilds[i]];
				if (me.allowCreation(collection)) {
					var addButton = me.getComponent("add");
					if (addButton) {
						// enable menu items
						if (addButton.menu) {
							// disable all buttons
							Ext.Array.each(addButton.menu.items.items, function(menu) {
								menu.hide();
							});

							if (parentCollection.childlimit && node.childNodes.length >= parentCollection.childlimit) {
								return;
							}

							// enable allow add menu buttons
							for (var i = 0; i < parentCollection.allowedchilds.length; i++) {
								var collection = me.xpd.flatten.collections[parentCollection.allowedchilds[i]];
								if (collection) {
									var menu = addButton.menu.getComponent("add" + collection.id);
									if (menu) {
										menu.show();
										addButton.enable();
									}
								}
							}
						}
					}
				}
			}
		}
		else {
			var addButton = me.getComponent("add");
			if (addButton) {
				addButton.disable();
			}
		}
	},
	/* ----------------------------------------------------------------------------------------------------
			Check if add allowed
		 ---------------------------------------------------------------------------------------------------- */
	allowCreation: function(collection) {
		if (!collection) {
			return false;
		}

		if (collection.organizer && collection.organizer.allowCreation) {
			return true;
		}

		if (collection.entity) {
			return false;
		}

		return true;
	},
	/* ----------------------------------------------------------------------------------------------------
			Check if add allowed
		 ---------------------------------------------------------------------------------------------------- */
	isAddAllow: function(node) {
		var me = this;

		if (me.wrapper.folder.cid == "" && node.data.ID == -1) {
			return true;
		}
		else {
			return false;
		}
	},
	/* ----------------------------------------------------------------------------------------------------
			I18N translation
		 ---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return ip2.folderorganizer.getTextValue(key);
	}
});
Ext.define('Ext.ux.folderorganizer.TreeSelModel', {
	extend: 'Ext.selection.TreeModel',
	onKeyPress: function(e, t) {
		var key = e.getKey(),
		selected, 
		checked;
        
		if (key === e.SPACE) {
			e.stopEvent();
			selected = this.getLastSelected();
			if (selected) {
				this.view.onCheckChange(selected);
			}
		}
		else if (key === e.ENTER) {
			e.stopEvent();
			selected = this.getLastSelected();
			if (selected) {
				if (!selected.isExpanded()) {
					selected.expand();
				}
			}
		}
		else {
			this.callParent(arguments);
		}
	}
});
Ext.define("Ext.ux.folderorganizer.Util", {

	singleton: true,

	addCollectionColumns: function(i_self, a_columns) {

		a_columns = a_columns || [];

		var collection;
		var cid;
		var a_collectionColumns = [];

		i_self.collectionColumns = i_self.collectionColumns || {};

		// find cid for all children
		var findAllChildrenCid = function(cid) {
			var o_collection = Ext.ux.folderorganizer.Util.getXpdCollection(i_self, cid);
			if (!o_collection || !o_collection.allowedchilds) {
				return;
			}
			Ext.Array.each(o_collection.allowedchilds, function(n_child) {
				i_self.collectionColumns[o_collection.allowedchilds[n_child]] = {};
				if (o_collection.allowedchilds[n_child] != cid) {
					findAllChildrenCid(o_collection.allowedchilds[n_child]);
				}
			});
		};

		if (Ext.isEmpty(i_self.cid)) {
			// all collections
			Ext.Object.each(i_self.xpd.collections, function(s_key, o_value) {
				i_self.collectionColumns[o_value.id] = {};
			});
		}
		else {
			if (Ext.isObject(i_self.cid)) {
				if (i_self.cid.child) {
					findAllChildrenCid(i_self.cid.root);
				}
				else {
					findAllChildrenCid(i_self.cid);
				}
			}
			else {
				findAllChildrenCid(i_self.cid);
			}
		}

		var addColumn = function(o_column, o_collection, s_name, s_cid) {

			if (o_column && o_column.index) {

				if (!s_name || o_column.cidColumn) {
					s_cid = o_column.index;
					s_name = "__cid__";
				}

				var o_result = Ext.Object.merge({}, o_column, {
					dataIndex: "PROPERTIES",
					renderer: function(value, meta, record, rowIndex, colIndex) {
						var o_values = Ext.decode(value, true) || {};
						if (i_self.collectionColumns[o_values.__cid__] && i_self.collectionColumns[o_values.__cid__][colIndex]) {
							var s_property = i_self.collectionColumns[o_values.__cid__][colIndex].property;
							var value = o_values[s_property];

							if (s_property == "__cid__") {
								value = ip2.xpd.translate(i_self.xpd, i_self.xpd.flatten.collections[value].title);
							}
							if (Ext.isObject(value)) {
								return ip2.i18n(value);
							}
							else {
								return value;
							}
						}
						else {
							return "";
						}
					}
				});

				a_collectionColumns.push(o_result);

				i_self.collectionColumns[s_cid][o_column.index] = Ext.apply({}, {
					title: (s_name == "__cid__") ? "Type" : ip2.xpd.translate(i_self.xpd, o_collection.title),
					property: s_name
				});
			}
		};

		Ext.Object.each(i_self.collectionColumns, function(s_key, o_value) {
			var o_organizer;
			var o_collection = Ext.ux.folderorganizer.Util.getXpdCollection(i_self, s_key);
			if (o_collection && o_collection.organizer) {
				o_organizer = o_collection.organizer;
				addColumn(o_organizer.column, o_collection, s_key);
			}
			if (o_collection && o_collection.properties) {
				Ext.Object.each(o_collection.properties, function(s_property, o_property) {
					if (o_property.organizer) {
						o_organizer = o_property.organizer;
						addColumn(o_organizer.column, o_property, s_property, s_key);
					}
				});
			}
		});

		a_columns = a_columns.concat(a_collectionColumns);
		return a_columns;
	},

	setCollectionColumnHeader: function(me, node) {

		if (me.extraColumns && me.extraColumns.length > 0) {
			return;
		}

		if (!node.data.PROPERTIES) {
			return;
		}

		var props = Ext.decode(node.data.PROPERTIES, true) || {};
		if (props.__cid__ == me.previousNodeCid) {
			return;
		}
		me.previousNodeCid = props.__cid__;

		var s_title;
		var a_columns = (Ext.isFunction(me.getView)) ? me.getView().getGridColumns() : me.treegrid.getView().getGridColumns();

		Ext.Array.each(a_columns, function(i_column, n_index) {
			if (!i_column.isTreeColumn) {
				var o_collection = me.collectionColumns[props.__cid__];
				if (o_collection && o_collection[n_index]) {
					s_title = ip2.i18n(o_collection[n_index].header) || ip2.i18n(o_collection[n_index].title);
				}
				else {
					s_title = "";
				}
				i_column.setText(s_title);
			}
		});
	},

	getXpdCollectionByNode: function(me, node) {

		var cid = Ext.ux.folderorganizer.Util.getXpdCollectionId(me, node);

		if (cid == 0) {
			cid = parseInt((Ext.isArray(me.cid)) ? me.cid[0] : me.cid);
		}

		return Ext.ux.folderorganizer.Util.getXpdCollection(me, cid);
	},

	getXpdCollectionId: function(me, node) {

		if (node.data.cid) {
			return parseInt(node.data.cid);
		}
		else if (node.data.PROPERTIES) {
			var properties = {};
			if (ip2.isStringedObject(node.data.PROPERTIES)) {
				properties = Ext.decode(node.data.PROPERTIES, true) || {};
			}
			else {
				var o_props = {};
				var a_split = node.data.PROPERTIES.split(",");
				ip2.each(a_split, function(s_props) {
					var a_propsplit = s_props.split(":");
					if (a_propsplit.length == 2) {
						o_props[a_propsplit[0].trim()] = a_propsplit[1].trim();
					}
				});
				properties = o_props;
				node.data.PROPERTIES = JSON.stringify(o_props);
			}
			return parseInt(properties.__cid__);
		}
		else if (node.data[me.propertyNameMapping.PROPERTIES]) {
			var properties = Ext.decode(node.data[me.propertyNameMapping.PROPERTIES], true) || {};
			return parseInt(properties.__cid__);
		}
		else {
			return 0;
		}
	},

	getXpdCollection: function(me, cid) {

		if (me.xpd && me.xpd.flatten.collections[cid]) {
			return me.xpd.flatten.collections[cid];
		}
		else {
			return null;
		}
	}
});
Ext.define("Ext.ux.folderorganizer.Itemgrid", {
	extend: "Ext.grid.Panel",
	alias: "widget.folderitemgrid",
	border: 0,
	multiSelect: true,
	autoScroll: true,
	collapable: false,
	selModel: {
		mode: "SINGLE"
	},
	config: {
		collection: {},
		hasAssociation: false,
		wrapper: null,
		cid: 0,
		namePrefix: "itemGrid",
		filter: [],
		uiName: "portfolio"
	},
	initComponent: function() {

		var i_self = this;

		var o_collection = i_self.getCollection();

		i_self.name = i_self.getNamePrefix() + "_grid";
		i_self.itemId = i_self.name;
		i_self.setHasAssociation(i_self.getWrapper() ? true : false);

		// collection information from xpd ?
		if (o_collection) {
			o_collection.dmdName = o_collection.dmd.split(".").shift();
			i_self.store = i_self.setupCollection();
		}

		if (!i_self.getStore()) {
			Ext.ux.folderorganizer.Alert({
				title: i_self.getI18N("invalidConfig"),
				msg: i_self.getI18N("missingConfigOptions")
			});
		}

		var i_store = i_self.getStore();

		i_store.on({
			beforeload: {
				fn: function(i_store, i_operation) {

					var i_proxy = i_store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();

					if (i_self.filter) {
						var a_add = [];
						var a_filters = i_self.getFilter();
						Ext.Array.each(a_filters, function(o_filter) {
							if (o_filter.value) {
								var s_filter = o_filter.property + " = " + o_filter.value;
								a_add.push(s_filter);
							}
						});
						if (a_add.length > 0) {
							var s_where = a_add.join(" AND ");
							Ext.apply(o_extraParams, {
								where: s_where
							});
						}
					}

					delete o_extraParams.filter;

					var o_sorters = i_store.getSorters();

					var a_sort = [];
					var s_sort = "";

					Ext.Array.each(o_sorters.items, function(o_sort) {
						var s_sorter = o_sort.getProperty() + " " + o_sort.getDirection();
						a_sort.push(s_sorter);
					});
					var s_sort = a_sort.join(", ");
					o_extraParams.sort = s_sort;
					o_extraParams.dir = "";
				}
			}
		});

		var o_viewConfig = i_self.viewConfig;

		if (!o_viewConfig) {
			o_viewConfig = {
				copy: (i_self.copyNode === true) ? true : false,
				variableRowHeight: true
			};
			if (i_self.getHasAssociation()) {
				Ext.apply(o_viewConfig, {
					plugins: {
						ptype: "gridviewdragdrop",
						dragGroup: "organizerItems",
						enableDrag: true
					}
				});
			}
		}
		else {
			o_viewConfig.variableRowHeight = true;
		}

		i_self.columns = i_self.columns || i_self.getModelColumns();

		var i_model = i_store.getModel();

		delete i_self.buttons;

		i_self.callParent();

		i_self.on({
			afterrender: {
				fn: function(i_grid) {
					i_self.keyMapping();
					var i_toolbar = i_self.down("toolbar");
					if (i_toolbar && i_toolbar.hideLink) {
						i_toolbar.hideLink();
					}
				}
			},
			selectionchange: {
				fn: function(i_selectionModel, a_records) {
					if (a_records.length > 0) {
						var i_wrapper = i_self.getWrapper();
						i_wrapper.fireEvent("rowselection", i_self.getCid(), a_records);
					}
				}
			},
			itemcontextmenu: {
				fn: function(i_view, i_selected, i_html, index, i_event) {

					i_event.preventDefault();
					i_view.getSelectionModel().select(i_selected);

					var i_element = Ext.get(i_html);
					var o_coords = i_event.getXY();
					var i_record = i_selected;

					if (ip2.isAccessible("app." + i_self.collection.dmdName + ".data." + i_self.collection.entity + ".update") ||
						ip2.isAccessible("app." + i_self.collection.dmdName + ".data." + i_self.collection.entity + ".read")) {
						var i_menu = Ext.widget("menu", {
							items: [{
									xtype: "menuitem",
									text: ip2.i18n({
										da: "Redigér " + i_self.title.toLowerCase(),
										en: "Edit " + i_self.title.toLowerCase()
									}),
									iconCls: "pf-edit",
									handler: function() {

										var o_size = Ext.ux.file.util.Handler.getWindowSize();
										var o_collection = i_self.getCollection();

										var i_window = Ext.widget("window", {
											modal: false,
											animateTarget: i_element,
											closable: true,
											collapsible: true,
											resizable: true,
											width: o_size.width * 0.9,
											height: o_size.height * 0.9,
											layout: "fit"
										});

										var o_config = {
											dmd: o_collection.dmd,
											entityName: o_collection.entity
										};

										ip2.addChild(i_window, i_record, "update", o_config);
										i_window.mon(ip2.App, "entityupdate:" + o_collection.entity, function(i_record) {
											i_store.load();
										});
										i_window.show();
									}
								}
							]
						});
						i_menu.showAt([o_coords[0], o_coords[1]]);
					}
				}
			},
			nodeadded: {
				fn: function(i_node) {
					i_store.load();
				}
			},
			noderemoved: {
				fn: function(i_node) {
					i_store.load();
				}
			}
		});

		var i_toolbar = Ext.widget("entitytoolbar", {
			model: i_model,
			dmdInfo: {
				dmd: o_collection.dmd,
				entityName: o_collection.entity,
				uiName: o_collection.uiName || "portfolio"
			},
			entityInfo: ip2.dmd.getInfo({
				dmd: o_collection.dmd || "dmd/webshop.dmd",
				view: o_collection.uiName || "portfolio",
				entity: o_collection.entity,
				context: "grid"
			}),
			store: i_self.getStore(),
			grid: i_self,
			dock: "top",
			hasExport: false,
			allowNew: false
		});

		i_self.addDocked(i_toolbar);

		i_store.load();
	},

	/* ----------------------------------------------------------------------------------------------------
	Add new row
	---------------------------------------------------------------------------------------------------- */
	addRow: function() {
		alert("add");
	},

	/* ----------------------------------------------------------------------------------------------------
	Refresh the view
	---------------------------------------------------------------------------------------------------- */
	refresh: function() {

		var i_self = this;
		var i_store = i_self.getStore();
		i_store.load();
	},

	/* ----------------------------------------------------------------------------------------------------
	Calculate and return the paging limit depending on the area available
	---------------------------------------------------------------------------------------------------- */
	getPagingLimit: function() {

		var i_self = this;
		var height = 0;
		var limit = 0;
		if (i_self.ownerCt && i_self.ownerCt.getHeight) {
			// does the grid lives inside an container ?
			height = i_self.ownerCt.getHeight();
		}
		if (height == 0) {
			height = ip2.body.init().getHeight();
		}
		height = height - i_self.headerHeight;

		// calculate page size
		limit = Math.floor(height / i_self.rowHeight);
		return limit;
	},

	/* ----------------------------------------------------------------------------------------------------
	Create grid columns
	---------------------------------------------------------------------------------------------------- */
	getModelColumns: function() {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_model = i_store.getModel();
		var o_model = Ext.apply({}, i_model.prototype.dmdModel);
		var i_wrapper = i_self.getWrapper();
		var o_collection = i_self.getCollection();
		var s_uiName = i_self.getUiName();
		var a_gridcolumns = [];
		var a_displayColumns = i_self.displayColumns || [];

		Ext.Array.each(a_displayColumns, function(s_column) {
			s_column = s_column;
		});

		if (o_collection) {
			if (o_collection.uiName) {
				s_uiName = o_collection.uiName;
				a_gridcolumns = i_self.createGridColumnUI(s_uiName, a_displayColumns);
			}
			else {
				Ext.Object.each(o_collection.properties, function(s_key, o_property) {
					if (o_property.databasebind) {

						var o_column = i_self.applyGridColumnInformation({
							name: o_property.databasebind,
							title: ip2.xpd.translate(o_collection, o_property.title)
						});
						a_gridcolumns.push(o_column);
					}
				});
			}

			// if columns still empty, try to find isTitle fields
			if (Ext.isEmpty(a_gridcolumns)) {

				Ext.Object.each(o_collection.properties, function(s_key, o_property) {
					if (o_property.isTitle) {

						var o_column = i_self.applyGridColumnInformation({
							name: s_key,
							title: ip2.xpd.translate(i_wrapper.xpd, o_property.title)
						});

						o_column.header = o_column.title;
						o_column.dataIndex = o_collection.propertyFieldName;

						o_column.renderer = function(value, i_meta, i_record, n_rowIndex, n_colIndex) {

							var i_column = this.columns[n_colIndex];
							var s_field = o_collection.propertyFieldName;
							var s_property = i_record.get(s_field);
							var o_property = {};

							if (s_property) {
								o_property = Ext.decode(s_property, true) || {};
							}

							if (o_property[i_column.name]) {
								value = o_property[i_column.name];
							}

							return value;
						};
						a_gridcolumns.push(o_column);
					}
				});
			}
		}
		else {
			a_gridcolumns = i_self.createGridColumnUI(s_uiName, a_displayColumns);
		}

		// if columns still empty, use all fields
		if (Ext.isEmpty(a_gridcolumns)) {
			var columns = o_model.columns;

			var a_columns = [];
			if (Ext.isArray(columns)) {
				a_columns = columns.slice();
			}
			else {
				Ext.Object.each(columns, function(s_key, o_column) {

					var o_clone = Ext.apply({}, o_column);
					o_clone.name = s_key;
					a_columns.push(o_clone);
				});
			}

			Ext.Array.each(a_columns, function(o_column) {
				a_gridcolumns.push(o_column);
			});
		}

		return a_gridcolumns;
	},

	/* ----------------------------------------------------------------------------------------------------
	Create grid column UI
	---------------------------------------------------------------------------------------------------- */
	createGridColumnUI: function(s_uiName, displayColumns) {

		var i_self = this;
		var o_uiTypes = ip2.loadUItypes();
		var i_store = i_self.getStore();
		var i_model = i_store.getModel();
		var o_model = Ext.apply({}, i_model.prototype.dmdModel);
		var o_entity = Ext.apply({}, i_model.prototype.entity);
		var a_return = [];

		var o_view = o_entity.ui.grids[s_uiName] || o_entity.ui.grids.portfolio;
		var a_columns = o_view.columns.slice();

		Ext.Array.each(a_columns, function(o_column) {

			var o_clone = Ext.apply({}, o_column);

			if (o_clone.hide) {
				return true;
			}

			if (o_clone.from && !Ext.String.startsWith(o_clone.from, "(")) {
				o_clone.name = o_clone.from + "_" + o_clone.name;
			}

			if (o_clone.uitype) {
				var o_type = o_uiTypes[o_clone.uitype];
				if (o_type) {
					var o_grid = o_type.grid;
					if (o_grid && o_grid.renderer) {
						o_clone.renderer = o_grid.renderer;
					}
				}
			}

			if (!o_clone.renderer) {
				o_clone.renderer = function(value, metaData, record, rowIndex, colIndex, store) {
					if (Ext.isString(value) && Ext.String.startsWith(value, "{")) {
						return ip2.i18n(value);
					}
					return value;
				};
			}
			a_return.push(i_self.applyGridColumnInformation(o_clone));
		});

		return a_return;
	},

	/* ----------------------------------------------------------------------------------------------------
	Apply grid column information
	---------------------------------------------------------------------------------------------------- */
	applyGridColumnInformation: function(o_config) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_model = i_store.getModel();
		var o_model = i_model.prototype.dmdModel;
		var o_entity = i_model.prototype.entity;
		var o_columns = i_model.prototype.columns;
		var a_columns = [];

		if (Ext.isArray(o_config.name)) {

			o_config.titleFields = o_config.name;

			o_config.renderer = function(value, i_meta, i_record, n_rowIndex, n_colIndex) {

				var i_column = this.columns[n_colIndex];
				var s_property = i_record.get("PROPERTIES");
				var o_property = {};

				if (s_property) {
					o_property = Ext.decode(s_property, true) || {};
				}

				Ext.Array.each(o_config.name, function(s_name) {
					if (o_property[s_name]) {
						value = o_property[s_name];
						return false;
					}
				});

				if (o_property[i_column.name]) {
					value = o_property[i_column.name];
				}

				return value;
			};
			o_config.dataIndex = "PROPERTIES";
		}
		else {
			o_config.dataIndex = o_config.name;
		}

		if (Ext.isObject(o_columns)) {

			Ext.Object.each(o_columns, function(s_key, o_column) {

				var o_clone = Ext.apply({}, o_column);
				o_clone.name = s_key;
				a_columns.push(o_clone);
			});
		}
		else {
			a_columns = o_columns.slice();
		}

		var o_field = {
			column: {}
		};;

		Ext.Array.each(a_columns, function(o_column) {
			if (o_config.dataIndex == o_column.name) {
				o_field.column = o_column;
				return false;
			}
		});

		// set column width / flex
		if (!o_config.width) {
			o_config.flex = 1;
		}

		Ext.applyIf(o_config, o_field.column);

		if (o_config.dataIndex == "PROPERTIES" && o_config.title) {
			o_config.header = o_config.title;
		}

		// Translate the o_config header
		if (o_config.header) {
			var s_title = o_config.header;
			if (Ext.isObject(s_title)) {
				o_config.header = ip2.dmdTranslate(o_model, s_title);
			}
		}
		else if (o_config.title) {
			var s_title = o_config.title;
			if (Ext.isObject(s_title)) {
				o_config.header = ip2.i18n(s_title);
			}
			else {
				o_config.header = s_title;
			}
		}

		return o_config;
	},

	/* ----------------------------------------------------------------------------------------------------
	Setup using collection information from xpd
	---------------------------------------------------------------------------------------------------- */
	setupCollection: function() {

		var i_self = this;
		var i_wrapper = i_self.getWrapper();
		var o_collection = i_self.getCollection();
		var a_sorters = [];

		var properties = function() {
			//"filter": "jsonPropsIn(properties, "__cid__", "5,6") = 1",
			var args = Array.prototype.slice.call(arguments);
			var cids = args.join(",");
			return "jsonPropsIn(" + me.collection.propertyFieldName + ", \"__cid__\", \"" + cids + "\") = 1";
		};

		var s_title = i_self.title || ip2.xpd.translate(i_wrapper.xpd, i_self.collection.title);

		i_self.setNamePrefix("hasMany");
		i_self.setTitle(s_title);
		i_self.iconCls = "ip2-tree-application-group";
		i_self.setCid(o_collection.id);

		if (o_collection.xpdbind) {
			i_self.setFilter(eval(o_collection.xpdbind));
		};

		var i_model = ip2.model({
			dmd: o_collection.dmd,
			entityName: o_collection.entity,
			uiName: o_collection.uiName || "portfolio",
			context: o_collection.context || "grid",
			dataLibrary: (i_wrapper && i_wrapper.wrapper && Ext.isFunction(i_wrapper.wrapper.getDataLibrary)) ? i_wrapper.wrapper.getDataLibrary() : "",
			container: i_wrapper.wrapper.ownerCt
		});

		var o_params = {
			action: "getRows",
			context: "grid",
			uiName: o_collection.uiName || "portfolio",
			dmdFile: o_collection.dmd || "dmd/webshop.dmd",
			language: o_collection.languageColumn ? ip2.session.getLanguage() : "",
			languageColumn: o_collection.languageColumn || ""
		};


		if (i_self.getCid()) {

			var a_fields = i_model.getFields();

			var i_cidField = Ext.create("Ext.data.Field", {
				name: "cid",
				type: "int"
			});

			a_fields.push(i_cidField);

			i_model.addFields(a_fields);

			var o_extraData = [{
				"property": "cid",
				"value": i_self.getCid()
			}];

			o_params.extraData = Ext.encode(o_extraData);
		}

		if (o_collection.entity) {
			var o_info = ip2.dmd.getInfo({
				dmd: o_collection.dmd || "dmd/webshop.dmd",
				view: o_collection.uiName,
				entity: o_collection.entity,
				context: "grid"
			});
			var o_ui = o_info.view;

			//var ui = ip2.entity.getUI(o_collection.entity, "grids", o_collection.uiName);
			if (o_ui.sort) {
				o_params.sort = o_ui.sort;
				a_sorters = Ext.Array.map(o_ui.sort.split(","), function (s_value) {
					var a_split = Ext.Array.filter(s_value.split(" "), Boolean);
					return {
						property: a_split[0],
						direction: a_split[1] ? a_split [1] : "ASC"
					};
				});
			}
		}

		var i_store = Ext.create("Ext.data.BufferedStore", {
			model: i_model,
			sorters: a_sorters,
			remoteSort: true,
			autoSync: false,
			pageSize: 100,
			proxy: ip2.getProxyByEntity({
				dmd: o_collection.dmd || "dmd/webshop.dmd",
				view: o_collection.uiName,
				entity: o_collection.entity,
				context: "grid"
			})
		});

		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();
		Ext.apply(o_extraParams, o_params);

		return i_store;
	},

	/* ----------------------------------------------------------------------------------------------------
	Keyboard mapping (short-cut)
	---------------------------------------------------------------------------------------------------- */
	keyMapping: function() {

		var i_self = this;

		var i_keyMap = Ext.create("Ext.util.KeyMap", {
			target: i_self.getEl(),
			binding: [
				{
					key: "b",
					ctrl: true,
					fn: function() {
						i_self.addRow();
					},
					scope: this,
					defaultEventAction: "stopEvent"

				}
			]
		});
	},

	/* ----------------------------------------------------------------------------------------------------
	Set focus
	---------------------------------------------------------------------------------------------------- */
	setFocus: function(s_component) {

		var i_self = this;

		if (s_component == "grid") {
			var selModel = i_self.getSelectionModel();
			i_self.getView().focus();
			selModel.select(0);
			var records = selModel.getSelection();
			i_self.fireEvent("selectionchange", selModel, records);
		}
		else {
			if (!i_self[s_component]) {
				return false;
			}

			i_self[s_component].focus();
		}

		return true; // set focus successed
	},

	/* ----------------------------------------------------------------------------------------------------
	Get the i18n text
	---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return (ip2.folderorganizer) ? ip2.folderorganizer.getTextValue(key) : key;
	}
});
Ext.define('Ext.ux.folderorganizer.Content', {
	extend: 'Ext.tab.Panel',
	border: 0,
	initComponent: function() {
		var me = this;

		me.counter = 0;
		me.folderSelection = {};

		Ext.tip.QuickTipManager.init();

		// flatten xpd, if passed
		if (me.xpd) {
			me.xpd.flatten = ip2.xpd.flatten(me.xpd);
			ip2.each(me.xpd.flatten.collections, function(collection) {
				collection.uiName = me.uiName || 'portfolio';
			});
		}

		me.items = [];
		me.contents = [];

		me.listeners = {
			nodeselection: function(node) {
				me.folderNodeSelected(node);
			}
		};

		me.callParent();
	},

	/* ----------------------------------------------------------------------------------------------------
	    Folder node selected -> Show content depending on cid
	   ---------------------------------------------------------------------------------------------------- */
	folderNodeSelected: function(node) {
		var me = this;
		var o_rowprops;

		me.folderSelection = node;

		if (node.get("rowProps")) {
			o_rowprops = Ext.decode(node.get("rowProps"));
		}

		if (me.alwaysShowGrid) {
			var collection = this.xpd.flatten.collections[3];
			if (collection && collection.entity) {
				if (Ext.isEmpty(me.contents[collection.id])) {
					me.contents[collection.id] = me.createChild(this.xpd, collection, true);
					me.add(me.contents[collection.id]);
				}
			}
		}
		else {
			// hide and collaps all children
			me.hideChildren();

			var properties = Ext.decode(node.data.PROPERTIES, true) || {};
			var parentCid = properties.__cid__;

			if (!parentCid || parentCid == 0) {
				return;
			}

			var childrenCids = me.getChildrenCids(parentCid);
			if (!childrenCids) {
				return;
			}

			var o_collections = me.xpd.flatten.collections;
			for (var i = 0; i < childrenCids.length; i++) {
				var collection = o_collections[childrenCids[i]];
				if (collection && collection.entity) {
					if (Ext.isEmpty(me.contents[collection.id])) {
						me.contents[collection.id] = me.createChild(this.xpd, collection, true);
						me.add(me.contents[collection.id]);
					}
				}
			}
		}
		me.showChildren(node, childrenCids, o_rowprops);
	},

	showChildren: function(i_node, a_childrenCids, o_rowprops) {

		var i_self = this;
		var o_properties = Ext.decode(i_node.get("PROPERTIES"));
		var o_collections = i_self.xpd.flatten.collections;

		Ext.Array.each(a_childrenCids, function(n_cid) {

			var o_collection = o_collections[n_cid];

			if (o_collection.entity) {

				var i_child = i_self.contents[n_cid];

				var i_element = i_child.getEl();

				if (i_element) {

					i_child.tab.show();
					i_element.setDisplayed(true);

					if (Ext.isFunction(i_child.doLayout)) {

						i_child.doLayout();
					}
					else if (Ext.isFunction(i_child.updateLayout)) {
						i_child.updateLayout();
					}
				}
			}
		});

		i_self.setActiveTab(0);
	},

	hideChildren: function() {

		var i_self = this;
		var a_children = i_self.items.items;

		Ext.Array.each(a_children, function(i_child) {

			var i_element = i_child.getEl();

			if (i_element) {

				i_child.tab.hide();
				i_element.setDisplayed(false);
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
	    get children cids
	   ---------------------------------------------------------------------------------------------------- */
	getChildrenCids: function(cid) {
		var collection = this.xpd.flatten.collections[cid];
		if (collection) {
			return collection.allowedchilds;
		}
		else {
			return [];
		}
	},

	/* ----------------------------------------------------------------------------------------------------
	    create child
	   ---------------------------------------------------------------------------------------------------- */
	createChild: function(o_xpd, collection, collapsed) {
		var me = this;

		if (collection.widget) {
			return me.createWidget(collection);
		}
		else if (collection.dmd && collection.entity) {
			return me.createDmdPagingGrid(collection);
		}
		else {
			return Ext.create('Ext.panel.Panel', {
				wrapper: me,
				title: ip2.xpd.translate(me.xpd, collection.title),
				iconCls: 'ip2-tree-application-group',
				collection: me.xpd.flatten.collections[collection.id],
				collapsed: collapsed
			});
		}
	},

	/* ----------------------------------------------------------------------------------------------------
	    create Item grid
	   ---------------------------------------------------------------------------------------------------- */
	createDmdPagingGrid: function(collection) {
		var me = this;

		var panel = Ext.create('Ext.ux.folderorganizer.Itemgrid', {
			wrapper: me,
			displayFilterField: true,
			namePrefix: collection.entity,
			buttons: ['refresh'],
			collection: this.xpd.flatten.collections[collection.id],
			filter: (this.filter) ? this.filter : null,
			copyNode: (me.copyNode === true) ? true : false
		});
		panel.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved']);

		return panel;
	},

	/* ----------------------------------------------------------------------------------------------------
	    create Widget
	   ---------------------------------------------------------------------------------------------------- */
	createWidget: function(collection) {
		return Ext.create('Ext.ux.container.Ip2Widget', {
			src: collection.widget,
			border: false,
			collection: collection
		});
	},

	/* ----------------------------------------------------------------------------------------------------
	    Set menu button status (disabled / enable)
	   ---------------------------------------------------------------------------------------------------- */
	setMenuStatus: function(menu, id, status) {
		menu.getComponent(id).setDisabled(status);
	},

	/* ----------------------------------------------------------------------------------------------------
	    Get i18n text by language
	   ---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return ip2.folderorganizer.getTextValue(key);
	}
});
Ext.define('Ext.ux.folderorganizer.TreeSelector', {

	extend: 'Ext.tree.Panel',

	alias: [
		'widget.ip2TreeSelector',
		'widget.ip2treeSelector',
		'widget.ip2treeselector'
	],

	useArrows: true,

	rootVisible: false,

	singleExpand: false,

	autoScroll: true,

	border: true,

	initComponent: function () {

		var me = this;

		me.title = ip2.i18n(me.title);

		me.initialize();

		me.clearSelection();

		// initialize tree column
		me.columns = [{
			xtype: 'treecolumn',
			dataIndex: 'TITLE',
			flex: 1,
			text: ip2.i18n({
				da: 'Beskrivelse',
				en: 'Description'
			}),
			renderer: function (value, meta, record, rowIndex, colIndex, store, view) {
				if (value && value.length > 0) {
					return ip2.i18n(value);
				}
				else {
					var props = {};
					if (ip2.isStringedObject(record.data.PROPERTIES)) {
						props = Ext.decode(record.data.PROPERTIES);
					}
					else {
						var o_props = {};
						var a_split = record.data.PROPERTIES.split(",");
						ip2.each(a_split, function(s_props) {
							var a_propsplit = s_props.split(":");
							if (a_propsplit.length == 2) {
								o_props[a_propsplit[0].trim()] = a_propsplit[1].trim();
							}
						});
						props = o_props;
						record.data.PROPERTIES = JSON.stringify(o_props);
					}
					var cid = props.__cid__;
					var collection = me.getXpdCollection(cid);
					var title = '';

					if (collection && collection.properties) {
						for (var name in collection.properties) {
							if (collection.properties[name].isTitle) {
								title = me.concatTitle(title, props[name]);
							}
						}
						title = ip2.i18n(title);
					}
					if (title.length == 0) {
						if (me.environment && record.data[me.environment]) {
							props = Ext.decode(record.data[me.environment]);
							if (props && props.properties && props.properties.title) {
								title = ip2.i18n(props.properties.title);
							}
						}
					}
					if (title.length == 0) {
						if (record.data.rowProps || record.data.extraProps) {
							props = Ext.decode(record.data.rowProps || record.data.extraProps);
							if (props && props.properties && props.properties.title) {
								title = ip2.i18n(props.properties.title);
							}
							if (title.length == 0) {
								if (props && props.properties && props.properties.name) {
									title = ip2.i18n(props.properties.name);
								}
							}
						}
					}
					return title;
				}
			}
		}];

		if (me.xpd) {
			me.columns = Ext.ux.folderorganizer.Util.addCollectionColumns(me, me.columns);
		}

		me.hideHeaders = true;
		if (me.columns.length > 1) {
			me.hideHeaders = false;
		}

		var extraParams = {
			action: 'treeStore',
			entity: me.entity,
			cid: me.cid.root,
			childCid: me.cid.child,
			xpd: me.xpdPath,
			dmd: me.dmdPath,
			menus: '',
			displayRootNode: me.displayRootNode,
			displayCheckbox: true,
			language: ip2.session.getLanguage(),
			idField: me.propertyNameMapping.ID,
			parentidField: me.propertyNameMapping.PARENTID,
			propertiesField: me.propertyNameMapping.PROPERTIES
		};

		if (me.omitCid) {
			extraParams.omitCid = me.cid.child;
		}
		if (me.environment) {
			extraParams.environment = me.environment;
		}
		if (me.extraProps) {
			extraParams.extraProps = me.extraProps;
		}
		if (me.filter) {
			extraParams.filter = me.filter;
		}

		var fields = [
			{
				name: 'TITLE',
				type: 'string',
				title: 'Folder'
			},
			{
				name: 'ID',
				type: 'int'
			},
			{
				name: 'PARENTID',
				type: 'int'
			},
			{
				name: 'PROPERTIES',
				type: 'string'
			}
		];

		// extra data model fields
		if (me.environment) {
			fields.push({
				name: 'extraProps',
				type: 'string'
			});
		}
		if (me.extraProps) {
			fields.push({
				name: 'rowProps',
				type: 'string'
			});
		}

		// Insert extra columns
		if (me.extraColumns && me.extraColumns.length > 0) {

			for (var i = 0; i < me.extraColumns.length; i++) {

				var column = Ext.apply({}, me.extraColumns[i]);

				if (Ext.isObject(column.text)) {
					column.text = ip2.i18n(column.text);
				}

				// ui type and renderer
				if (column.uitype && ip2.uitypes[column.uitype]) {
					var uitype = ip2.uitypes[column.uitype];

					// uitype require ?
					if (uitype.require) {
						Ext.require(uitype.require);
					}
					column.subRenderer = uitype.editor.renderer;

					//column.renderer = uitype.editor.renderer;
					column.renderer = function(value, meta, record, rowIndex, colIndex, store, view) {
						if (me.environment && record.data[me.environment]) {

							var header = view.getGridColumns()[colIndex];
							var props = Ext.decode(record.data[me.environment]);

							if (props && props.properties) {
								var value = props.properties[header.dataIndex];
								return header.subRenderer.call(header, value);
							}
						}
					};
				}
				me.hideHeaders = false;
				me.columns.push(column);
			}
		}

		var s_model = ip2.unique('FolderOrganizerModel-');

		Ext.define(s_model, {
			extend: 'Ext.data.Model',
			fields: fields,
			proxy: {
				type: 'ajax',
				url: me.proxy,
				extraParams: extraParams
			}
		});

		me.store = Ext.create('Ext.data.TreeStore', {
			model: s_model,
			clearOnLoad: false,
			autoLoad: true,
			listeners: {
				beforeload: {
					fn: function(store, operation) {
						var i_node = operation.node;
						var i_proxy = operation.getProxy();
						var o_extraParams = i_proxy.getExtraParams();
						o_extraParams.node = i_node.get("ID");
						delete operation.node;
					}
				},
				'load': {
					fn: function (i_store, a_records, b_success, i_node) {
						if (me.expandRootNode && i_node.getId() == 'root') {
							ip2.each(a_records, function(i_record) {
								i_record.expand();
							});
						}
					}
				}
			}
		});

		me.rowMenu = Ext.create('Ext.menu.Menu', {
			items: [{
				text: ip2.i18n({ da: 'Sæt flueben på alle underliggende rækker', en: 'Check all rows below' }),
				iconCls: 'ip2-icon-checks',
				handler: function() {
					me.checkAllNodesBelow(me.node);
				}
			},{
				text: ip2.i18n({ da: 'Fjern flueben på alle underliggende rækker', en: 'Uncheck all rows below' }),
				iconCls: 'ip2-icon-undo',
				handler: function() {
					me.uncheckAllNodesBelow(me.node);
				}
			}]
		});

		me.listeners = me.listeners || {};

		Ext.apply(me.listeners, {
			itemcontextmenu: function(view, node, item, index, e) {
				e.stopEvent();
				me.getSelectionModel().select(node);
				me.node = node;
				var coords = e.getXY();
				me.rowMenu.showAt([coords[0], coords[1]]);
			},
			checkchange: function(node, checked) {
				if (checked && !node.isLeaf() && me.multiChoice) {
					// new checked and multi choice active
					var showWarning = true;

					var cid = Ext.ux.folderorganizer.Util.getXpdCollectionId(me, node);
					var collection = Ext.ux.folderorganizer.Util.getXpdCollection(me, cid);
					if (collection && collection.allowedchilds && collection.allowedchilds[0] && collection.allowedchilds[0] == me.cid.child) {
						showWarning = false;
					}

					if (showWarning) {
						me.multiChoice.node = node;
						me.multiChoice.show();
					}
				}
				else {
					me.checkChangeSingleNode(node, checked);
				}
			},
			select: function(view, node, index, e) {
				Ext.ux.folderorganizer.Util.setCollectionColumnHeader(me, node);
			}
		});

		me.callParent(arguments);

		var parent = (Ext.isFunction(me.wrapper.getRecord)) ? me.wrapper : (Ext.isFunction(me.wrapper.getDataParent)) ? me.wrapper.getDataParent() : null;

		if (parent instanceof Ext.ux.container.Ip2Widget) {
			var i_form = parent.up("entityform");
			if (i_form) {
				parent = i_form;
			}
		};

		if (parent && Ext.isFunction(parent.getRecord)) {

			me.record = parent.getRecord(me);

			if (me.record) {
				me.onParentLoad();
			}

			// wait for data parent store loaded
			else {

				var store = me.wrapper.getDataParent().getStore();

				store.on('load', function (store, records) {

					if (Ext.isArray(records)) {
						me.record = records[0];
						me.onParentLoad();
					}
				});
			}
		}
		me.enableBubble("dirtychange");
	},

	/**
	 * @method on parent load
	 *
	 */
	onParentLoad: function () {

		var me = this;

		me.clearSelection();

		me.getData(me.setExisting);
	},

	isDirty: function () {

		var i_cmp = this;
		var i_store = i_cmp.store;
		var a_nodes = i_store.getData().items;
		var b_dirty = false;

		ip2.each(a_nodes, function(i_node) {
			if (i_node.dirty) {
				b_dirty = true;
			}
		});

		return b_dirty;
	},

	resetDirty: function() {

		var i_self = this;
		var i_store = i_self.getStore();
		var a_nodes = i_store.getData().items;
		ip2.each(a_nodes, function(i_node) {
			i_node.oldChecked = i_node.get("checked");
			i_node.dirty = false;
		});
		i_self.fireEvent("dirtychange", i_self, false);
	},

	/**
	 * @method Set Existing: set checkbox as checked for already existing relation
	 *
	 */
	setExisting: function (a_records) {

		var i_cmp = this;

		i_cmp.existing = {
			ID: []
		};

		if (!a_records) {
			return;
		}

		// create unique array with parents
		var a_parentTokens = [];

		// Build the parentToken array
		Ext.Array.each(a_records, function (i_record) {

			var s_parents = i_record.get('parents');
			var a_parents = s_parents.split(',');

			Ext.Array.each(a_parents, function (n_parent) {
				// Only push if not already in parentToken array
				if (Ext.Array.indexOf(a_parentTokens, n_parent) == -1) {
					a_parentTokens.push(n_parent);
				}
			});
		});

		// expand all parents and set check mark when expanding is finished
		i_cmp.expandParent({
			index: 0,
			parents: a_parentTokens,
			records: a_records,
			success: function (a_records) {

				Ext.Array.each(a_records, function (i_base) {

					var s_parents = i_base.get('parents');
					var a_parents = s_parents.split(',');
					var s_token = a_parents.pop();

					i_cmp.setCheck(s_token, true);
					i_cmp.existing.ID.push(s_token);

					// Make sure the relevant record checked is not flagged
					// as dirty due to check change
					var i_record = i_cmp.store.findRecord("ID", s_token, 0, true, false, false);
					if (i_record) {
						var b_clean = false;
						if (Ext.Object.getSize(i_record.modified) == 1) {
							b_clean = true;
						}
						i_record.raw.checked = true;
						if (b_clean) {
							i_record.dirty = false;
						}
					}
				});
				i_cmp.getView().refresh();
			}
		});
	},

	/**
	 * @method expand parent
	 *
	 */
	expandParent: function (args) {

		var me = this;

		if (args.index >= args.parents.length) {

			var task = new Ext.util.DelayedTask(function () {
				Ext.callback(args.success, me, [args.records]);
			});

			task.delay(300);

			return false;
		}

		var node = me.store.findNode("ID", args.parents[args.index], true, 0, false, false);

		if (node && !node.isExpanded()) {

			node.expand(false, function () {

				args.index = args.index + 1;

				var task = new Ext.util.DelayedTask(function () {
					me.expandParent(args);
				});

				task.delay((args.index >= args.parents.length) ? 0 : 300);
			}, me);
		}
		else {

			args.index = args.index + 1;

			me.expandParent(args);
		}
	},

	/**
	 * @method check all nodes below
	 *
	 */
	checkAllNodesBelow: function (node) {
		var me = this;

		var setCheck = function(node) {
			node.set('checked', true);
			me.checkChangeSingleNode(node, true);
			if (node.hasChildNodes()) {
				for (var i = 0; i < node.childNodes.length; i++) {
					setCheck(node.childNodes[i]);
				}
			}
		};

		node.expand(true, function() {
			setCheck(node);
		});
	},

	/**
	 * @method uncheck all nodes below
	 *
	 */
	uncheckAllNodesBelow: function (node) {
		var me = this;

		var setUncheck = function(node) {
			node.set('checked', false);
			me.checkChangeSingleNode(node, false);
			if (node.hasChildNodes()) {
				for (var i = 0; i < node.childNodes.length; i++) {
					setUncheck(node.childNodes[i]);
				}
			}
		};

		node.expand(true, function() {
			setUncheck(node);
		});
	},

	/**
	 * @method set uncheck for already check (single selection)
	 *
	 */
	singleSelection: function () {
		var me = this;

		for (var i = 0; i < me.existing.ID.length; i++) {
			me.setCheck(me.existing.ID[i], false);
		}
		me.existing.ID = [];

		for (var i = 0; i < me.checkedItems.ID.length; i++) {
			me.setCheck(me.checkedItems.ID[i], false);
		}
		me.checkedItems.ID = [];
	},

	/**
	 * @method set check or uncheck
	 *
	 */
	setCheck: function (s_token, b_checked) {

		var i_cmp = this;
		var i_store = i_cmp.store;
		var i_node = i_store.findNode("ID", s_token, 0, true, false, false);

		if (i_node) {
			i_node.set('checked', b_checked);
		}
	},

	/**
	 * @method set check or uncheck for single node and update array
	 *
	 */
	checkChangeSingleNode: function (node, checked) {

		var me = this;

		var token = node.data.ID;

		if (me.checkedItems.ID.indexOf(token) > -1) {
			var pos = me.checkedItems.ID.indexOf(token);
			me.checkedItems.ID.splice(pos, 1);
		}
		if (me.uncheckedItems.ID.indexOf(token) > -1) {
			var pos = me.uncheckedItems.ID.indexOf(token);
			me.uncheckedItems.ID.splice(pos, 1);
		}
		if (checked) {
			// new checked
			if (!me.multiSelect) {
				me.singleSelection();
			}
			me.checkedItems.ID.push(token);
			me.setCheck(token, true);
		}
		else {
			// existing unchecked
			me.uncheckedItems.ID.push(token);
		}

		me.fireEvent('change', me, me.checkedItems.ID);
	},

	/**
	 * @method getvalue
	 *
	 */
	getValue: function () {

		return this.checkedItems;
	},

	/**
	 * @method doSave
	 *
	 */
	doSave: function () {
		var me = this;

		// checked
		for (var i = 0; i < me.checkedItems.ID.length; i++) {
			var node = me.getNode(me.checkedItems.ID[i]);
			var token = node.data.ID;
			me.doUpdate('update', token);
		}

		// unchecked
		if (me.multiSelect || me.checkedItems.ID.length == 0) {

			for (var i = 0; i < me.uncheckedItems.ID.length; i++) {

				var node = me.getNode(me.uncheckedItems.ID[i]);
				var token = node.data.ID;
				me.doUpdate('remove', token);
			}
		}

		me.existing.ID = me.checkedItems.ID;
		me.clearSelection();
		me.resetDirty();

		me.fireEvent('savecomplete', me, true);
	},

	/**
	 * @method doUpdate
	 *
	 */
	doUpdate: function (action, token) {

		var me = this;

		Ext.Ajax.request({
			url: me.proxy,
			params: {
				action: (action == 'update') ? 'addItemToParent' : 'removeItemFromParent',
				token: token,
				item: me.getKeyValue(),
				cid: me.cid.child
			}
		});
	},

	/**
	 * @method doDelete (empty function). Make you own function :-)
	 *
	 */
	doDelete: function () {

		var me = this;

		var key = {
			product: me.getKeyValue()
		};

		// existing
		for (var i = 0; i < me.existing.ID.length; i++) {
			var node = me.getNode(me.existing.ID[i]);
			var token = node.data.ID;
			me.setCheck(token, false);
			me.doUpdate('remove', token);
		}

		// checked
		for (var i = 0; i < me.checkedItems.ID.length; i++) {
			var node = me.getNode(me.checkedItems.ID[i]);
			var token = node.data.ID;
			me.setCheck(token, false);
			me.doUpdate('remove', token);
		}
	},

	/**
	 * @method get data for this product
	 *
	 */
	getData: function (f_callback) {

		var i_cmp = this;
		var i_store = i_cmp._dataStore;

		if (!i_store) {

			var s_entity = i_cmp.entity;
			var s_proxy = i_cmp.proxy;
			var n_token = i_cmp.getKeyValue();
			var n_cid = i_cmp.cid.child;
			var s_action;

			// Find correct action to use for service
			switch (s_entity) {
				case 'WSHSTCET00':
					s_action = 'getParentByOrganizedPage';
				break;
				default:
					s_action = 'getParentByOrganizedItem';
				break;
			}

			i_store = i_cmp._dataStore = Ext.create('Ext.data.Store', {
				autoLoad: false,
				fields: [
					{ name: 'ID', type: 'string' },
					{ name: 'parents', type: 'string' }
				],
				idProperty: 'ID',
				proxy: {
					type: 'ajax',
					url: s_proxy,
					extraParams: {
						action: s_action,
						token: n_token,
						entity: s_entity,
						cid: n_cid
					},
					reader: {
						type: 'json',
						rootProperty: 'rows'
					}
				}
			});
		}

		i_store.on({
			'load': {
				fn: function (i_self, a_records) {
					f_callback.call(i_cmp, a_records);
				},
				scope: i_cmp,
				single: true
			}
		});

		i_store.load();
	},

	/**
	 * @method getKeyValue
	 *
	 */
	getKeyValue: function () {
		var me = this;

		if (me.record) {
			switch (me.entity) {
				case 'WSHSTCET00':
					return (me.record.data.link && me.record.data.link.token) ? me.record.data.link.token : 0;
				break;
				default:
					return me.record.data.ITMITMTKN || me.record.id;
				break;
			}
		}
		else {
			return '';
		}
	},

	/**
	 * @method get node data
	 *
	 */
	getNode: function (id) {

		var i_self = this;
		var i_store = i_self.getStore();
		return i_store.findNode("ID", id, id, id, true);
	},

	/**
	 * @method clean up selection
	 *
	 */
	clearSelection: function () {

		this.checkedItems = {
			ID: []
		};
		this.uncheckedItems = {
			ID: []
		};
	},

	/**
	 * @method: Get XPD collection by cid
	 *
	 */
	getXpdCollection: function (n_cid) {

		var i_cmp = this;
		var o_xpd = i_cmp.xpd;
		var o_return = null;

		if (o_xpd && o_xpd.flatten.collections[n_cid]) {
			o_return = o_xpd.flatten.collections[n_cid];
		}

		return o_return;
	},

	/**
	 * @method: Concat nice title
	 *
	 */
	concatTitle: function (title, value) {

		var v = value || '';

		return (title) ? title + ' ' + v : v;
	},

	initialize: function () {

		var me = this;

		me.cid = me.cid || {
			root: 0,
			child: 0
		};
		me.displayRootNode = Ext.isBoolean(me.displayRootNode) ? me.displayRootNode : true;
		me.expandRootNode = Ext.isBoolean(me.expandRootNode) ? me.expandRootNode : true;
		me.multiSelect = Ext.isBoolean(me.multiSelect) ? me.multiSelect : true;
		me.omitChild = Ext.isBoolean(me.omitChild) ? me.omitChild : true;

		if (!me.propertyNameMapping) {

			if (me.entity && me.entity == 'WSHNAMET00') {
				me.propertyNameMapping = {
					ID: 'NAMNAMTKN',
					PARENTID: 'NAMPNTTKN',
					PROPERTIES: 'NAMPROP'
				};
			}
			else if (me.entity && me.entity == 'WSHSTCET00') {
				me.propertyNameMapping = {
					ID: 'STCSTCTKN',
					PARENTID: 'STCPNTTKN',
					PROPERTIES: 'STCPROP'
				};
			}
			else {
				me.propertyNameMapping = {
					ID: 'FLDFLDTKN',
					PARENTID: 'FLDPNTTKN',
					PROPERTIES: 'FLDPROP'
				};
			}
		}
		me.propertyNameMappingReverse = {};
		for (var key in me.propertyNameMapping) {
			me.propertyNameMappingReverse[me.propertyNameMapping[key]] = key.toString();
		}

		// initialize dmd -& xpd path and object
		me.dmdName = me.dmd;
		me.dmdPath = me.dmdName;
		me.xpdName = me.xpd;
		me.xpdPath = me.xpdName;
		me.xpd = ip2.resource.get(me.xpdName);

		if (me.xpd) {
			me.xpd.flatten = ip2.xpd.flatten(me.xpd);
		}

		// prepare multi choice dialog box
		if (me.addToAllChildren && me.addToAllChildren.allow && me.addToAllChildren.warning && me.addToAllChildren.multiChoiceDialog) {
			var mcd = me.addToAllChildren.multiChoiceDialog;
			var questions = [];
			for (var i = 0; i < mcd.questions.length; i++) {
				questions.push({
					answer: i,
					question: ip2.i18n(mcd.questions[i])
				});

				switch (i) {
					case 0:
						questions[i].icon = '/system/images/icons/16x16/check2.png';
					break;
					case 1:
						questions[i].icon = '/system/images/icons/16x16/checks.png';
					break;
					case 2:
						questions[i].icon = '/system/images/icons/16x16/undo.png';
					break;
				}
			}
			me.multiChoice = Ext.create('Ext.ux.folderorganizer.MultiChoice', {
				title: ip2.i18n(mcd.title),
				questions: questions,
				guideLine: ip2.i18n(mcd.guideLine),
				modal: true,
				handler: function(answer) {
					switch (answer) {
						case 0:

							// do nothing
						break;
						case 1:

							// mark all below
							me.checkAllNodesBelow(this.node);
						break;
						case 2:
							this.node.set('checked', false);
						break;
					}
				}
			});
		}
	}

});
/**
 * @class Ext.ux.ip2.component.groupSelector.Selector
 *
 * @extend Ext.container.Container
 *
 */

Ext.define('Ext.ux.folderorganizer.Selector', {

	alias: ['widget.ip2GroupSelector'],

	extend: 'Ext.ux.form.JsonForm',

	plugins: [
		{
			ptype: 'datatracker'
		}
	],

	config: {

		fieldsetConfig: {

			padding: 15
		},

		cid: null,

		valueKey: null,

		fieldsetTitle: 'Fieldset',

		proxy: null,

		defaultHive: 'admin',

		dmd: null,

		entity: null,

		xpd: null,

		trackerParent: null,

		batchName: null,

		propertyNameMapping: {
			ID: 'ID',
			PARENTID: 'PARENTID',
			PROPERTIES: 'PROPERTIES'
		}

	},

	collections: null,

	border: false,

	keyField: null,

	_store: null,

	initComponent: function() {

		var selector = this,
			fieldsetConfig;

		selector.initConfig(selector.initialConfig);

		if (selector.proxy && selector.proxy.length > 0) {
			selector.serviceUrl = selector.proxy;
		}
		else {
			selector.serviceUrl = ip2.getWepshopProxyUrl(selector.wrapper);
		}

		selector.callParent();

		selector.collections = [];

		// Prepare the fieldset config to add to selector
		fieldsetConfig = selector.getFieldsetConfig();

		// Setup property name
		selector.propertyNameMapping = selector.getPropertyNameMapping();
		selector.propertyNameMappingReverse = {};
		for (var key in selector.propertyNameMapping) {
			selector.propertyNameMappingReverse[selector.propertyNameMapping[key]] = key.toString();
		}

		Ext.Object.merge(fieldsetConfig, {
			xtype: 'fieldset',
			items: [
				{
					xtype: 'checkboxgroup',
					vertical: true,
					columns: 2,
					border: false,
					listeners: {
						'added': {
							fn: function(self) {

								selector._checkboxgroup = self;
							}
						}
					}
				}
			]
		});

		// Add fieldset to selector and set private variable
		selector._fieldset = selector.add(fieldsetConfig);

		// Prepare the store for selector
		selector.dmdName = selector.getDmd();
		selector.dmdPath = selector.dmdName,

		selector.setStore({
			dmdName: selector.dmdName,
			entityName: selector.getEntity(),
			dataLibrary: selector.dataLibrary || ''
		});

		// Load and add the XPD to the selector
		selector.addXpd();

		if (selector.cid) {

			selector.doAfterInit();
		}
		else if (selector.whoami) {

			selector.doWhoami(selector.whoami);
		}

		return selector;
	},

	addXpd: function() {

		var selector = this;
		var servicePath = "/ip2-services/";

		selector.xpdName = selector.getXpd();
		selector.xpdPath = selector.xpdName;

		// Get the flattened XPD in a synchronized request and add to selector
		selector.xpd = ip2.resource.get(selector.xpdName, true);

		return selector;
	},

	doAfterInit: function() {

		this.cid.child = Ext.isArray(this.cid.child) ? this.cid.child : [this.cid.child];
		this.cid.parent = Ext.isArray(this.cid.parent) ? this.cid.parent : [this.cid.parent];

		var selector = this;

		// Prepare an collections array to store found collections in
		selector.collections = [];

		// Iterate each found cid child to find collections to push to selector
		Ext.Array.each(selector.cid.child, function(cid) {

			// Get the collection from the xpd via the iterated cid
			var collection = selector.xpd.collections[cid];

			// and push it..
			selector.collections.push(collection);

			// Iterate each of the found collections properties to look for
			// database bound key to set as selectors keyField
			Ext.Object.each(collection.properties, function(key) {

				if (collection.properties[key].isKey) {

					selector.keyField = collection.properties[key].databasebind;

					return false;
				}
			});
		});

		// Get the datatracker parent to get a record to use
		if (Ext.isFunction(selector.getDataParent)) {

			selector.doDataTracker();
		}
		else {

			selector.on({
				'datatrackerinit': {
					fn: function() {

						selector.doDataTracker();
					}
				}
			});
		}
	},

	doDataTracker: function() {

		var selector = this,
			dataParent = selector.getDataParent(),
			record = dataParent.getRecord();

		// Data parent record is already loaded and found
		if (record) {

			selector.record = record;

			// Everything is honky dory - lets actually load
			selector.onParentLoad();
		}

		// No record yet - wait for data parent store loaded
		else {

			var store = selector.getDataParent().getStore();

			store.on('load', function(store, records) {

				if (Ext.isArray(records)) {

					record = records[0];

					selector.record = record;

					selector.onParentLoad();
				}
			});
		}
	},

	/**
	 * @method getChildComponent
	 *
	 */
	onParentLoad: function() {

		var selector = this;

		selector.clearSelection();

		selector.getData(function (fetched) {

			Ext.define('Ext.ux.folderorganizer.model.GroupSelector', {
				extend: 'Ext.data.Model',
				fields: [
					{ name: 'ID', type: 'int' },
					{ name: 'TITLE', type: 'string' },
					{ name: 'CID', type: 'int' }
				],
				idProperty: 'ID',
				proxy: {
					type: 'ajax',

					// TODO: To join with comma on selector.cid.parent
					url: selector.serviceUrl + '?action=getProductGroups&cid=' + selector.cid.parent + '&skipGrandParent=true&delimiter=/',
					extraParams: {
						action: 'getProductGroups',
						dataLibrary: selector.dataLibrary || '',
						cid: selector.cid.parent,
						skipGrandParent: true,
						delimiter: '/',
						xpd: selector.xpdPath,
						orderBy: selector.orderBy || ''
					}
				}
			});

			selector.breadCrumbStore = Ext.create('Ext.data.Store', {
				model: 'Ext.ux.folderorganizer.model.GroupSelector',
				autoLoad: true,
				listeners: {
					load: function(store, records) {

						store.records = records;

						selector.addFields(fetched);
					}
				}
			});
		});
	},

	/**
	 * @method addFields
	 *
	 */
	addFields: function(fetched) {

		fetched = fetched || [];

		var selector = this,
			checkboxGroup = selector.getCheckboxgroup(),
			alreadyID = [],

			store = selector.breadCrumbStore,
			records = store.records || [],
			checkboxes = [];

		//columnWidth = selector.getColumnWidth(records),
		//containerWidth = fieldset.getWidth(),
		//columns = Math.floor(containerWidth / columnWidth);

		Ext.Array.each(fetched, function(selected) {

			var record,
				parentId,
				checkbox;

			parentId = selected.data.PARENTID;

			record = store.getById(parentId);

			if (record) {

				checkbox = selector.createCheckbox(record.data, selected.data.ID);

				checkboxes.push(checkbox);

				alreadyID.push(record.data.ID);
			}
		});

		// Iterate all records and add checkboxes to the group
		Ext.Array.each(records, function(record) {

			var checkbox;

			// Filter away those whos ID is in the alreadyID array
			// They will already have been added to checkboxes array
			if (Ext.Array.indexOf(alreadyID, record.data.ID) == -1) {

				checkbox = selector.createCheckbox(record.data, 0);

				checkboxes.push(checkbox);
			}
		});

		checkboxGroup.removeAll();

		checkboxGroup.add(checkboxes);

		return selector;
	},

	/**
	 * @method createCheckbox
	 *
	 */
	createCheckbox: function(data, recordID) {

		var selector = this;

		return {
			xtype: 'checkbox',
			name: 'selector_' + data.ID,
			parentId: +(data.ID),
			boxLabel: data.TITLE,
			checked: (recordID > 0) ? true : false,
			recordID: recordID,
			cid: data.CID,
			listeners: {
				change: function(box, newValue) {

					var pos;

					//if ( selector.checkedItems.PARENTID.indexOf(box.name) > -1 ) {
					if (Ext.Array.indexOf(selector.checkedItems.PARENTID, box.parentId) > -1) {

						pos = selector.checkedItems.PARENTID.indexOf(box.parentId);

						selector.checkedItems.PARENTID.splice(pos, 1);

						selector.checkedItems.ID.splice(pos, 1);
					}

					//if ( selector.uncheckedItems.PARENTID.indexOf(box.name) > -1 ) {
					if (Ext.Array.indexOf(selector.uncheckedItems.PARENTID, box.parentId) > -1) {

						pos = selector.uncheckedItems.PARENTID.indexOf(box.parentId);

						selector.uncheckedItems.PARENTID.splice(pos, 1);

						selector.uncheckedItems.ID.splice(pos, 1);
					}

					if (newValue) {

						// new checked
						if (!box.originalValue) {

							selector.checkedItems.PARENTID.push(box.parentId);

							selector.checkedItems.ID.push(box.recordID);
						}
					}

					// existing unchecked
					else if (box.originalValue) {

						selector.uncheckedItems.PARENTID.push(box.parentId);

						selector.uncheckedItems.ID.push(box.recordID);
					}
				}
			}
		};
	},

	doWhoami: function(whoami) {

		var selector = this,
			flatten = selector.xpd,
			children = [],
			parents = [],
			fixXpdbind;

		fixXpdbind = function(s) {

			var o = {};

			s.replace(/([a-z]+)\(([0-9,\s]+)\),?/gi, function(_, name, values) {
				o[name] = values.replace(/\s/g, '').split(',');
			});

			return o;
		};

		ip2.each(flatten.collections, function(coll, key) {

			if (key != 'all') {
				key = +key;

				var almostTrue = false;

				if (coll.dmdpath && coll.entity) {
					almostTrue = coll.entity == whoami.entity && coll.dmdpath.toLowerCase() == whoami.dmdPath.toLowerCase();
				}

				if (almostTrue) {

					if (coll.xpdbind) {

						var o = fixXpdbind(coll.xpdbind);

						ip2.each(o, function(cids, prop) {

							var index = -1;

							ip2.each(cids, function(cid, i) {
								if (cid == whoami.data[prop].__cid__) index = i;
							});

							if (index > -1) {
								children.push(key);
							}
						});
					}
					else {
						children.push(key);
					}
				}
			}
		});

		var inserted = 0;

		ip2.each(children.slice(), function(childId, index) {
			index += inserted;
			var allowedparents = flatten.collections[childId].allowedparents;

			parents = parents.concat(allowedparents);

			var insert = allowedparents.length - 1;
			inserted += insert;

			ip2.each(Array.apply(null, new Array(insert)), function() {
				children.splice(index, 0, childId);
			});
		});

		// TODO: Convert back to real array - we grab first right now for testing purposes
		selector.cid = {
			child: children,
			parent: parents
		};

		if (whoami.valueKey)
			selector.valueKey = whoami.valueKey;

		selector.doAfterInit();
	},

	getCheckboxgroup: function() {

		return this._checkboxgroup;
	},
	getFieldset: function() {

		return this._fieldset;
	},

	getStore: function() {

		var selector = this;

		return selector._store;
	},
	setStore: function(settings) {

		var selector = this,
			batchName = selector.getBatchName();

		selector._store = ip2._store({
			type: 'batch',
			model: ip2.model({
				dmd: settings.dmdName,
				entityName: settings.entityName,
				dataLibrary: settings.dataLibrary
			}),
			autoSync: false,
			batchName: batchName
		});

		selector._store.proxy.extraParams = {
			storeId: ip2.storeId(),
			uiName: 'common',
			context: 'form'
		};

		return selector;
	},

	/**
	 * @method getColumnWidth
	 *
	 */
	getColumnWidth: function(records) {

		var i = 0,
			maxLen = 0;

		for (; i < records.length; i++) {

			if (records[i].data.TITLE.length > maxLen)
				maxLen = records[i].data.TITLE.length;
		}

		return Math.floor((maxLen * 5.8) + 24); // title length + checkbox width;
	},

	/**
	 * @method getData
	 *
	 */
	getData: function(callback) {

		var selector = this,
			key = selector.getValueKey(),
			value = selector.getKeyValue();

		// get existing item data and load the records into writer store
		Ext.define('data', {
			extend: 'Ext.data.Model',
			fields: [
				{ name: 'ID', type: 'int' },
				{ name: 'PARENTID', type: 'int' },
				{ name: 'PROPERTIES', type: 'string' }
			],
			idProperty: 'ID',
			proxy: {
				type: 'ajax',
				url: selector.serviceUrl + '?action=getproperties&key=' + key + '&value=' + value,
				reader: {
					type: 'json',
					root: 'rows'
				},
				extraParams: {
					entity: 'WSHFLDET00',
					dataLibrary: selector.dataLibrary || ''
				}
			}
		});

		Ext.create('Ext.data.Store', {
			model: 'data',
			autoLoad: true,
			listeners: {
				load: function(store, records) {

					// Return the records as an array in the callback
					// Becomes "alreadySelected"

					Ext.callback(callback, selector, [records]);
				}
			}
		});
	},

	/**
	 * @method getKeyValue
	 *
	 */
	getKeyValue: function() {

		var selector = this;

		return (selector.record) ? selector.record.data[selector.keyField] : '';
	},

	/**
	 * @method doSave
	 *
	 */
	doSave: function(reload) {

		var selector = this;

		reload = reload || false;

		var neededToSync = 0;

		var checkLength = function(cancelWrite) {

			if (neededToSync === 0) {

				selector._store.fireEvent(cancelWrite ? 'cancelwrite' : 'write');
			}
		};

		Ext.Array.each(selector.collections, function(collection) {

			var saveLength = selector.checkedItems.ID.length,
				deleteLength = selector.uncheckedItems.ID.length;

			neededToSync += saveLength + deleteLength;

			// Checked items
			Ext.Array.each(selector.checkedItems.ID, function(id, index) {

				var record = selector.createRecord({
					action: 'updateRow',
					id: id,
					parentId: selector.checkedItems.PARENTID[index],
					properties: collection.properties
				});

				record.save({
					success: function(rec) {

						record.checkbox.recordID = rec.data.ID;
						record.checkbox.resetOriginalValue();

						neededToSync--;

						checkLength();
					}
				});
			});

			// Unchecked items
			Ext.Array.each(selector.uncheckedItems.ID, function(id, index) {

				var record = selector.createRecord({
					action: 'deleteRow',
					id: id,
					parentId: selector.uncheckedItems.PARENTID[index],
					properties: collection.properties
				});

				record.checkbox.resetOriginalValue();
				record.destroy({
					success: function() {

						neededToSync--;

						checkLength();
					}
				});
			});
		});

		selector.clearSelection();

		if (reload)	selector.onParentLoad();

		checkLength(true);

		selector.fireEvent('savecomplete', selector, true);
	},

	createRecord: function(settings) {

		var selector = this,
			model,
			properties,
			record,
			checkbox,
			cid,
			store = selector.getStore();

		// Get the model to use on record
		model = store.proxy.getModel();

		// Set the action
		store.proxy.extraParams.dmdPath = selector.dmdPath;
		store.proxy.extraParams.action = settings.action;

		// Get the checkbox - has values for us to use!
		checkbox = selector.down('[name=selector_' + settings.parentId + ']');

		// Get the CID from checkbox
		cid = checkbox.cid;

		// Create the properties object we will be saving
		properties = {
			// Set the properties cid matched up against index position of child on properties object
			__cid__: selector.cid.child[ Ext.Array.indexOf(selector.cid.parent, cid) ]
		};

		var propertyHandler = function(val, k, parent) {

			if (val === null) {
				val = parent[k];
			}
			try {
				var o = JSON.parse(val);
				parent[k] = o;
				return o;
			}
			catch (e) {
				return val;
			}
		};

		// Add to the properties object that we save!
		Ext.Object.each(settings.properties, function(key, object) {

			var bound = object.databasebind,
				data = selector.record.data;

			if (bound) {

				if (Ext.isArray(bound)) {

					// TODO: This is to make backwards compatible with old XPD definition:
					// (['title', 'header', 'name'] is really eq: ['properties.title', 'properties.header', 'properties.name'])
					bound = Ext.Array.map(bound, function(v) {
						return 'properties.' + v;
					});
				}
				else {

					bound = ip2.xpd.fixDatabasebind(bound);
				}

				Ext.Array.some(bound, function(o) {

					var value = ip2.getProperty(o, data, propertyHandler);

					if (value) {

						properties[key] = value;

						return true;
					}
				});
			}
		});

		// Create the record!
		var data = {};
		data[selector.propertyNameMapping.ID] = settings.id,
		data[selector.propertyNameMapping.PARENTID] = settings.parentId;
		data[selector.propertyNameMapping.PROPERTIES] = Ext.encode(properties);
		record = Ext.create(model.modelName, data);

		record.checkbox = checkbox;

		return record;
	},

	/**
	 * @method doDelete
	 *
	 */
	doDelete: function() {

		var selector = this;

		return selector;
	},

	/**
	 * @method clean up selection
	 *
	 */
	clearSelection: function() {

		var selector = this;

		selector.checkedItems = {
			PARENTID: [],
			ID: []
		};

		selector.uncheckedItems = {
			PARENTID: [],
			ID: []
		};
	}
});
Ext.define('Ext.ux.grid.column.ActionColumn', {
	extend: 'Ext.grid.column.Action',
	alias: ['widget.ip2actioncolumn', 'widget.ip2ActionColumn'],

	constructor: function(config) {
		var me = this,
		cfg = Ext.apply({}, config),
            
		items = cfg.items || me.items || [me],
		hasGetClass,
		i,
		len;

		me.origRenderer = cfg.renderer || me.renderer;
		me.origScope = cfg.scope || me.scope;
        
		me.renderer = me.scope = cfg.renderer = cfg.scope = null;
        
		cfg.items = null;
		cfg.width = 22;
		cfg.align = 'center';
		cfg.iconCls = 'ip2-gridaction-icon ip2-ux-icon-' + cfg.icon.toLowerCase();
		cfg.icon = null;

		me.callParent([cfg]);
            
		me.items = items;

		for (i = 0, len = items.length; i < len; ++i) {
			if (items[i].getClass) {
				hasGetClass = true;
				break;
			}
		}
        
		if (me.origRenderer || hasGetClass) {
			me.hasCustomRenderer = true;
		}
	}     
});
Ext.define("Ext.ux.mailChimp.Panel", {
	extend: "Ext.window.Window",
	alias: ["widget.mailchimppanel"],
	title: "Subscribe",
	layout: "fit",
	modal: true,
	autoScroll: true,
	initComponent: function() {
		var me = this;

		me.items = Ext.create("Ext.form.Panel", {
			bodyPadding: 15,
			width: 600,
			url: "/ip2-services/" + "wshMailChimp.aspx?action=subscribe&listid=" + me.listid,
			layout: "anchor",
			defaults: {
				anchor: "100%"
			},
			defaultType: "textfield",
			items: [{
				fieldLabel: ip2.i18n({ da: "Email", en: "Email" }),
				name: "email",
				vtype: "email",
				allowBlank: false
			}],
			buttons: [{
				text: ip2.i18n({ da: "Gem", en: "Save" }),
				formBind: true,
				disabled: true,
				handler: function() {
					var form = this.up("form").getForm();
					if (form.isValid()) {
						form.submit({
							success: function(form, action) {
								if (Ext.isFunction(me.success)) {
									me.success.call(window, action.result.response);
								}

								me.close();
							},
							failure: function(form, action) {
								Ext.Msg.alert("Failed", action.result.response.error);
							}
						});
					}
				}
			},{
				text: ip2.i18n({ da: "Nulstil", en: "Reset" }),
				handler: function() {
					this.up("form").getForm().reset();
				}
			},{
				text: ip2.i18n({ da: "Luk", en: "Close" }),
				handler: function() {
					me.close();
				}
			}]
		});

		me.callParent();
	}
});
Ext.define("Ext.ux.mailChimp.Grid", {
	extend: "Ext.grid.Panel",
	alias: ["widget.mailchimpgrid"],
	border: false,
	viewConfig: {
		loadMask: true,
		variableRowHeight: true
	},
	initComponent: function() {
		var me = this;

		var modelName = "mailchimpmembers";

		if (!Ext.ClassManager.isCreated(modelName)) {
			Ext.define(modelName, {
				extend: "Ext.data.Model",
				fields: [
				{ name: "id", type: "string" },
				{ name: "email", type: "string" },
				{ name: "info_changed", type: "string" },
				{ name: "status", type: "string" }
				],
				proxy: {
					type: "ajax",
					url: "/ip2-services/" + "wshMailChimp.aspx",
					reader: {
						type: "json",
						rootProperty: "response.data",
						totalProperty: "total"
					}
				}
			});
		}

		me.columns = [
			{ header: ip2.i18n({ da: "Email", en: "Email" }), dataIndex: "email", flex: 3 },
			{ header: ip2.i18n({ da: "Status", en: "Status" }), dataIndex: "status", flex: 1 },
			{ header: ip2.i18n({ da: "Ændret d.", en: "Changed" }), dataIndex: "info_changed", flex: 1 }
		];

		me.store = Ext.create("Ext.data.BufferedStore", {
			model: modelName,
			pageSize: 100,
			remoteSort: true
		});

		me.dockedItems = [{
			xtype: "toolbar",
			itemId: "actionbar",
			dock: "top",
			items: [{
				xtype: "button",
				itemId: "subscribe",
				text: ip2.i18n({
					da: "Tilmeld ny",
					en: "Subscribe new"
				}),
				iconCls: "pf-add",
				handler: function() {
					me.subscribe();
				}
			}],
			listeners: {
				afterrender: function() {
					me.setButtonsDisable();
				}
			}
		}];

		var rowMenu = Ext.create("Ext.menu.Menu", {
			items: [{
				xtype: "menuitem",
				itemId: "unsubscribe",
				text: ip2.i18n({
					da: "Afmeld",
					en: "Unsubscribe"
				}),
				iconCls: "pf-delete",
				handler: function () {
					me.unsubscribe();
				}
			}]
		});

		me.listeners = {
			itemcontextmenu: function(view, records, item, index, e) {
				e.stopEvent();

				me.getSelectionModel().select(records);

				var coords = e.getXY();
				rowMenu.showAt([coords[0], coords[1]]);
			},
			search: function(o_params) {

				var i_store = me.store;
				var i_proxy = i_store.getProxy();
				var o_extraParams = i_proxy.getExtraParams();

				o_extraParams = Ext.apply(o_extraParams, o_params);
				i_store.loadPage(1);
			}
		};

		me.callParent();
	},
	subscribe: function() {
		var me = this;

		Ext.create("Ext.ux.mailChimp.Panel", {
			listid: me.getListId(),
			success: function(data) {
				me.store.loadPage(1);
			}
		}).show();
	},
	unsubscribe: function() {
		var me = this;

		var records = me.getSelectionModel().getSelection();
		if (records.length == 0) {
			Ext.MessageBox.show({
				msg: ip2.i18n({ da: "Du skal vælge en række først...", en: "Select one row..." }),
				icon: Ext.MessageBox.WARNING
			});

			setTimeout(function() {
				Ext.MessageBox.hide();
			}, 1000);
			return;
		}

		Ext.Msg.show({
			title: ip2.i18n({ da: "Bekræft", en: "Confirm" }),
			msg: ip2.i18n({ da: "Vil du afmelde dette medlem af listen ?", en: "Do you want to unsubscribe this member ?" }),
			buttons: Ext.Msg.OKCANCEL,
			icon: Ext.Msg.WARNING,
			fn: function(btn) {
				if (btn == "ok") {
					Ext.Ajax.request({
						url: "/ip2-services/" + "wshMailChimp.aspx",
						params: {
							action: "unsubscribe",
							email: records[0].data.email,
							listid: me.getListId()
						},
						record: records[0],
						success: function(response, request) {
							me.store.loadPage(1);
						}
					});
				}
			}
		});
	},
	getListId: function() {

		var me = this;
		var value;

		var i_panel = me.previousSibling("panel");
		if (i_panel) {
			var i_fieldcontainer = i_panel.down("fieldcontainer");
			if (i_fieldcontainer) {
				var i_listId = i_fieldcontainer.down("#listid");
				if (i_listId) {
					value = i_listId.getValue();
				}
			}
		}

		return value;
	},
	setButtonsEnable: function() {

		var me = this;
		var i_toolbar = me.down("#actionbar");
		if (i_toolbar) {
			var i_subscribe = i_toolbar.down("#subscribe");
			if (i_subscribe) {
				i_subscribe.enable();
			}
		}
	},
	setButtonsDisable: function() {
		var me = this;
		var i_toolbar = me.down("#actionbar");
		if (i_toolbar) {
			var i_subscribe = i_toolbar.down("#subscribe");
			if (i_subscribe) {
				i_subscribe.disable();
			}
		}
	}
});
if (!Ext.ClassManager.isCreated("listComboModel")) {
	Ext.define("listComboModel", {
		extend: "Ext.data.Model",
		fields: [
			{ name: "id", type: "string" },
			{ name: "name", type: "string" }
		],
		proxy: {
			type: "ajax",
			url: "/ip2-services/" + "wshMailChimp.aspx?action=list",
			reader: {
				type: "json",
				rootProperty: "response.data",
				totalProperty: "total"
			}
		}
	});
}

Ext.define("Ext.ux.mailChimp.ListCombo", {
	extend: "Ext.form.field.ComboBox",
	alias: ["widget.mailchimplistcombo"],
	fieldLabel: ip2.i18n({ da: "Liste", en: "List" }),
	displayField: "name",
	valueField: "id",
	queryMode: "remote",
	typeAhead: false,
	selectOnTab: true,
	emptyText: ip2.i18n({ da: "Vælg en liste...", en: "Select a list..." }),
	triggers: {
		clear: {
			cls: "x-form-clear-trigger",
			weight: 1,
			handler: "onTrigger1Click",
			scope: "this"
		},
		picker: {
			weight: 2,
			handler: "onTriggerClick",
			scope: "this"
		}
	},
	listConfig: {
		width: 600
	},
	initComponent: function() {
		var me = this;

		me.store = Ext.create("Ext.data.Store", {
			model: "listComboModel"
		});

		me.callParent();
	},
	onTrigger1Click: function() {
		this.clearValue();

		this.up("panel").setSearchDisable();
	}
});
Ext.define("Ext.ux.mailChimp.SearchPanel", {
	extend: "Ext.form.Panel",
	alias: ["widget.mailchimpsearchpanel"],
	border: false,
	bodyPadding: 10,
	defaults: {
		xtype: "textfield",
		labelAlign: "left",
		labelWidth: 120,
		width: 500
	},
	layout: {
		type: "anchor"
	},
	initComponent: function() {
		var me = this;

		me.items = [{
			xtype: "fieldcontainer",
			itemId: "fieldcontainer",
			layout: "hbox",
			hideLabel: true,
			width: "100%",
			defaults: {
				xtype: "textfield",
				labelWidth: 50
			},
			items: [{
				xtype: "mailchimplistcombo",
				name: "listid",
				itemId: "listid",
				width: 500,
				listeners: {
					select: function() {
						me.setSearchEnable();
					}
				}
			},{
				xtype: "splitter",
				width: 15,
				style: "display:none;"
			},{
				xtype: "textfield",
				fieldLabel: ip2.i18n({ da: "Søg", en: "Search" }),
				name: "search",
				itemId: "search",
				width: 500,
				disabled: true,
				enableKeyEvents: true,
				listeners: {
					keypress: function(field, eventObject) {
						if (eventObject.getKey() == eventObject.ENTER) {
							if (field.getValue().length > 0) {
								me.submitSearch("search-members");
							}
							else {
								me.submitSearch();
							}
						}
					}
				},
				triggers: {
					clear: {
						weight: 1,
						cls: "x-form-clear-trigger",
						scope: "this",
						handler: "onTrigger1Click"
					},
					search: {
						weight: 1,
						cls: "x-form-search-trigger",
						scope: "this",
						handler: "onTrigger2Click"
					}
				},
				onTrigger1Click: function() {
					this.setValue("");

					me.submitSearch();
				},
				onTrigger2Click: function() {
					if (this.getValue().length > 0) {
						me.submitSearch("search-members");
					}
					else {
						me.submitSearch();
					}
				}
			},{
				xtype: "splitter",
				width: 15,
				style: "display:none;"
			},{
				xtype: "checkbox",
				hideLabel: true,
				boxLabel: ip2.i18n({ da: "Udmeldte", en: "Unsubscribed" }),
				name: "unsubscribed",
				itemId: "unsubscribed",
				disabled: true,
				listeners: {
					change: function(field) {
						me.submitSearch();
					}
				}
			}]
		}];

		me.callParent();
	},
	setSearchEnable: function() {
		var me = this;

		me.nextSibling("grid").setButtonsEnable();

		me.down("#unsubscribed").enable();
		me.down("#search").enable();

		me.submitSearch();
	},
	setSearchDisable: function() {
		var me = this;

		me.nextSibling("grid").setButtonsDisable();

		me.down("#unsubscribed").disable();
		me.down("#search").disable();
	},
	submitSearch: function(action) {
		var me = this;

		var params = {
			action: (action) ? action : "members",
			listid: me.down("#listid").getValue(),
			status: (me.down("#unsubscribed").getValue() == true) ? "unsubscribed" : "subscribed",
			search: me.down("#search").getValue()
		};

		me.nextSibling("grid").fireEvent("search", params);
	}
});

Ext.define("Ext.ux.toolbar.ExtendedPaging", {

	extend: "Ext.toolbar.Paging",

	alias: "widget.extendedpagingtoolbar",

	mixins: {
		componentController: "Ext.ux.util.ComponentController"
	},

	refs: [
		{
			ref: "searchField",
			selector: "#searchfield"
		},
		{
			ref: "searchButton",
			selector: "#searchbutton"
		},
		{
			ref: "pagesizeCombo",
			selector: "#pagesizecombo"
		},
		{
			ref: "refreshButton",
			selector: "#refresh"
		},
		{
			ref: "pagePrev",
			selector: "#prev"
		},
		{
			ref: "pageNext",
			selector: "#next"
		},
		{
			ref: "pageFirst",
			selector: "#first"
		},
		{
			ref: "pageLast",
			selector: "#last"
		}
	],

	/**
	 * @cfg {Boolean} [pageSizeEdit=true]
	 */
	pageSizeEdit: true,
	/**
	 * @cfg {Boolean} [pageSearch=true]
	 */
	pageSearch: true,
	/**
	 * @cfg {Boolean} [inputItemTrigger=true]
	 */
	inputItemTrigger: true,
	/**
	 * @cfg {Number} [pageSearchWidth=100]
	 */
	pageSearchWidth: 100,
	/**
	 * @cfg {String/Object} [pageSearchEmptyText="i18n"]
	 */
	pageSearchEmptyText: "",
	/**
	 * @cfg {String} [pageSearchParam="query"]
	 */
	pageSearchParam: "query",

	onBeforeRefresh: null,
	onAfterRefresh: null,
	onPageRefresh: null,

	/**
	     * @cfg {Boolean} displayInfo
	     * true to display the displayMsg
	     */

	/**
	     * @cfg {Boolean} prependButtons
	     * true to insert any configured items _before_ the paging buttons.
	     */

	/**
	     * @cfg {String} displayMsg
	     * The paging status message to display. Note that this string is
	     * formatted using the braced numbers {0}-{2} as tokens that are replaced by the values for start, end and total
	     * respectively. These tokens should be preserved when overriding this string if showing those values is desired.
	     */

	/**
	     * @cfg {String} emptyMsg
	     * The message to display when no records are found.
	     */

	/**
	     * @cfg {String} beforePageText
	     * The text displayed before the input item.
	     */

	/**
	     * @cfg {String} afterPageText
	     * Customizable piece of the default paging text. Note that this string is formatted using
	     * {0} as a token that is replaced by the number of total pages. This token should be preserved when overriding this
	     * string if showing the total page count is desired.
	     */

	/**
	     * @cfg {String} firstText
	     * The quicktip text displayed for the first page button.
	     * **Note**: quick tips must be initialized for the quicktip to show.
	     */

	/**
	     * @cfg {String} prevText
	     * The quicktip text displayed for the previous page button.
	     * **Note**: quick tips must be initialized for the quicktip to show.
	     */

	/**
	     * @cfg {String} nextText
	     * The quicktip text displayed for the next page button.
	     * **Note**: quick tips must be initialized for the quicktip to show.
	     */

	/**
	     * @cfg {String} lastText
	     * The quicktip text displayed for the last page button.
	     * **Note**: quick tips must be initialized for the quicktip to show.
	     */

	/**
	     * @cfg {String} refreshText
	     * The quicktip text displayed for the Refresh button.
	     * **Note**: quick tips must be initialized for the quicktip to show.
	     */

	/**
	     * @cfg {Number} inputItemWidth
	     * The width in pixels of the input field used to display and change the current page number.
	     */

	/**
	 * @private
	 */
	_currentPage: 1,

	_storeInitialized: false,

	/**
	 * Gets the standard paging items in the toolbar
	 * @private
	 */
	getPagingItems: function() {

		var i_cmp = this;
		var i_store = i_cmp.store;
		var a_items = [];
		var o_initial = i_cmp.initialConfig;
		var b_pageSizeEdit = o_initial.pageSizeEdit || i_cmp.pageSizeEdit;
		var b_pageSearch = o_initial.pageSearch || i_cmp.pageSearch;

		Ext.apply(i_cmp, {
			pageSearchEmptyText: o_initial.pageSearchEmptyText || ip2.i18n({
				da: "Søg...",
				en: "Search..."
			})
		});

		// Back, first etc..
		a_items.push(
			{
				xtype: "button",
				itemId: "first",
				iconCls: "pf-previous",
				tooltip: i_cmp.firstText,
				overflowText: i_cmp.firstText,
				disabled: true,
				handler: i_cmp.moveFirst,
				scope: i_cmp
			},
			{
				xtype: "button",
				itemId: "prev",
				iconCls: "pf-arrow-left",
				tooltip: i_cmp.prevText,
				overflowText: i_cmp.prevText,
				disabled: true,
				handler: i_cmp.movePrevious,
				scope: i_cmp
			},
			{
				xtype: "tbspacer",
				itemId: "firstSpacer"
			},
			{
				xtype: "tbtext",
				itemId: "beforeTextItem",
				text: i_cmp.beforePageText
			},
			{
				xtype: "numberfield",
				itemId: "inputItem",
				name: "inputItem",
				allowDecimals: false,
				minValue: 1,
				hideTrigger: !i_cmp.inputItemTrigger,
				enableKeyEvents: true,
				selectOnFocus: true,
				submitValue: false,
				width: i_cmp.inputItemTrigger ? i_cmp.inputItemWidth + 15 : i_cmp.inputItemWidth,
				margins: "-1 2 3 2",
				isFormField: false,
				listeners: {
					scope: i_cmp,
					keydown: i_cmp.onPagingKeyDown,
					change: i_cmp.onPagingTrigger,
					blur: i_cmp.onPagingBlur
				}
			},
			{
				xtype: "tbtext",
				itemId: "afterTextItem",
				text: Ext.String.format(i_cmp.afterPageText, 1)
			},
			{
				xtype: "tbspacer",
				itemId: "lastSpacer"
			},
			{
				xtype: "button",
				itemId: "next",
				iconCls: "pf-arrow-right",
				tooltip: i_cmp.nextText,
				overflowText: i_cmp.nextText,
				handler: i_cmp.moveNext,
				scope: i_cmp
			},
			{
				xtype: "button",
				itemId: "last",
				iconCls: "pf-next",
				tooltip: i_cmp.lastText,
				overflowText: i_cmp.lastText,
				handler: i_cmp.moveLast,
				scope: i_cmp
			}
		);

		// Unless pageLimitEdit is configured to false add combo
		if (b_pageSizeEdit) {

			var a_values = [10, 20, 30, 40, 50, 100];

			if (Ext.Array.indexOf(a_values, i_store.pageSize) == -1) {
				a_values.push(i_store.pageSize);
				Ext.Array.sort(a_values, function (a, b) {
					return a > b;
				});
			}

			a_items.push(
				{
					xtype: "tbspacer",
					hidden: !b_pageSizeEdit
				},
				{
					xtype: "tbtext",
					itemId: "pagesizecombolabel",
					hidden: !b_pageSizeEdit,
					text: ip2.i18n({
						da: "Vis",
						en: "Show"
					})
				},
				{
					xtype: "combobox",
					itemId: "pagesizecombo",
					hidden: !b_pageSizeEdit,
					maskRe: /[0-9]/g,
					isFormField: false,
					size: 5,
					value: i_store.pageSize,
					store: a_values,
					scope: i_cmp
				}
			);
		}

		if (b_pageSearch) {
			// Add the search field and search button
			a_items.push([
				"-",
				{
					xtype: "textfield",
					itemId: "searchfield",
					enableKeyEvents: true,
					isFormField: false,
					emptyText: i_cmp.pageSearchEmptyText,
					width: i_cmp.pageSearchWidth
				},
				{
					xtype: "button",
					itemId: "searchbutton",
					disabled: true,
					iconCls: "pf-magnifying_glass"
				}
			]);
		}

		// Add the refresh button
		a_items = Ext.Array.merge(a_items, [
			{
				xtype: "tbspacer",
				itemId: "refreshSpacer"
			},
			{
				xtype: "button",
				itemId: "refresh",
				iconCls: "pf-refresh",
				text: o_initial.refreshText || i_cmp.refreshText,
				tooltip: o_initial.refreshText || i_cmp.refreshText,
				overflowText: o_initial.refreshText || i_cmp.refreshText,
				preventDefault: true,
				handler: i_cmp.onRefreshButton,
				scope: i_cmp
			}
		]);

		return a_items;
	},

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		i_cmp.initComponentController();

		i_cmp.addControls();

		return i_cmp;
	},

	addControls: function () {

		var i_cmp = this;

		i_cmp.on({
			afterrender: {
				fn: function () {

					var i_store = i_cmp.getStore();
					var n_count = i_store.getCount();
					var n_total = i_store.getTotalCount();

					var a_paginationArrows = [
						i_cmp.down("#first"),
						i_cmp.down("#prev"),
						i_cmp.down("#next"),
						i_cmp.down("#last"),
						i_cmp.down("#firstSpacer"),
						i_cmp.down("#lastSpacer"),
						i_cmp.down("#refreshSpacer")
					];

					var a_paginationInput = [
						i_cmp.down("#beforeTextItem"),
						i_cmp.down("#afterTextItem"),
						i_cmp.down("#inputItem")
					];

					var n_width = i_cmp.getWidth();
					var n_min = 380;

					// If we only have 1 page to show for - no pagination
					if (n_total <= n_count) {

						n_min = 250;

						ip2.each(a_paginationInput, function (i_item) {
							i_item.hide();
						});
						ip2.each(a_paginationArrows, function (i_item) {
							i_item.hide();
						});
					}

					// pagination needed
					else {

						ip2.each(a_paginationArrows, function (i_item) {
							i_item.show();
						});

						// Will only show pagination numberfield if over 600px
						if (n_width - 220 > n_min) {
							ip2.each(a_paginationInput, function (i_item) {
								i_item.show();
							});
						}
						else {
							ip2.each(a_paginationInput, function (i_item) {
								i_item.hide();
							});
						}
					};
				},
				buffer: 100
			}
		});

		i_cmp.control({
			searchField: {
				keyup: i_cmp.onTextSearch,
				scope: i_cmp
			},
			searchButton: {
				click: i_cmp.onButtonSearch,
				scope: i_cmp
			},
			pagesizeCombo: {
				change: i_cmp.onPageSizeChange,
				scope: i_cmp
			},
			pagePrev: {
				click: i_cmp.onPageRefresh,
				scope: i_cmp
			},
			pageNext: {
				click: i_cmp.onPageRefresh,
				scope: i_cmp
			},
			pageFirst: {
				click: i_cmp.onPageRefresh,
				scope: i_cmp
			},
			pageLast: {
				click: i_cmp.onPageRefresh,
				scope: i_cmp
			}
		});

		return i_cmp;
	},

	getStore: function () {

		return this.store;
	},

	onPagingTrigger: function () {

		var i_cmp = this;
		var o_data = i_cmp.getPageData();
		var n_page = i_cmp.readPageFromInput(o_data);

		if (n_page != false) {
			n_page = Math.min(Math.max(1, n_page), o_data.pageCount);
			if (n_page != o_data.currentPage) {
				if (i_cmp.fireEvent("beforechange", i_cmp, n_page) !== false) {
					if (Ext.isNumber(n_page)) {
						i_cmp.store.loadPage(n_page);
					}
				}
			}
		}
	},

	performSearch: function (value) {

		var i_cmp = this;
		var s_queryParam = i_cmp.pageSearchParam;
		var i_field = i_cmp.getSearchField();
		var s_query = value || i_field.getValue();
		var i_store = i_cmp.store;
		var o_data = i_cmp.getPageData();

		i_cmp._currentPage = i_cmp.readPageFromInput(o_data);

		if (s_query) {
			i_store.proxy.extraParams[s_queryParam] = s_query;
		}
		else {
			delete i_store.proxy.extraParams[s_queryParam];
		}

		i_cmp.doRefresh();

		return i_cmp;
	},

	onButtonSearch: function () {

		var i_cmp = this;

		i_cmp.performSearch();

		i_cmp.store.loadPage(1);

		return i_cmp;
	},
	onTextSearch: function (i_self, event) {

		var i_cmp = this;
		var s_queryParam = i_cmp.pageSearchParam;
		var i_button = i_cmp.getSearchButton();
		var i_field = i_cmp.getSearchField();
		var s_value = i_field.getValue();
		var i_store = i_cmp.store;
		var s_query = i_store.proxy.extraParams[s_queryParam];

		if (!s_value) {
			i_button.disable();
			if (s_query) {
				delete i_store.proxy.extraParams[s_queryParam];
				i_cmp.store.loadPage(i_cmp._currentPage);
			}
		}
		else {

			if (event.browserEvent.keyIdentifier == "Enter") {
				i_cmp.onButtonSearch();
			}

			i_button.enable();
		}

		return i_cmp;
	},

	onPageSizeChange: function (i_self, n_value) {
		var i_cmp = this,
			i_store = i_cmp.store;

		i_store.pageSize = n_value;
		i_store.proxy.extraParams.limit = n_value;

		i_cmp.store.loadPage(1);
	},
	onPageRefresh: function () {

		var i_cmp = this;
		var i_store = i_cmp.getStore();

		i_store.on({
			load: {
				fn: function () {
					i_cmp.fireEvent("afterfresh", i_cmp);
					i_cmp.onAfterRefresh && i_cmp.onAfterRefresh(i_cmp);
				},
				single: true
			}
		});

		i_cmp.fireEvent("beforerefresh", i_cmp);
		i_cmp.onBeforeRefresh && i_cmp.onBeforeRefresh(i_cmp);

		i_cmp.fireEvent("refresh", i_cmp);
	},
	doRefresh: function() {

		var i_cmp = this;
		var i_store = i_cmp.store;
		var n_current = i_store.currentPage;

		i_cmp.onPageRefresh();

		if (i_cmp.fireEvent("beforechange", i_cmp, n_current) !== false) {
			i_cmp.store.loadPage(n_current);
		}
	},
	onRefreshButton: function () {

		var i_cmp = this;
		var i_searchField = i_cmp.getSearchField();
		var i_searchButton = i_cmp.getSearchButton();

		if (i_searchField && i_searchField.getValue()) {
			i_cmp.performSearch();
		}
		else {
			i_cmp.doRefresh();
		}
	}
});
if (!Ext.ClassManager.isCreated("Ext.ux.data.model.Locale")) {
	Ext.define("Ext.ux.data.model.Locale", {
		extend: "Ext.data.Model",
		fields: [
			{
				name: "code",
				type: "string"
			},
			{
				name: "language",
				type: "auto"
			},
			{
				name: "country",
				type: "string"
			},
			{
				name: "flag",
				type: "string"
			}
		],
		idProperty: "code"
	});
}
Ext.define("Ext.ux.data.store.Locale", {

	extend: "Ext.data.Store",

	model: "Ext.ux.data.model.Locale",

	autoLoad: true,

	proxy: {
		type: "memory"
	},

	data: [
		{
			country: "Afrikan Republic",
			language: {
				da: "Afrikaans",
				en: "Afrikaans"
			},
			code: "af",
			flag: "flag_central_african_republic"
		},
		{
			country: "Bulgaria",
			language: {
				da: "Bulgarisk",
				en: "Bulgarian"
			},
			code: "bg",
			flag: "flag_bulgaria"
		},
		{
			country: "Czech Republic",
			language: {
				da: "Czech",
				en: "Czech"
			},
			code: "cs",
			flag: "flag_czech_republic"
		},
		{
			country: "Denmark",
			language: {
				da: "Dansk",
				en: "Danish"
			},
			code: "da",
			flag: "flag_da"
		},
		{
			country: "Germany",
			language: {
				da: "Tysk",
				en: "German"
			},
			code: "de",
			flag: "flag_de"
		},
		{
			country: "Great Britain",
			language: {
				da: "Engelsk",
				en: "English"
			},
			code: "en",
			flag: "flag_en"
		},
		{
			country: "Spain",
			language: {
				da: "Spansk",
				en: "Spanish"
			},
			code: "es",
			flag: "flag_es"
		},
		{
			country: "Estonia",
			language: {
				da: "Estonian",
				en: "Estonian"
			},
			code: "et",
			flag: "flag_estonia"
		},
		{
			country: "Iran",
			language: {
				da: "Persian",
				en: "Persian"
			},
			code: "fa",
			flag: "flag_iran"
		},
		{
			country: "Finland",
			language: {
				da: "Finnish",
				en: "Finnish"
			},
			code: "fi",
			flag: "flag_fi"
		},
		{
			country: "France",
			language: {
				da: "Fransk",
				en: "French"
			},
			code: "fr",
			flag: "flag_france"
		},
		{
			country: "Greece",
			language: {
				da: "Græsk",
				en: "Greek"
			},
			code: "gr",
			flag: "flag_greece"
		},
		{
			country: "Hebrew",
			language: {
				da: "Hebraisk",
				en: "Hebrew"
			},
			code: "he",
			flag: "flag_israel"
		},
		{
			country: "Croatian",
			language: {
				da: "Croatian",
				en: "Croatian"
			},
			code: "hr",
			flag: "flag_croatia"
		},
		{
			country: "Hungary",
			language: {
				da: "Hungarian",
				en: "Hungarian"
			},
			code: "hu",
			flag: "flag_hungary"
		},
		{
			country: "Indonesia",
			language: {
				da: "Indonesian",
				en: "Indonesian"
			},
			code: "id",
			flag: "flag_indonesia"
		},
		{
			country: "Italy",
			language: {
				da: "Italian",
				en: "Italian"
			},
			code: "it",
			flag: "flag_italy"
		},
		{
			country: "Japan",
			language: {
				da: "Japansk",
				en: "Japaness"
			},
			code: "ja",
			flag: "flag_japan"
		},
		{
			country: "Korea",
			language: {
				da: "Korean",
				en: "Korean"
			},
			code: "ko",
			flag: "flag_north_korea"
		},
		{
			country: "Lithuania",
			language: {
				da: "Lithuanian",
				en: "Lithuanian"
			},
			code: "lt",
			flag: "flag_lithuania"
		},
		{
			country: "Latvia",
			language: {
				da: "Latvian",
				en: "Latvian"
			},
			code: "lv",
			flag: "flag_latvia"
		},
		{
			country: "Macedonia (FYROM)",
			language: {
				da: "Macedonian (FYROM)",
				en: "Macedonian (FYROM)"
			},
			code: "mk",
			flag: "flag_macedonia"
		},
		{
			country: "Nederland",
			language: {
				da: "Hollandsk",
				en: "Dutch"
			},
			code: "nl",
			flag: "flag_netherlands_antilles"
		},
		{
			country: "Norway",
			language: {
				da: "Norsk (Bokmal)",
				en: "Norwegian (Bokmal)"
			},
			code: "no_NB",
			flag: "flag_no"
		},
		{
			country: "Poland",
			language: {
				da: "Polsk",
				en: "Polish"
			},
			code: "pl",
			flag: "flag_poland"
		},
		{
			country: "Portugal",
			language: {
				da: "Portuguese",
				en: "Portuguese"
			},
			code: "pt",
			flag: "flag_portugal"
		},
		{
			country: "Romania",
			language: {
				da: "Romanian",
				en: "Romanian"
			},
			code: "ro",
			flag: "flag_romania"
		},
		{
			country: "Russia",
			language: {
				da: "Russian",
				en: "Russian"
			},
			code: "ru",
			flag: "flag_russia"
		},
		{
			country: "Slovakia",
			language: {
				da: "Slovak",
				en: "Slovak"
			},
			code: "sk",
			flag: "flag_slovakia"
		},
		{
			country: "Slovenia",
			language: {
				da: "Slovenian",
				en: "Slovenian"
			},
			code: "sl",
			flag: "flag_slovenia"
		},
		{
			country: "Serbian",
			language: {
				da: "Serbian",
				en: "Serbian"
			},
			code: "sr",
			flag: "flag_serbia"
		},
		{
			country: "Sweden",
			language: {
				da: "Svensk",
				en: "Swedish"
			},
			code: "sv_SE",
			flag: "flag_sv"
		},
		{
			country: "Thailand",
			language: {
				da: "Thai",
				en: "Thai"
			},
			code: "th",
			flag: "flag_thailand"
		},
		{
			country: "Turkey",
			language: {
				da: "Turkish",
				en: "Turkish"
			},
			code: "tr",
			flag: "flag_turkey"
		},
		{
			country: "Ukraine",
			language: {
				da: "Ukrainian",
				en: "Ukrainian"
			},
			code: "ukr",
			flag: "flag_ukraine"
		},
		{
			country: "Vietnam",
			language: {
				da: "vietnamesisk",
				en: "Vietnamese"
			},
			code: "vn",
			flag: "flag_vietnam"
		},
		{
			country: "People's Republic of China",
			language: {
				da: "Chinese (Simplified) Legacy",
				en: "Chinese (Simplified) Legacy"
			},
			code: "zh_CN",
			flag: "flag_china"
		},
		{
			country: "Taiwan",
			language: {
				da: "Chinese (Traditional) Legacy",
				en: "Chinese (Traditional) Legacy"
			},
			code: "zh_TW",
			flag: "flag_china"
		}
	]
});
Ext.define("Ext.ux.form.field.LocaleComboBox", {

	extend: "Ext.form.field.ComboBox",

	alias: [
		"widget.localeComboBox",
		"widget.localeCombo",
		"widget.ip2LocaleLanguageComboBox"
	],

	displayField: "code",
	valueField: "code",
	queryMode: "local",
	typeAhead: false,

	store: null,

	requires: [
		"Ext.ux.data.store.Locale"
	],

	initComponent: function () {

		var i_self = this;

		Ext.apply(i_self, {
			emptyText: ip2.i18n({
				da: "Vælg et sprog",
				en: "Choose a language"
			}),
			store: i_self.createStore(),
			tpl: i_self.createListTemplate(),
			displayTpl: i_self.createDisplayTemplate()
		});

		i_self.callParent(arguments);

		return i_self;
	},

	createStore: function () {

		var i_self = this;
		var i_store = Ext.create("Ext.ux.data.store.Locale", {});

		return i_store;
	},

	createListTemplate: function () {

		var i_self = this;

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"<li role=\"option\" class=\"x-boundlist-item\">",
					"<div>",
						"<div style=\"float: left; width: 16px; height: 14px; margin-top:4px;\" class=\"AIL-icon AIL-icon-18 icon-{flag}\"></div>",
						"<div style=\"margin-left: 20px;\">{country} - {[this.renderer(values.language)]}</div>",
					"</div>",
				"</li>",
			"</tpl>",
			{
				renderer: function(value) {
					return ip2.i18n(value);
				}
			}
		);

		return i_tpl;
	},

	createDisplayTemplate: function() {

		var i_self = this;

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"{[typeof values === \"string\" ? values : this.renderer(values)]}",
				"<tpl if=\"xindex < xcount\">" + i_self.delimiter + "</tpl>",
			"</tpl>",
			{
				renderer: function(values) {
					return ip2.i18n(values.language);
				}
			}
		);

		return i_tpl;
	}
});
Ext.define('Ext.ux.form.field.BasketItems', {

	requires: [
		'Ext.container.Container',
		'Ext.form.field.Field'
	],

	extend: 'Ext.container.Container',

	alias: [
		'widget.ip2basketitems',
		'widget.ip2BasketItems'
	],

	mixins: {
		field: 'Ext.form.field.Field'
	},

	changeListener: function() {
		var i_cmp = this;

		var s_value = this.getValue();

		var o_value;

		try {
			o_value = JSON.parse(s_value);
		}
		catch (e) {
			o_value = s_value;
		}

		var a_itemTokens = Ext.Array.map(o_value.rows, function(o_item) {
			return [o_item.itemToken, o_item.quantity || 1].join(':');
		});

		var o_xpd = ip2.resource.get('product.xpd', true);

		// Back in the good ol days we called the product.xpd for itemprop.xpd
		if (!o_xpd) {
			o_xpd = ip2.resource.get('itemprop.xpd', true);
		}

		var o_props = o_xpd.collections.all;

		var a_fields = [];
		var a_columns = [];

		Ext.Object.each(o_props, function(key, o_prop) {
			if (o_prop.grids && Ext.Array.indexOf(o_prop.grids, 'basket') > -1) {
				a_fields.push(key);

				a_columns.push({
					header: ip2.xpd.translate(o_xpd, o_prop.title),
					dataIndex: key
				});
			}
		});

		// {"rows":[{"itemToken":"347","quantity":3,"tkn":0.11544480361044407},{"itemToken":"35","quantity":12,"tkn":0.016003133729100227},{"itemToken":"337","quantity":3,"tkn":0.6085524319205433},{"itemToken":"22","quantity":3,"tkn":0.20539662498049438,"uom":"STK"}]}
		Ext.Ajax.request({
			url: '/pp-services/getitm.aspx',
			params: {
				action: 'getitms',
				items: a_itemTokens.join(',')
			},
			success: function(response) {
				var o_resp = JSON.parse(response.responseText);

				a_rows = Ext.Array.map(o_value.rows, function(o_item, key) {
					var o_data;

					Ext.Array.some(o_resp.rows, function(o) {
						if (o.itemToken == o_item.itemToken || o.id == o_item.itemToken || o.itmitmtkn == o_item.itemToken) {
							o_data = o;
							return true;
						}
					});

					return o_data ? Ext.apply(o_item, o_data) : o_item;
				});

				Ext.Array.each(a_rows, function(o_item) {
					o_item.id = o_item.tkn;
				});

				i_cmp.removeAll();
				i_cmp.add({
					xtype: 'grid',
					store: {
						fields: a_fields,
						data: {
							rows: a_rows
						},
						proxy: {
							type: 'memory',
							reader: {
								type: 'json',
								root: 'rows'
							}
						}
					},
					columns: a_columns
				});
			}
		});
	},

	initComponent: function() {

		this.on('change', this.changeListener);

		this.callParent(arguments);

		return this;
	},
	disable: function () {
		return this;
	},
	enable: function () {
		return this;
	}
});
Ext.define('Ext.ux.form.field.Gridpicker', {
	extend: 'Ext.form.ComboBox',
	alias: ['widget.ux.form.field.gridpicker'],

	// copied from ComboBox

	initComponent: function() {

		var i_self = this;

		var o_listConfig = i_self.listConfig = i_self.listConfig || {};
		o_listConfig = Ext.Object.merge(o_listConfig, {
			enableColumnMove: false,
			enableColumnHide: false,
			enableColumnResize: false,
			features: [{
				ftype: "grouping",
				groupHeaderTpl: '{name} ({rows.length})',
				hideGroupedHeader: true,
				enableGroupingMenu: false,
				startCollapsed: true
			}],
			columns: [
				{
					dataIndex: "key",
					text: ip2.i18n({
						da: "Type",
						en: "Type"
					}),
					flex: 1,
					menuDisabled: true
				},
				{
					dataIndex: 'group',
					flex: 1,
					menuDisabled: true
				}
			]
		});
		i_self.store.sorters = [{
			property: 'key',
			direction: 'ASC'
		}];
		i_self.callParent(arguments);
	},

	createPicker: function() {

		var i_self = this;
		var i_picker;
		var menuCls = Ext.baseCSSPrefix + 'menu';
		var opts = Ext.apply({
			selModel: {
				mode: i_self.multiSelect ? 'SIMPLE' : 'SINGLE'
			},
			floating: true,
			hidden: true,
			ownerCt: i_self.ownerCt,
			cls: i_self.el.up('.' + menuCls) ? menuCls : '',
			store: i_self.store,
			displayField: i_self.displayField,
			focusOnToFront: false,
			pageSize: i_self.pageSize
		}, i_self.listConfig, i_self.defaultListConfig);

		i_picker = i_self.picker = Ext.widget('gridpanel', opts);

		// hack: pass getNode() to the view
		i_picker.getNode = function() {
			i_picker.getView().getNode(arguments);
		};

		if (!i_picker.initialConfig.maxHeight) {
			i_picker.on({
				beforeshow: i_self.onBeforePickerShow,
				scope: i_self
			});
		}

		i_self.mon(i_picker, {
			itemclick: function(i_picker, i_record) {

				var i_self = this;
				var a_records = i_picker.getSelection();
				if (!i_self.multiSelect) {
					i_self.setValue(i_record);
					i_self.collapse();
				}
				else {
					i_self.setValue(a_records);
				}
				i_self.fireEvent("select", i_self, a_records);
			},
			scope: i_self
		});

		i_self.mon(i_picker.getSelectionModel(), {
			'beforeselect': i_self.onBeforeSelect,
			'beforedeselect': i_self.onBeforeDeselect,
			scope: i_self
		});

		return i_picker;
	}
});
Ext.define("Ext.ux.form.field.UploadPicker", {

	extend: "Ext.form.field.ComboBox",

	alias: ["widget.uploadpicker"],

	triggers: {
		clear: {
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			weight: 1,
			handler: "onClearClick",
			hidden: true,
			scope: "this"
		},
		upload: {
			cls: "x-ux-form-trigger-upload",
			tooltip: ip2.i18n({
				da: "Upload en fil",
				en: "Upload a file"
			}),
			weight: 3,
			scope: "this"
		},
		picker: {
			weight: 2,
			handler: "onTriggerClick",
			scope: "this"
		},
	},

	pageSize: 6,
	displayField: "path",
	valueField: "path",
	typeAhead: true,
	minChars: 4,
	enableKeyEvents: true,
	queryParam: "search",
	queryMode: "remote",
	lastQuery: "",
	triggerAction: "all",

	config: {
		invalidText: ip2.i18n({
			da: "Filen skal af typen $extensions",
			en: "The file must be in $extensions format"
		}),
		needLoad: true,
		fileuploadForm: null,
		uploadOnly: false,
		uploadText: ip2.i18n({
			da: "Uploader fil to server",
			en: "Uploading file to server"
		}),
		path: "/",
		extensions: "gif,png,jpg,jpeg,bmp",
		ignoreStaticDir: false,
		browseService: "/ip2-services/webbios.aspx?pathList=",
		uploadService: "/ip2-services/webbios.aspx?action=movestmf&path=",
		convertFromPdf: false,
		uploadActions: [],
		image: "",
		scaling: null
	},

	listeners: {
		afterrender: {
			fn: function (i_field) {
				var value = i_field.getValue();
				if (i_field.inputEl) {


					if (Ext.isEmpty(value)) {
						i_field.getTrigger("clear").hide();
					}
					else {
						i_field.getTrigger("clear").show();
					}

					if (i_field.readOnly) {
						i_field.getTrigger("clear").hide();
					}
				}
			},
			single: true
		},
		change: {
			fn: function (i_field, value) {
				if (i_field.inputEl) {

					var a_values = Ext.Array.from(value);

					if (a_values.length === 0) {
						i_field.allQuery = "";
						i_field.clearValue();
						i_field.getTrigger("clear").hide();
					}
					else {
						i_field.allQuery = i_field.lastQuery;
						if (!i_field.readOnly) {
							i_field.getTrigger("clear").show();
						}
					}
				}
			}
		},
		enable: {
			fn: function (i_field) {

				var s_value = i_field.getValue();

				i_field.getTrigger("clear")[s_value ? "show" : "hide"]();
			},
			buffer: 10
		},
		disable: {
			fn: function (i_field) {
				i_field.getTrigger("clear").hide();
			},
			buffer: 10
		},
		writeablechange: {
			fn: function (i_field, b_readOnly) {

				i_field.getTrigger("clear")[b_readOnly ? "hide" : "show"]();


			},
			buffer: 10
		},
		uploadComplete: {
			fn: function(i_self, a_files) {

				var b_converFromPdf = i_self.getConvertFromPdf();
				var a_actions = i_self.getUploadActions() || [];

				var s_url = a_files[0];

				if (b_converFromPdf) {

					i_self.doConvert(a_files, function(o_result) {

						if (o_result && o_result.destination) {

							if (s_url != o_result.destination) {
								s_url = o_result.destination;

								i_self.setValue(s_url);
							}
						}

						i_self.doUploadActions(s_url);
					});
				}
				else {
					i_self.doUploadActions(s_url);
				}
			}
		}
	},

	initComponent: function () {

		var i_self = this;
		var o_initial = Ext.apply({}, i_self.initialConfig);

		// Overload the extensions config to a comma seperated list if array was supplied
		if (o_initial.extensions && Ext.isArray(o_initial.extensions)) {
			o_initial.extensions = o_initial.extensions.join(",");
		}

		Ext.apply(i_self, {
			extensions: o_initial.extensions || i_self.extensions,
			invalidText: o_initial.invalidText || i_self.invalidText,
			path: o_initial.path || i_self.path,
			pageSize: o_initial.pageSize || i_self.pageSize,
			browseService: o_initial.browseService || i_self.browseService,
			uploadService: o_initial.uploadService || i_self.uploadService,
			ignoreStaticDir: o_initial.ignoreStaticDir || i_self.ignoreStaticDir
		});

		// Lets make sure our services have static dir set for each if using own
		var s_preset = ip2.preset.staticPath || "pp-static";
		var b_ignoreStaticDir = i_self.ignoreStaticDir;

		if (i_self.browseService != o_initial.browseService) {

			if (i_self.path.indexOf(s_preset) == -1 && !b_ignoreStaticDir) {
				i_self.path = [s_preset, i_self.path].join("/");
				i_self.path = ip2.cleanPath(i_self.path);
			}

			i_self.browseService += i_self.path;
		}

		if (i_self.uploadService != o_initial.uploadService) {

			if (i_self.path.indexOf(s_preset) == -1 && !b_ignoreStaticDir) {
				i_self.path = [s_preset, i_self.path].join("/");
				i_self.path = ip2.cleanPath(i_self.path);
			}

			i_self.uploadService += i_self.path;

			i_self.uploadService += "&ignorestaticdir=true";
		}

		//console.log(i_self.uploadService, i_self.browseService);

		i_self.createStore();

		// Setup validation and invalid text
		(function () {

			// Create the invalid text
			i_self.invalidText = ip2.microTemplate(i_self.invalidText, {
				extensions: i_self.extensions
			});

			var s_vtypeKey = ip2.unique("ExtendedImageValidation", "");
			var o_config = {};

			o_config[s_vtypeKey] = function (value) {

				var a_extensions = i_self.extensions.split(",");
				if (a_extensions.length > 0) {
					if (a_extensions.indexOf("*") == -1) {
						var r_extensions = new RegExp("^.*\.(" + a_extensions.join("|") + ")$");
						return r_extensions.test(value.toLowerCase());
					}
					return true;
				}
				else {
					return false;
				}
			};
			o_config[s_vtypeKey + "Text"] = i_self.invalidText;

			Ext.apply(Ext.form.VTypes, o_config);

			Ext.apply(i_self, {
				vtype: s_vtypeKey,
				vtypeKey: s_vtypeKey
			});
		})();

		if (i_self.uploadOnly) {
			i_self.editable = false;
			i_self.typeAhead = false;
		}

		i_self.callParent(arguments);

		i_self.on({
			afterrender: {
				fn: function() {
					i_self.onAfterrender();
				},
				single: true
			},
			keydown: {
				fn: function(item, event) {
					if (event.ctrlKey && (event.keyCode == 90 || event.keyCode == 82 || event.keyCode == 89)) {
						if (i_self.isValid()) {
							i_self.needLoad = false;
							if (i_self.isExpanded) {
								i_self.collapse();
							}
						}
					}
				}
			},
			paste: {
				element: "inputEl",
				fn: function(event, inputEl) {
					if (i_self.isValid()) {
						i_self.needLoad = false;
						if (i_self.isExpanded) {
							i_self.collapse();
						}
					}
				}
			},
			beforequery: {
				fn: function() {
					var value = i_self.getValue();
					if (value) {
						var b_isUrl = i_self.isURL(value);
						if (b_isUrl) {
							i_self.setImage(value);
							return false;
						}
						else {
							if (!i_self.needLoad) {
								i_self.needLoad = true;
								return false;
							}
						}
					}
				}
			},
			change: {
				fn: function(item, value) {

					if (!value) {
						i_self.allQuery = "";
						i_self.setImage(value);
					}
					else {
						if (i_self.isValid()) {
							var b_isUrl = i_self.isURL(value);
							if (b_isUrl) {
								if (i_self.isExpanded) {
									i_self.collapse();
								}
							}
							var s_value = "";
							if (Ext.isNumber(value)) {
								s_value = i_self.getDisplayValue();
							}
							else {
								s_value = value;
							}
							i_self.setImage(value);
							i_self.setImage(value);
							i_self.allQuery = i_self.lastQuery;
						}
						else {
							i_self.allQuery = value;
							i_self.setImage(value);
						}
					}
				}
			},
			enable: {
				fn: function(i_field) {

					if (i_field.uploadOnly) {

						setTimeout(function() {
							i_field.setReadOnly(true);
							var o_triggers = i_field.getTriggers();
							o_triggers.picker.hide();
							o_triggers.upload.show();
						}, 10);
					}
				}
			}
		});

		return i_self;
	},

	onExpand: function() {
		var i_self = this;
		i_self.ignoreSelection++;
		i_self.callParent(arguments);
	},

	isURL: function(value) {
		var s_value = String(value);
		var r_http = /^(ftps?|https?):\/\//;
		return r_http.test(s_value);
	},

	initValue: function () {

		var i_self = this;

		if (!i_self.value) {
			i_self.value = i_self.lastValue = i_self.originalValue = i_self.getRawValue();
		}
		else {
			i_self.lastValue = i_self.originalValue = i_self.value;
		}

		return i_self;
	},

	isDirty: function () {

		var i_self = this;

		var i_selectedRecord = i_self.getSelectedRecord();

		var s_value = i_selectedRecord ? i_selectedRecord.get(i_self.valueField) : i_self.getValue() || i_self.getRawValue();

		var s_original = i_self.originalValue;

		return s_value != s_original;
	},

	onHandelChange: function(i_field, value) {


		var i_self = this;
		var i_el = i_self.bodyEl;
		var s_uploadText = i_self.uploadText;
		var s_vtypeKey = i_self.vtypeKey;
		var s_path = ip2.cleanPath(i_self.path) + "/";
		var i_fileField = i_self.getFileuploadField();

		var s_value = i_fileField.getValue();
		var b_allowed = Ext.form.VTypes[s_vtypeKey](s_value);
		var i_trigger_el = i_self.triggerEl.elements[1];

		i_field.isHandling = true;

		if (!s_value) {
			i_self.clearInvalid();
		}

		if (!b_allowed) {
			ip2.messageBox({
				icon: Ext.Msg.ERROR,
				title: ip2.i18n({
					da: "<b>Fejl</b>",
					en: "<b>Error</b>"
				}),
				message: i_self.invalidText,
				closable: false,
				yesText: ip2.i18n({
					da: "Ok",
					en: "OK"
				}),
				yesFn: function () {
					i_field.isHandling = false;
				},
				cancelFn: function() {
					i_field.isHandling = false;
				}
			});
		}
		else {
			var a_files = i_field.fileInputEl.dom.files;
			var msg = ip2.i18n({
				da: "Kontrolerer fil....",
				en: "Checking file..."
			});
			i_self.disable();
			i_el.mask(msg);

			Ext.ux.file.util.Handler.checkFiles(s_path, a_result, function (o_result) {

				var a_update = o_result.update;
				var a_create = o_result.create;

				var b_update = false;
				var b_create = false;
				var b_cancel = false;

				if (a_update.length > 0) {
					b_update = true;
					s_path = ip2.cleanPath(i_self.path) + "/";
					Ext.ux.file.util.Handler.getUIConflickWindow(i_trigger_el,
						i_self,
						s_path,
						a_update,
						function (cancel, a_override, a_rename) {
							b_cancel = cancel;
							if (a_override.length !== 0 || a_rename.length !== 0) {
								var o_record;
								var msg = "";
								var b_rename = false;
								if (a_rename.length > 0) {
									b_rename = true;
									o_record = a_rename[0];
									msg = s_uploadText;
								}
								else {
									msg = ip2.i18n({
										da: "Overskriver fil....",
										en: "Overwriting file..."
									});
									o_record = a_override[0];
								}

								i_el.mask(msg);

								var s_uploadpath = i_self.path;
								var s_name = b_rename === true ? o_record.suggestedName : o_file.name;
								var s_url = ip2.cleanPath([i_self.path, s_name].join("/"));
								if (Ext.ux.file.util.Handler.hasFileManager()) {
									Ext.ux.file.util.Handler.createRecords(s_uploadpath, [o_record], b_rename, function () {
										if (!b_create) {
											i_el.unmask();
											i_self.enable();
											i_self.setValue(s_url);
											i_field.isHandling = false;
											i_self.fireEvent("uploadComplete", i_self, [s_url]);
										}
										else {
											i_el.mask(s_uploadText);
										}
									});
								}
								else {
									Ext.ux.file.util.Handler.uploadFiles(s_uploadpath, [o_record], b_rename, function () {
										if (!b_create) {
											i_el.unmask();
											i_self.enable();
											i_self.setValue(s_url);
											i_field.isHandling = false;
											i_self.fireEvent("uploadComplete", i_self, [s_url]);
										}
										else {
											i_el.mask(s_uploadText);
										}
									});
								}
							}
							else {
								if (!b_create) {
									i_el.unmask();
									i_self.clearInvalid();
									i_self.enable();
									i_field.isHandling = false;
								}
							}
						}, false);
				}
				if (a_create.length > 0) {
					b_create = true;
					if (!b_update) {
						i_el.mask(s_uploadText);
					}

					var s_uploadpath = i_self.path;
					var s_url = ip2.cleanPath([i_self.path, o_file.name].join("/"));
					if (Ext.ux.file.util.Handler.hasFileManager()) {
						Ext.ux.file.util.Handler.createRecords(s_uploadpath, [o_file], false, function () {
							if (!b_update || b_cancel) {
								i_el.unmask();
								i_self.enable();
								i_self.setValue(s_url);
								i_field.isHandling = false;
								i_self.fireEvent("uploadComplete", i_self, [s_url]);
							}
						});
					}
					else {
						Ext.ux.file.util.Handler.uploadFiles(s_uploadpath, [o_file], false, function () {
							if (!b_update || b_cancel) {
								i_el.unmask();
								i_self.enable();
								i_self.setValue(s_url);
								i_field.isHandling = false;
								i_self.fireEvent("uploadComplete", i_self, [s_url]);
							}
						});
					}
				}
			});


		}
		i_field.reset();
	},

	addFormControls: function () {

		var i_self = this;
		var i_fileField = i_self.getFileuploadField();

		i_fileField.on({
			change: {
				fn: function (i_field, value) {
					if (!i_field.isHandling) {
						i_self.onHandelChange(i_field, value);
					}
				}
			}
		});
	},

	createStore: function () {

		var i_self = this;

		i_self.store = Ext.create("Ext.data.Store", {
			fields: ["name", "path"],
			autoLoad: false,
			pageSize: 6,
			proxy: {
				type: "ajax",
				url: i_self.browseService,
				reader: {
					type: "json",
					rootProperty: "rows",
					totalProperty: "totalRows"
				},
				extraParams: {
					func: "listDirByExtension",
					extnList: i_self.extensions,
					metaData: true,
					sort: true
				}
			}
		});
		var i_store = i_self.store;
		i_store.load();

		return i_self;
	},

	getTemplate: function() {

		var i_self = this;

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"<span style=\"",
					"width: 43px;",
					"height: 37px;",
					"background-image: url({[this.getUrl(values.path)]});",
					"background-size: 35px;",
					"background-position: 50% 50%;",
					"background-repeat: no-repeat;",
					"display: inline-block;",
				"\"></span>",
				"<span style=\"",
					"height: 45px;",
					"position: relative;",
					"top: -13px;",
					"padding-left: 10px;",
				"\">{name}</span>",
			"</tpl>",
			{
				getUrl: function(s_value) {

					var a_value = s_value.split(".");
					var s_extensions = a_value.pop().toLowerCase();

					if (Ext.ux.file.util.Handler.imageExtension.indexOf(s_extensions) == -1) {
						return Ext.ux.file.util.Handler.getUrlByExtension(s_value);
					}

					s_value = "/ip2-services/scaleImage.aspx?".concat(
						Ext.Object.toQueryString({
							width: 43,
							height: 37,
							path: s_value,
							padCanvas: false,
							_dc: ip2.getDcTimestamp()
						})
					);

					return s_value;
				}
			}
		);
		return i_tpl;
	},

	createPicker: function() {

		var i_self = this;
		var i_picker;

		var o_options = Ext.apply({
			xtype: "boundlist",
			pickerField: i_self,
			selectionModel: i_self.pickerSelectionModel,
			floating: true,
			hidden: true,
			store: i_self.store,
			preserveScrollOnRefresh: true,
			pageSize: 6,
			tpl: i_self.tpl,
			itemTpl: i_self.getTemplate(),
			createPagingToolbar: function() {
				var i_toolbar = Ext.widget("pagingtoolbar", {
					itemId: "pagingToolbar",
					pageSearch: false,
					pageSizeEdit: false,
					store: i_self.store,
					border: false,
					displayInfo: true
				});

				i_self._toolbar = i_toolbar;

				return i_toolbar;
			}
		}, i_self.listConfig, i_self.defaultListConfig);

		i_picker = i_self.picker = Ext.widget(o_options);

		if (i_self.pageSize) {
			i_picker.pagingToolbar.on("beforechange", i_self.onPageChange, i_self);
		}

		if (!i_picker.initialConfig.maxHeight) {
			i_picker.on({
				beforeshow: i_self.onBeforePickerShow,
				scope: i_self
			});
		}

		i_picker.getSelectionModel().on({
			beforeselect: i_self.onBeforeSelect,
			beforedeselect: i_self.onBeforeDeselect,
			scope: i_self
		});

		return i_picker;
	},

	onAfterrender: function () {

		var i_self = this;
		var s_icon = i_self.getValue();
		var i_el = i_self.getEl();
		var i_input = i_self.inputEl;
		var o_triggers = i_self.getTriggers();

		// Create the fake form to handle uploads
		var i_form = Ext.widget("form", {
			itemId: "fileuploadform",
			renderTo: Ext.getBody(),
			border: false,
			hidden: true,
			items: [
				{
					xtype: "fileuploadfield",
					itemId: "fileuploadfield",
					buttonOnly: true,
					listeners: {
						afterrender: {
							fn: function (i_field) {

								i_self.fileuploadForm = i_field.up("#fileuploadform");
								i_self.addFormControls();
								i_self.fileuploadForm.getEl().insertAfter(i_el);

								var i_uploadDomEl = i_self.getTrigger("upload").getEl();

								i_uploadDomEl.addListener("click", function() {

									i_self.isUploading = true;

									var i_field = i_self.getFileuploadField();
									var i_inputEl = i_field.fileInputEl;
									var i_inputElDom = i_inputEl.dom;

									i_inputElDom.click.apply(i_inputElDom);

									setTimeout(function() {
										i_self.isUploading = false;
									}, 100);
								});
							}
						}
					}
				}
			]
		});

		if (s_icon && Ext.isString(s_icon)) {
			i_self.setImage(s_icon);
		}

		if (i_self.uploadOnly) {
			i_self.setReadOnly(true);
			o_triggers.upload.show();
		}

		// var i_dropzone = Ext.widget("ux.grid.dropzone", {
		// 	renderTo: Ext.getBody(),
		// 	wrapper: i_self.inputWrap,
		// 	zones: [{
		// 		path: i_self.path,
		// 		title: "",
		// 		maxItems: 1
		// 	}],
		// 	style: {
		// 		"position": "absolute",
		// 		"padding": "5px",
		// 		"font-size": "5px",
		// 		"border": "1px solid black"
		// 	},
		// 	dropFn: function(s_value, o_drop) {

		// 		if (s_value) {

		// 			i_self.setValue(s_value);
		// 		}
		// 	}
		// });

		// i_dropzone.getEl().insertBefore(i_self.inputWrap);

		return i_self;
	},

	onPageChange: function(toolbar, newPage) {

		this.loadPage(newPage, {
			rawQuery: true
		});
		return false;
	},

	onBindStore: function(store, initial) {
		this.callParent(arguments);
		this.pickerSelectionModel.deselectOnContainerClick = false;
	},

	setValue: function(value) {

		var i_self = this;
		i_self.callParent(arguments);
		if (value && Ext.isString(value)) {
			i_self.setImage(value);
		}

		if (i_self.uploadOnly) {
			var o_triggers = i_self.getTriggers();
			i_self.setReadOnly(true);
			o_triggers.upload.show();
		}
	},

	onDestroy: function () {

		var i_self = this;
		var i_form = i_self.getFileuploadForm();

		i_form && i_form.destroy();

		i_self.callParent();
	},

	getFileuploadField: function () {

		var i_self = this;
		var i_form = i_self.getFileuploadForm();

		return i_form.down("#fileuploadfield");
	},

	doCrop: function(a_files) {

		Ext.Array.each(a_files, function(s_url) {
			Ext.Ajax.request({
				method: "POST",
				url: "/ip2-services/ip2transaction.aspx",
				jsonData: {
					action: "imageUtl.image_cropTiles",
					image: s_url
				},
				success: function(o_response) {},
				faliure: function(o_err) {}
			});
		});
	},

	doUploadActions: function(s_url) {

		var i_self = this;

		var a_actions = i_self.getUploadActions() || [];

		Ext.Array.each(a_actions, function(o_config) {

			var o_parms = o_config.params || {};
			var s_path = o_config.path;

			if (o_parms.hasOwnProperty("media")) {
				o_parms.media = s_url;
			}
			else {
				o_parms.image = s_url;
			}

			Ext.Ajax.request({
				method: "POST",
				url: s_path,
				jsonData: o_parms,
				success: function(o_response) {
				},
				faliure: function(o_err) {
				}
			});
		});
	},

	doConvert: function(a_files, f_callback) {

		var i_self = this;
		var i_el = i_self.bodyEl;

		i_el.mask(ip2.i18n({
			da: "Konverterer...",
			en: "Converting...."
		}));

		Ext.Array.each(a_files, function(s_url) {
			Ext.Ajax.request({
				method: "POST",
				url: "/ip2-services/ip2transaction.aspx",
				jsonData: {
					action: "pdfutils.createThumbnail",
					path: s_url
				},
				success: function(o_response) {

					i_el.unmask();

					var o_result = Ext.decode(o_response.responseText, true) || {
						success: false
					};

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

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

					i_el.unmask();

					var i_template = Ext.create("Ext.XTemplate",
						"<tpl>",
							"<p><strong>Error {msgid}</strong><p>",
							"<p>Message <i>{text}</i></p>",
						"</tpl>"
					);

					i_template.compile();

					ip2.messageBox({
						icon: Ext.Msg.ERROR,
						title: ip2.i18n({
							da: "<b>" + o_err.statusText + "</b>",
							en: "<b>" + o_err.statusText + "</b>"
						}),
						message: i_template.apply(o_result),
						closable: false,
						yesText: ip2.i18n({
							da: "Ok",
							en: "OK"
						}),
						yesFn: function () {
							f_callback(null);
						}
					});
				}
			});
		});
	},

	onClearClick: function () {

		var i_self = this;

		i_self.clearValue();

		return i_self;
	},

	getValue: function() {

		var i_self = this;

		var value = i_self.callOverridden(arguments);

		if (!value) {
			var i_selectedRecord = i_self.getSelectedRecord();

			value = i_selectedRecord ? i_selectedRecord.get(i_self.valueField) : i_self.getRawValue();
		}

		return value;
	},

	updateImage: function(s_value) {

		var i_self = this;
		var i_inputEl = i_self.inputEl;
		var i_inputWrap = i_self.inputWrap;
		var i_imageEl;

		if (s_value && i_inputEl) {

			i_inputEl.setStyle("padding-left", "50px");

			i_imageEl = i_inputWrap.down("span");

			if (!i_imageEl) {

				var i_template = Ext.create("Ext.XTemplate",
					"<span ",
					 "style=\"",
						"position: absolute;",
						"top: 4px;",
						"left: 10px;",
						"background-image: url({url});",
						"background-size: contain;",
						"background-position: center;",
						"height: 30px;",
						"width: 35px;",
						"background-repeat: no-repeat",
					"\"></span>"
				);

				var s_html = i_template.apply({
					url: s_value
				});

				i_inputWrap.insertFirst(Ext.DomHelper.createDom(s_html))

			}
			else {
				i_imageEl.show();
				i_imageEl.setStyle("background-image", "url(" + s_value + ")")
			}
		}
		else {
			if (i_inputEl) {
				i_inputEl.setStyle("padding-left", "5px");
			}
			if (i_inputWrap) {
				i_imageEl = i_inputWrap.down("span");

				if (i_imageEl) {
					i_imageEl.hide();
				}
			}
		}
	}
});
Ext.define("Ext.ux.form.field.UploadPickerManager", {
	extend: "Ext.ux.form.field.UploadPicker",
	alias: "widget.uploadpickermanager",

	triggers: {
		picker: {
			weight: 1,
			handler: 'onTriggerClick',
			scope: 'this'
		},
		search: {
			cls: 'x-ux-form-trigger-search',
			weight: 2,
			tooltip: ip2.i18n({
				da: "Søg i filmanager",
				en: "Search in file manager"
			}),
			handler: "onTrigger2Click",
			scope: "this"
		},
		upload: {
			cls: 'x-ux-form-trigger-upload',
			tooltip: ip2.i18n({
				da: "Upload en fil",
				en: "Upload a file"
			}),
			weight: 3,
			scope: "this"
		}
	},

	displayField: "FILNAME",

	valueField: "FILFILTKN",

	minChars: 1,

	typeAhead: true,

	typeAheadDelay: 250,

	queryDelay: 1000,

	loadCount: 0,

	record: undefined,

	submitRaw: false,

	initComponent: function() {
		var i_self = this;
		i_self.displayTpl = Ext.create("Ext.XTemplate",
			'<tpl for=".">',
				'<tpl if="this.checkBlank(values.FILFILTKN, values.FILNAME) == true">',
					'',
				'</tpl>',
				'<tpl if="this.checkBlank(values.FILFILTKN, values.FILNAME) == false">',
					'<tpl if="values.FILEXTERNAL == true">',
						'{FILORIPATH}',
					'</tpl>',
					'<tpl if="values.FILEXTERNAL == false">',
						'{FILPATH}{FILNAME}',
					'</tpl>',
				'</tpl>',
			'</tpl>',
			{
				checkBlank: function(FILFILTKN, FILNAME) {
					if (FILFILTKN && FILNAME) {
						return false;
					}
					return true;
				}
			}
		);
		i_self.callParent(arguments);
		if (i_self.saveUrl == undefined) {
			var s_path = ip2.cleanPath(i_self.path) + "/";
			var o_hive = Ext.ux.file.util.Handler.getHiveByPath(s_path);
			i_self.saveUrl = o_hive.saveUrl;
		}
		i_self.createStore();

		i_self.on({
			afterrender: {
				fn: function(item) {
					item.createDropzone();
				}
			}
		});

		return i_self;
	},

	getTemplate: function() {
		var i_self = this;
		var i_tpl = Ext.create("Ext.XTemplate",
			'<tpl for=".">',
				'<tpl if="this.isExternal({FILEXTERNAL}) == true">',
					'<span style="',
						'width: 43px;',
						'height: 37px;',
						'background-image: url({[this.getExtension(values.FILORIPATH)]});',
						'background-size: 35px;',
						'background-position: 50% 50%;',
						'background-repeat: no-repeat;',
						'display: inline-block;',
					'"></span>',
						'<span style="',
						'height: 45px;',
						'position: relative;',
						'top: -13px;',
						'padding-left: 10px;',
					'">{FILORIPATH} (' + ip2.i18n({ da: "ekstern", en: "external" }) + ')</span>',
				'</tpl>',
				'<tpl if="this.isExternal({FILEXTERNAL}) == false">',
					'<span style="',
						'width: 43px;',
						'height: 37px;',
						'background-image: url({[this.getExtension(values.FILPATH + values.FILNAME)]});',
						'background-size: 35px;',
						'background-position: 50% 50%;',
						'background-repeat: no-repeat;',
						'display: inline-block;',
					'"></span>',
						'<span style="',
						'height: 45px;',
						'position: relative;',
						'top: -13px;',
						'padding-left: 10px;',
					'">{FILPATH}{FILNAME}</span>',
				'</tpl>',
			'</tpl>',
			{
				isExternal: function(o_value) {
					var b_isExternal = o_value.FILEXTERNAL;
					return b_isExternal ? true : false;
				}
			},
			{
				getExtension: function(path) {
					var s_value = path;
					var a_value = s_value.split(".");
					var s_extensions = a_value.pop();
					if (Ext.ux.file.util.Handler.imageExtension.indexOf(s_extensions) == -1) {
						return Ext.ux.file.util.Handler.getUrlByExtension(path);
					}
					return "'" + path + "'";
				}
			}
		);
		return i_tpl;
	},

	doSave: function(f_callback) {
		var i_self = this;
		var s_raw = i_self.getRawValue();
		if (i_self.submitRaw) {
			return s_raw;
		}
		var s_value = Number(i_self.getSubmitValue());
		var s_path = ip2.cleanPath(i_self.path) + "/";
		if (Ext.isNumber(s_value)) {
			f_callback(true);
		}
		else {
			var b_isUrl = i_self.isURL(s_raw);
			if (b_isUrl) {
				var s_name = s_raw.split("/").pop();
				var a_files = [s_name];
				Ext.ux.file.util.Handler.getRecordsByName(s_path, a_files, function(a_records) {

					if (a_records.length > 0) {
						var a_conflict = [{
							name: s_name,
							src: s_raw,
							http: a_records[0].data.FILORIPATH,
							external: a_records[0].data.FILEXTERNAL
						}];

						var i_windowConflick = Ext.widget("fileconflict", {
							files: a_conflict,
							path: s_path,
							width: 900,
							height: 600,
							okFn: function(a_override, a_rename) {
								if (a_override.length > 0) {
									if (i_self.saveUrl) {
										Ext.ux.file.util.Handler.curlFileFromURL(s_path, s_raw, function() {
											a_records[0].set("FILORIPATH", s_raw);
											Ext.ux.file.util.Handler.upsertRecords(a_records, function(a_records) {
												i_self.setValue(a_records);
												f_callback(true);
											});
										});
									}
									else {
										a_records[0].set("FILORIPATH", s_raw);
										Ext.ux.file.util.Handler.upsertRecords(a_records, function(a_records) {
											i_self.setValue(a_records);
											f_callback(true);
										});
									}
								}
								if (a_rename.length > 0) {
									if (i_self.saveUrl) {
										var s_name = a_rename[0].suggestedName;
										Ext.ux.file.util.Handler.createRecordByUrlWithName(s_path, s_raw, s_name, function(a_records) {
											i_self.setValue(a_records);
											f_callback(true);
										});
									}
									else {
										var a_file = [{
											name: a_rename[0].suggestedName,
											size: 0,
											external: true
										}];
										Ext.ux.file.util.Handler.createRecordsNoUploadNoImageInfo(s_path, a_file, function(a_records) {
											var o_record = a_records[0];
											o_record.set("FILFILTKN", 0);
											o_record.set("FILORIPATH", s_raw);
											Ext.ux.file.util.Handler.upsertRecords(a_records, function(a_records) {
												i_self.setValue(a_records);
												f_callback(true);
											});
										});
									}
								}
								if (a_override.length == 0 && a_rename.length == 0) {
									f_callback(false);
								}
							},
							cancelFn: function() {
								f_callback(false);
							}
						});

						i_windowConflick.show();
					}
					else {
						if (i_self.saveUrl) {
							Ext.ux.file.util.Handler.createRecordByUrl(s_path, s_raw, function(a_records) {
								i_self.setValue(a_records);
								f_callback(true);
							});
						}
						else {
							var a_file = [{
								name: s_name,
								size: 0,
								external: true
							}];
							Ext.ux.file.util.Handler.createRecordsNoUploadNoImageInfo(s_path, a_file, function(a_records) {
								var o_record = a_records[0];
								o_record.set("FILFILTKN", 0);
								o_record.set("FILORIPATH", s_raw);
								Ext.ux.file.util.Handler.upsertRecords(a_records, function(a_records) {
									i_self.setValue(a_records);
									f_callback(true);
								});
							});
						}
					}
				});
			}
			else {
				var a_raw = s_raw.split("/");
				var s_name = a_raw.pop();
				var s_path = a_raw.join("/") + "/";
				Ext.ux.file.util.Handler.getRecordByName(s_path, s_name, function(a_records) {
					if (a_records.length == 0) {
						f_callback(false);
						var s_title = ip2.i18n({
							da: "Fejl",
							en: "Error"
						});
						var s_msg = ip2.i18n({
							da: "Ingen fil fundet, vælg en anden",
							en: "No fil found, please choosen another"
						});

						Ext.Msg.show({
							title: s_title,
							msg: s_msg,
							buttons: Ext.Msg.OK,
							icon: Ext.Msg.ERROR
						});
					}
					else {
						var o_record = a_records[0];
						i_self.setValue(o_record);
						f_callback(true);
					}
				});
			}
		}
	},

	onTrigger2Click: function() {
		var i_self = this;
		var a_triggers = i_self.triggerEl.elements;
		var el = a_triggers[1];
		var s_path = ip2.cleanPath(i_self.path) + "/";
		var wnd = Ext.widget("filesearch", {
			animateTarget: el,
			path: s_path,
			okFn: function(o_record) {
				i_self.setValue([o_record]);
			}
		});

		wnd.show();
	},

	createStore: function () {

		var i_self = this;
		var s_path = ip2.cleanPath(i_self.path) + "/";
		var i_store = Ext.create('Ext.data.Store', {
			model: ip2.model({
				dmd: "dmd/webshop.dmd",
				entityName: "WSHFILET00",
				context: 'grid',
				uiName: "portfolio"
			}),
			autoLoad: false,
			pageSize: i_self.pageSize,
			proxy: {
				type: 'ajax',
				url: '/ip2-Services/ip2dmdproxy.aspx',
				reader: {
					type: 'json',
					rootProperty: 'rows',
					totalProperty: 'totalRows'
				},
				extraParams: {
					dmdFile: 'dmd/webshop.dmd',
					model: "WSHFILET00",
					context: "grid",
					uiName: "portfolio",
					action: "getRows",
					sort: "FILFILTKN",
					dir: "asc",
					where: "FILPATH = '" + s_path + "'"
				}
			}
		});

		i_store.load();

		i_self.store = i_store;

		return i_self;
	},

	createDropzone: function() {
		var i_self = this;
		var s_path = ip2.cleanPath(i_self.path) + "/";
		var el = i_self.inputEl;

		var o_dropbox = Ext.widget("gallerydropbox", {
			flex: 1,
			dropText: ip2.i18n({ da: "Drop for at tilføje file", en: "Drop to add file" }),
			path: s_path,
			extensions: Ext.isDefined(i_self.extensions) ? i_self.extensions : Ext.ux.file.util.Handler.extensions,
			maxItems: 1,
			style: {
				"position": "absolute",
				"padding": "5px",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"font-size": "25px"
			},
			listeners: {
				bodydragenter: function(i_dropbox, o_event) {
					if (i_self.inputEl) {
						var inputWidth = i_self.inputEl.getWidth();
						var dropzoneWidth = i_self.dropzone.el.getWidth();
						if (dropzoneWidth != inputWidth) {
							i_self.dropzone.setWidth(inputWidth);

							var i_dropzone = i_self.dropzone;

							var f_layout = i_dropzone.doLayout || i_dropzone.updateLayout;

							f_layout.call(i_dropzone);
						}

						i_self.dropzone.getEl().setStyle("display", "inline");
						i_self.dropzone.getEl().setStyle("opacity", "0.7");
					}
				},
				bodydragleave: function(i_dropbox, o_event) {
					i_self.dropzone.getEl().setStyle("display", "none");
					i_self.dropzone.getEl().setStyle("opacity", "0");
				},
				drop: {
					fn: function(i_dropbox, a_files, o_event) {
						var plugin = i_dropbox.getDDPlugin();
						var bodyEl = i_self.bodyEl;
						if (plugin.enableDrop) {
							var msg = ip2.i18n({
								da: "Kontrolerer file....",
								en: "Checking file..."
							});

							bodyEl.mask(msg);
							Ext.ux.file.util.Handler.checkFiles(i_dropbox.path, a_files, function(o_result) {
								bodyEl.unmask();
								var a_update = o_result.update;
								var a_create = o_result.create;
								var b_update = false;
								var b_cancel = false;
								var b_create = false;
								var a_result = [];
								if (a_update.length > 0) {
									b_update = true;
									Ext.ux.file.util.Handler.getUIConflickWindow(bodyEl, i_self, i_dropbox.path, a_update,
										function(cancel, a_records) {
											b_cancel = cancel;
											ip2.each(a_records, function(o_record) {
												a_result.push(o_record);
											});
											if (!b_create) {
												bodyEl.unmask();
												if (a_result.length > 0) {
													i_self.setValue(a_result);
												}
											}
											else {
												var msg = ip2.i18n({
													da: "Opretter file....",
													en: "Creating file..."
												});
												bodyEl.mask(msg);
											}
										}
									);
								}
								if (a_create.length > 0) {
									b_create = true;
									if (!b_update) {
										bodyEl.unmask();
										var msg = ip2.i18n({
											da: "Opretter file....",
											en: "Creating file..."
										});
										bodyEl.mask(msg);
									}
									Ext.ux.file.util.Handler.createRecords(i_dropbox.path, a_create, false, function(a_records) {
										b_create = false;
										ip2.each(a_records, function(o_record) {
											a_result.push(o_record);
										});
										if (!b_update) {
											bodyEl.unmask();
											i_self.setValue(a_result);
										}
										if (b_cancel) {
											bodyEl.unmask();
											i_self.setValue(a_result);
										}
									});
								}
							});
						}
					}
				},
				dragenter: {
					fn: function(i_dropbox, o_event) {
						var plugin = i_dropbox.getDDPlugin();
						var items = o_event.dataTransfer.items || o_event.dataTransfer.files;
						if (i_dropbox.maxItems) {
							if (items.length > i_dropbox.maxItems && i_dropbox.maxItems != -1) {
								i_dropbox.addCls(plugin.failureCls);
								plugin.enableDrop = false;
							}
						}
					}
				},
				dragleave: {
					fn: function(i_dropbox, o_event) {
						var plugin = i_dropbox.getDDPlugin();
						plugin.enableDrop = true;
					}
				}
			}
		});
		var i_dropzone = Ext.widget("container", {
			layout: "fit",
			renderTo: Ext.getBody(),
			style: {
				"background-color": "white",
				"position": "absolute",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"display": "none",
				"opacity": "0"
			},
			items: [o_dropbox]
		});
		i_self.dropzone = i_dropzone;
		i_dropzone.getEl().insertBefore(el);
	},

	setValue: function(value, f_callback) {

		var i_self = this;
		var s_url = "";

		if (value && (typeof value !== "object")) {
			var s_path = ip2.cleanPath(i_self.path) + "/";
			var id = Number(value);
			if (Ext.isNumber(id)) {
				if (i_self.loadCount == 0) {
					i_self.loadCount++;
					Ext.ux.file.util.Handler.getRecordById(id, function(o_record) {
						if (o_record) {
							i_self.setValue(o_record, f_callback);
						}
					});
				}
			}
			else {
				if (i_self.loadCount == 0) {
					i_self.loadCount++;
					var a_split = value.split("/");
					var s_name = a_split.pop();
					var s_valuePath = a_split.join("/");
					if (s_valuePath) {
						s_path = s_valuePath + "/";
					}
					Ext.ux.file.util.Handler.getRecordByName(s_path, s_name, function(a_records) {
						if (a_records) {
							var o_record = a_records[0];
							i_self.setValue(o_record, f_callback);
						}
					});
				}
			}
		}
		else {
			i_self.loadCount = 0;
			if (value) {
				var o_record = undefined;

				if (Ext.isArray(value)) {
					o_record = value[0];
				}
				else {
					o_record = value;
				}
				if (o_record) {
					i_self.record = o_record;

					var b_isExternal = o_record.get("FILEXTERNAL");

					if (b_isExternal) {
						s_url = o_record.get("FILORIPATH");
					}
					else {
						s_url = o_record.get("FILPATH") + o_record.get("FILNAME");
					}
					i_self.setIconCls(i_self.getCSS(s_url));
					i_self.callParent(arguments);
					i_self.fireEvent("select", i_self, [o_record]);
					if (f_callback) {
						f_callback();
					}
				}
			}
		}
	},

	getRecord: function() {
		var i_self = this;
		return i_self.record;
	},

	isURL: function(value) {
		var s_value = String(value);
		var r_http = new RegExp('\\b(ftps?|https?)(:\/\/)', 'g');
		var a_match = s_value.match(r_http);
		return a_match ? true : false;
	},

	onHandelChange: function(item, value) {

		if (!value) {
			return;
		}
		var i_self = this;
		var i_el = i_self.bodyEl;
		var s_path = ip2.cleanPath(i_self.path) + "/";
		var i_fileField = i_self.getFileuploadField();
		var a_files = item.fileInputEl.dom.files;
		var s_extension = a_files[0].name.split(".").pop().toLowerCase();
		var a_extensions = i_self.extensions.split(",");

		if (a_extensions.indexOf(s_extension) != -1) {
			var el = i_self.triggerEl.elements[1];
			var msg = ip2.i18n({
				da: "Kontrolerer fil....",
				en: "Checking file..."
			});
			i_el.mask(msg);
			Ext.ux.file.util.Handler.checkFiles(s_path, a_files, function(o_result) {
				i_el.unmask();

				var a_update = o_result.update;
				var a_create = o_result.create;

				var b_update = false;
				var b_create = false;
				var b_cancel = false;

				var a_result = [];

				if (a_update.length > 0) {
					b_update = true;
					Ext.ux.file.util.Handler.getUIConflickWindow(el, i_self, s_path, a_update, function(cancel, a_records) {
						b_cancel = cancel;
						ip2.each(a_records, function(o_record) {
							a_result.push(o_record);
						});
						if (!b_create) {
							i_el.unmask();
							i_self.setValue(a_result);
						}
						else {
							var msg = ip2.i18n({
								da: "Opretter filer....",
								en: "Creating files..."
							});
							i_el.mask(msg);
						}
					});
				}
				if (a_create.length > 0) {
					b_create = true;
					if (!b_update) {
						var msg = ip2.i18n({
							da: "Opretter filer....",
							en: "Creating files..."
						});
						i_el.mask(msg);
					}
					Ext.ux.file.util.Handler.createRecords(s_path, a_create, false, function(a_records) {
						b_create = false;
						ip2.each(a_records, function(o_record) {
							a_result.push(o_record);
						});
						if (!b_update) {
							i_el.unmask();
							i_self.setValue(a_result);
						}
						if (b_cancel) {
							i_el.unmask();
							i_self.setValue(a_result);
						}
					});
				}
			});
		}
		else {
			var s_title = ip2.i18n({
				da: "Fejl",
				en: "Error"
			});
			var s_msg = ip2.i18n({
				da: "Denne fil type er ikke tilladt",
				en: "This fil type is not allowed"
			});

			Ext.Msg.show({
				title: s_title,
				msg: s_msg,
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
		}
		item.reset();
	}
});
Ext.define("Ext.ux.form.field.UploadPickerRelation", {
	extend: "Ext.form.FieldContainer",
	mixins: {
		field: 'Ext.form.field.Field'
	},
	alias: "widget.uploadpickerrelation",

	picker: null,
	layout: "fit",
	relation: null,
	model: null,

	value: '',

	initComponent: function() {

		var i_self = this;

		i_self.callParent();

		i_self.add(i_self.createPicker());

		i_self.initField();

		delete i_self.relation;

		i_self.on({
			afterrender: {
				fn: function(i_field) {
					var i_record = i_field.record;
					var s_key = i_record != undefined ? i_record.idProperty : '';
					var n_tkn = i_record != undefined ? i_record.get(s_key) : 0;
					i_self.getDBRelation(n_tkn, function(i_relation) {
						if (i_relation) {
							var i_picker = i_self.getPicker();
							i_picker.setValue(i_relation.get("RELCHDTKN"), function() {
								var i_xpdeditorfield = null;
								i_self.setValue(i_relation.get("RELCHDTKN"));
								i_picker.resetOriginalValue();
								i_self.resetOriginalValue();

								i_xpdeditorfield = i_self.up("xpdeditorfield");
								if (i_xpdeditorfield) {
									i_xpdeditorfield.resetOriginalValue();
									i_xpdeditorfield.fireEvent("reset", i_xpdeditorfield);
								}
								var i_entityform = i_self.up("entityform");
								if (i_entityform) {
									i_entityform.fireEvent("dirtychange", i_entityform);
								}
							});
						}
					});
					i_self.picker.on({
						change: {
							fn: function(i_picker, value) {
								i_self.setValue(value);
							}
						}
					});
				}
			}
		});
	},

	createPicker: function() {
		var i_self = this;
		var o_config = ip2.extend(i_self.initialConfig, {
			submitRaw: false,
			isFormField: false,
			isWidget: true
		});

		delete o_config.fieldLabel;
		var i_picker = Ext.widget("uploadpickermanager", o_config);
		i_self.picker = i_picker;
		return i_picker;
	},

	getModel: function() {
		var i_self = this;
		if (!i_self.model) {
			i_self.model = ip2.model({
				dmd: "dmd/webshop.dmd",
				entityName: "WSHRELET00",
				context: 'grid',
				uiName: "portfolio"
			});
		}
		return i_self.model;
	},

	getTypeEnumValue: function (s_key, enumValue) {

		var i_self = this;
		var s_lang = wsh.i18n.getPrimary();

		var i_ns = ip2.resource.get('adm.ns', true);
		var o_value = i_ns.getEnumValue(s_key + '~' + enumValue);

		return o_value[s_lang];
	},

	getRelation: function() {
		var i_self = this;
		return i_self.relation;
	},

	getDBRelation: function(n_tkn, f_callback) {
		var i_self = this;
		var n_parentrelationtype = i_self.getTypeEnumValue('parentRelationTypes', i_self.parentEnumType);
		var n_childrelationtype = i_self.getTypeEnumValue('childRelationTypes', i_self.childEnumType);
		var a_batch = [];

		a_batch.push({
			type: 'get',
			dmd: 'dmd/webshop.dmd',
			entity: 'WSHRELET00',
			context: 'grid',
			uiName: 'portfolio',
			where: 'RELPNTTKN = ' + n_tkn + " AND RELPNTTYP =" + n_parentrelationtype + " AND  RELCHDTYP = " + n_childrelationtype,
			page: 1,
			start: 0,
			limit: -1
		});

		Ext.Ajax.request({
			url: '/ip2-Services/ip2dmdproxy.aspx',
			jsonData: {
				transaction: {
					batch: a_batch
				}
			},
			success: function (o_response) {

				var o_result = JSON.parse(o_response.responseText);
				var o_batch = o_result.batch[0];
				var o_relation;
				var i_relation;
				var Model = i_self.getModel();
				if (o_batch && o_batch.rows) {
					if (o_batch.rows.length > 0) {
						o_relation = o_batch.rows[0];
						o_relation.RELPNTTYP = n_parentrelationtype;
						o_relation.RELCHDTYP = n_childrelationtype;
						o_relation.RELPNTTKN = n_tkn;

						i_relation = Model.create(o_relation);
						i_self.relation = i_relation;
					}
				}
				f_callback(i_relation);
			}
		});
	},

	getPicker: function() {
		var i_self = this;
		return i_self.picker;
	},

	getValue: function() {

		var i_self = this;
		var i_picker = i_self.getPicker();
		if (i_self.submitRaw) {
			var i_relation = i_self.getRelation();
			if (i_relation) {
				delete i_self.relation;
				i_self.deleteRelation(i_relation, function() {});
			}
			return i_picker.getRawValue();
		}
		else {
			return i_picker.getValue();
		}
	},

	setValue: function(value) {
		var i_self = this;
		if (i_self.getPicker()) {
			i_self.picker.setValue(value);
		}
		i_self.mixins.field.setValue.call(i_self, value);
	},

	doSave: function(f_callback) {
		var i_self = this;
		var i_picker = i_self.getPicker();
		var i_relation = i_self.getRelation();
		if (i_self.submitRaw) {
			i_self.deleteRelation(i_relation, function() {
				delete i_self.relation;
				f_callback(i_self.getValue());
			});
		}
		else {
			i_picker.doSave(function() {
				var n_value = i_self.getValue();
				var i_relation = i_self.getRelation();
				if (!i_relation) {
					var n_parentrelationtype = i_self.getTypeEnumValue('parentRelationTypes', i_self.parentEnumType);
					var n_childrelationtype = i_self.getTypeEnumValue('childRelationTypes', i_self.childEnumType);
					i_relation = i_self.getModel().create({
						RELPNTTYP: n_parentrelationtype,
						RELCHDTYP: n_childrelationtype,
						RELPNTTKN: i_self.record.get(i_self.record.idProperty)
					});
				}
				i_relation.set("RELCHDTKN", n_value);
				i_self.upsertRelation(i_relation, function(i_relation) {
					i_self.relation = i_relation;
					f_callback(i_relation);
				});
			});
		}
	},

	deleteRelation: function(i_record, f_callback) {

		if (i_record) {
			var i_self = this;
			var a_batch = [];

			var key = {};
			key[i_record.idProperty] = i_record.get(i_record.idProperty);
			a_batch.push({
				type: 'delete',
				dmd: 'dmd/webshop.dmd',
				entity: "WSHRELET00",
				key: key
			});

			Ext.Ajax.request({
				url: '/ip2-Services/ip2dmdproxy.aspx',
				jsonData: {
					transaction: {
						batch: a_batch
					}
				},
				success: function (o_response) {
					f_callback();
				}
			});
		}
		else {
			f_callback();
		}
	},

	upsertRelation: function(i_relation, f_callback) {
		var i_self = this;
		var a_batch = [];

		var key = {};
		key[i_relation.idProperty] = i_relation.get(i_relation.idProperty);
		a_batch.push({
			type: 'upsert',
			dmd: 'dmd/webshop.dmd',
			entity: "WSHRELET00",
			key: key,
			row: i_relation.data
		});

		Ext.Ajax.request({
			url: '/ip2-Services/ip2dmdproxy.aspx',
			jsonData: {
				transaction: {
					batch: a_batch
				}
			},
			success: function (o_response) {
				var o_result = JSON.parse(o_response.responseText);
				var o_batch = o_result.batch[0];
				var o_record = o_batch.row;
				i_relation.set(o_record);
				f_callback(i_relation);
			}
		});
	}
});
Ext.define("Ext.ux.form.field.DownloadPicker", {

    extend: "Ext.ux.form.field.UploadPicker",

    alias: [
        "widget.downloadpicker",
    ],

    triggers: {
        download: {
            cls: "x-ux-form-trigger-download",
            handler: "onDownloadClick",
            tooltip: ip2.i18n({
                da: "Download fil",
                en: "Donwload file"
            }),
            hidden: true,
            weight: 3,
            scope: "this",
            onClick: function() {

                var i_self = this;
                var args = arguments;
                var e = i_self.clickRepeater ? args[1] : args[0];
                var handler = i_self.handler;
                var i_field = i_self.field;

                if (handler && i_self.isFieldEnabled()) {

                    Ext.callback(i_self.handler, i_self.scope, [
                        i_field,
                        i_self,
                        e
                    ], 0, i_field);
                }
            }
        }
    },

    listeners: {
        afterrender: {
            fn: function(i_field) {

                var s_value = i_field.getValue();

                var i_trigger = i_field.getTrigger("download");

                if (i_trigger) {
                    i_trigger[Ext.isEmpty(s_value) ? "hide" : "show"]();
                }
            }
        },
        change: {
            fn: function(i_field, s_value) {

                var i_trigger = i_field.getTrigger("download");

                if (i_trigger) {
                    i_trigger[Ext.isEmpty(s_value) ? "hide" : "show"]();
                }
            }
        },
        enable: {
			fn: function(i_field) {

				var s_value = i_field.getValue();

				i_field.getTrigger("download")[Ext.isEmpty(s_value) ? "hide" : "show"]();
			},
			buffer: 10
		},
		disable: {
			fn: function(i_field) {
                
				i_field.getTrigger("download").hide();
			},
			buffer: 10
		},
		writeablechange: {
			fn: function(i_field, b_readOnly) {

				var s_value = i_field.getValue();

				if (!b_readOnly) {
				    i_field.getTrigger("download")[Ext.isEmpty(s_value) ? "hide" : "show"]();
				}
			},
			buffer: 10
		}
    },

    onDownloadClick: function() {

		var i_self = this;

        var s_value = i_self.getValue();
        
        var anchor = document.createElement("a");
        anchor.href = s_value;
        anchor.download = s_value;
        document.body.appendChild(anchor);
        anchor.click();

        document.body.removeChild(anchor);
	}
})
Ext.define("Ext.ux.form.field.IncludeComboBox", {

	extend: "Ext.form.FieldContainer",

	mixins: {
		"field": "Ext.form.field.Field",
		"componentController": "Ext.ux.util.ComponentController"
	},

	alias: [
		"widget.includecombo",
		"widget.includecombobox"
	],

	refs: [
		{
			ref: "form",
			selector: "#typeForm"
		},
		{
			ref: "typesGroup",
			selector: "#typesGroup"
		},
		{
			ref: "typeInclude",
			selector: "#typeInclude"
		},
		{
			ref: "typeExclude",
			selector: "#typeExclude"
		},
		{
			ref: "typeAll",
			selector: "#typeAll"
		},
		{
			ref: "keysCombo",
			selector: "#keysCombo"
		}
	],

	value: "",

	layout: "anchor",

	typeConfig: null,
	listConfig: null,
	_includeComboValue: false,

	config: {
		asString: true
	},

	initComponent: function () {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;
		

		i_cmp.value = o_config.value = Ext.decode(o_config.value) || o_config.value;

		// Sanitize the configuration from deprecated
		var o_typeConfig = (function () {

			var o_type = {};
			var o_default = {
				includeLabel: {
					da: "Inkluder i",
					en: "Include in"
				},
				excludeLabel: {
					da: "Udelad fra",
					en: "Exclude from"
				},
				allLabel: {
					da: "Brug alle",
					en: "Use all"
				}
			};

			if (o_config.typeConfig) {
				if (o_config.typeConfig.includeText) {
					o_config.typeConfig.includeLabel = o_config.typeConfig.includeText;
				}
				if (o_config.typeConfig.excludeText) {
					o_config.typeConfig.excludeLabel = o_config.typeConfig.excludeText;
				}
				if (o_config.typeConfig.allText) {
					o_config.typeConfig.allLabel = o_config.typeConfig.allText;
				}
				o_type = Ext.Object.merge(o_default, o_config.typeConfig);
			}
			else {
				if (o_config.includeLabel) {
					o_type.includeLabel = o_config.includeLabel;
				}
				if (o_config.excludeLabel) {
					o_type.excludeLabel = o_config.excludeLabel;
				}
				if (o_config.allLabel) {
					o_type.allLabel = o_config.allLabel;
				}

				o_type = Ext.Object.merge(o_default, o_type);
			}

			return o_type;
		})();

		var o_listConfig = (function () {

			var o_list = {};

			if (o_config.listConfig) {
				o_list.dmd = o_config.listConfig.dmd;
				o_list.entity = o_config.listConfig.entity;
				o_list.view = o_config.listConfig.uiName;
			}
			else {
				o_list.dmd = o_config.dmd;
				o_list.entity = o_config.entity;
				o_list.view = o_config.view;
			}

			Ext.Object.merge(o_list, ip2.pick(o_config, [
				"extraParams",
				"pageSize",
				"emptyText"
			]));

			return o_list;
		})();

		Ext.apply(i_cmp, {
			items: i_cmp.createItems(o_typeConfig, o_config, o_listConfig)
		});

		i_cmp.initComponentController();

		i_cmp.callParent(arguments);

		i_cmp.initField();

		i_cmp.control({
			"typeAll": {
				change: i_cmp.onComponentChange,
				scope: i_cmp
			},
			"typeInclude": {
				change: i_cmp.onComponentChange,
				scope: i_cmp
			},
			"typeExclude": {
				change: i_cmp.onComponentChange,
				scope: i_cmp
			}
		});

		i_cmp.setValue(i_cmp.value);
		i_cmp.resetOriginalValue();

		return i_cmp;
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value;

		if (Ext.isString(value)) {
			value = Ext.decode(value, true) || value;
		}

		if (Ext.isEmpty(value)) {
			value = i_self.getValue();
		}

		i_self.value = i_self.lastValue = i_self.originalValue = value;
		i_self.resetOriginalValue();
	},

	onComponentChange: function () {

		var i_cmp = this;
		var i_all = i_cmp.getTypeAll();
		var i_combo = i_cmp.getKeysCombo();
		var s_fn = i_all.getValue() ? "hide" : "show";

		i_combo[s_fn]();

		setTimeout(function () {
			i_cmp.checkChange();
		}, 0);

		return i_cmp;
	},

	checkChange: function() {

		var i_self = this;
		if (!i_self.suspendCheckChange) {
			var newVal = i_self.getValue();
			var oldVal = i_self.lastValue;

			var s_new = JSON.stringify(newVal);
			var s_old = JSON.stringify(oldVal);

			if (!i_self.isEqual(s_new, s_old) && !i_self.isDestroyed) {
				i_self.lastValue = newVal;
				i_self.fireEvent("change", i_self, newVal, oldVal);
				i_self.onChange(newVal, oldVal);
			}
		}
	},

	getValue: function () {

		var i_cmp = this;
		var i_type = i_cmp.getTypesGroup();
		var i_combo = i_cmp.getKeysCombo();
		var s_type = i_type.getChecked()[0] ? i_type.getChecked()[0].getGroupValue() : i_type.getValue().type;

		if (s_type == "all") {
			return "";
		}
		else {

			var o_value = i_type.getValue();
			var comboValue = i_cmp.value && i_cmp.value.keys ? i_cmp.value.keys : "";

			if (i_cmp._includeComboValue) {
				comboValue = i_combo.getValue();

				if (Ext.isArray(comboValue)) {

					if (comboValue.length == 1) {
						comboValue = comboValue[0];
					}
				}

				if (comboValue) {
					o_value.keys = comboValue;
				}
			}
			else {
				o_value.keys = comboValue;
			}

			if (!o_value.keys) {
				o_value = "";
			}

			return i_cmp.getAsString() ? Ext.encode(o_value, true) || "" : o_value;
		}
	},

	setValue: function (value) {

		var i_cmp = this;
		var i_type = i_cmp.getTypesGroup();
		var i_combo = i_cmp.getKeysCombo();

		if (Ext.isString(value)) {
			value = Ext.decode(value, true) || value;
		}

		if (value && value.type) {
			i_type.setValue(value);
		}
		else {
			i_type.setValue({ type: "all" });
		}

		if (value && value.keys) {

			var a_value = Ext.Array.from(value.keys);
			var comboValue = a_value.length == 1 ? a_value[0] : a_value;

			i_combo.show();
			i_combo.setValue(comboValue);
		}
		else {
			i_combo.setValue([]);
			i_combo.hide();
		}

		i_cmp.mixins.field.setValue.call(i_cmp, value);

		return i_cmp;
	},

	isDirty: function () {

		var i_cmp = this;
		var value = i_cmp.getValue();
		var originalValue = i_cmp.originalValue;

		var b_dirty = ip2.isEqual(value, originalValue);

		return !b_dirty;
	},

	disable: function() {

		var i_cmp = this;
		i_cmp.callParent(arguments);

		var i_all = i_cmp.getTypeAll();
		var i_include = i_cmp.getTypeInclude();
		var i_exclude = i_cmp.getTypeExclude();

		i_all.disable();
		i_include.disable();
		i_exclude.disable();
	},

	createItems: function(o_typeConfig, o_config, o_listConfig) {

		var i_self = this;

		var a_items = [
			{
				xtype: "form",
				itemId: "typeForm",
				border: false,
				layout: "anchor",
				items: [
					{
						xtype: "radiogroup",
						itemId: "typesGroup",
						vertical: true,
						columns: 1,
						isFormField: false,
						items: [
							{
								itemId: "typeAll",
								boxLabel: ip2.i18n(o_typeConfig.allLabel),
								name: "type",
								inputValue: "all",
								readOnly: i_self.readOnly,
								checked: (function () {
									var b_checked = false;
									if (!o_config.value) {
										b_checked = true;
									}
									return b_checked;
								})(),
								isFormField: false
							},
							{
								itemId: "typeInclude",
								boxLabel: ip2.i18n(o_typeConfig.includeLabel),
								name: "type",
								inputValue: "include",
								readOnly: i_self.readOnly,
								checked: (function () {
									var b_checked = false;
									if (o_config.value && o_config.value.type == "include") {
										b_checked = true;
									}
									return b_checked;
								})(),
								isFormField: false
							},
							{
								itemId: "typeExclude",
								boxLabel: ip2.i18n(o_typeConfig.excludeLabel),
								name: "type",
								inputValue: "exclude",
								readOnly: i_self.readOnly,
								checked: (function () {
									var b_checked = false;
									if (o_config.value && o_config.value.type == "exclude") {
										b_checked = true;
									}
									return b_checked;
								})(),
								isFormField: false
							}
						]
					},
					(function () {
						var o_comboConfig = ip2.extend({
							itemId: "keysCombo",
							name: "keys",
							isFormField: false,
							anchor: "100%",
							hidden: true,
							forceSelection: true,
							readOnly: i_self.readOnly,
							listeners: {
								change: {
									fn: function () {
										i_self.checkChange();
									}
								},
								afterrender: {
									fn: function () {
										i_self._includeComboValue = true;
									},
									single: true
								}
							},
							value: (function () {

								var value = i_self.value || {
									keys: []
								};

								return value.keys || [];
								
							})()
						}, o_listConfig);
						var i_combo = Ext.widget("entitycombobox", o_comboConfig);
						return i_combo;
					})()
				]
			}
		];

		return a_items;
	}
});
Ext.define("Ext.ux.form.field.ISOTimestampField", {
	extend: "Ext.form.FieldContainer",
	mixins: {
		field: "Ext.form.field.Field"
	},

	alias: "widget.isotimestampfield",

	config: {
		dateParseFormat: ip2.date2dbDate.parseFormat,
		dateFormat: ip2.date2dbDate.format,
		format: "d-m-Y",
		datevalue: "",
		timevalue: 0,

		maxValue: 0,
		minValue: 0,
		step: 0,
		asHigh: false,

		decimalPrecision: 0,
		forcePrecision: true,
		decimalSeparator: ":",

		dateField: undefined,
		timeField: undefined,
		microField: undefined,

		secondsValue: "00",

		date: true,
		time: true,
		micro: false,
		seconds: false,

		"native": false
	},

	altFormats: "|d-n-Y|d-n-y|j-n-Y|j-n-y|" +
	"|d/n/Y|d/n/y|j/n/Y|j/n/y|" +
	"|d-m-Y|d-m-y|j-m-Y|j-m-y|" +
	"|d/m/Y|d/m/y|j/m/Y|j/m/y|" +
	"|m/d/Y|m/d/y|m/j/Y|m/j/y|" +
	"|m-d-Y|m-d-y|m/j/Y|m/j/y|" +
	"|n/d/Y|n/d/y|n/j/Y|n/j/y|" +
	"|n-d-Y|n-d-y|n-j-Y|n-j-y|" +
	"|Y-m-d|y-m-d|Y-n-d|y-n-d|" +
	"|Y-m-j|y-m-j|Y-n-j|y-n-j|" +
	"|Y/m/d|y/m/d|Y/n/d|y/n/d|" +
	"|Y/m/j|y/m/j|Y/n/j|y/n/j|" +
	"|d.m.Y|d.m.y|j.m.Y|j.m.y|" +
	"|d.n.Y|d.n.y|j.n.Y|j.n.y|" +
	"|m.d.Y|m.d.Y|m.j.Y|m.j.y|" +
	"|n.d.Y|n.d.y|n.j.Y|n.j.y|" +
	"|Y.m.d|y.m.d|Y.m.j|y.m.j|" +
	"|Y.n.d|y.n.d|Y.n.j|y.n.j|" +
	"|dmY|dmy|jmY|jmy|" +
	"|dnY|dny|jnY|jny|" +
	"|mdY|mdy|mjY|mjy|" +
	"|ndY|ndy|njY|njy|" +
	"|Ymd|ymd|Ymj|ymj|" +
	"|Ynd|ynd|Ynj|ynj|",

	layout: {
		type: "hbox",
		align: "stretch"
	},
	defaults: {
		"margin": "0 5 0 0"
	},
	readOnly: false,

	initComponent: function () {

		var i_self = this;
		i_self.callParent();

		i_self.fieldLabel = i_self.fieldLabel;
		if (!i_self.step) {
			i_self.step = i_self.seconds ? 0.0001 : 0.01;
		}
		i_self.maxValue = i_self.seconds ? 23.5959 : 23.59;
		i_self.minValue = 0.00;
		i_self.decimalPrecision = i_self.seconds ? 4 : 2;
		var i_datefield = i_self.createDateField();
		var i_timefield = i_self.createTimeField();
		var i_microfield = i_self.createMicroField();

		if (!i_self.getDate()) {
			i_datefield.hidden = true;
		}
		if (!i_self.getTime()) {

			i_timefield.hidden = true;
			i_self.micro = false;

			i_datefield.setMargin("0 0 0 0");
		}
		if (!i_self.getMicro()) {
			i_microfield.hidden = true;
		}

		i_datefield.on({
			change: {
				fn: function(item) {
					i_self.checkChange();
				}
			}
		});

		i_timefield.on({
			change: {
				fn: function(item) {
					i_self.checkChange();
				},
				buffer: 250
			}
		});

		i_self.setDateField(i_datefield);
		i_self.setTimeField(i_timefield);
		i_self.setMicroField(i_microfield);

		i_self.add(i_datefield);
		i_self.add(i_timefield);
		i_self.add(i_microfield);

		i_self.initField();
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value;
		var date;

		if (Ext.isDate(value)) {
			date = value;
		}
		else {
			if (value) {
				var a_split = [];

				if (!i_self.date) {

					var i_date = new Date();
					var n_year = i_date.getFullYear();
					var n_month = i_date.getMonth() + 1;
					var n_day = i_date.getDate();

					a_split = value.split(".");

					a_split = Ext.Array.map(a_split, function(s_value) {
						var s_return = s_value;
						var n_value = parseInt(s_value);
						if (n_value) {
							if (n_value < 10 && s_value.length < 2) {
								s_return = "0" + s_value;
							}
						}
						else {
							if (!isNaN(n_value)) {
								if (s_value.length < 2) {
									s_return = "0" + s_value;
								}
							}
							else {
								s_return = "00";
							}
						}
						return s_return;
					});
					value = a_split.join(".");

					if (a_split.length < 3) {
						value = value + ".00";
					}

					var s_date = n_year + "-" + n_month + "-" + n_day;
					var s_value = s_date + "-" + value + ".000000";
					date = Ext.Date.parse(s_value, "Y-n-d-H.i.s.u");
				}
				else {
					if (Ext.isArray(value)) {
						value = value[0];
					}
					a_split = value.split("-");
					if (a_split[1].length == 2) {
						date = Ext.Date.parse(value, i_self.dateParseFormat);
					}
					else {
						// WHEN THE MONTH HAS A NO LEADING ZERO
						date = Ext.Date.parse(value, "Y-n-d-H.i.s.u");
					}
				}
			}
		}

		if (date) {
			var time;

			var h = date.getHours();
			var m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
			var s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
			var mi;

			if (Ext.isDate(value)) {
				mi = date.getMilliseconds() < 10 ? "0" + date.getMilliseconds() : date.getMilliseconds();
			}
			else {
				if (value) {
					var a_values = value.split(".");
					if (a_values.length == 4) {
						mi = a_values[3];
					}
					else {
						mi = "000000";
					}
				}
				else {
					mi = "0000";
				}

				//mi = parseFloat(mi);
			}
			if (i_self.seconds) {
				time = parseFloat(h + "." + m + "" + s);
			}
			else {
				time = parseFloat(h + "." + m);
				i_self.secondsValue = s;
			}

			var i_datefield = i_self.getDateField();
			var i_timefield = i_self.getTimeField();
			var i_microfield = i_self.getMicroField();

			i_datefield.setValue(date);
			i_timefield.setValue(time);
			i_microfield.setValue(mi);

			i_datefield.resetOriginalValue();
			i_timefield.resetOriginalValue();
			i_microfield.resetOriginalValue();
		}

		i_self.originalValue = i_self.lastValue = i_self.value = i_self.getValue();
		i_self.resetOriginalValue();
	},

	createDateField: function () {

		var i_self = this;

		var i_dateField = Ext.create("Ext.form.field.Date", {
			format: Ext.util.Format.dateFormat || i_self.format,
			submitFormat: "Y-m-d",
			altFormats: i_self.altFormats,
			isFormField: false,
			selectOnFocus: i_self.selectOnFocus || false,
			emptyText: i_self.emptyText,
			readOnly: i_self.readOnly,
			value: i_self.datevalue !== "" ? i_self.datevalue : "",
			flex: 1
		});
		return i_dateField;
	},

	focus: function() {

		var i_self = this;
		var i_datefield = i_self.getDateField();
		i_datefield.focus(false, 10);
	},

	createTimeField: function () {

		var i_self = this;

		var i_field = Ext.create("Ext.form.field.Number", {
			dateField: i_self.getDateField(),
			forcePrecision: i_self.forcePrecision,
			decimalPrecision: i_self.decimalPrecision,
			decimalSeparator: i_self.decimalSeparator,
			maxValue: i_self.maxValue,
			minValue: i_self.minValue,
			selectOnFocus: i_self.selectOnFocus || false,
			value: i_self.timevalue !== 0 ? i_self.timevalue : 0,
			step: i_self.step,
			fieldStyle: "text-align: right;",
			isFormField: false,
			readOnly: i_self.readOnly,
			margin: "0 0 0 0",
			parseValue: function (value) {

				if (i_self.decimalPrecision > 2) {
					value = String(value).replace(/\:/g, ".");
					var lastIndex = String(value).lastIndexOf(".");
					if (lastIndex > 2) {
						var valueBefore = String(value).substring(0, lastIndex);
						value = valueBefore + String(value).substr(lastIndex + 1, 2);
					}
				}
				else {
					value = String(value).replace(/\:/g, ".");
				}

				value = parseFloat(String(value));

				return isNaN(value) ? "" : value;
			},

			setValue: function (value) {

				if (i_self.decimalPrecision > 2) {
					value = String(value).replace(/\:/g, ".");
					var lastIndex = String(value).lastIndexOf(".");
					if (lastIndex > 2) {
						var valueBefore = String(value).substring(0, lastIndex);
						value = valueBefore + String(value).substr(lastIndex + 1, 2);
					}
				}
				value = typeof value == "number" ? value : String(value).replace(this.decimalSeparator, ".").replace(/,/g, "");

				//v = isNaN(v) ? '' : String(v).replace(".", this.decimalSeparator);
				value = parseFloat(value);
				value = isNaN(value) ? "" : i_self.forcePrecision ? value.toFixed(i_self.decimalPrecision) : parseFloat(value);

				//this.setRawValue(value);
				return Ext.form.NumberField.superclass.setValue.call(this, parseFloat(value));
			},

			validateValue: function (value) {

				if (i_self.decimalPrecision > 2) {
					value = String(value).replace(/\:/g, ".");
					var lastIndex = String(value).lastIndexOf(".");
					if (lastIndex > 2) {
						var valueBefore = String(value).substring(0, lastIndex);
						value = valueBefore + String(value).substr(lastIndex + 1, 2);
					}
				}
				if (value.length < 1) {
					// if it's blank and textfield didn't flag it then it's valid
					return true;
				}
				value = String(value).replace(this.decimalSeparator, ".").replace(/,/g, "");
				if (isNaN(value)) {
					this.markInvalid(this.nanText.replace("{0}", value));
					return false;
				}
				var num = this.parseValue(value);
				if (num < this.minValue) {
					this.markInvalid(this.minText.replace("{0}", this.minValue));
					return false;
				}
				else if (num > this.maxValue) {
					this.markInvalid(this.maxText.replace("{0}", this.maxValue));
					return false;
				}
				else {
					this.clearInvalid();
				}
				return true;
			},

			getSubmitValue: function() {

				var i_field = this;

				var value = i_field.valueToRaw(i_field.value);
				value = String(value).replace(/\:/g, ".");
				return value;
			},

			//valueToRaw: function (c) {
			//    var b = this,
			//    a = b.decimalSeparator;
			//    c = b.parseValue(c);
			//    c = b.fixPrecision(c);
			//    c = Ext.isNumber(c) ? c : parseFloat(String(c).replace(a, "."));
			//    c = isNaN(c) ? "" : String(c).replace(".", a);
			//    return c
			//}

			valueToRaw: function (value) {

				var i_field = this;

				var decimalSeparator = i_self.decimalSeparator;
				value = isNaN(value) ||
					value == null ? 0 : i_self.forcePrecision ?
							parseFloat(value.toFixed(i_self.decimalPrecision)) : parseFloat(value);
				value = Ext.isNumber(value) ? value : parseFloat(String(value).replace(decimalSeparator, "."));

				var hours = "";
				var minutes = "";
				var seconds = "";
				var decimalIndex = 0;
				var number = 0;

				if (isNaN(value)) {
					value = "";
				}
				else {
					var hourIndex = String(value).indexOf(".");
					var preHours = "";
					var preMins = "";
					var preSecs = "";
					if (hourIndex == -1) {
						if (String(value).length == 3) {
							preHours = String(value).substr(0, 1);
							preMins = String(value).substr(1, 2);
							value = preHours + "." + preMins;
							hourIndex = String(value).indexOf(".");
							value = parseFloat(value).toFixed(i_self.decimalPrecision);
						}
						else if (String(value).length == 4) {
							preHours = String(value).substr(0, 2);
							preMins = String(value).substr(2, 2);
							value = preHours + "." + preMins;
							hourIndex = String(value).indexOf(".");
							value = parseFloat(value).toFixed(i_self.decimalPrecision);
						}

						else if (String(value).length == 5) {
							preHours = String(value).substr(0, 2);
							preMins = String(value).substr(2, 2);
							preSecs = String(value).substr(4, 1);
							value = preHours + "." + preMins + preSecs;
							hourIndex = String(value).indexOf(".");
							value = parseFloat(value).toFixed(i_self.decimalPrecision);
						}

						else if (String(value).length == 6) {
							preHours = String(value).substr(0, 2);
							preMins = String(value).substr(2, 2);
							preSecs = String(value).substr(4, 2);
							value = preHours + "." + preMins + preSecs;
							hourIndex = String(value).indexOf(".");
							value = parseFloat(value).toFixed(i_self.decimalPrecision);
						}
					}

					if (hourIndex == -1) {
						hours = value;
					}
					else {
						hours = String(value).substring(0, String(value).indexOf("."));
					}

					var step = i_self.step;
					var stepSeconds = 0;
					var stepMinues = 0;

					var stepIndex = String(step).indexOf(".") + 1;
					var stepDecimal = String(step).substring(stepIndex, String(step).length);

					if (String(step).length == 5) {
						stepDecimal = parseInt(stepDecimal);
					}

					if (String(stepDecimal).length < 2) {
						stepDecimal += "0";
					}

					if (String(step).length == 6) {
						stepDecimal = parseInt(stepDecimal);
					}
					else if (String(step).length > 6) {
						stepDecimal = parseInt(String(step).substr(stepIndex, 4));
					}

					stepDecimal = parseInt(stepDecimal);

					if (stepDecimal >= 1000) {
						stepMinues = parseInt(String(stepDecimal).substr(0, 2));
						stepSeconds = parseInt(String(stepDecimal).substr(2, 2));
					}
					else {
						if (stepDecimal > 100) {
							stepMinues = parseInt(String(stepDecimal).substr(0, 1));
							stepSeconds = parseInt(String(stepDecimal).substr(1, 2));
						}
						else {
							if (stepDecimal > 9) {
								stepSeconds = parseInt(String(stepDecimal).substr(0, 2));
							}
							else {
								stepSeconds = parseInt(String(stepDecimal).substr(0, 1));
							}
						}
					}
					if (i_self.decimalPrecision == 4) {
						decimalIndex = String(value).indexOf(".") + 1;
						if (decimalIndex === 0) {
							minutes = "";
						}

						else {
							minutes = String(value).substring(decimalIndex, decimalIndex + 2);
							if (String(minutes).length < 2) {
								minutes += "0";
							}
						}

						seconds = String(value).substring((decimalIndex + 2), ((decimalIndex + 2) + 2));

						if (minutes === "") {
							minutes = 0;
						}

						if (seconds === "") {
							seconds = 0;
						}

						var diffMin = minutes;
						var diffSec = seconds;

						if (String(diffSec).length < 2) {
							diffSec += "0";
						}

						if (parseInt(diffSec) > 59) {
							if ((parseInt(diffSec) + parseInt(stepSeconds)) >= 100) {
								number = (parseInt(diffSec) + parseInt(stepSeconds));
								var diffSeconds = number - 100;
								diffSec = 60 - (parseInt(stepSeconds) - diffSeconds);
							}
							else {
								diffSec = diffSec - 60;
								diffMin = parseInt(minutes);
								diffMin++;
								if (diffMin < 10) {
									diffMin = "0" + diffMin;
								}

								minutes = diffMin;

								if (diffSec < 10) {
									diffSec = "0" + diffSec;
								}
							}
						}
						if (parseInt(minutes) > 59) {
							if (parseInt(minutes) + stepMinues >= 100) {
								var diffMinutes = (parseInt(minutes) + stepMinues) - 100;
								diffMin = 60 - (stepMinues - diffMinutes);
							}
							else {
								diffMin = minutes - 60;
								if (diffMin < 10) {
									diffMin = "0" + diffMin;
								}
								hours++;
							}
						}
						if (String(diffSec).length < 2) {
							diffSec = "0" + diffSec;
						}

						seconds = diffSec;

						if (String(diffMin).length < 2) {
							diffMin = "0" + diffMin;
						}

						minutes = diffMin;
						value = i_field.parseValue(hours + "." + diffMin + "." + diffSec);
					}
					else {

						decimalIndex = String(value).indexOf(".") + 1;
						var decimals = String(value).substring(decimalIndex, String(value).length);
						var diff = 0;
						if (decimals.length < 2) {
							if (decimalIndex === 0) {
								decimals = "00";
							}
							else {
								decimals += "0";
							}
						}

						if (parseInt(decimals) > 59) {
							if ((parseInt(decimals) + parseInt(stepDecimal)) >= 100) {
								number = (parseInt(decimals) + parseInt(stepDecimal));
								var diffNumber = number - 100;
								diff = 60 - (parseInt(stepDecimal) - diffNumber);
							}
							else {
								diff = decimals - 60;
								hours++;
								if (diff < 10) {
									diff = "0" + diff;
								}
							}
							value = i_field.parseValue(hours + "." + diff);
						}
					}
				}
				value = i_self.forcePrecision ? Ext.isNumber(value) ? value.toFixed(i_self.decimalPrecision) :
				parseFloat(value).toFixed(i_self.decimalPrecision) : parseFloat(value);

				if (i_self.decimalPrecision != 4) {
					if (hours < 10) {
						value = "0" + String(value);
					}
					value = (value).replace(/\./g, decimalSeparator);
				}
				else {
					if (hours < 10) {
						hours = "0" + hours;
					}
					value = String(hours) + "." + String(minutes) + "." + String(seconds);
					value = (value).replace(/\./g, decimalSeparator);
				}
				return String(value);
			}
		});

		i_field.width = i_self.readOnly ? i_self.seconds ? 110 : 90 : i_self.seconds ? 110 : 90;

		return i_field;
	},

	createMicroField: function () {

		var i_field = Ext.create("Ext.form.field.Text", {
			readOnly: true,
			width: 50,
			isFormField: false
		});

		return i_field;
	},

	getValue: function () {

		var i_self = this;
		var value = "";

		var dateValue = i_self.getDateField().getSubmitValue();

		if (dateValue) {

			var timeValue = i_self.getTimeField().getSubmitValue();
			var microValue = i_self.getMicroField().getValue();
			var i_microLength = microValue.length;
			if (i_microLength < 6) {
				while (i_microLength < 6) {
					microValue = microValue + "0";
					i_microLength++;
				}
			}
			if (!i_self.time) {
				if (i_self.asHigh) {
					timeValue = "23.59";
				}
			}
			if (!i_self.seconds) {
				if (i_self.asHigh) {
					i_self.secondsValue = "59";
				}
				timeValue = timeValue + "." + i_self.secondsValue;
			}
			if (i_self.asHigh) {
				microValue = "999999";
			}

			if (!i_self.date) {
				value = timeValue;
			}
			else {
				value = dateValue + "-" + timeValue + "." + microValue;
			}
		}

		if (i_self.getNative()) {
			value = Ext.Date.parse(value, i_self.dateParseFormat);
		}

		return value;
	},

	getRawValue: function() {

		var i_self = this;
		var i_datefield = i_self.getDateField();
		var i_timefield = i_self.getTimeField();

		var s_value = i_datefield.getRawValue();

		var s_time = i_timefield.getRawValue();

		if (s_value) {
			s_value = s_value + " " + s_time;
		}

		return s_value;
	},

	setValue: function (value) {

		var i_self = this;
		i_self.value = value;
		var date;

		if (value) {
			if (Ext.isDate(value)) {
				date = value;
			}
			else {
				if (value) {
					var a_split = [];

					if (!i_self.date) {

						var i_date = new Date();
						var n_year = i_date.getFullYear();
						var n_month = i_date.getMonth() + 1;
						var n_day = i_date.getDate();

						a_split = value.split(".");

						a_split = Ext.Array.map(a_split, function(s_value) {
							var s_return = s_value;
							var n_value = parseInt(s_value);
							if (n_value) {
								if (n_value < 10 && s_value.length < 2) {
									s_return = "0" + s_value;
								}
							}
							else {
								if (!isNaN(n_value)) {
									if (s_value.length < 2) {
										s_return = "0" + s_value;
									}
								}
								else {
									s_return = "00";
								}
							}
							return s_return;
						});
						value = a_split.join(".");

						if (a_split.length < 3) {
							value = value + ".00";
						}

						var s_date = n_year + "-" + n_month + "-" + n_day;
						var s_value = s_date + "-" + value + ".000000";
						date = Ext.Date.parse(s_value, "Y-n-d-H.i.s.u");
					}
					else {
						if (Ext.isArray(value)) {
							value = value[0];
						}
						a_split = value.split("-");
						if (a_split[1].length == 2) {
							date = Ext.Date.parse(value, i_self.dateParseFormat);
						}
						else {
							// WHEN THE MONTH HAS A NO LEADING ZERO
							date = Ext.Date.parse(value, "Y-n-d-H.i.s.u");
						}
					}
				}
			}

			if (date) {
				var time;

				var h = date.getHours();
				var m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
				var s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
				var mi;

				if (Ext.isDate(value)) {
					mi = date.getMilliseconds() < 10 ? "0" + date.getMilliseconds() : date.getMilliseconds();
				}
				else {
					if (value) {
						var a_values = value.split(".");
						if (a_values.length == 4) {
							mi = a_values[3];
						}
						else {
							mi = "000000";
						}
					}
					else {
						mi = "0000";
					}

					//mi = parseFloat(mi);
				}
				if (i_self.seconds) {
					time = parseFloat(h + "." + m + "" + s);
				}
				else {
					time = parseFloat(h + "." + m);
					i_self.secondsValue = s;
				}

				i_self.getDateField().setValue(date);
				i_self.getTimeField().setValue(time);
				i_self.getMicroField().setValue(mi);
				i_self.value = i_self.getValue();

				var b_reset = false;

				if (i_self.getDateField().originalValue === undefined) {
					i_self.getDateField().originalValue = i_self.getDateField().getValue();
					b_reset = true;
				}

				if (i_self.getTimeField().originalValue === undefined || i_self.getTimeField().originalValue === 0) {
					i_self.getTimeField().originalValue = i_self.getTimeField().getValue();
					b_reset = true;
				}
				if (i_self.getMicroField().originalValue === undefined || i_self.getMicroField().originalValue === "") {
					i_self.getMicroField().originalValue = i_self.getMicroField().getValue();
					b_reset = true;
				}

				if (b_reset) {
					i_self.resetOriginalValue();
				}
			}
		}
		else {
			var i_dateField = i_self.getDateField();
			var i_timeField = i_self.getTimeField();
			var i_microField = i_self.getMicroField();

			i_dateField.setValue(null);
			i_timeField.setValue(null);
			i_microField.setValue(null);
		}

	},

	isDirty: function () {

		var i_self = this;

		var originalValue = i_self.originalValue;
		var value = i_self.getValue();

		var b_dirty = originalValue != value;

		if (i_self.getNative()) {
			b_dirty = !Ext.Date.isEqual(originalValue, value);
		}

		return b_dirty;
	},

	isValid: function() {

		var i_self = this;
		var i_datefield = i_self.getDateField();
		var i_timefield = i_self.getTimeField();

		return (i_datefield.isValid() && i_timefield.isValid());
	}

});
Ext.define("Ext.ux.form.field.ISOTimestampDisplayfield", {
	extend: "Ext.form.field.Display",
	alias: "widget.isotimestampdisplayfield",

	config: {
		isoField: null
	},

	initComponent: function () {

		var i_self = this;

		var o_config = i_self.initialConfig;
		var i_field = Ext.widget("isotimestampfield", o_config);
		i_field.isFormField = false;
		i_self.setIsoField(i_field);
		i_self.callParent();
	},

	setValue: function(value) {

		var i_self = this;
		var i_isofield = i_self.getIsoField();

		i_isofield.setValue(value);

		i_self.callParent([i_isofield.getRawValue()]);
	},

	getValue: function() {

		var i_self = this;
		var i_isofield = i_self.getIsoField();

		return i_isofield.getValue();
	},

	getSubmitValue: function() {

		var i_self = this;
		var i_isofield = i_self.getIsoField();

		return i_isofield.getValue();
	}
});
Ext.define('Ext.ux.form.field.KeywordDensityChecker', {

	extend: 'Ext.container.Container',

	alias: ['widget.ip2KeywordDensityChecker'],

	mixins: {
		field: 'Ext.form.field.Field'
	},

	ignorelist: 'du er i og på til af at har for med om fra sig jeg det se vi nu hos din et mod gør kan den vil før år her få var som må nok'.split(' '),
	maxCombinedWords: 4,

	changeListener: function() {

		var a_densities = this.calculateDensity(this.getValue());

		var a_items = [];

		Ext.Array.each(a_densities, function(a_wordList, key) {
			var n_words = key + 1;

			var o_grid = {
				xtype: 'grid',
				title: ip2.i18n({
					da: n_words + ' ord',
					en: n_words == 1 ? '1 word' : n_words + ' words'
				}),
				store: {
					fields: ['word', 'times', 'density'],
					data: {
						items: a_wordList
					},
					proxy: {
						type: 'memory',
						reader: {
							type: 'json',
							root: 'items'
						}
					}
				},
				columns: [
					{
						header: ip2.i18n({
							da: 'Sætning',
							en: 'Sentence'
						}),
						dataIndex: 'word'
					},
					{
						header: ip2.i18n({
							da: 'Antal matches',
							en: 'Match Count'
						}),
						dataIndex: 'times'
					},
					{
						header: ip2.i18n({
							da: 'Keyword tæthed',
							en: 'Keyword Density'
						}),
						dataIndex: 'density',
						xtype: 'templatecolumn',
						tpl: '{[values.density*100]}%'
					}
				]
			};

			a_items.push(o_grid);
		});

		this.removeAll();

		this.add({
			xtype: 'tabpanel',
			items: a_items
		});
	},

	_addDensityWord: function(list, word) {
		if (list[word]) {
			list[word]++;
		}
		else {
			list[word] = 1;
		}
	},

	calculateDensity: function(s_words) {
		var i_cmp = this;

		s_words = s_words.replace(/[\n\s]+/g, ' ').toLowerCase();

		a_words = s_words.split(' ');

		// used to store word counters:
		var o_density = {};

		var n_maxCombinedWords = this.maxCombinedWords;

		Ext.Array.each(a_words, function(s_word, n_key) {
			var a_wordList = [];

			for (var i = 0; i < n_maxCombinedWords; i++) {
				if (a_words[n_key - i] != null) {
					a_wordList.unshift(a_words[n_key - i]);

					i_cmp._addDensityWord(o_density, a_wordList.join(' '));
				}
				else {
					break;
				}
			}
		});

		// remove ignored words:
		Ext.Array.each(this.ignorelist, function(s_word) {
			delete o_density[s_word];
		});

		// calculate density
		var a_densities = [];

		Ext.Object.each(o_density, function(s_prop, n_times) {
			var n_length = s_prop.split(' ').length;

			if (a_densities[n_length - 1] == null) {
				a_densities[n_length - 1] = [];
			}

			a_densities[n_length - 1].push({
				word: s_prop,
				times: n_times,
				density: Math.round(n_times * n_length / a_words.length * 100) / 100
			});
		});

		Ext.Array.each(a_densities, function(a_wordList) {

			a_wordList.sort(function(a, b) {
				return b.density - a.density || b.times - a.times || b.word - a.word;
			});
		});

		return a_densities;
	},

	initComponent: function() {

		this.on('change', this.changeListener);

		this.callParent();

		return this;
	}
});

Ext.define("Ext.ux.form.field.ThumbnailComboBox", {

	extend: "Ext.form.field.ComboBox",

	alias: [
		"widget.thumbnailcombo",
		"widget.thumbnailcombobox"
	],

	triggers: {
		clear: {
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			weight: 1,
			handler: "clearValue",
			hidden: true,
			scope: "this"
		},
		picker: {
			weight: 2,
			handler: "onTriggerClick",
			scope: "this"
		}
	},

	config: {
		path: "",
		extension: ""
	},

	listeners: {
		change: {
			fn: function (i_field, value) {
				if (i_field.inputEl) {

					var a_values = Ext.Array.from(value);

					i_field.getTrigger("clear")[Ext.isEmpty(a_values) ? "hide" : "show" ]();
				}
			}
		},
		enable: {
			fn: function (i_field) {

				var s_value = i_field.getValue();

				i_field.getTrigger("clear")[s_value ? "show" : "hide"]();
			},
			buffer: 10
		},
		disable: {
			fn: function (i_field) {
				i_field.getTrigger("clear").hide();
			},
			buffer: 10
		},
		writeablechange: {
			fn: function (i_field, b_readOnly) {

				var s_value = i_field.getValue();
				var b_allowAdd = i_field.getAllowAdd();

				i_field.getTrigger("clear")[b_readOnly || !s_value ? "hide" : "show"]();
			},
			buffer: 10
		},
		autosize: {
			fn: function (i_field) {
				var i_picker = i_field.getPicker();
				i_picker.setWidth(i_field.bodyEl.getWidth());
			},
			buffer: 1
		}
	},

	initComponent: function () {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;
		var s_path = o_config.path;

		var i_template = Ext.create("Ext.XTemplate", 
			"<tpl for=\".\">",
				"<span style=\"",
					"width: 43px;",
					"height: 37px;",
					"background-image: url(" + s_path + "/{key}.png);",
					"background-size: 35px;",
					"background-position: 1px 2px;",
					"background-repeat: no-repeat;",
					"display: inline-block;",
				"\"></span>",
				"<span style=\"",
					"height: 45px;",
					"position: relative;",
					"top: -13px",
				"\">{name}</span>",
			"</tpl>"
		);

		Ext.apply(i_cmp, {
			height: o_config.imageHeight,
			editable: false,
			listConfig: {
				itemTpl:i_template
			}
		});

		i_cmp.extendListener(i_cmp, "select", function (i_self, i_record) {
			if (i_record) {
				i_cmp.setInputIcon(i_record.get("key"));
			}
		});

		i_cmp.callParent(arguments);

		i_cmp.on({
			afterrender: {
				fn: i_cmp.onAfterRender,
				single: true,
				scope: i_cmp
			}
		});

		return i_cmp;
	},

	initValue: function () {

		var i_cmp = this;

		i_cmp.mixins.field.initValue.call(i_cmp);
	},

	onAfterRender: function () {

		var i_cmp = this;
		var i_el = i_cmp.getEl();
		var i_input = i_cmp.inputEl;
		var s_icon = i_cmp.getValue();

		i_input.setStyle({
			"height": "45px",
			"padding-left": "45px",
			"background-repeat": "no-repeat"
		});

		if (s_icon) {
			i_cmp.setInputIcon(s_icon);
		}

		return i_cmp;
	},

	extendListener: function(xtype, name, newFn) {

		var listener;
		var oldFn;

		if (xtype.listeners && xtype.listeners[name]) {

			listener = xtype.listeners[name];

			// Listener is object made
			if (listener.fn && Ext.isFunction(listener.fn)) {

				oldFn = listener.fn;
			}

			// Listener is shorthand made
			else if (Ext.isFunction(listener)) {

				oldFn = listener;
			}

			if (oldFn) {
				delete xtype.listeners[name];
			}
		}

		if (!xtype.listeners) {
			xtype.listeners = {};
		}

		xtype.listeners[name] = {
			fn: function() {

				//var args = Array.prototype.slice.call(arguments);

				if (oldFn) {

					oldFn.apply(this, arguments);
				}

				if (newFn) {

					newFn.apply(this, arguments);
				}
			}
		};

		return xtype;
	},

	setIcon: function (icon) {

		var i_cmp = this;
		var s_path = i_cmp.path;
		var i_input = i_cmp.inputEl;

		if (Ext.isArray(icon)) {
			icon = icon[0];
		}

		if (Ext.isString(icon) && icon.length) {
			i_input.setStyle({
				"background-image": "url(" + s_path + "/" + icon + ".png)",
				"background-size": "35px",
				"background-position": "4px 4px"
			});
		}

		return i_cmp;
	},

	setInputIcon: function (m_icon) {

		var i_cmp = this;
		var i_input = i_cmp.inputEl;

		if (i_input && i_input.dom) {
			i_cmp.setIcon(m_icon);
		}
		else {

			i_cmp.on({
				afterrender: {
					fn: function() {
						i_cmp.setIcon(m_icon);
					},
					scope: i_cmp,
					single: true
				}
			});
		}

		return i_cmp;
	},

	setValue: function (value) {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		// Set the icon value
		i_cmp.setInputIcon(value);

		return i_cmp;
	}
});

Ext.define('Ext.ux.form.ExtendedFieldContainer', {

	alias: ['widget.extendedfieldcontainer', 'widget.ExtendedFieldContainer', 'widget.extendedFieldContainer'],

	extend: 'Ext.form.FieldContainer',

	mixins: {
		field: 'Ext.form.field.Field'
	},

	statics: {

		addNoValidation: function(tobind, preventValidation) {

			preventValidation = preventValidation || false;

			Ext.applyIf(tobind, {
				preventValidation: preventValidation,
				stopValidation: function() {

					var field = this,
						checkChange = field.suspendCheckChange;

					field.preventValidation = true;

					field.validateOnBlur = false;

					field.validateOnChange = false;

					field.suspendCheckChange = 1;

					if (field.unsetActiveError) {
						field.unsetActiveError();
					}

					if (field.clearInvalid) {
						field.clearInvalid();
					}

					field.doComponentLayout();

					field.fireEvent('validitychange', field, true);

					field.suspendCheckChange = checkChange;

					return field;
				},
				startValidation: function() {

					var field = this,
						checkChange = field.suspendCheckChange,
						errors;

					field.preventValidation = false;

					errors = field.getErrors.call(field);

					field.validateOnBlur = true;

					field.validateOnChange = true;

					field.suspendCheckChange = 0;

					field.setActiveError(errors);

					field.markInvalid(errors);

					field.doComponentLayout();

					field.fireEvent('validitychange', field, field.isValid());

					field.suspendCheckChange = checkChange;

					return field;
				}
			});

			if (tobind.isComponent) {

				if (!tobind._getErrors) {

					tobind._getErrors = tobind.getErrors;

					tobind.getErrors = function(value) {

						var field = this,
							preventValidation = field.preventValidation;

						return preventValidation === true ? [] : field._getErrors(value);
					};
				}

				if (!tobind.ownerCt) {

					tobind.on({
						'added': {
							fn: function(self) {

								if (self.preventValidation) {
									self.stopValidation();
								}
							}
						}
					});
				}
				else {

					if (tobind.preventValidation) {

						tobind.stopValidation();
					}
				}
			}
			else {

				var newFn = function(item) {

					if (!item._getErrors)
						item._getErrors = item.getErrors;

					item.getErrors = function(value) {

						var field = this,
							preventValidation = field.preventValidation;

						return preventValidation === true ? [] : field._getErrors(value);
					};

					if (item.preventValidation === true)
						item.stopValidation();
				};

				ip2.extendConfigListener(item, 'added', fn);
			}

			return tobind;
		}
	},

	config: {

		preventValidation: false
	},

	allowBlank: true,

	value: '',

	boundConfig: {
		validation: [
			'allowBlank',
			'blankText',
			'emptyText',
			'invalidCls',
			'invalidText',
			'maxLengthText',
			'minLengthText',
			'regex',
			'validateOnBlur',
			'validateOnChange',
			'validator',
			'vtype',
			'vtypeText'
		],
		events: [
			'change',
			'blur',
			'focus'
		]
	},

	blankText: 'This field is required',

	maxLengthText: 'The maximum length for this field is {0}',

	minLengthText: 'The minimum length for this field is {0}',

	boundComponents: null,

	boundValidationComponents: null,

	_isValidationBound: null,

	preventValidation: null,

	initComponent: function() {

		var field = this,
			config = field.initialConfig;

		field.boundValidationComponents = [];

		field.boundComponents = [];

		field._isValidationBound = false;

		field.fixComponentLayout();

		field.callParent();

		field.initField();

		field.setPreventValidation(config.preventValidation);

		if (field.getPreventValidation()) {

			field.on({
				'added': {
					fn: function(self) {

						console.log('I am added and will validation bind');
						self.stopValidation();
					}
				}
			});
		}

		return field;
	},

	getPreventValidation: function() {

		return this.preventValidation;
	},

	setPreventValidation: function(toSet) {

		toSet = toSet || false;

		this.preventValidation = toSet;

		return this;
	},

	getEventNames: function(component) {

		var field = this,
			events = {
				has: [],
				hasNot: []
			};

		Ext.Object.each(component.events, function(key) {

			if (Ext.Array.indexOf(field.boundConfig.events, key) > -1) {

				var toPush = component.events[key] ? events.has : events.hasNot;

				toPush.push(key);
			}
		});

		return events;
	},

	applyComponentBind: function(tobind) {

		var field = this,
			bindArray = [];

		if (Ext.typeOf(tobind) != 'array')
			bindArray.push(tobind);

		Ext.Array.each(bindArray, function(bindee) {

			// Is bindee a component already made?
			if (bindee.isComponent) {

				field.applyValidationBind(bindee)
					.applyEventsBind(bindee)
					.applyDirtyBind(bindee);

				field.boundComponents.push(bindee);
			}

			// Then we must assume a config object to create one
			else {

				var addedFn;

				addedFn = function(self) {

					field.applyValidationBind(self)
						.applyEventsBind(self)
						.applyDirtyBind(self);

					field.boundComponents.push(self);
				};

				ip2.extendConfigListener(bindee, 'added', addedFn);
			}
		});

		return tobind;
	},

	applyEventsBind: function(component) {

		var field = this,
			eventNames,
			events;

		eventNames = field.getEventNames(component);

		Ext.Array.each(eventNames.hasNot, function(name) {

			field.addEvent(name);
		});

		events = eventNames.has.concat(eventNames.hasNot);

		Ext.Array.each(events, function(name) {

			component.on(name, function() {

				field.fireEvent.call(field, name, field);
			}, component);
		});

		return this;
	},
	applyValidationBind: function(component) {

		var field = this,
			validitychange;

		validitychange = {
			fn: function(cmp, isValid, eOpts) {

				field.fireEvent('validitychange', field, isValid, eOpts);
			}
		};

		field.boundValidationComponents.push(component);

		if (!field._isValidationBound && !field._getErrors) {

			field._getErrors = field.getErrors;

			field.getErrors = function(value) {

				var field = this,
					preventValidation = field.preventValidation;

				return preventValidation === true ? [] : field._getErrors(value);
			};

			field._isValidationBound = true;
		}

		if (!component._getErrors) {

			component._getErrors = component.getErrors;

			component.getErrors = function(value) {

				var component = this,
					parent = field,
					preventValidation = field.preventValidation;

				return preventValidation === true ? [] : component._getErrors(value);
			};
		}

		component.on({
			'validitychange': validitychange
		});

		field.fireEvent('validationbind', field, [component]);

		return field;
	},
	applyDirtyBind: function(component) {

		var field = this;

		component.on({
			'dirtychange': {
				fn: function() {

					field.checkDirty();
				}
			}
		});

		return field;
	},

	// TODO: REMOVE WHEN I AM SURE WTF WENT ON HERE!
	applyValidationConfig: function(component) {

		var field = this,
			initialConfig = field.initialConfig,
			validationProps;

		validationProps = [
			'allowBlank',
			'blankText',
			'emptyText',
			'invalidCls',
			'invalidText',
			'maxLengthText',
			'minLengthText',
			'regex',
			'validateOnBlur',
			'validateOnChange',
			'validator',
			'vtype',
			'vtypeText'
		];

		Ext.Array.each(validationProps, function(property) {

			var value;

			value = initialConfig[property];

			if (typeof value !== 'undefined')
				component[property] = value;
		});

		component._isValidationBound = true;

		return component;
	},

	// bindValidationComponent - DEPRECATED - RENAME YOUR METHOD TO: applyComponentBind
	bindValidationComponent: function(tobind) {

		var field = this;

		console.log(field.xtype, 'clean up here, this component class needs to rename its method "bindValidationComponent" -> "applyComponentBind"');

		return field.applyComponentBind(tobind);
	},

	fixComponentLayout: function(items) {

		items = items || this.items;

		var field = this,
			config = field.initialConfig.componentLayout || null;

		if (config && !Ext.isEmpty(items))
			doLayout(items);

		function doLayout(items) {

			Ext.Array.each(items, function(item) {

				if (Ext.isObject(item)) {

					Ext.Object.each(config, function(key, layout) {

						if (item.name == key && !Ext.isEmpty(layout)) {

							Ext.Object.merge(item, layout);
						}
					});

					if (!Ext.isEmpty(item.items))
						doLayout(item.items);
				}
				else if (Ext.isArray(item)) {

					doLayout(item);
				}
			});
		}
	},

	isValid: function() {

		var field = this,
			value;

		value = field.getValue();

		return field.disabled || field.validateValue(value);
	},

	getErrors: function(value) {

		var field = this,
			errorsArray = [],
			boundArray = field.boundValidationComponents;

		Ext.Array.each(boundArray, function(bound) {

			var errors;

			if (Ext.isFunction(bound.getErrors)) {

				errors = bound.getErrors(value);

				if (errors.length)
					errorsArray = Ext.Array.merge(errorsArray, errors);
			}
		});

		return errorsArray;
	},

	stopValidation: function() {

		var field = this,
			boundArray = field.boundValidationComponents;

		field.preventValidation = true;

		Ext.Array.each(boundArray, function(bound) {

			var checkChange = bound.suspendCheckChange;

			bound.validateOnBlur = false;

			bound.validateOnChange = false;

			bound.suspendCheckChange = 1;

			if (bound.unsetActiveError) {
				bound.unsetActiveError();
			}

			if (bound.clearInvalid) {
				bound.clearInvalid();
			}

			bound.doComponentLayout();

			bound.fireEvent('validitychange', bound, true);

			bound.suspendCheckChange = checkChange;
		});

		//field.fireEvent('validitychange', field, true);

		return field;
	},

	startValidation: function() {

		var field = this,
			boundArray = field.boundValidationComponents;

		field.preventValidation = false;

		Ext.Array.each(boundArray, function(bound) {

			var errors = bound.getErrors(),
				checkChange = bound.suspendCheckChange;

			bound.validateOnBlur = true;

			bound.validateOnChange = true;

			bound.suspendCheckChange = 0;

			bound.setActiveError(errors);

			bound.markInvalid(errors);

			bound.doComponentLayout();

			bound.fireEvent('validitychange', bound, bound.isValid());

			bound.suspendCheckChange = checkChange;
		});

		//field.suspendCheckChange = 0;

		//field.fireEvent('validitychange', field, field.isValid());

		return field;
	},

	clearInvalid: function() {

		var field = this,
			boundArray = field.boundValidationComponents;

		Ext.Array.each(boundArray, function(bound) {

			if (Ext.isFunction(bound.clearInvalid))
				bound.clearInvalid();
		});

		return field;
	},

	markInvalid: function(errors) {

		errors = errors || [];

		var field = this,
			boundArray = field.boundValidationComponents;

		Ext.Array.each(boundArray, function(bound) {

			if (Ext.isFunction(bound.markInvalid))
				bound.markInvalid(errors);
		});

		return field;
	},

	unsetActiveError: function() {

		var field = this,
			boundArray = field.boundValidationComponents;

		Ext.Array.each(boundArray, function(bound) {

			if (Ext.isFunction(bound.unsetActiveError))
				bound.unsetActiveError.apply(bound);
		});

		return field;
	},

	setActiveError: function(errors) {

		var field = this,
			boundArray = field.boundValidationComponents;

		Ext.Array.each(boundArray, function(bound) {

			if (Ext.isFunction(bound.setActiveError))
				bound.setActiveError.apply(bound, errors);
		});

		return field;
	},

	validateValue: function(value) {

		var field = this,
			errors,
			isValid;

		errors = field.getErrors(value);

		isValid = Ext.isEmpty(errors);

		return isValid;
	}
});
Ext.define("Ext.ux.form.field.AceTextArea", {

	statics: {
		n: 0,
		ace: null
	},

	requires: [
		"Ext.form.field.TextArea",
		"Ext.ux.util.ace.Editor"
	],

	mixins: {
		"ace": "Ext.ux.util.ace.Editor"
	},

	extend: "Ext.form.field.TextArea",

	alias: [
		"widget.acetextarea",
		"widget.acetextareafield"
	],

	// CONFIG
	loadMask: true,

	// PROPERTIES
	_loadMask: null,
	_internalValueChange: false,
	_editorActionEl: null,

	config: {
		asArray: false,
		asJson: false,
		splitRegEx: /\n/g,
		joinDelimiter: null
	},

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		i_cmp.on({
			aceloaded: {
				fn: i_cmp.initAceTextArea,
				scope: i_cmp
			},
			editorchange: {
				fn: function (i_self, i_editor, value) {
					i_cmp.value = value;
					i_cmp.checkChange();
				}
			},
			editorvalidate: {
				fn: function(i_self, i_editor) {
					i_cmp.validate();
				}
			}
		});

		i_cmp.initAce();

		return i_cmp;
	},

	initAceTextArea: function () {

		var i_cmp = this;

		var f_init = function (i_self) {
			var i_inputEl = i_self.inputEl;

			// Create a container for AceEditor with height of textarea
			var s_height = Ext.DomQuery.getStyle(i_inputEl, "height");
			var s_id = "aceeditortextarea-wrapper-" + i_cmp.getRewriter().n++;
			var s_classNames = i_inputEl.getAttribute("class");

			var o_styles = Ext.apply({}, {
				width: "100%",
				height: "100%",
				position: "relative"
			});

			setTimeout(function () {

				i_inputEl.setStyle("display", "none");
				var s_value = i_inputEl.getValue() || "";
				var i_actionEl = Ext.DomHelper.insertBefore(i_inputEl, {
					tag: "div",
					id: s_id,
					style: o_styles,
					cls: s_classNames
				});

				i_cmp._editorActionEl = Ext.get(i_actionEl);
				i_cmp.suspendCheckChange++;
				i_cmp.initEditor(s_id);
				i_cmp.setEditorValue(s_value);
				i_cmp.resetOriginalValue();
				i_cmp.suspendCheckChange--;
			}, 10);
		};

		if (!i_cmp.inputEl) {
			i_cmp.on("afterrender", f_init, i_cmp, { single: true });
		}
		else {
			f_init(i_cmp);
		}
	},

	setValue: function (value) {

		var i_cmp = this;

		if (Ext.isObject(value)) {
			value = JSON.stringify(value, null, "\t");
		}
		else if (Ext.isArray(value)) {

			if (i_cmp.getAsArray()) {
				var s_delimiter = i_cmp.getJoinDelimiter();
				if (s_delimiter === null) {
					value = value.join("\n");
				}
				else {
					value = value.join(s_delimiter);
				}
			}

			value = value;
		}

		var b_internal = i_cmp._internalValueChange;

		if (i_cmp.getEditor()) {
			if (!b_internal) {
				i_cmp.setEditorValue(value);
			}
		}
		else {
			i_cmp.needSet = true;
		}

		i_cmp.callParent([value]);

		return i_cmp;
	},

	getValue: function() {

		var i_self = this;
		var value = i_self.value;
		if (value) {
			if (i_self.asJson) {
				value = Ext.decode(value, true);
			}
			else if (i_self.getAsArray()) {
				value = value.split(i_self.getSplitRegEx());
			}
		}

		return value;
	},

	getSubmitValue: function() {

		var i_self = this;
		return i_self.getValue();
	},

	isDirty: function() {

		var i_self = this;
		var originalValue = i_self.originalValue;
		var value = i_self.getValue();

		if (i_self.getAsJson()) {

			var i_editor = i_self.getEditor();
			if (i_editor) {
				originalValue = JSON.stringify(originalValue, null, "\t");
				value = i_editor.getValue();
			}
			else {
				originalValue = Ext.encode(originalValue);
				value = Ext.encode(value);
			}
		}
		else {
			originalValue = Ext.encode(originalValue);
			value = Ext.encode(value);
		}

		return originalValue != value;
	},

	didValueChange: function(newVal, oldVal) {

		if (Ext.isObject(newVal)) {
			newVal = Ext.encode(newVal);
		}

		if (Ext.isObject(oldVal)) {
			oldVal = Ext.encode(oldVal);
		}

		return !this.isEqual(newVal, oldVal);
	},

	setError: function(error) {
		var me = this;
		var msgTarget = me.msgTarget;
		var prop;
		if (me.rendered) {
			if (msgTarget == "title" || msgTarget == "qtip") {
				prop = msgTarget == "qtip" ? "data-errorqtip" : "title";
				me.getEditor().container.setAttribute(prop, error || "");
			}
			else {
				me.updateLayout();
			}
		}
	},

	getErrors: function () {

		var i_cmp = this;
		var a_errors = i_cmp.callParent(arguments);
		var a_editorErrors = i_cmp.getEditorErrors();

		return a_errors.concat(a_editorErrors);
	},

	getRewriter: function () {
		return Ext.ux.form.field.AceTextArea;
	}
});
Ext.define("Portfolio.ux.form.field.i18n.text.AceTextArea", {

	extend: "Ext.ux.form.field.AceTextArea",

	xtype: "portfolio-i18n-acetextarea",

	requries: [
		"Ext.ux.form.field.AceTextArea"
	],

	alias: [
		"widget.i18n-acetextarea"
	],

	triggers: {
		"type": {
			cls: "",
			onClick: function() {
				var me = this;
				var args = arguments;
				var e = me.clickRepeater ? args[1] : args[0];
				var handler = me.handler;
				var field = me.field;
				if (handler && me.isFieldEnabled()) {
					Ext.callback(me.handler, me.scope, [
						field,
						me,
						e
					], 0, field);
				}
			},
			handler: function () {

				var i_self = this;

				var o_bodySize = Ext.getBody().getSize();

				var i_trigger = i_self.getTrigger("type");
				var i_menu = i_self.getSelections();

				i_menu.show();
				i_menu.alignTo(i_trigger.getEl(), "tr-tr");

				var n_bottom = i_menu.body.getBottom();

				if (n_bottom > o_bodySize.height) {
					i_menu.alignTo(i_self.getEl(), "br-tr");
				}
			}
		}
	},

	listeners: {
		afterrender: {
			fn: function (i_field) {

				var i_self = this;
				var b_active = i_self.getLanguageActive();

				var a_currrent = i_self.getLanguages();
		
				Ext.Array.each(a_currrent, function (s_lang) {

					var i_typeTrigger = i_self.getTrigger("type");

					var i_element = i_typeTrigger.getEl();

					if (i_element.hasCls("icon trigger flag " + s_lang + "-default")) {
						i_element.removeCls("icon trigger flag " + s_lang + "-default");
					}

				});

				var i_typeTrigger = i_self.getTrigger("type");

				var i_element = i_typeTrigger.getEl();

				if (!i_self.disabled) {
					i_element.show();
				}

				i_self.updateLanguageActive(b_active);

			}
		},
		editorready: {
			fn: function(i_field) {

				var i_self = this;
				i_self.setValue(i_self.getStored());
			}
		},
		writeablechange: {
			fn: function(i_field, b_readOnly) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.show();
				}
			},
			buffer: 10
		},
		enable: {
			fn: function(i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.show();
				}
			},
			buffer: 10
		},
		disable: {
			fn: function(i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.hide();
				}	
			},
			buffer: 10
		}
	},

	config: {
		languageActive: false,
		language: "en",
		primary: "en",
		languages: [],
		stored: {},
		selections: null,
		asString: false,
		langContext: "portfolio"
	},

	initComponent: function() {

		var i_self = this;

		var a_currrent = wsh.getLanguages(i_self.getLangContext());
		
		i_self.setLanguages(a_currrent);

		var s_current = ip2.getUser().get("USRLNG") || "en";

		i_self.setLanguage(s_current);
		i_self.setPrimary(s_current);

		i_self.callParent(arguments);

		i_self.createMenu();
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value;
		var s_current = i_self.getLanguage();
		var b_active = i_self.getLanguageActive();
		var a_languages = i_self.getLanguages();

		var o_stored = i_self.getStored();

		var s_raw = value;

		if (ip2.isStringedObject(s_raw)) {
			s_raw = Ext.decode(value, true) || value;
		}

		if (Ext.isObject(s_raw)) {

			o_stored = Ext.clone(s_raw);

			s_raw = o_stored[s_current];

			b_active = true;
		}
		else {
			o_stored[s_current] = s_raw;
		}

		Ext.Array.each(a_languages, function (s_key) {
			var s_value = o_stored[s_key] || "";
			o_stored[s_key] = s_value;
		});

		i_self.setStored(o_stored);
		i_self.setValue(s_raw);

		if (b_active) {
			i_self.setLanguageActive(true);
		}

		i_self.originalValue = i_self.lastValue = i_self.getValue();
		i_self.resetOriginalValue();
	},

	updateLanguageActive: function(b_active) {

		var i_self = this;
		var i_typeTrigger = i_self.getTrigger("type");

		var s_current = i_self.getLanguage();
		var s_primary = i_self.getPrimary();

		if (i_typeTrigger) {
			if (i_typeTrigger.rendered) {
				var i_element = i_typeTrigger.getEl();
				if (b_active) {
					i_element.removeCls("pf-earth2");
					i_element.addCls("icon trigger flag " + s_current);
				}
				else {
					i_element.removeCls("icon trigger flag " + s_current);
					i_element.addCls("pf-earth2");
				}
			}
			else {
				if (b_active) {
					i_typeTrigger.cls = " icon trigger flag " + s_current;
				}
			}
		}

		if (!b_active) {
			i_self.setLanguage(s_primary);
		}
	},

	createMenu: function() {

		var i_self = this;

		var a_items = [];

		var i_typeTrigger = i_self.getTrigger("type");

		var a_languages = i_self.getLanguages();

		Ext.Array.each(a_languages, function (s_key) {

			var i_menuItem = Ext.widget("menuitem", {
				itemId: s_key,
				text: s_key,
				iconCls: "icon flag " + s_key,
				handler: function (i_item) {

					var i_element = i_typeTrigger.getEl();
					var b_active = i_self.getLanguageActive();
					var s_current = i_self.getLanguage();

					i_element.removeCls("icon flag " + s_current);

					i_self.setLanguage(i_item.itemId);

					if (!b_active) {
						i_self.setLanguageActive(true);
					}
					else {
						i_self.updateLanguageActive(b_active);
					}

					i_self.checkChange();
				}
			});

			a_items.push(i_menuItem);
		});

		var i_menuItem = Ext.widget("menuitem", {
			itemId: "off",
			text: "Default",
			iconCls: "pf-earth2",
			handler: function (i_item) {
				i_self.setLanguageActive(false);
				i_self.checkChange();
			}
		});

		a_items.push(i_menuItem);

		var i_menu = Ext.widget("menu", {
			items: a_items,
			listeners: {
				beforeshow: {
					fn: function (i_menu) {

						var a_items = i_menu.query("menuitem");

						var s_current = i_self.getLanguage();

						var b_active = i_self.getLanguageActive();

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

							i_item.enable();

							if (i_item.itemId == "off" || i_self.readOnly) {
								if (!b_active) {
									i_item.disable();
								}
							}
						});

						if (b_active) {

							var i_found = Ext.Array.findBy(a_items, function (i_item) {
								return s_current == i_item.itemId;
							});

							i_found.disable();
						}
					}
				}
			}
		});

		i_self.setSelections(i_menu);
	},

	getValue: function() {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var i_editor = i_self.getEditor();
		var s_value = i_editor ? i_editor.getValue() : i_self.getRawValue();

		var b_active = i_self.getLanguageActive();

		if (b_active) {

			var o_stored = i_self.getStored();
			var s_raw = i_editor ? i_editor.getValue() : i_self.getRawValue();

			s_value = Ext.decode(s_raw, true) || s_raw;

			if (Ext.isObject(s_raw)) {
				s_value = JSON.stringify(s_raw, null, "\t");
			}

			o_stored[s_current] = s_value;

			s_value = Ext.clone(o_stored);
		}

		if (i_self.getAsString()) {

			if (Ext.isObject(s_value)) {
				s_value = Ext.encode(s_value);
			}
		}

		return s_value;
	},

	getSubmitValue: function () {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var s_value = i_self.getRawValue();

		var b_active = i_self.getLanguageActive();

		if (b_active) {

			var o_stored = i_self.getStored();
			var s_raw = i_self.getRawValue();

			o_stored[s_current] = s_raw;

			s_value = Ext.clone(o_stored);
		}

		if (i_self.getAsString()) {

			if (Ext.isObject(s_value)) {
				s_value = Ext.encode(s_value);
			}
		}

		return s_value;
	},

	setValue: function(value) {

		var i_self = this;

		i_self.callOverridden([value]);

		var s_current = i_self.getLanguage();

		var o_stored = i_self.getStored();
		var i_editor = i_self.getEditor();

		var s_raw = value;

		if (ip2.isStringedObject(s_raw)) {
			s_raw = Ext.decode(value, true) || value;
		}

		if (Ext.isObject(s_raw)) {

			s_raw = JSON.stringify(s_raw[s_current], null, "\t");
		}
		else {
			o_stored[s_current] = s_raw;
		}

		if (i_editor) {
			i_editor.setValue(s_raw);
		}
	},

	isDirty: function() {

		var i_self = this;

		var value = i_self.getValue();

		var s_originalValue = Ext.encode(i_self.originalValue, true) || i_self.originalValue;
		var s_value = Ext.encode(value, true) || value;

		return s_originalValue != s_value;
	},

	didValueChange: function (newValue, oldValue) {

		var s_originalValue = Ext.encode(newValue, true) || newValue;
		var s_value = Ext.encode(oldValue, true) || oldValue;

		return s_originalValue != s_value;
	},

	updateLanguage: function(value) {

		var i_self = this;

		if (i_self.rendered) {
			var o_stored = i_self.getStored();

			var s_value = o_stored[value];

			i_self.setValue(s_value);
		}
	},

	clear: function() {

		var i_self = this;

		i_self.suspendCheckChange++;
		i_self.setValue("");
		i_self.suspendCheckChange--;
	}
});
Ext.define("Portfolio.ux.form.field.i18n.text.TextArea", {

	extend: "Ext.form.field.TextArea",

	xtype: "portfolio-i18n-textarea",

	alternateClassName: [
		"Ext.ux.form.field.i18n.TextArea"
	],

	alias: [
		"widget.i18n-textarea",
		"widget.i18ntextareafield"
	],

	triggers: {
		"type": {
			cls: "",
			onClick: function() {
				var me = this;
				var args = arguments;
				var e = me.clickRepeater ? args[1] : args[0];
				var handler = me.handler;
				var field = me.field;
				if (handler && me.isFieldEnabled()) {
					Ext.callback(me.handler, me.scope, [
						field,
						me,
						e
					], 0, field);
				}
			},
			handler: function () {

				var i_self = this;

				var o_bodySize = Ext.getBody().getSize();

				var i_trigger = i_self.getTrigger("type");
				var i_menu = i_self.getSelections();

				i_menu.show();
				i_menu.alignTo(i_trigger.getEl(), "tr-tr");

				var n_bottom = i_menu.body.getBottom();

				if (n_bottom > o_bodySize.height) {
					i_menu.alignTo(i_self.getEl(), "br-tr");
				}
			}
		}
	},

	listeners: {
		afterrender: {
			fn: function (i_field) {

				var i_self = this;
				var b_active = i_self.getLanguageActive();

				var a_currrent = i_self.getLanguages();

				Ext.Array.each(a_currrent, function(s_lang) {

					var i_typeTrigger = i_self.getTrigger("type");

					var i_element = i_typeTrigger.getEl();

					if (i_element.hasCls("icon trigger flag " + s_lang + "-default")) {
						i_element.removeCls("icon trigger flag " + s_lang + "-default");
					}
				});

				var i_typeTrigger = i_self.getTrigger("type");

				var i_element = i_typeTrigger.getEl();

				if (!i_self.disabled) {
					i_element.show();
				}
				
				i_self.updateLanguageActive(b_active);

			}
		},
		enable: {
			fn: function(i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.show();
				}
			},
			buffer: 10
		},
		disable: {
			fn: function(i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.hide();
				}	
			},
			buffer: 10
		}
	},

	config: {
		languageActive: false,
		language: "en",
		primary: "en",
		languages: [],
		stored: {},
		selections: null,
		asString: false,
		langContext: "portfolio"
	},

	initComponent: function() {

		var i_self = this;
		
		var a_currrent = wsh.getLanguages(i_self.getLangContext());
		
		i_self.setLanguages(a_currrent);

		var s_current = ip2.getUser().get("USRLNG") || "en";

		i_self.setLanguage(s_current);
		i_self.setPrimary(s_current);

		i_self.callParent(arguments);

		i_self.createMenu();
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value;
		var s_current = i_self.getLanguage();
		var b_active = i_self.getLanguageActive();
		var a_languages = i_self.getLanguages();

		var o_stored = i_self.getStored();

		var s_raw = value;

		if (ip2.isStringedObject(s_raw)) {
			s_raw = Ext.decode(value, true) || value;
		}

		if (Ext.isObject(s_raw)) {

			o_stored = Ext.clone(s_raw);

			s_raw = o_stored[s_current];

			b_active = true;
		}
		else {
			o_stored[s_current] = s_raw;
		}

		Ext.Array.each(a_languages, function (s_key) {
			var s_value = o_stored[s_key] || "";
			o_stored[s_key] = s_value;
		});

		i_self.setStored(o_stored);
		i_self.setValue(s_raw);

		if (b_active) {
			i_self.setLanguageActive(true);
		}

		i_self.originalValue = i_self.lastValue = i_self.getValue();
		i_self.resetOriginalValue();
	},

	updateLanguageActive: function(b_active) {

		var i_self = this;
		var i_typeTrigger = i_self.getTrigger("type");

		var s_current = i_self.getLanguage();
		var s_primary = i_self.getPrimary();

		if (i_typeTrigger) {

			if (i_typeTrigger.rendered) {

				var i_element = i_typeTrigger.getEl();

				if (b_active) {

					i_element.removeCls("pf-earth2");
					i_element.addCls("icon trigger flag " + s_current);
				}
				else {
					i_element.removeCls("icon trigger flag " + s_current);

					if (i_element.hasCls("icon trigger flag " + s_current + "-default")) {
						i_element.removeCls("icon trigger flag " + s_current + "-default");
					}

					i_element.addCls("pf-earth2");
				}
			}
			else {
				if (b_active) {
					i_typeTrigger.cls = " icon trigger flag " + s_current;
				}
			}
		}

		if (!b_active) {
			i_self.setLanguage(s_primary);
		}
	},

	createMenu: function() {

		var i_self = this;

		var a_items = [];

		var i_typeTrigger = i_self.getTrigger("type");

		var a_languages = i_self.getLanguages();

		Ext.Array.each(a_languages, function (s_key) {

			var i_menuItem = Ext.widget("menuitem", {
				itemId: s_key,
				text: s_key,
				iconCls: "icon flag " + s_key,
				handler: function (i_item) {

					var i_element = i_typeTrigger.getEl();
					var b_active = i_self.getLanguageActive();
					var s_current = i_self.getLanguage();

					i_element.removeCls("icon flag " + s_current);

					i_self.setLanguage(i_item.itemId);

					if (!b_active) {
						i_self.setLanguageActive(true);
					}
					else {
						i_self.updateLanguageActive(b_active);
					}

					i_self.checkChange();
				}
			});

			a_items.push(i_menuItem);
		});

		var i_menuItem = Ext.widget("menuitem", {
			itemId: "off",
			text: "Default",
			iconCls: "pf-earth2",
			handler: function (i_item) {
				i_self.setLanguageActive(false);
				i_self.checkChange();
			}
		});

		a_items.push(i_menuItem);

		var i_menu = Ext.widget("menu", {
			items: a_items,
			listeners: {
				beforeshow: {
					fn: function (i_menu) {

						var a_items = i_menu.query("menuitem");

						var s_current = i_self.getLanguage();

						var b_active = i_self.getLanguageActive();

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

							i_item.enable();

							if (i_item.itemId == "off" || i_self.readOnly) {
								if (!b_active) {
									i_item.disable();
								}
							}
						});

						if (b_active) {

							var i_found = Ext.Array.findBy(a_items, function (i_item) {
								return s_current == i_item.itemId;
							});

							i_found.disable();
						}
					}
				}
			}
		});

		i_self.setSelections(i_menu);
	},

	getValue: function() {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var s_value = i_self.getRawValue();

		var b_active = i_self.getLanguageActive();

		if (b_active) {

			var o_stored = i_self.getStored();
			var s_raw = i_self.getRawValue();

			o_stored[s_current] = s_raw;

			s_value = Ext.clone(o_stored);
		}

		return s_value;
	},

	getSubmitValue: function () {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var s_value = i_self.getRawValue();

		var b_active = i_self.getLanguageActive();

		if (b_active) {

			var o_stored = i_self.getStored();
			var s_raw = i_self.getRawValue();

			o_stored[s_current] = s_raw;

			s_value = Ext.clone(o_stored);
		}

		if (i_self.getAsString()) {

			if (Ext.isObject(s_value)) {
				s_value = Ext.encode(s_value);
			}
		}

		return s_value;
	},

	setValue: function(value) {

		var i_self = this;

		var s_current = i_self.getLanguage();

		var o_stored = i_self.getStored();

		var s_raw = value;

		if (ip2.isStringedObject(s_raw)) {
			s_raw = Ext.decode(value, true) || value;
		}

		if (Ext.isObject(s_raw)) {

			o_stored = Ext.copy(s_raw);

			i_self.setLanguageActive(true);

			s_raw = o_stored[s_current];
		}
		else {
			o_stored[s_current] = s_raw;
		}

		i_self.setRawValue(s_raw);

		if (i_self.rendered) {
			i_self.checkChange();
		}
	},

	isDirty: function() {

		var i_self = this;

		var value = i_self.getValue();

		var s_originalValue = Ext.encode(i_self.originalValue, true) || i_self.originalValue;
		var s_value = Ext.encode(value, true) || value;

		return s_originalValue != s_value;
	},

	didValueChange: function(newValue, oldValue) {

		var s_originalValue = Ext.encode(newValue, true) || newValue;
		var s_value = Ext.encode(oldValue, true) || oldValue;

		return s_originalValue != s_value;
	},

	updateLanguage: function(value) {

		var i_self = this;

		if (value) {
			var o_stored = i_self.getStored();

			var s_value = o_stored[value];

			i_self.setValue(s_value);
		}
	},

	clear: function() {

		var i_self = this;

		i_self.suspendCheckChange++;
		i_self.setValue("");
		i_self.suspendCheckChange--;
	}
});
Ext.define("Portfolio.ux.form.field.i18n.text.TextField", {

	extend: "Ext.form.field.Text",

	xtype: "portfolio-i18n-textfield",

	alias: [
		"widget.i18n-textfield",
		"widget.i18ntextfield"
	],

	alternateClassName: [
		"Ext.ux.form.field.i18n.Text"
	],

	triggers: {
		"type": {
			cls: "",
			onClick: function() {
				var me = this;
				var args = arguments;
				var e = me.clickRepeater ? args[1] : args[0];
				var handler = me.handler;
				var field = me.field;
				if (handler && me.isFieldEnabled()) {
					Ext.callback(me.handler, me.scope, [
						field,
						me,
						e
					], 0, field);
				}
			},	
			handler: function() {

				var i_self = this;

				var o_bodySize = Ext.getBody().getSize();

				var i_trigger = i_self.getTrigger("type");
				var i_menu = i_self.getSelections();

				i_menu.show();
				i_menu.alignTo(i_trigger.getEl(), "tr-tr");

				var n_bottom = i_menu.body.getBottom();

				if (n_bottom > o_bodySize.height) {
					i_menu.alignTo(i_self.getEl(), "br-tr");
				}
			}
		}
	},

	listeners: {
		afterrender: {
			fn: function(i_field) {

				var i_self = this;
				var b_active = i_self.getLanguageActive();

				var a_currrent = i_self.getLanguages();

				Ext.Array.each(a_currrent, function (s_lang) {

					var i_typeTrigger = i_self.getTrigger("type");

					var i_element = i_typeTrigger.getEl();

					if (i_element.hasCls("icon trigger flag " + s_lang + "-default")) {
						i_element.removeCls("icon trigger flag " + s_lang + "-default");
					}
				});

				var i_typeTrigger = i_self.getTrigger("type");

				var i_element = i_typeTrigger.getEl();

				if (!i_self.disabled) {
					i_element.show();
				}

				i_self.updateLanguageActive(b_active);

			}
		},
		writeablechange: {
			fn: function(i_field, b_readOnly) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.show();
				}
			},
			buffer: 10
		},
		enable: {
			fn: function(i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.show();
				}
			},
			buffer: 10
		},
		disable: {
			fn: function(i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.hide();
				}	
			},
			buffer: 10
		}
	},

	config: {
		languageActive: false,
		language: "en",
		primary: "en",
		languages: [],
		stored: {},
		selections: null,
		asString: false,
		langContext: "portfolio"
	},

	initComponent: function() {

		var i_self = this;

		var a_currrent = wsh.getLanguages(i_self.getLangContext());
		
		i_self.setLanguages(a_currrent);

		var s_current = ip2.getUser().get("USRLNG") || "en";

		i_self.setLanguage(s_current);
		i_self.setPrimary(s_current);

		i_self.callParent(arguments);

		i_self.createMenu();
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value;
		var s_current = i_self.getLanguage();
		var b_active = i_self.getLanguageActive();
		var a_languages = i_self.getLanguages();

		var o_stored = i_self.getStored();

		var s_raw = value;

		if (ip2.isStringedObject(s_raw)) {
			s_raw = Ext.decode(value, true) || value;
		}

		if (Ext.isObject(s_raw)) {

			o_stored = Ext.clone(s_raw);

			s_raw = o_stored[s_current];

			b_active = true;
		}
		else {
			o_stored[s_current] = s_raw;
		}

		i_self.setValue(s_raw);

		Ext.Array.each(a_languages, function(s_key) {
			var s_value	= o_stored[s_key] || "";
			o_stored[s_key] = s_value;
		});

		i_self.setStored(o_stored);

		if (b_active) {
			i_self.setLanguageActive(true);
		}

		i_self.originalValue = i_self.lastValue = i_self.getValue();
		i_self.resetOriginalValue();
	},

	updateLanguageActive: function(b_active) {

		var i_self = this;
		var i_typeTrigger = i_self.getTrigger("type");

		var s_current = i_self.getLanguage();
		var s_primary = i_self.getPrimary();

		if (i_typeTrigger) {
			if (i_typeTrigger.rendered) {
				var i_element = i_typeTrigger.getEl();
				if (b_active) {
					i_element.removeCls("pf-earth2");
					i_element.addCls("icon trigger flag " + s_current);
				}
				else {
					i_element.removeCls("icon trigger flag " + s_current);
					i_element.addCls("pf-earth2");
				}
			}
			else {
				if (b_active) {
					i_typeTrigger.cls = " icon trigger flag " + s_current;
				}
			}
		}

		if (!b_active) {
			i_self.setLanguage(s_primary);
		}
	},

	createMenu: function() {

		var i_self = this;

		var a_items = [];

		var i_typeTrigger = i_self.getTrigger("type");

		var a_languages = i_self.getLanguages();

		Ext.Array.each(a_languages, function(s_key) {

			var i_menuItem = Ext.widget("menuitem", {
				itemId: s_key,
				text: s_key,
				iconCls: "icon flag " + s_key,
				handler: function(i_item) {

					var i_element = i_typeTrigger.getEl();
					var b_active = i_self.getLanguageActive();
					var s_current = i_self.getLanguage();

					i_element.removeCls("icon flag " + s_current);

					i_self.setLanguage(i_item.itemId);

					if (!b_active) {
						i_self.setLanguageActive(true);
					}
					else {
						i_self.updateLanguageActive(b_active);
					}

					i_self.checkChange();
				}
			});

			a_items.push(i_menuItem);
		});

		var i_menuItem = Ext.widget("menuitem", {
			itemId: "off",
			text: "Default",
			iconCls: "pf-earth2",
			handler: function (i_item) {
				i_self.setLanguageActive(false);
				i_self.checkChange();
			}
		});

		a_items.push(i_menuItem);

		var i_menu = Ext.widget("menu", {
			items: a_items,
			listeners: {
				beforeshow: {
					fn: function(i_menu) {

						var a_items = i_menu.query("menuitem");

						var s_current = i_self.getLanguage();

						var b_active = i_self.getLanguageActive();

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

							i_item.enable();

							if (i_item.itemId == "off") {
								if (!b_active || i_self.readOnly) {
									i_item.disable();
								}
							}
						});

						if (b_active) {

							var i_found = Ext.Array.findBy(a_items, function(i_item) {
								return s_current == i_item.itemId;
							});

							i_found.disable();
						}
					}
				}
			}
		});

		i_self.setSelections(i_menu);
	},

	getValue: function() {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var s_value = i_self.getRawValue();

		var b_active = i_self.getLanguageActive();

		if (b_active) {

			var o_stored = i_self.getStored();
			var s_raw = i_self.getRawValue();

			o_stored[s_current] = s_raw;

			s_value = Ext.clone(o_stored);
		}


		if (i_self.getAsString()) {

			if (Ext.isObject(s_value)) {
				s_value = Ext.encode(s_value);
			}
		}

		return s_value;
	},

	getSubmitValue: function () {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var s_value = i_self.getRawValue();

		var b_active = i_self.getLanguageActive();

		if (b_active) {

			var o_stored = i_self.getStored();
			var s_raw = i_self.getRawValue();

			o_stored[s_current] = s_raw;

			s_value = o_stored;
		}

		if (i_self.getAsString()) {

			if (Ext.isObject(s_value)) {
				s_value = Ext.encode(s_value);
			}
		}

		return s_value;
	},

	getSubmitData: function() {

		var i_self = this;
		return i_self.getValue();
	},

	setValue: function(value) {

		var i_self = this;

		var s_current = i_self.getLanguage();

		var o_stored = i_self.getStored();

		var s_raw = value;

		if (ip2.isStringedObject(s_raw)) {
			s_raw = Ext.decode(value, true) || value;
		}

		if (Ext.isObject(s_raw)) {

			o_stored = Ext.clone(s_raw);

			i_self.setLanguageActive(true);

			s_raw = o_stored[s_current];
		}
		else {
			o_stored[s_current] = s_raw;
		}

		i_self.setRawValue(s_raw);

		if (i_self.rendered) {
			i_self.checkChange();
		}
	},

	isDirty: function() {

		var i_self = this;

		var value = i_self.getValue();

		var s_originalValue = Ext.encode(i_self.originalValue, true) || i_self.originalValue;
		var s_value = Ext.encode(value, true) || value;

		return s_originalValue != s_value;
	},

	updateLanguage: function(value) {

		var i_self = this;

		if (value) {
			var o_stored = i_self.getStored();

			var s_value = o_stored[value];

			i_self.setValue(s_value);
		}
	},

	didValueChange: function (newValue, oldValue) {

		var s_originalValue = Ext.encode(newValue, true) || newValue;
		var s_value = Ext.encode(oldValue, true) || oldValue;

		return s_originalValue != s_value;
	},

	clear: function() {

		var i_self = this;

		i_self.suspendCheckChange++;
		i_self.setValue("");
		i_self.suspendCheckChange--;
	}
});
Ext.define("Portfolio.ux.form.field.i18n.text.MarkdownField", {

    extend: "Ext.form.field.TextArea",

	xtype: "portfolio-i18n-textmarkdownfield",

	mixins: [
		"Ext.mixin.Mashup"
	],

	requiredScripts: [
		"//cdn.jsdelivr.net/simplemde/latest/simplemde.min.css",
		"//cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"
	],

	alias: [
		"widget.i18n-textmarkdownfield",
		"widget.i18ntextmarkdownfield"
	],

	alternateClassName: [
		"Ext.ux.form.field.i18n.TextMarkdownField"
	],

	triggers: {
		"type": {
			cls: "",
			onClick: function() {
				var me = this;
				var args = arguments;
				var e = me.clickRepeater ? args[1] : args[0];
				var handler = me.handler;
				var field = me.field;
				if (handler && me.isFieldEnabled()) {
					Ext.callback(me.handler, me.scope, [
						field,
						me,
						e
					], 0, field);
				}
			},
			handler: function() {

				var i_self = this;

				var o_bodySize = Ext.getBody().getSize();

				var i_trigger = i_self.getTrigger("type");
				var i_menu = i_self.getSelections();

				i_menu.show();
				i_menu.alignTo(i_trigger.getEl(), "tr-tr");

				var n_bottom = i_menu.body.getBottom();

				if (n_bottom > o_bodySize.height) {
					i_menu.alignTo(i_self.getEl(), "br-tr");
				}
			}
		}
	},

	listeners: {
		render: {
			fn: function(i_field) {
				var i_self = this;

				var i_simpleMDE = new SimpleMDE({
					element: i_self.inputEl.el.dom,
					status: false,
					spellChecker: false
				});

				var i_codemirror = i_simpleMDE.codemirror;

				i_codemirror.on("change", function () {
					i_self.setValue(i_simpleMDE.value());
					i_self.checkChange();
				});

				i_simpleMDE.gui.toolbar.style.border = "none";

				i_codemirror.getWrapperElement().style.border = "none";
				i_codemirror.getWrapperElement().style.borderTop = "1px solid #ddd";

				i_codemirror.getWrapperElement().style.setProperty("height", "auto");

				i_codemirror.getWrapperElement().style.setProperty("min-height", "80px");
				i_codemirror.getScrollerElement().style.setProperty("min-height", "80px");

				var value = i_self.getValue();

				if (Ext.isEmpty(value)) {
					value = "";
				}
				else if (Ext.isObject(value)) {
					var s_current = i_self.getLanguage();
					var b_active = i_self.getLanguageActive();

					if (b_active) {
						value = value[s_current];
					}
					else {
						value = Ext.encode(value);
					}
				}

				i_simpleMDE.value(value);


				i_self.setSimpleMDE(i_simpleMDE);
			}
		},
		afterrender: {
			fn: function(i_field) {

				var i_self = this;
				var b_active = i_self.getLanguageActive();

				var a_languages = i_self.getLanguages();

				Ext.Array.each(a_languages, function (s_lang) {

					var i_typeTrigger = i_self.getTrigger("type");

					var i_element = i_typeTrigger.getEl();

					if (i_element.hasCls("icon trigger flag " + s_lang + "-default")) {
						i_element.removeCls("icon trigger flag " + s_lang + "-default");
					}
				});

				var i_typeTrigger = i_self.getTrigger("type");

				var i_element = i_typeTrigger.getEl();

				if (!i_self.disabled) {
					i_element.show();
				}
				i_self.updateLanguageActive(b_active);
			}
		},
		writeablechange: {
			fn: function(i_field, b_readOnly) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.show();
				}
			},
			buffer: 10
		},
		enable: {
			fn: function(i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.show();
				}
			},
			buffer: 10
		},
		disable: {
			fn: function(i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.hide();
				}	
			},
			buffer: 10
		},
		resize: {
			fn: function() {

				var i_self = this;
				var i_inputEl = i_self.bodyEl;
				var i_simpleMDE = i_self.getSimpleMDE();

				var n_height = (i_inputEl.getHeight(true) - i_simpleMDE.gui.toolbar.clientHeight);

				var i_codemirror = i_simpleMDE.codemirror;
				var i_wrapper = i_codemirror.getWrapperElement();
				var i_scroller = i_codemirror.getScrollerElement();

				i_wrapper.style.maxHeight = i_scroller.style.maxHeight = n_height + "px";
				i_wrapper.style.paddingBottom = i_wrapper.style.paddingTop = "1px";
			}
		}
	},

	config: {
		languageActive: false,
		language: "en",
		primary: "en",
		languages: [],
		stored: {},
		selections: null,
		asString: false,
		simpleMDE: null
	},

	initComponent: function() {

		var i_self = this;
		var a_languages = i_self.getLanguages();
		var s_current = ip2.getUser().get("USRLNG") || "en";

		if (a_languages.length === 0) {

			a_languages.push(s_current);

			i_self.setLanguages(a_languages);
		}

		i_self.setLanguage(s_current);
		i_self.setPrimary(s_current);

		i_self.callParent(arguments);

		i_self.createMenu();
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value;
		var s_current = i_self.getLanguage();
		var b_active = i_self.getLanguageActive();
		var a_languages = i_self.getLanguages();

		var o_stored = i_self.getStored();

		var s_raw = value;

		if (ip2.isStringedObject(s_raw)) {
			s_raw = Ext.decode(value, true) || value;
		}

		if (Ext.isObject(s_raw)) {

			o_stored = Ext.clone(s_raw);

			s_raw = o_stored[s_current];

			b_active = true;
		}
		else {
			o_stored[s_current] = s_raw;
		}

		i_self.setValue(s_raw);

		Ext.Array.each(a_languages, function(s_key) {
			var s_value	= o_stored[s_key] || "";
			o_stored[s_key] = s_value;
		});

		i_self.setStored(o_stored);

		if (b_active) {
			i_self.setLanguageActive(true);
		}

		i_self.originalValue = i_self.lastValue = i_self.getValue();
		i_self.resetOriginalValue();
	},

	updateLanguageActive: function(b_active) {

		var i_self = this;
		var i_typeTrigger = i_self.getTrigger("type");

		var s_current = i_self.getLanguage();
		var s_primary = i_self.getPrimary();

		if (i_typeTrigger) {
			if (i_typeTrigger.rendered) {
				var i_element = i_typeTrigger.getEl();
				if (b_active) {
					i_element.removeCls("pf-earth2");
					i_element.addCls("icon trigger flag " + s_current);
				}
				else {
					i_element.removeCls("icon trigger flag " + s_current);
					i_element.addCls("pf-earth2");
				}
			}
			else {
				if (b_active) {
					i_typeTrigger.cls = " icon trigger flag " + s_current;
				}
			}
		}

		if (!b_active) {
			i_self.setLanguage(s_primary);
		}
	},

	createMenu: function() {

		var i_self = this;

		var a_items = [];

		var i_typeTrigger = i_self.getTrigger("type");

		var a_languages = i_self.getLanguages();

		Ext.Array.each(a_languages, function(s_key) {

			var i_menuItem = Ext.widget("menuitem", {
				itemId: s_key,
				text: s_key,
				iconCls: "icon flag " + s_key,
				handler: function(i_item) {

					var i_element = i_typeTrigger.getEl();
					var b_active = i_self.getLanguageActive();
					var s_current = i_self.getLanguage();

					i_element.removeCls("icon flag " + s_current);

					i_self.setLanguage(i_item.itemId);

					if (!b_active) {
						i_self.setLanguageActive(true);
					}
					else {
						i_self.updateLanguageActive(b_active);
					}

					i_self.checkChange();
				}
			});

			a_items.push(i_menuItem);
		});

		var i_menuItem = Ext.widget("menuitem", {
			itemId: "off",
			text: "Default",
			iconCls: "pf-earth2",
			handler: function (i_item) {
				i_self.setLanguageActive(false);
				i_self.checkChange();
			}
		});

		a_items.push(i_menuItem);

		var i_menu = Ext.widget("menu", {
			items: a_items,
			listeners: {
				beforeshow: {
					fn: function(i_menu) {

						var a_items = i_menu.query("menuitem");

						var s_current = i_self.getLanguage();

						var b_active = i_self.getLanguageActive();

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

							i_item.enable();

							if (i_item.itemId == "off" || i_self.readOnly) {
								if (!b_active) {
									i_item.disable();
								}
							}
						});

						if (b_active) {

							var i_found = Ext.Array.findBy(a_items, function(i_item) {
								return s_current == i_item.itemId;
							});

							i_found.disable();
						}
					}
				}
			}
		});

		i_self.setSelections(i_menu);
	},

	getValue: function() {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var s_value = i_self.getRawValue();

		var b_active = i_self.getLanguageActive();

		if (b_active) {

			var o_stored = i_self.getStored();
			var s_raw = i_self.getRawValue();

			o_stored[s_current] = s_raw;

			s_value = Ext.clone(o_stored);
		}

		if (i_self.getAsString()) {

			if (Ext.isObject(s_value)) {
				s_value = Ext.encode(s_value);
			}
		}

		return Ext.clone(s_value);
	},

	getSubmitData: function() {

		var i_self = this;
		return i_self.getValue();
	},

	getSubmitValue: function() {

		var i_self = this;
		return i_self.getValue();
	},

	setValue: function(value) {

		var i_self = this;

		var s_current = i_self.getLanguage();

		var o_stored = i_self.getStored();

		var s_raw = value;

		if (ip2.isStringedObject(s_raw)) {
			s_raw = Ext.decode(value, true) || value;
		}

		if (Ext.isObject(s_raw)) {

			o_stored = Ext.clone(s_raw);

			i_self.setLanguageActive(true);

			s_raw = o_stored[s_current];
		}
		else {
			o_stored[s_current] = s_raw;
		}

		var i_simpleMDE = i_self.getSimpleMDE();

		if (i_simpleMDE) {

			var s_code = i_simpleMDE.value();

			if (s_code != s_raw) {
				i_simpleMDE.value(s_raw);
			}
		}

		i_self.setRawValue(s_raw);

		if (i_self.rendered) {
			i_self.checkChange();
		}
	},

	isDirty: function() {

		var i_self = this;

		var value = i_self.getValue();

		var s_originalValue = Ext.encode(i_self.originalValue, true) || i_self.originalValue;
		var s_value = Ext.encode(value, true) || value;

		return s_originalValue != s_value;
	},

	didValueChange: function(newValue, oldValue) {

		var s_new = Ext.encode(newValue, true) || newValue;
		var s_old = Ext.encode(oldValue, true) || oldValue;

		return s_new != s_old;
	},

	checkChange: function () {

		var i_self = this;
		var newVal;
		var oldVal;

		if (!i_self.suspendCheckChange && !i_self.destroying && !i_self.destroyed) {
			newVal = i_self.getValue();
			oldVal = i_self.lastValue;
			if (i_self.didValueChange(newVal, oldVal)) {
				i_self.lastValue = Ext.clone(newVal);
				i_self.fireEvent("change", i_self, newVal, oldVal);
				i_self.onChange(newVal, oldVal);
			}
		}
	},

	updateLanguage: function(value) {

		var i_self = this;

		if (value) {
			var o_stored = i_self.getStored();

			var s_value = o_stored[value];

			i_self.setValue(s_value);
		}
	},

	clear: function() {

		var i_self = this;

		i_self.suspendCheckChange++;
		i_self.setValue("");
		i_self.suspendCheckChange--;
	}
});
Ext.define("Portfolio.ux.form.field.i18n.hook.TextField", {

	extend: "Ext.form.field.Text",

	xtype: "portfolio-i18n-hook-textfield",

	alternateClassName: [
		"Ext.ux.form.field.i18n.hook.TextField",
		"Ext.ux.form.field.i18nHook.Text"
	],

	alias: [
		"widget.i18n-hook-textfield",
		"widget.i18nhooktextfield"
	],

	triggers: {
		"type": {
			cls: "",
			handler: function () {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");
				var i_menu = i_self.getSelections();

				i_menu.show();
				i_menu.alignTo(i_trigger.getEl(), "tr-tr");
				i_menu.toFront();
			}
		}
	},

	listeners: {
		afterrender: {
			fn: function (i_field) {

				var i_self = this;
				var b_active = i_self.getLanguageActive();

				i_self.updateLanguageActive(b_active);

			}
		},
		writeablechange: {
			fn: function (i_field, b_readOnly) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_trigger.rendered) {
					i_trigger[b_readOnly ? "hide" : "show"]();
				}
			},
			buffer: 10
		},
		enable: {
			fn: function (i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_trigger.rendered) {
					i_trigger.show();
				}
			},
			buffer: 10
		},
		disable: {
			fn: function (i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_trigger.rendered) {
					i_trigger.hide();
				}
			},
			buffer: 10
		}
	},

	config: {
		languageActive: false,
		language: "en",
		primary: "en",
		languages: [],
		stored: {},
		selections: null,
		asString: false,
		defaultProperty: "",
		propertyHost: null,
		langContext: "portfolio"
	},

	initComponent: function() {

		var i_self = this;

		var a_currrent = wsh.getLanguages(i_self.getLangContext());
		
		i_self.setLanguages(a_currrent);

		var s_current = ip2.getUser().get("USRLNG") || "en";

		if (!i_self.getPropertyHost()) {
			i_self.setPropertyHost(i_self.name + "_CARRIER");
		}

		i_self.setLanguage(s_current);
		i_self.setPrimary(s_current);

		i_self.callParent(arguments);

		i_self.createMenu();
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value || "";
		var s_current = i_self.getLanguage();
		var a_languages = i_self.getLanguages();

		var o_stored = i_self.getStored() || {};

		var o_meta = {
			key: {},
			defaultProperty: i_self.getDefaultProperty(),
			active: 0
		};

		o_meta.key[i_self.name] = 0;

		var o_value = Ext.decode(value, true) || {
			meta: o_meta,
			text: {},
			"default": value
		};

		if (!Ext.isObject(o_value)) {

			o_value = {
				meta: o_meta,
				text: {},
				"default": ""
			};
		}
		else {

			Ext.apply(o_meta, o_value.meta);
		}

		var s_raw = o_value["default"];

		var b_active = o_meta.active;

		o_stored = Ext.clone(o_value.text);

		if (b_active) {
			s_raw = o_stored[s_current];
		}
		else {
			o_stored[s_current] = s_raw;
		}

		i_self.setValue(s_raw);

		i_self.originalValue = i_self.lastValue = i_self.value = Ext.clone(o_value);
		i_self.resetOriginalValue();

		Ext.Array.each(a_languages, function(s_key) {
			var s_value	= o_stored[s_key] || "";
			o_stored[s_key] = s_value;
		});

		i_self.setStored(o_stored);

		if (b_active) {
			i_self.setLanguageActive(true);
		}
	},

	updateLanguageActive: function(b_active) {

		var i_self = this;
		var i_typeTrigger = i_self.getTrigger("type");

		var s_current = i_self.getLanguage();
		var s_primary = i_self.getPrimary();

		if (i_typeTrigger) {
			if (i_typeTrigger.rendered) {
				var i_element = i_typeTrigger.getEl();
				if (b_active) {
					i_element.removeCls("pf-earth2");
					i_element.addCls("icon trigger flag " + s_current);
				}
				else {
					i_element.removeCls("icon trigger flag " + s_current);
					i_element.addCls("pf-earth2");
				}
			}
			else {
				if (b_active) {
					i_typeTrigger.cls = " icon trigger flag " + s_current;
				}
			}
		}

		if (!b_active) {
			i_self.setLanguage(s_primary);
		}


		var o_stored = i_self.getStored();
		var o_value = i_self.value || {};

		var s_value;

		if (!b_active) {

			s_value = o_value["default"];
			i_self.setValue(s_value);
		}
		else {

			o_value["default"] = i_self.getRawValue();

			o_stored.en = o_stored.en || o_value["default"];

			s_value = o_stored[s_current];
			i_self.setValue(s_value);
		}

		if (i_self.rendered) {
			i_self.checkChange();
		}
	},

	createMenu: function() {

		var i_self = this;

		var a_items = [];

		var i_typeTrigger = i_self.getTrigger("type");

		var a_languages = i_self.getLanguages();

		Ext.Array.each(a_languages, function (s_key) {

			var i_menuItem = Ext.widget("menuitem", {
				itemId: s_key,
				text: s_key,
				iconCls: "icon flag " + s_key,
				handler: function (i_item) {

					var i_element = i_typeTrigger.getEl();
					var b_active = i_self.getLanguageActive();
					var s_current = i_self.getLanguage();

					i_element.removeCls("icon flag " + s_current);

					i_self.setLanguage(i_item.itemId);

					if (!b_active) {
						i_self.setLanguageActive(true);
					}
					else {
						i_self.updateLanguageActive(b_active);
					}

					i_self.checkChange();
				}
			});

			a_items.push(i_menuItem);
		});

		var i_menuItem = Ext.widget("menuitem", {
			itemId: "off",
			text: "Default",
			iconCls: "pf-earth2",
			handler: function (i_item) {
				i_self.setLanguageActive(false);
				i_self.checkChange();
			}
		});

		a_items.push(i_menuItem);

		var i_menu = Ext.widget("menu", {
			items: a_items,
			listeners: {
				beforeshow: {
					fn: function (i_menu) {

						var a_items = i_menu.query("menuitem");

						var s_current = i_self.getLanguage();

						var b_active = i_self.getLanguageActive();

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

							i_item.enable();

							if (i_item.itemId == "off") {
								if (!b_active) {
									i_item.disable();
								}
							}
						});

						if (b_active) {

							var i_found = Ext.Array.findBy(a_items, function (i_item) {
								return s_current == i_item.itemId;
							});

							i_found.disable();
						}
					}
				}
			}
		});

		i_self.setSelections(i_menu);
	},

	getValue: function() {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var s_default = "";

		var o_initial = i_self.initialConfig;

		var b_active = i_self.getLanguageActive();

		var o_meta = {
			key: {},
			defaultProperty: i_self.getDefaultProperty(),
			active: b_active ? 1 : 0
		};

		o_meta.key[i_self.name] = o_initial.value || 0;

		var o_stored = i_self.getStored();
		var s_raw = i_self.getRawValue();

		s_default = s_raw;

		if (b_active) {

			o_stored[s_current] = s_raw;

			if (o_stored.en) {
				s_default = o_stored.en;
			}
		}

		var o_value = {
			meta: o_meta,
			text: o_stored,
			"default": s_default
		};

		i_self.value = o_value;

		return o_value;
	},

	getSubmitValue: function() {

		var i_self = this;
		var o_value = i_self.getValue();
		var o_text = o_value.text;

		var s_raw = i_self.getRawValue();

		if (!o_text.en) {
			o_text.en = s_raw;
			o_value["default"] = o_text.en;
		}

		return o_value;
	},

	setValue: function(value) {

		var i_self = this;

		var b_active = i_self.getLanguageActive();
		var s_current = i_self.getLanguage();

		var s_value = value;

		if (Ext.isObject(value)) {

			s_value = value["default"];

			if (b_active) {
				s_value = ip2.i18n(value.text);
			}
		}

		if (!s_value) {

			var o_value = i_self.value || i_self.lastValue || {
				text: {}
			};

			if (!b_active) {
				s_value = o_value["default"];
			}
			else {
				s_value = o_value.text[s_current];
			}
		}

		i_self.setRawValue(s_value);

		if (i_self.rendered) {
			i_self.checkChange();
		}
	},

	setCarrierValue: function(s_value) {

		var i_self = this;
		var o_initial = i_self.initialConfig;
		var o_stored = i_self.getStored();

		var a_languages = i_self.getLanguages();

		s_value = s_value || "";

		var o_meta = {
			key: {},
			defaultProperty: i_self.getDefaultProperty(),
			active: 0
		};

		o_meta.key[i_self.name] = o_initial.value || 0;

		var o_value = Ext.decode(s_value, true) || {
			meta: o_meta,
			text: {},
			"default": ""
		};

		var b_active = o_value.active ? true : false;

		var o_text = Ext.clone(o_value.text);

		Ext.Array.each(a_languages, function(s_key) {
			var s_value	= o_text[s_key] || "";
			o_text[s_key] = s_value;
		});

		Ext.apply(o_stored, o_text);

		if (!o_stored.en) {
			o_stored.en = o_value["default"];
		}

		i_self.value = o_value;

		i_self.setStored(o_stored);

		if (Ext.isObject(o_value)) {

			s_value = o_value["default"];

			if (b_active) {
				s_value = ip2.i18n(o_value.text);
			}
		}

		i_self.suspendCheckChange++;
		i_self.setValue(s_value);
		i_self.setLanguageActive(b_active);
		i_self.resetOriginalValue();
		i_self.suspendCheckChange--;
		i_self.checkChange();
	},

	resetOriginalValue: function() {

		var i_self = this;

		i_self.originalValue = Ext.clone(i_self.getValue());
		i_self.checkDirty();
	},

	checkChange: function() {

		var i_self = this;
		var o_newValue;
		var o_oldValue;

		if (!i_self.suspendCheckChange) {

			o_newValue = Ext.clone(i_self.getValue());
			o_oldValue = Ext.clone(i_self.lastValue);

			if (!i_self.isDestroyed && i_self.didValueChange(o_newValue, o_oldValue)) {
				i_self.lastValue = o_newValue;
				i_self.fireEvent("change", i_self, o_newValue, o_oldValue);
				i_self.onChange(o_newValue, o_oldValue);
			}
		}
	},

	didValueChange: function(o_newValue, o_oldValue) {

		var s_newValue = Ext.encode(o_newValue);
		var s_oldValue = Ext.encode(o_oldValue);

		return s_newValue != s_oldValue;
	},

	isDirty: function() {

		var i_self = this;

		var b_active = i_self.getLanguageActive();

		var value = i_self.getValue();

		var o_original = i_self.originalValue;

		var b_dirty = false;

		if (b_active) {
			var s_originalValue = Ext.encode(i_self.originalValue, true) || i_self.originalValue;
			var s_value = Ext.encode(value, true) || value;

			b_dirty = s_originalValue != s_value;
		}
		else {
			b_dirty = value["default"] != o_original["default"] || (b_active != o_original.meta.active);
		}

		return b_dirty;
	},

	updateLanguage: function(value) {

		var i_self = this;

		if (value) {
			var o_stored = i_self.getStored();

			var s_value = o_stored[value];

			i_self.setValue(s_value);

			if (i_self.rendered) {
				var o_newValue = Ext.clone(i_self.getValue());
				var o_oldValue = Ext.clone(i_self.lastValue);

				i_self.fireEvent("change", i_self, o_newValue, o_oldValue);
			}
		}
	},

	clear: function() {

		var i_self = this;

		var o_initial = i_self.initialConfig;

		var b_active = i_self.getLanguageActive();

		var o_meta = {
			key: {},
			defaultProperty: i_self.getDefaultProperty(),
			active: b_active ? 1 : 0
		};

		o_meta.key[i_self.name] = o_initial.value || 0;

		var o_value = {
			meta: o_meta,
			text: {},
			"default": ""
		};

		i_self.value = o_value;
		i_self.suspendCheckChange++;
		i_self.setValue("");
		i_self.suspendCheckChange--;
	}
});
Ext.define("Portfolio.ux.form.field.i18n.hook.TextArea", {

	extend: "Ext.form.field.TextArea",

	xtype: "portfolio-i18n-hook-textarea",

	alternateClassName: [
		"Ext.ux.form.field.i18n.hook.TextArea"
	],

	alias: [
		"widget.i18n-hook-textarea"
	],

	triggers: {
		"type": {
			cls: "",
			handler: function () {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");
				var i_menu = i_self.getSelections();

				i_menu.show();
				i_menu.alignTo(i_trigger.getEl(), "tr-tr");
				i_menu.toFront();
			}
		}
	},

	listeners: {
		afterrender: {
			fn: function (i_field) {

				var i_self = this;
				var b_active = i_self.getLanguageActive();

				i_self.updateLanguageActive(b_active);

			}
		},
		writeablechange: {
			fn: function(i_field, b_readOnly) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_self.rendered) {
					i_trigger.el.show();
				}
			},
			buffer: 10
		},
		enable: {
			fn: function (i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_trigger.rendered) {
					i_trigger.show();
				}
			},
			buffer: 10
		},
		disable: {
			fn: function (i_field) {

				var i_self = this;

				var i_trigger = i_self.getTrigger("type");

				if (i_trigger.rendered) {
					i_trigger.hide();
				}
			},
			buffer: 10
		}
	},

	config: {
		languageActive: false,
		language: "en",
		primary: "en",
		languages: [],
		stored: {},
		selections: null,
		asString: false,
		defaultProperty: "",
		propertyHost: null,
		langContext: "portfolio"
	},

	initComponent: function() {

		var i_self = this;
		
		var a_currrent = wsh.getLanguages(i_self.getLangContext());
		
		i_self.setLanguages(a_currrent);

		var s_current = ip2.getUser().get("USRLNG") || "en";

		if (!i_self.getPropertyHost()) {
			i_self.setPropertyHost(i_self.name + "_CARRIER");
		}

		i_self.setLanguage(s_current);
		i_self.setPrimary(s_current);

		i_self.callParent(arguments);

		i_self.createMenu();
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value || "";
		var s_current = i_self.getLanguage();
		var a_languages = i_self.getLanguages();

		var o_stored = i_self.getStored() || {};

		var o_meta = {
			key: {},
			defaultProperty: i_self.getDefaultProperty(),
			active: 0
		};

		o_meta.key[i_self.name] = 0;

		var o_value = Ext.decode(value, true) || {
			meta: o_meta,
			text: {},
			"default": value
		};

		if (!Ext.isObject(o_value)) {

			o_value = {
				meta: o_meta,
				text: {},
				"default": ""
			};
		}
		else {

			Ext.apply(o_meta, o_value.meta);
		}

		var s_raw = o_value["default"];

		var b_active = o_meta.active;

		o_stored = Ext.clone(o_value.text);

		if (b_active) {
			s_raw = o_stored[s_current];
		}
		else {
			o_stored[s_current] = s_raw;
		}

		i_self.setValue(s_raw);

		i_self.originalValue = i_self.lastValue = i_self.value = Ext.clone(o_value);
		i_self.resetOriginalValue();

		Ext.Array.each(a_languages, function(s_key) {
			var s_value	= o_stored[s_key] || "";
			o_stored[s_key] = s_value;
		});

		i_self.setStored(o_stored);

		if (b_active) {
			i_self.setLanguageActive(true);
		}
	},

	updateLanguageActive: function(b_active) {

		var i_self = this;
		var i_typeTrigger = i_self.getTrigger("type");

		var s_current = i_self.getLanguage();
		var s_primary = i_self.getPrimary();

		if (i_typeTrigger) {
			if (i_typeTrigger.rendered) {
				var i_element = i_typeTrigger.getEl();
				if (b_active) {
					i_element.removeCls("pf-earth2");
					i_element.addCls("icon trigger flag" + s_current);
				}
				else {
					i_element.removeCls("icon trigger flag" + s_current);
					i_element.addCls("pf-earth2");
				}
			}
			else {
				if (b_active) {
					i_typeTrigger.cls = " icon trigger flag" + s_current;
				}
			}
		}

		if (!b_active) {
			i_self.setLanguage(s_primary);
		}


		var o_stored = i_self.getStored();
		var o_value = i_self.value || {};

		var s_value;

		if (!b_active) {

			s_value = o_value["default"];
			i_self.setValue(s_value);
		}
		else {

			o_value["default"] = i_self.getRawValue();

			o_stored.en = o_stored.en || o_value["default"];

			s_value = o_stored[s_current];
			i_self.setValue(s_value);
		}

		if (i_self.rendered) {
			i_self.checkChange();
		}
	},

	createMenu: function () {

		var i_self = this;

		var a_items = [];

		var i_typeTrigger = i_self.getTrigger("type");

		var a_languages = i_self.getLanguages();

		Ext.Array.each(a_languages, function (s_key) {

			var i_menuItem = Ext.widget("menuitem", {
				itemId: s_key,
				text: s_key,
				iconCls: "icon flag " + s_key,
				handler: function (i_item) {

					var i_element = i_typeTrigger.getEl();
					var b_active = i_self.getLanguageActive();
					var s_current = i_self.getLanguage();

					i_element.removeCls("icon flag" + s_current);

					i_self.setLanguage(i_item.itemId);

					if (!b_active) {
						i_self.setLanguageActive(true);
					}
					else {
						i_self.updateLanguageActive(b_active);
					}

					i_self.checkChange();
				}
			});

			a_items.push(i_menuItem);
		});

		var i_menuItem = Ext.widget("menuitem", {
			itemId: "off",
			text: "Default",
			iconCls: "pf-earth2",
			handler: function (i_item) {
				i_self.setLanguageActive(false);
				i_self.checkChange();
			}
		});

		a_items.push(i_menuItem);

		var i_menu = Ext.widget("menu", {
			items: a_items,
			listeners: {
				beforeshow: {
					fn: function (i_menu) {

						var a_items = i_menu.query("menuitem");

						var s_current = i_self.getLanguage();

						var b_active = i_self.getLanguageActive();

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

							i_item.enable();

							if (i_item.itemId == "off") {
								if (!b_active) {
									i_item.disable();
								}
							}
						});

						if (b_active) {

							var i_found = Ext.Array.findBy(a_items, function (i_item) {
								return s_current == i_item.itemId;
							});

							i_found.disable();
						}
					}
				}
			}
		});

		i_self.setSelections(i_menu);
	},

	getValue: function() {

		var i_self = this;
		var s_current = i_self.getLanguage();
		var s_default = "";

		var o_initial = i_self.initialConfig;

		var b_active = i_self.getLanguageActive();

		var o_meta = {
			key: {},
			defaultProperty: i_self.getDefaultProperty(),
			active: b_active ? 1 : 0
		};

		o_meta.key[i_self.name] = o_initial.value || 0;

		var o_stored = i_self.getStored();
		var s_raw = i_self.getRawValue();

		s_default = s_raw;

		if (b_active) {

			o_stored[s_current] = s_raw;

			if (o_stored.en) {
				s_default = o_stored.en;
			}
		}

		var o_value = {
			meta: o_meta,
			text: o_stored,
			"default": s_default
		};

		i_self.value = o_value;

		return o_value;
	},

	getSubmitValue: function() {

		var i_self = this;
		var o_value = i_self.getValue();
		var o_text = o_value.text;

		var s_raw = i_self.getRawValue();

		if (!o_text.en) {
			o_text.en = s_raw;
			o_value["default"] = o_text.en;
		}

		return o_value;
	},

	setValue: function(value) {

		var i_self = this;

		var b_active = i_self.getLanguageActive();
		var s_current = i_self.getLanguage();

		var s_value = value;

		if (Ext.isObject(value)) {

			s_value = value["default"];

			if (b_active) {
				s_value = ip2.i18n(value.text);
			}
		}

		if (!value) {

			var o_value = i_self.value || i_self.lastValue || {
				text: {}
			};

			if (!b_active) {
				s_value = o_value["default"];
			}
			else {
				s_value = o_value.text[s_current];
			}
		}

		i_self.setRawValue(s_value);

		if (i_self.rendered) {
			i_self.checkChange();
		}
	},

	setCarrierValue: function(s_value) {

		var i_self = this;
		var o_initial = i_self.initialConfig;
		var o_stored = i_self.getStored();

		var a_languages = i_self.getLanguages();

		s_value = s_value || "";

		var o_meta = {
			key: {},
			defaultProperty: i_self.getDefaultProperty(),
			active: 0
		};

		o_meta.key[i_self.name] = o_initial.value || 0;

		var o_value = Ext.decode(s_value, true) || {
			meta: o_meta,
			text: {},
			"default": ""
		};

		var b_active = o_value.active ? true : false;

		var o_text = Ext.clone(o_value.text);

		Ext.Array.each(a_languages, function(s_key) {
			var s_value	= o_text[s_key] || "";
			o_text[s_key] = s_value;
		});

		Ext.apply(o_stored, o_text);

		if (!o_stored.en) {
			o_stored.en = o_value["default"];
		}

		i_self.value = o_value;

		i_self.setStored(o_stored);

		if (Ext.isObject(o_value)) {

			s_value = o_value["default"];

			if (b_active) {
				s_value = ip2.i18n(o_value.text);
			}
		}

		i_self.suspendCheckChange++;
		i_self.setValue(s_value);
		i_self.setLanguageActive(b_active);
		i_self.resetOriginalValue();
		i_self.suspendCheckChange--;
		i_self.checkChange();
	},

	resetOriginalValue: function() {

		var i_self = this;

		i_self.originalValue = Ext.clone(i_self.getValue());
		i_self.checkDirty();
	},

	checkChange: function() {

		var i_self = this;
		var o_newValue;
		var o_oldValue;

		if (!i_self.suspendCheckChange) {

			o_newValue = Ext.clone(i_self.getValue());
			o_oldValue = Ext.clone(i_self.lastValue);

			if (!i_self.isDestroyed && i_self.didValueChange(o_newValue, o_oldValue)) {
				i_self.lastValue = o_newValue;
				i_self.fireEvent("change", i_self, o_newValue, o_oldValue);
				i_self.onChange(o_newValue, o_oldValue);
			}
		}
	},

	didValueChange: function(o_newValue, o_oldValue) {

		var s_newValue = Ext.encode(o_newValue);
		var s_oldValue = Ext.encode(o_oldValue);

		return s_newValue != s_oldValue;
	},

	isDirty: function() {

		var i_self = this;

		var b_active = i_self.getLanguageActive();

		var value = i_self.getValue();

		var o_original = i_self.originalValue;

		var b_dirty = false;

		if (b_active) {
			var s_originalValue = Ext.encode(i_self.originalValue, true) || i_self.originalValue;
			var s_value = Ext.encode(value, true) || value;

			b_dirty = s_originalValue != s_value;
		}
		else {
			b_dirty = value["default"] != o_original["default"] || (b_active != o_original.meta.active);
		}

		return b_dirty;
	},

	updateLanguage: function(value) {

		var i_self = this;

		if (value) {
			var o_stored = i_self.getStored();

			var s_value = o_stored[value];

			i_self.setValue(s_value);

			if (i_self.rendered) {
				var o_newValue = Ext.clone(i_self.getValue());
				var o_oldValue = Ext.clone(i_self.lastValue);

				i_self.fireEvent("change", i_self, o_newValue, o_oldValue);
			}
		}
	},

	clear: function() {

		var i_self = this;

		var o_initial = i_self.initialConfig;

		var b_active = i_self.getLanguageActive();

		var o_meta = {
			key: {},
			defaultProperty: i_self.getDefaultProperty(),
			active: b_active ? 1 : 0
		};

		o_meta.key[i_self.name] = o_initial.value || 0;

		var o_value = {
			meta: o_meta,
			text: {},
			"default": ""
		};

		i_self.value = o_value;
		i_self.suspendCheckChange++;
		i_self.setValue("");
		i_self.suspendCheckChange--;
	}
});
Ext.define("Portfolio.ux.form.field.pd.Picker", {
    
    extend: "Ext.form.field.ComboBox",

    alternateClassName: [
        "Ext.ux.form.field.pd.Picker"
    ],

    alias: [
        "widget.pd-picker"
    ],

    isFormField: false,
    
    editable: true,

    typeAHead: true,

    minChars: 1,

    config: {
        url: "/pd/collection"
    },

    valueField: "name",
    
    displayField: "label",

    initComponent: function() {

        var i_self = this;
        
        Ext.apply(i_self, {
            tpl: i_self.createListTpl(),
            displayTpl: i_self.createDisplayTpl(),
            store: i_self.createStore(),
            listeners: {
                select: {
                    fn: function(i_field, i_record) {
                        i_self.fireEvent("changecollection", i_record.get("name"), i_field.lastValue);
                    }
                }
            }
        });

        i_self.callParent(arguments);

        i_self.enableBubble([
            "changecollection"
        ]);
    },

    createStore: function() {

        var i_self = this;

        var a_data = Portfolio.pd.util.Cache.load(i_self.getUrl());

        var a_filtered = Ext.Array.filter(a_data, function(o_config) {
            return o_config.type == "formCollection" && !o_config.isTemplate;
        });

        var i_store = Ext.create("Ext.data.Store", {
            autoLoad: true,
            fields: [
                {
                    name: "name",
                    type: "auto"
                },
                {
                    name: "label",
                    type: "auto"
                }
            ],
            data: a_filtered
        });

        return i_store;
    },

    createListTpl: function() {

        var i_template = Ext.create("Ext.XTemplate",
            "<tpl for=\".\">",
                "<li role=\"option\" class=\"x-boundlist-item\" style=\"text-overflow: ellipsis; white-space: nowrap; overflow:hidden;\">",
                    "{[this.getValue(values.label)]}",
                "</li>",
            "</tpl>",
            {
                getValue: function(value) {
                    return ip2.i18n(value, value);
                }
            }
        );

        return i_template;
    },

    createDisplayTpl: function() {
        
        var i_self = this;

        var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
			"{[typeof values === \"string\" ? values : this.renderer(values.label)]}",
			"<tpl if=\"xindex < xcount\">" + i_self.delimiter + "</tpl>",
			"</tpl>",
			{
				renderer: function(value) {
                    return ip2.i18n(value, value);
                }
			}
		);
		return i_tpl;
    }
});Ext.define("Portfolio.ux.form.field.BindingField", {

	xtype: "portfolio-form-field-binding",

	extend: "Ext.form.FieldSet",

	alias: [
		"widget.portfolio-bindigfield"
	],

	alternateClassName: [
		"Ext.ux.form.field.BindingField"
	],

	mixins: {
		field: "Ext.form.field.Field"
	},

	layout: {
		type: "vbox",
		align: "stretch"
	},

	config: {
		altField: null,
		ctrlField: null,
		shiftField: null,
		keyField: null
	},

	collapsible: true,
	collapsed: true,

	constructor: function(o_config) {

		var i_self = this;
		i_self.title = (o_config.fieldLabel || o_config.title) || i_self.title;

		Ext.apply(i_self, o_config);

		i_self.callOverridden();
	},

	initComponent: function() {

		var i_self = this;

		i_self.callParent(arguments);

		var i_altField = Ext.widget("checkbox", {
			fieldLabel: "Alt",
			isFormField: false
		});

		var i_ctrlField = Ext.widget("checkbox", {
			fieldLabel: "Ctrl",
			isFormField: false
		});

		var i_shiftField = Ext.widget("checkbox", {
			fieldLabel: "Shift",
			isFormField: false
		});

		var i_keyField = Ext.widget("combobox", {
			fieldLabel: ip2.i18n({
				da: "Tast",
				en: "Key"
			}),
			displayField: "key",
			valueField: "value",
			isFormField: false,
			store: i_self.createStore()
		});

		i_self.add([
			i_altField,
			i_ctrlField,
			i_shiftField,
			i_keyField
		]);

		i_self.setAltField(i_altField);
		i_self.setCtrlField(i_ctrlField);
		i_self.setShiftField(i_shiftField);
		i_self.setKeyField(i_keyField);

		i_self.mon(i_altField, "change", function(i_field) {
			i_self.checkChange();
		});

		i_self.mon(i_ctrlField, "change", function(i_field) {
			i_self.checkChange();
		});

		i_self.mon(i_shiftField, "change", function(i_field) {
			i_self.checkChange();
		});

		i_self.mon(i_keyField, "change", function(i_field) {
			i_self.checkChange();
		});

		i_self.mixins.field.initField.call(i_self);
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value || "";
		var o_value = value;

		if (Ext.isString(value)) {
			o_value = Ext.decode(value, true) || {};
		}

		Ext.applyIf(o_value, {
			alt: false,
			ctrl: false,
			shift: false,
			keyCode: null
		});

		var i_altField = i_self.getAltField();
		var i_ctrlField = i_self.getCtrlField();
		var i_shiftField = i_self.getShiftField();
		var i_keyField = i_self.getKeyField();

		i_altField.setValue(o_value.alt);
		i_ctrlField.setValue(o_value.ctrl);
		i_shiftField.setValue(o_value.shift);
		i_keyField.setValue(o_value.keyCode);

		i_self.originalValue = i_self.lastValue = i_self.getValue();
		i_self.resetOriginalValue();
	},

	getValue: function() {

		var i_self = this;

		var i_altField = i_self.getAltField();
		var i_ctrlField = i_self.getCtrlField();
		var i_shiftField = i_self.getShiftField();
		var i_keyField = i_self.getKeyField();

		var o_result = {
			alt: i_altField.getValue(),
			ctrl: i_ctrlField.getValue(),
			shift: i_shiftField.getValue(),
			keyCode: i_keyField.getValue()
		};

		return o_result;
	},

	getSubmitData: function() {

		var i_self = this;
		return i_self.getValue();
	},

	setValue: function(value) {

		var i_self = this;

		var i_altField = i_self.getAltField();
		var i_ctrlField = i_self.getCtrlField();
		var i_shiftField = i_self.getShiftField();
		var i_keyField = i_self.getKeyField();

		var o_value = value;

		if (Ext.isString(value)) {
			o_value = Ext.decode(value, true) || {
				alt: false,
				ctrl: false,
				shift: false,
				keyCode: null
			};
		}

		i_altField.setValue(o_value.alt);
		i_ctrlField.setValue(o_value.ctrl);
		i_shiftField.setValue(o_value.shift);
		i_keyField.setValue(o_value.keyCode);
	},

	isDirty: function() {

		var i_self = this;
		var o_value = i_self.getValue();
		var o_originalValue = i_self.originalValue;

		var s_value = Ext.encode(o_value);
		var s_originalValue = Ext.encode(o_originalValue);

		return s_originalValue != s_value;
	},

	didValueChange: function(newVal, oldVal) {

		var i_self = this;

		var s_value = Ext.encode(newVal);
		var s_oldValue = Ext.encode(oldVal);

		return s_value != s_oldValue;
	},

	createStore: function() {

		var a_data = [];
		var a_temp = [];

		var a_numbers = [
			"ZERO",
			"ONE",
			"TWO",
			"THREE",
			"FOUR",
			"FIVE",
			"SIX",
			"SEVEN",
			"EIGHT",
			"NINE"
		];

		var a_integers = [
			0,
			1,
			2,
			3,
			4,
			5,
			6,
			7,
			8,
			9
		];

		var o_map = {
			ZERO: {
				key: 0
			},
			ONE: {
				key: 1
			},
			TWO: {
				key: 2
			},
			THREE: {
				key: 3
			},
			FOUR: {
				key: 4
			},
			FIVE: {
				key: 5
			},
			SIX: {
				key: 6
			},
			SEVEN: {
				key: 7
			},
			EIGHT: {
				key: 8
			},
			NINE: {
				key: 9
			}
		};

		var a_keys = Ext.Object.getKeys(Ext.event.Event);

		var a_filtered = Ext.Array.filter(a_keys, function(s_key) {
			if (s_key.length > 1 && !Ext.Array.contains(a_numbers, s_key)) {
				return false;
			}
			var value = Ext.event.Event[s_key];
			var n_parsed = Ext.Number.from(value, NaN);
			return !isNaN(n_parsed);
		}).sort();

		Ext.Array.each(a_filtered, function(s_key) {
			var o_value = {
				key: s_key,
				value: Ext.event.Event[s_key]
			};

			if (Ext.Array.contains(a_numbers, s_key)) {

				o_value.key = o_map[s_key].key;

				a_temp.push(o_value);
			}
			else {

				a_data.push(o_value);
			}
		});

		a_temp.sort(function(a, b) {
			return a_integers.indexOf(a.key) - a_integers.indexOf(b.key);
		});

		a_data = a_data.concat(a_temp);

		var i_store = Ext.create("Ext.data.Store", {
			fields: [
				{
					name: "key",
					type: "string"
				},
				{
					name: "value",
					type: "int"
				}
			],
			autoLoad: true,
			data: a_data
		});

		return i_store;
	}
});
Ext.define("Portfolio.ux.form.field.MarkdownField", {

    extend: "Ext.form.field.TextArea",

	xtype: "portfolio-ux-form-field-markdownfield",

	mixins: [
		"Ext.mixin.Mashup"
	],

	requiredScripts: [
		"//cdn.jsdelivr.net/simplemde/latest/simplemde.min.css",
		"//cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"
	],

	alias: [
        "widget.ux-markdownfield",
        "widget.markdown",
	],

	alternateClassName: [
		"Ext.ux.markdown.Field"
    ],

	listeners: {
		render: {
			fn: function() {

				var i_self = this;

				var i_simpleMDE = new SimpleMDE({
					element: i_self.inputEl.el.dom,
					status: false,
					spellChecker: false
				});

				i_self.setSimpleMDE(i_simpleMDE);

				var i_codemirror = i_simpleMDE.codemirror;

				i_codemirror.on("change", function () {

					i_self.value = i_simpleMDE.value();

					if (i_self.value != i_self.lastValue) {

						i_self.lastValue = i_self.value;

						i_self.fireEvent("change", i_self, i_self.value, i_self.lastValue);
						i_self.onChange(i_self.value, i_self.lastValue);
					}
				});

				i_simpleMDE.gui.toolbar.style.border = "none";

				i_codemirror.getWrapperElement().style.border = "none";
				i_codemirror.getWrapperElement().style.borderTop = "1px solid #ddd";

				i_codemirror.getWrapperElement().style.setProperty("height", "auto");

				i_codemirror.getWrapperElement().style.setProperty("min-height", "80px");
				i_codemirror.getScrollerElement().style.setProperty("min-height", "80px");

				i_simpleMDE.value(i_self.getValue());

			}
		},
		resize: {
			fn: function() {

				var i_self = this;
				var i_inputEl = i_self.bodyEl;
				var i_simpleMDE = i_self.getSimpleMDE();

				var n_height = (i_inputEl.getHeight(true) - i_simpleMDE.gui.toolbar.clientHeight);

				var i_codemirror = i_simpleMDE.codemirror;
				var i_wrapper = i_codemirror.getWrapperElement();
				var i_scroller = i_codemirror.getScrollerElement();

				i_wrapper.style.maxHeight = i_scroller.style.maxHeight = n_height + "px";
				i_wrapper.style.paddingBottom = i_wrapper.style.paddingTop = "1px";
			}
		}
	},

	config: {
		simpleMDE: null
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
	},

	isDirty: function() {

		var i_self = this;
		var i_simpleMDE = i_self.getSimpleMDE();

		var s_originalValue = i_self.originalValue;
		var s_value = i_simpleMDE.value();

		return s_value != s_originalValue;
	},

	getValue: function() {

		var i_self = this;

		var s_value = i_self.value;

		var i_simpleMDE = i_self.getSimpleMDE();

		if (i_simpleMDE) {
			s_value = i_simpleMDE.value();
		}

		return s_value;
	},

	getSubmitValue: function() {

		var i_self = this;

		return i_self.getValue();
	}
});
Ext.define('Ext.ux.stackorganizer.column.IconRenderer', {

	initIconRenderer: function () {

		var i_cmp = this;

		Ext.apply(i_cmp, {
			renderer: function (s_value, o_meta, i_record) {

				var o_layout = i_record.get('layout') || {};
				var s_type = i_record.get('ptype');
				var s_icon;
				var s_classes;
				var s_background;

				s_icon = (function () {

					var a_stuff = [];

					// Add possible design layout property
					var s_design = o_layout.design || "";
					if (s_design) {
						s_design = s_design.split('-').shift();
						a_stuff.push('design-' + s_design);
					}

					// Add possible imageposition layout property
					var s_position = o_layout.imageposition || "";
					if (s_position) {
						a_stuff.push('img-' + s_position);
					}

					// Add possible columns layout property
					var s_columns = o_layout.columns || "";
					if (s_columns) {
						a_stuff.push('col-' + s_columns);
					}

					return a_stuff.join(' ');
				})();

				// Deal with possible background color css styling
				s_background = o_layout.backgroundcolor || "#FFFFFF";
				var bgElement = s_background ? '<div class="background" style="background-color:' + s_background + '"></div>' : '';
				if (s_type != "mediagallery") {
					s_classes = [s_type, s_icon].join(' ');
				}
				else {
					s_classes = s_type;
				}
				return new Ext.XTemplate('<table class="type">',
					'<tr><td valign="middle">',
						'<div class="x-ux-stack-icon">',
							'<div class="preview ' + s_classes + '"></div>',
							bgElement,
						'<div>',
					'</td></tr>',
				'</table>').html;
			}
		});
	}
});
Ext.define('Ext.ux.stackorganizer.column.GridIcon', {

	extend: 'Ext.grid.column.Column',

	alias: ['widget.stackicongridcolumn'],

	mixins: {
		'iconRenderer': 'Ext.ux.stackorganizer.column.IconRenderer'
	},

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		i_cmp.initIconRenderer();

		return i_cmp;
	}
});
Ext.define('Ext.ux.stackorganizer.column.Icon', {

	extend: 'Ext.grid.column.Column',

	alias: ['widget.stackiconcolumn'],

	mixins: {
		'iconRenderer': 'Ext.ux.stackorganizer.column.IconRenderer'
	},

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		i_cmp.initIconRenderer();

		return i_cmp;
	}
});
Ext.define('Ext.ux.stackorganizer.column.MoveDown', {

	extend: 'Ext.ux.themed.ActionColumn',

	alias: ['widget.stackmovedowncolumn'],

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});
Ext.define('Ext.ux.stackorganizer.column.MoveUp', {

	extend: 'Ext.ux.themed.ActionColumn',

	alias: ['widget.stackmoveupcolumn'],

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});
Ext.define("Ext.ux.stackorganizer.column.Properties", {

	extend: "Ext.grid.column.Column",

	alias: ["widget.stackpropertiescolumn"],

	config: {
		stack: false
	},

	initComponent: function () {

		var i_cmp = this;

		Ext.apply(i_cmp, {
			renderer: function (s_value, o_meta, i_record, n_row, n_col, i_store, i_view) {

				var s_id = i_record.internalId;
				var s_lang = ip2.session.getLanguage();
				var o_prop = i_record.get("properties") || {};
				var s_output;
				var a_output = [];

				// TOPLINK TITLE
				a_output.push((function () {

					var o_title = i_record.get("title");
					var o_placeholder = o_title;

					if (ip2.isStringedObject(o_title)) {
						o_title = Ext.decode(o_title);
					}
					else {

						o_placeholder = {};
						if (Ext.isObject(o_title)) {
							o_placeholder = o_title;
						}
						else {
							o_placeholder[s_lang] = o_title;
						}
					}

					if (!o_title) {

						o_placeholder = o_prop.title || o_prop.header || o_prop.name;

						if (ip2.isStringedObject(o_placeholder)) {
							o_placeholder = Ext.decode(o_placeholder);
						}
						else {
							if (!Ext.isObject(o_placeholder)) {
								var o_temp = {};
								o_temp[s_lang] = o_placeholder;
								o_placeholder = o_temp;
							}
						}
					}

					o_title = o_placeholder;

					return {
						id: "toplink",
						label: ip2.i18n({
							da: "Toplink",
							en: "Toplink"
						}),
						value: ip2.i18n(o_title)
					};
				})());

				// TITLE
				/*
					a_output.push((function () {

						var value = o_prop.title,
							s_value = value;

						if ( Ext.isObject(value) ) {
							s_value = value[s_lang];
						}

						return o_prop.title ? {
							id: "title",
							label: ip2.i18n({
								da: "Titel",
								en: "Title"
							}),
							value: s_value
						} : null
					})());
				*/

				// HEADER
				a_output.push((function () {

					return o_prop.header ? {
						id: "header",
						label: ip2.i18n({
							da: "Rubrik",
							en: "Header"
						}),
						value: o_prop.header
					} : null;
				})());

				// SUB HEADER
				/*
					a_output.push((function () {
						return o_prop.subheader ? {
							id: "subheader",
							label: ip2.i18n({
								da: "Subheader",
								en: "Subheader"
							}),
							value: o_prop.subheader
						} : null
					})());
				*/

				// LINK
				a_output.push((function () {
					return o_prop.url ? {
						id: "link",
						label: ip2.i18n({
							da: "Link",
							en: "Link"
						}),
						value: o_prop.url.slice(0, 30) + "..."
					} : null;
				})());

				// TYPE/ID
				a_output.push((function () {

					var o_xpd = i_view.up().supportXpd;
					var s_token = i_record.get("token");
					var o_collection;
					var s_type = "";

					if (o_xpd) {
						o_xpd = ip2.xpd.flatten(o_xpd);

						var n_id = i_record.get(o_xpd.idProperty);

						if (n_id) {
							o_collection = o_xpd.collections[n_id];
							s_type = o_collection ? ip2.xpd.translate(o_xpd, o_collection.title) : i_record.get("ptype");

							//s_type = ip2.xpd.translate(o_xpd, o_collection.title);
						}
					}
					else {
						s_type = i_record.get("ptype");
					}

					return {
						id: "id",
						label: ip2.i18n({
							da: "ID",
							en: "ID"
						}),
						value: [s_type, s_token].join(" / ")
					};
				})());

				s_output = ["<table class=\"x-ux-stack-table\">",
					"<tr><td valign=\"middle\">",
						"<div id=\"x-ux-stack-record-" + s_id + "\" class=\"x-ux-stack-cell\">"].join("");

				s_output += i_cmp.renderOutput(a_output);

				s_output = [s_output, "</div>",
					"</td></tr>",
				"</table>"].join("");

				return s_output;
			}
		});

		i_cmp.callParent();

		return i_cmp;
	},
	renderOutput: function (a_output) {

		var s_output = "";

		Ext.Array.each(a_output, function (o_output) {

			if (o_output) {

				s_output += [
					"<div class=\"x-ux-stack-cell-" + o_output.id + "\">",
						"<div class=\"x-ux-stack-label\">" + o_output.label + ": </div>",
						"<div class=\"x-ux-stack-value\">" + o_output.value + "</div>",
					"</div>"
				].join("");
			}
		});

		return s_output;
	}
});
Ext.define('Ext.ux.stackorganizer.column.Specification', {

	extend: 'Ext.grid.column.Column',

	alias: ['widget.stackspecificationcolumn'],

	config: {
		stack: false
	},

	initComponent: function () {

		var i_cmp = this;

		Ext.apply(i_cmp, {
			renderer: function (s_value, o_meta, i_record, n_row, n_col, i_store, i_view) {

				var s_id = i_record.internalId;
				var o_properties = i_record.get('properties');
				var o_id;
				var o_name;
				var o_text;
				var s_toplink = '';

				o_id = {
					label: ip2.i18n({
						da: 'ID',
						en: 'ID'
					}),
					value: i_record.get('ptype') + ' / ' + i_record.get('pagetoken')
				};

				o_name = {
					label: ip2.i18n({
						da: 'Navn',
						en: 'Name'
					}),
					value: o_properties.name || o_properties.title || ''
				};

				o_text = {
					label: ip2.i18n({
						da: 'Tekst',
						en: 'Text'
					}),
					value: o_properties.description || ''
				};

				// If the config option "isStack" is true
				// This column is wrongly named since it is in fact bound up on the field "toplink"
				// which delivers a boolean, and is the interactive part of the specifications (checkbox)
				// Toplink checkbox is only rendered if this config option is true
				var b_stack = i_cmp.getIsStack();

				if (b_stack) {

					if (b_value == 'true') {
						b_value = true;
					}
					if (b_value == 'false' || !b_value || b_value == null) {
						b_value = false;
					}

					var o_toplink = {
						label: ip2.i18n({
							da: 'Toplink',
							en: 'Toplink'
						}),
						value: (b_value ? 'CHECKED' : '')
					};
					s_toplink = new Ext.XTemplate('<div class=x-ux-stack-cell-toplink">',
						'<div class=x-ux-stack-label">' + o_toplink.label + ': </div>',
						'<div class=x-ux-stack-value">',
							'<input id=x-ux-stack/' + s_id + '.toplink" type="checkbox" ' + o_toplink.value + ' />',
						'</div>',
					'</div>').html;
				}

				// Create the final HTML output by using XTemplate
				var s_output = new Ext.XTemplate('<table>',
					'<tr><td valign="middle">',
						'<div id=x-ux-stack-record-' + i_record.internalId + '" class=x-ux-stack-cell">',
							'<div class=x-ux-stack-cell-id">',
								'<div class=x-ux-stack-label">' + o_id.label + ': </div>',
								'<div class="x-ux-stack-value">' + o_id.value + '</div>',
							'</div>',
							'<div class=x-ux-stack-cell-name">',
								'<div class=x-ux-stack-label">' + o_name.label + ': </div>',
								'<div class="x-ux-stack-value">' + o_name.value + '</div>',
							'</div>',
							'<div class=x-ux-stack-cell-text">',
								'<div class=x-ux-stack-label">' + o_text.label + ': </div>',
								'<div class=x-ux-stack-value">' + o_text.value + '</div>',
							'</div>',
							s_toplink,
						'</div>',
					'</td></tr>',
				'</table>').html;

				// Run through the specifications render if the config settings "isStack" is true
				// to check or uncheck the checkbox again after render
				if (b_stack) {
					i_cmp.onSpecificationsRender(i_view);
				}

				return s_output;
			}
		});

		i_cmp.callParent();

		return i_cmp;
	},
	onSpecificationsRender: function (i_view) {

		var i_cmp = this;
		var i_store = i_view.up().getStore();
		var i_el = i_view.getEl();
		var a_input;

		// Move to back of stack so we know cell has been rendered
		setTimeout(function () {

			// Query out all input fields in .x-ux-stack-cell
			a_input = i_el.query('.x-ux-stack-cell input');

			Ext.Array.each(a_input, function (i_input) {

				i_input.addEventListener("change", function(o_event) {
					var i_self = this;
					var a_ref = i_self.id.split('/').pop().split('.'); // ex. "record-332.properties.toplink"
					var s_id = a_ref[0]; // the id of the record node
					var s_key = a_ref[1]; // the name of the property to get from the record
					var i_record = i_store.getNodeById(s_id);
					var b_checked = i_self.checked;

					o_event.stopPropagation();

					if (i_record) {

						var data = i_record.get(s_key);

						if (data != null) {
							if (!b_checked) {
								b_checked = '';
							}
							i_record.set(s_key, b_checked);
						}
					}
				});
			});
		}, 4);

		return i_cmp;
	}
});
Ext.define('Ext.ux.stackorganizer.column.TreeIcon', {

	extend: 'Ext.tree.Column',

	alias: ['widget.stackicontreecolumn'],

	mixins: {
		'iconRenderer': 'Ext.ux.stackorganizer.column.IconRenderer'
	},

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		i_cmp.initIconRenderer();

		return i_cmp;
	}
});
Ext.define('Ext.ux.stackorganizer.store.Grid', {
	extend: 'Ext.data.Store',
	autoLoad: false,
	proxy: {
		type: 'ajax',
		reader: {
			type: 'json'
		}
	}
});
Ext.define('Ext.ux.stackorganizer.store.Tree', {
	extend: 'Ext.data.TreeStore',
	autoLoad: false,
	proxy: {
		type: 'ajax',
		reader: {
			type: 'json'
		}
	}
});
/**
 * @class Ext.ux.CheckColumn
 * @extends Ext.grid.column.Column
 * <p>A Header subclass which renders a checkbox in each column cell which toggles the truthiness of the associated data field on click.</p>
 * <p><b>Note. As of ExtJS 3.3 this no longer has to be configured as a plugin of the GridPanel.</b></p>
 * <p>Example usage:</p>
 * <pre><code>
// create the grid
var grid = Ext.create('Ext.grid.Panel', {
    ...
    columns: [{
           text: 'Foo',
           ...
        },{
           xtype: 'checkcolumn',
           text: 'Indoor?',
           dataIndex: 'indoor',
           width: 55
        }
    ]
    ...
});
 * </code></pre>
 * In addition to toggling a Boolean value within the record data, this
 * class adds or removes a css class <tt>'x-grid-checked'</tt> on the td
 * based on whether or not it is checked to alter the background image used
 * for a column.
 */
Ext.define('Ext.ux.tree.column.CheckBox', {
	extend: 'Ext.grid.column.Column',
	alias: 'widget.treecheckcolumn',

	constructor: function() {
		this.callParent(arguments);
	},

	/**
	     * @private
	     * Process and refire events routed from the GridView's processEvent method.
	     */
	processEvent: function(type, view, cell, recordIndex, cellIndex, e) {

		if (type == 'mousedown' || (type == 'keydown' && (e.getKey() == e.ENTER || e.getKey() == e.SPACE))) {

			//var record = view.panel.store.getAt(recordIndex),
			var record = view.panel.store.getNodeById('someid'),
			dataIndex = this.dataIndex,
			checked = !record.get(dataIndex);

			record.set(dataIndex, checked);
			this.fireEvent('checkchange', this, recordIndex, checked);

			// cancel selection.
			return false;
		}
		else {
			return this.callParent(arguments);
		}
	},

	// Note: class names are not placed on the prototype bc renderer scope
	// is not in the header.
	renderer: function(value) {

		var cssPrefix = Ext.baseCSSPrefix,
		cls = [cssPrefix + 'grid-checkheader'];

		if (value) {
			cls.push(cssPrefix + 'grid-checkheader-checked');
		}
		return '<div class="' + cls.join(' ') + '">&#160;</div>';
	}
});
Ext.define("Ext.ux.stackorganizer.view.ContentGrid", {

	extend: "Ext.grid.Panel",

	alias: ["widget.stackcontentgrid"],

	mixins: {
		"keyMapping": "Ext.ux.util.KeyMapping"
	},

	xpd: "",

	supportXpd: "",

	tokenKey: null,

	collection: null,

	stack: null,

	stackId: null,

	filter: null,

	originalFilter: null,

	initComponent: function () {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;

		var s_supportXpd = o_config.supportXpd;
		var o_supportXpd = i_cmp.sanitizeXpdValue(s_supportXpd);

		Ext.apply(i_cmp, {
			viewConfig: {
				plugins: {
					ptype: "gridviewdragdrop",
					enableDrag: true,
					dragGroup: "grid2tree",
					allowContainerDrops: false
				}
			},
			columns: [
				{
					xtype: "themedactioncolumn",
					text: ip2.i18n({
						da: "Tilføj",
						en: "Add"
					}),
					iconCls: "pf-add",
					width: 50,
					handler: function (i_view, n_row, n_col, o_item, o_event) {

						var i_store = i_cmp.getStore();
						var i_record = i_store.getAt(n_row);

						i_cmp.fireEvent("stackadd", i_cmp, i_record, true);
					},
					tdCls: "x-ux-stack-column-action"
				},
				{
					text: ip2.i18n({
						da: "Stak ID",
						en: "Stack ID"
					}),
					hidden: true,
					dataIndex: "stackId"
				},
				{
					xtype: "stackiconcolumn",
					text: ip2.i18n({
						da: "Type",
						en: "Type"
					}),
					dataIndex: "ptype",
					width: 110
				},
				{
					xtype: "stackpropertiescolumn",
					dataIndex: "toplink",
					text: ip2.i18n({
						da: "Specifikationer",
						en: "Specifications"
					}),
					flex: 1
				}
			],
			dockedItems: [
				{
					xtype: "toolbar",
					height: 30,
					items: [
						{
							xtype: "button",
							iconCls: "pf-refresh",
							handler: function () {
								i_cmp.refreshData();
							}
						},
						"-",
						{
							xtype: "textfield",
							itemId: "searchfield",
							size: 40,
							enableKeyEvents: true,
							margin: "0 0 0 5",
							isFormField: false,
							onClear: function() {
								this.setValue("");
								this.getTrigger("clear").hide();
								i_cmp.refreshData();
							},
							onRefresh: function() {
								var value = this.getValue();
								if (!value) {
									this.getTrigger("clear").hide();
								}
								else {
									this.getTrigger("clear").show();
								}
								i_cmp.refreshData();
							},
							triggers: {
								clear: {
									weight: 1,
									cls: "x-form-clear-trigger",
									scope: "this",
									hidden: true,
									handler: "onClear"
								},
								search: {
									weight: 1,
									cls: "x-form-search-trigger",
									scope: "this",
									handler: "onRefresh"
								}
							},
							listeners: {
								"specialkey": {
									fn: function (i_self, e) {
										if (e.getKey() == e.ENTER) {
											value = this.getValue();
											if (!value) {
												this.getTrigger("clear").hide();
											}
											else {
												this.getTrigger("clear").show();
											}
											i_cmp.refreshData();
										}
									}
								}
							}
						}
					]
				}
			],
			supportXpd: o_supportXpd
		});

		i_cmp.callParent(arguments);

		i_cmp.on("itemdblclick", function (i_grid, i_record) {
			i_cmp.fireEvent("stackadd", i_cmp, i_record, true);
		});

		// Set the original filter
		var a_filter = i_cmp.getFilter();
		i_cmp.originalFilter = a_filter;

		i_cmp.on("afterrender", i_cmp.onAfterrender);

		i_cmp.initKeyMapping();

		return i_cmp;
	},

	sanitizeXpdValue: function (xpd) {

		if (Ext.isString(xpd)) {
			xpd = ip2.resource.get(xpd, true);
		}

		return xpd;
	},

	getModel: function() {

		var i_self = this;
		var o_collection = i_self.collection;
		var i_model = ip2.model({
			dmd: o_collection.dmd,
			entityName: o_collection.entity,
			uiName: "portfolio",
			context: "form"
		});
		return i_model;
	},

	onAfterrender: function () {

		var i_cmp = this;
		var i_store = i_cmp.getStore();

		i_cmp.loadItems(function (a_items) {
			i_store.loadData(a_items);
		});

		return i_cmp;
	},

	setStack: function (o_stack) {

		var i_cmp = this;

		i_cmp.stack = o_stack;

		i_cmp.refreshData();

		return i_cmp;
	},

	getFilter: function () {

		var i_cmp = this;
		var i_store = i_cmp.getStore();
		var o_collection = i_cmp.collection;
		var o_stack = i_cmp.stack;
		var a_tokens = [];
		var a_filter;

		// Check if the collection is the same as the root
		// Add that token or 0 if so
		if (o_collection.ptype == o_stack.ptype) {
			a_tokens.push(o_stack.token || 0);
		}

		Ext.Array.each(o_stack.children, function(o_child) {
			if (o_collection.ptype == o_child.ptype) {
				a_tokens.push(o_child.token);
			}
		});

		if (a_tokens.length) {
			o_stack = Ext.Object.merge({
				tokens: a_tokens.join(", ")
			}, o_stack);
		}
		else {
			delete o_collection.properties.token;
		}

		i_model = ip2.model({
			dmd: o_collection.dmd,
			entityName: o_collection.entity,
			context: "grid",
			uiName: "portfolio"
		});

		var a_filters = ip2.xpd.createFilter(o_collection, o_stack);
		if (a_tokens.length > 0) {
			var b_found = false;
			ip2.each(a_filters, function(o_filter) {
				if (o_filter.property == i_model.idProperty) {
					b_found = true;
				}
			});
			if (!b_found) {
				var o_filter = {
					property: i_model.idProperty,
					where: "not in (" + a_tokens.join(", ") + ")"
				};
				a_filters.push(o_filter);
			}
		}

		return a_filters;
	},
	getOriginalFilter: function () {

		return this.originalFilter;
	},
	isFilterDirty: function () {

		var i_cmp = this;
		var a_original = i_cmp.getOriginalFilter();
		var a_filter = i_cmp.getFilter();

		if (a_original === null || a_filter === null) {
			return false;
		}

		return ip2.isEqual(a_original, a_filter);
	},

	loadItems: function (f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_cmp = this;
		var o_supportXpd = i_cmp.supportXpd;
		var s_xpdPath = o_supportXpd._path;

		var o_collection = i_cmp.collection;
		var s_ptype = o_collection.ptype;
		var n_stackId = i_cmp.stackId;
		var s_search = i_cmp.down("#searchfield").getValue();

		var a_filter = i_cmp.getFilter();
		var s_filter = Ext.encode(a_filter);

		var o_params = {
			xpd: s_xpdPath,
			action: "getStackContent",
			ptype: s_ptype,
			stackId: n_stackId,
			filter: s_filter,
			uiName: "portfolio",
			context: "grid"
		};

		if (s_search.length) {
			o_params.search = s_search;
		}

		// Load the list data and add the initialize the components
		Ext.Ajax.request({
			url: "/wsh-services/wshproxy.aspx",
			params: o_params,
			success: function (o_response) {

				var a_items = [];

				try {
					a_items = Ext.decode(o_response.responseText);
				}
				catch (err) {
					console.log("TODO: Error handling via IP2 for Ext.ux.stackorganizer.ContentGrid on loadData method");
				}

				f_callback(a_items);
			}
		});

		return i_cmp;
	},

	refreshData: function (i_record) {

		var i_cmp = this;
		var i_store = i_cmp.getStore();
		var i_view = i_cmp.getView();
		var s_search = i_cmp.down("#searchfield").getValue();
		var i_add = null;

		i_cmp.setLoading(true);
		i_cmp.loadItems(function (a_items) {
			i_cmp.setLoading(false);
			i_store.loadData(a_items);
			if (i_record) {
				ip2.each(i_store.data.items, function(i_item) {
					if (i_item.get("token") == i_record.get(i_record.idProperty)) {
						i_add = i_item;
					}
				});
			}

			if (i_add) {
				i_cmp.fireEvent("stackadd", i_cmp, i_add, true);
			}
		});

		return i_cmp;
	}
});
Ext.define('Ext.ux.stackorganizer.view.StackTree', {

	extend: 'Ext.tree.Panel',

	alias: ['widget.stacktree'],

	mixins: {
		'keyMapping': 'Ext.ux.util.KeyMapping'
	},

	_silence: false,

	initComponent: function () {

		var i_cmp = this;

		Ext.apply(i_cmp, {
			viewConfig: {
				plugins: {
					ptype: 'treeviewdragdrop',
					enableDrag: true,
					enableDrop: true,
					dropGroup: "grid2tree",
					dragGroup: "grid2tree",
					allowContainerDrops: true,
					appendOnly: false,
					dropZone: {
						isValidDropPoint: function(node, position, dragZone, e, data) {

							var i_view = this;
							var a_records = data.records;
							var b_allowed = true;
							if (i_view.id == data.view.id) {
								ip2.each(a_records, function(i_record) {
									if (!i_record.isLeaf()) {
										b_allowed = false;
									}
								});
							}
							return b_allowed;
						},
						onContainerOver: function(dd, e, data) {

							var i_view = this;
							var a_records = data.records;
							var b_allowed = true;
							if (i_view.id == data.view.id) {

								ip2.each(a_records, function(i_record) {
									if (!i_record.isLeaf()) {
										b_allowed = false;
									}
								});
							}
							return b_allowed ? i_view.dropAllowed : e.getTarget('.' + i_view.indicatorCls) ? i_view.currentCls : i_view.dropNotAllowed;
						},
						onContainerDrop: function(dragZone, e, data) {

							var i_view = this;
							var a_records = data.records;
							var b_allowed = true;
							if (i_view.id == data.view.id) {
								ip2.each(a_records, function(i_record) {
									if (!i_record.isLeaf()) {
										b_allowed = false;
									}
								});
							}
							if (i_view.allowContainerDrops && b_allowed) {
								i_view.valid = true;
								i_view.currentPosition = 'append';
								i_view.overRecord = this.view.store.getRoot();
								i_view.onNodeDrop(this.overRecord, dragZone, e, data);
							}
							return b_allowed;
						}
					}
				},
				listeners: {
					beforedrop: {
						fn: function(node, data, overModel, dropPosition, dropHandler, e) {
							var i_view = this;
							var a_records = data.records;
							if (i_view.id != data.view.id) {
								data.copy = true;
							}
						}
					},
					drop: {
						fn: function(node, data, overModel, posistion) {
							var i_view = this;
							var a_records = data.records;
							if (i_view.id != data.view.id) {
								var i_owner = data.view.ownerCt;
								ip2.each(a_records, function(i_record) {
									i_owner.fireEvent('stackadd', i_owner, i_record, false);
								});
							}
						}
					}
				}
			},
			enableColumnResize: false,
			sortableColumns: false,
			enableColumnHide: false,
			columns: [
				{
					text: ip2.i18n({
						da: 'Titel',
						en: 'Title'
					}),
					hidden: true,
					dataIndex: 'title',
					renderer: function (value) {

						var s_title = value,
							o_title,
							s_lang = ip2.session.getLanguage();

						try {
							o_title = Ext.decode(value);
						}
						catch (e) {}

						if (o_title) {
							s_title = o_title[s_lang];
						}

						return s_title;
					}
				},
				{
					text: ip2.i18n({
						da: 'Token',
						en: 'Token'
					}),
					hidden: true,
					dataIndex: 'token'
				},
				{
					text: ip2.i18n({
						da: 'Stak ID',
						en: 'Stack ID'
					}),
					hidden: true,
					dataIndex: 'stackId'
				},
				{
					xtype: 'treecolumn',
					text: ip2.i18n({
						da: 'Toplink',
						en: 'Toplink'
					}),
					tooltip: ip2.i18n({
						da: 'Marker for at sætte som et toplink',
						en: 'Check to set as toplink'
					}),
					width: 80,
					tdCls: 'x-ux-stack-column-checkbox'
				},
				{
					xtype: 'stackiconcolumn',
					text: ip2.i18n({
						da: 'Type',
						en: 'Type'
					}),
					dataIndex: 'ptype',
					width: 110
				},
				{
					xtype: 'stackpropertiescolumn',
					dataIndex: 'properties',
					text: ip2.i18n({
						da: 'Specifikationer',
						en: 'Specifications'
					}),
					flex: 1
				},
				{
					xtype: 'actioncolumn',
					text: ip2.i18n({
						da: 'Flyt op',
						en: 'Move up'
					}),
					tooltip: ip2.i18n({
						da: 'Flyt op',
						en: 'Move up'
					}),
					iconCls: 'pf-arrow_up',
					width: 25,
					handler: function (i_view, n_row, n_col, o_item, o_event) {

						var i_store = i_cmp.getStore(),
							i_root = i_store.getRootNode(),
							i_node = i_root.getChildAt(n_row);

						i_cmp.moveUp(i_node, i_store, i_root, n_row, n_col, o_item, o_event);
					},
					tdCls: 'x-ux-stack-column-action'
				},
				{
					xtype: 'actioncolumn',
					text: ip2.i18n({
						da: 'Flyt ned',
						en: 'Move down'
					}),
					tooltip: ip2.i18n({
						da: 'Flyt ned',
						en: 'Move down'
					}),
					iconCls: 'pf-arrow_down',
					width: 25,
					handler: function (i_view, n_row, n_col, o_item, o_event) {

						var i_store = i_cmp.getStore();
						var i_root = i_store.getRootNode();
						var i_node = i_root.getChildAt(n_row);

						i_cmp.moveDown(i_node, i_store, i_root, n_row, n_col, o_item, o_event);
					},
					tdCls: 'x-ux-stack-column-action'
				},
				{
					xtype: 'actioncolumn',
					text: ip2.i18n({
						da: 'Fjern',
						en: 'Remove'
					}),
					tooltip: ip2.i18n({
						da: 'Fjern',
						en: 'Remove'
					}),
					iconCls: 'pf-navigate_cross',
					width: 25,
					handler: function (i_view, n_row) {
						var i_tree = i_view.ownerCt;
						var i_root = i_tree.getRootNode();
						var i_node = i_root.getChildAt(n_row);
						i_node.remove(false);
						i_tree.fireEvent("tree_delete", i_tree, i_node);
					},
					tdCls: 'x-ux-stack-column-action'
				}
			]
		});

		i_cmp.callParent();

		i_cmp.initKeyMapping();
		i_cmp.enableBubble("tree_delete");

		return i_cmp;
	},
	moveUp: function (i_node, i_store, i_root, n_row, n_col, o_item, o_event) {

		var i_cmp = this,
			i_prev = i_node.previousSibling;

		i_cmp._silence = true;

		// Select this node we are moving
		i_cmp.getSelectionModel().select(i_node);

		if (i_prev) {
			i_root.insertBefore(i_node, i_prev);
		}

		i_cmp._silence = false;

		return i_cmp;
	},
	moveDown: function (i_node, i_store, i_root, n_row, n_col, o_item, o_event) {

		var i_cmp = this,
			i_next = i_node.nextSibling;

		i_cmp._silence = true;

		// Select this node we are moving
		i_cmp.getSelectionModel().select(i_node);

		if (i_next) {
			i_root.insertBefore(i_next, i_node);
		}

		i_cmp._silence = false;

		return i_cmp;
	},
	getLastSelectedNode: function () {

		var i_cmp = this,
			a_selected = i_cmp.getSelectionModel().getSelection(),
			i_node;

		if (a_selected.length) {
			i_node = a_selected[a_selected.length - 1];
		}
		return i_node;
	},

	setNodeFocus: function (i_node) {

		var i_cmp = this,
			i_root = i_cmp.getRootNode();

		if (i_node) {
			i_cmp.getSelectionModel().select(i_node);
		}
		else {
			i_node = i_cmp.getLastSelectedNode();
		}

		if (i_node) {
			i_cmp.getView().focusRow(i_node);
		}

		return i_cmp;
	},
	setActiveFocus: function () {

		var i_cmp = this,
			i_view = i_cmp.getView(),
			i_model = i_view.getSelectionModel(),
			a_selected = i_model.getSelection(),
			i_selected;

		if (!a_selected.length) {
			i_selected = i_view.getStore().getAt(0);
			a_selected = i_selected ? [i_selected] : [];
		}

		i_view.focus();
		i_model.select(a_selected);

		return i_cmp;
	},

	cleanIndexes: function () {

		var i_cmp = this,
			i_root = i_cmp.getRootNode();

		Ext.Array.each(i_root.childNodes, function (o_child, n_index) {
			o_child.set('index', n_index);
		});

		return i_cmp;
	}
});
Ext.define('Ext.ux.stackorganizer.view.ContentAccordion', {
	extend: 'Ext.tab.Panel',
	alias: 'widget.stackcontentaccordion',

	config: {
		/**
		 * @cfg xpd object The not flattened XPD object
		 */
		xpd: null,
		/**
		 * @cfg stack object The stack as a node of data to use for filtering
		 */
		stack: null,
		/**
		 * @cfg tokenKey string
		 */
		tokenKey: null,
		/**
		 * @cfg collectionId number
		 */
		collectionId: null,
		/**
		 * @cfg dragConfig object Configuration for the DD
		 */
		dragConfig: null,
		fields: null
	},

	// The flattened XPD
	flattened: null,

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent();

		var o_xpd = i_cmp.getXpd();
		var i_xpd = ip2.xpd.flatten(o_xpd);
		var s_tokenKey = i_cmp.getTokenKey();
		var o_stack = i_cmp.getStack();
		var a_collections = [];

		i_cmp.flattened = i_xpd;

		// Create the collection array and sort it for sequences
		Ext.Object.each(i_xpd.collections, function (s_key, o_collection) {

			if (s_key != 'all') {

				n_pos = o_collection.sequence || 0;

				while (a_collections[n_pos]) {
					n_pos++;
				}

				a_collections[n_pos] = o_collection;
			}
		});

		// Iterate over each collection and build a grid/widget for each
		// to add to the accordion, if allowed per XPD
		Ext.Array.each(a_collections, function (o_collection) {

			// We need a collection, and one with a dmd and entity
			// if not we can not provide a entitygrid
			if (o_collection && o_collection.dmd && o_collection.entity) {

				var i_grid;
				var i_store;
				var b_allow;

				// Determine if the configured collectionId is an allowed parent
				// for this collection
				b_allow = (function () {

					var b_allow = false;
					var parents = o_collection.allowedparents;
					var n_id = i_cmp.getCollectionId();

					// Parents is an array
					// If array is empty or collectionId is in the allowedparent array
					// it is allowed
					if (Ext.isArray(parents)) {

						if (!parents.length) {
							b_allow = true;
						}
						else {
							b_allow = (Ext.Array.indexOf(parents, n_id) >= 0);
						}
					}

					return b_allow;
				})();

				if (!b_allow) {
					return false;
				}

				i_store = Ext.create('Ext.ux.stackorganizer.store.Grid', {
					fields: i_cmp.getFields()
				});

				i_grid = i_cmp.add({
					xtype: 'stackcontentgrid',
					title: ip2.xpd.translate(i_xpd, o_collection.title, ip2.session.getLanguage()),
					xpd: i_cmp.getXpd(),
					supportXpd: o_collection.xpd,
					tokenKey: i_cmp.getTokenKey(),
					stack: o_stack,
					stackId: o_collection.id,
					collection: o_collection,
					multiSelect: false,
					store: i_store,
					onLeftKey: function (i_self) {
						i_cmp.fireEvent('onLeftKey', i_cmp);
						i_cmp.onLeftKey && i_cmp.onLeftKey();
					}
				});

				i_cmp.relayEvents(i_grid, ['stackadd']);
			}

			i_cmp.setActiveTab(i_cmp.items.items[0]);
		});

		return i_cmp;
	},

	setActiveFocus: function () {

		var i_cmp = this;
		var i_active = i_cmp.getActiveTab();
		var a_selection;

		if (!i_active) {
			i_cmp.setActiveTab(0);
		}

		// Get currently selected items
		a_selection = i_active.getSelectionModel().getSelection();

		// If none selected, select the first one
		if (!a_selection.length) {
			var i_selected = i_active.getStore().getAt(0);
			a_selection = i_selected ? [i_selected] : [];
		}

		i_active.getView().focus();
		i_active.getSelectionModel().select(a_selection);

		return i_cmp;
	},

	getStackById: function(id) {

		var i_self = this;
		var a_items = i_self.query("stackcontentgrid[stackId=" + id + "]");
		if (a_items.length > 0) {
			return a_items[0];
		}
		return null;

	},

	/**
	 * @method refreshStackData
	 * Will go through all child grids and refresh their data based on the passed stack data argument
	 *
	 * @param o_stack object The stack data object needed to build new filters
	 */
	refreshStackData: function (o_stack) {

		o_stack = o_stack || this.getStack();

		var i_cmp = this;

		i_cmp.items.each(function (i_grid) {
			i_grid.setStack(o_stack);
		});

		return i_cmp;
	}
});
Ext.define("Ext.ux.stackorganizer.Panel", {

	extend: "Ext.panel.Panel",

	alias: "widget.stackpanel",

	mixins: {
		componentController: "Ext.ux.util.ComponentController"
	},

	refs: [
		{
			ref: "westRegion",
			selector: "#west"
		},
		{
			ref: "centerRegion",
			selector: "#center"
		},
		{
			ref: "stackTree",
			selector: "stacktree"
		},
		{
			ref: "accordion",
			selector: "stackcontentaccordion"
		}
	],

	config: {
		dataTokenKey: "",
		tokenKey: "__cid__",
		xpd: null,
		supportXpd: null,
		dataParent: null,
		cid: null,
		collectionId: null,
		defaultLanguage: "da",
		languages: null,
		fields: null,
	},

	originalValue: null,

	initComponent: function () {

		var i_self = this;
		var o_initial = Ext.apply({}, i_self.initialConfig);

		i_self.initComponentController();

		Ext.apply(i_self, {
			layout: "border",
			languages: o_initial.languages || wsh.getLanguages(),
			items: [
				{
					xtype: "panel",
					itemId: "west",
					region: "west",
					flex: 1,
					minWidth: 300,
					border: false,
					layout: "fit",
					cls: "x-ux-stack",
					split: true
				},
				{
					xtype: "panel",
					itemId: "center",
					region: "center",
					border: false,
					cls: "x-ux-stack",
					layout: "fit",
					flex: 1
				}
			]
		});

		i_self.callParent(arguments);

		// Sanitize the xpd values
		var xpd = i_self.xpd;
		i_self.xpd = i_self.sanitizeXpdValue(xpd);

		// Sanitize the support xpds
		var support = i_self.supportXpd;
		i_self.supportXpd = i_self.sanitizeXpdValue(support);

		i_self.fields = ["stacktoken", "token", i_self.tokenKey, "toplink", "title", "ptype", "layout", "properties", "stackId"];

		// Initilize the value - and if no value, do a fetch to get it and load
		// the components and add controls
		i_self.initValue();

		return i_self;
	},

	_initValue: function (o_stack) {

		var i_self = this;

		i_self.value = o_stack;

		return i_self;
	},

	initValue: function () {

		var i_self = this;
		var o_value = i_self.value;

		// No value supplied - we must fetch one
		if (!o_value) {
			// We have been supplied a cid - fetch the stack
			if (i_self.cid) {
				i_self.fetchStack(i_self.cid, function (o_value) {
					i_self._initValue(o_value);
					i_self.initChildren(o_value);
				});
			}

			// No cid supplied - we really need one!
			else {
				i_self.fireEvent("needcid", i_self, i_self);
				i_self.fetchStack(i_self.cid, function (o_value) {
					i_self._initValue(o_value);
					i_self.initChildren(o_value);
				});
			}
		}
		else {
			i_self._initValue(o_value);
			i_self.initChildren(o_value);
		}

		return i_self;
	},

	// Initialize the children components - the stacktree and content grids
	initChildren: function (o_stack) {

		var i_self = this;
		var o_xpd = ip2.xpd.flatten(i_self.supportXpd);
		var n_cid = i_self.cid;
		var n_id;

		o_stack = o_stack || i_self.getValue();

		// Find and set the collection id - used by to determine
		// allowedparents and allowedchildren
		n_id = o_xpd.collections[n_cid].stack;
		i_self.collectionId = n_id;

		// Now we have data we add the components
		i_self.addComponents(o_stack);

		// And the controls
		i_self.addControls();

		return i_self;
	},

	addControls: function () {

		var i_self = this;

		// The controls for beforedrop and drop in the stacktree are bound on the
		// components view in the method "addComponents"

		i_self.control({
			"stackTree": {
				"itemcontextmenu": i_self.onStackContext,
				"itemdblclick": i_self.onStackEditPage,
				"checkchange": i_self.onCheckBoxChange,
				"onDeleteKey": i_self.stackRemove,
				"onRightKey": i_self.swapToGrid,
				"scope": i_self
			},
			"accordion": {
				"stackadd": i_self.onStackAdd,
				"onLeftKey": i_self.swapToTree,
				"scope": i_self
			}
		});

		i_self.on({
			"tree_delete": {
				fn: function (tree, record) {
					i_self.onStackRemove(record);
					i_self.fireEvent("change", i_self);
				}
			}
		});

		i_self.getStackTree().getView().getStore().on({
			"add": {
				fn: function () {
					i_self.fireEvent("change", i_self);
				}
			}
		});

		return i_self;
	},

	swapToGrid: function () {

		var i_self = this;
		var i_tab = i_self.getAccordion();

		i_tab.setActiveFocus();

		return i_self;
	},

	swapToTree: function () {

		var i_self = this;
		var i_tree = i_self.getStackTree();

		i_tree.setActiveFocus();

		return i_self;
	},

	addComponents: function (o_stack) {

		var i_self = this;
		var o_xpd = i_self.xpd;
		var s_key = i_self.tokenKey;
		var i_west = i_self.getWestRegion();
		var i_center = i_self.getCenterRegion();

		// Add and create the list component with store

		var a_children = o_stack.children || [];

		Ext.Array.each(a_children, function(o_child) {
			o_child.iconCls = "x-tree-no-icon";
			o_child.leaf = true;
		});

		var i_stacktree = Ext.widget("stacktree", {
			layout: "fit",
			border: 0,
			supportXpd: i_self.supportXpd,
			viewConfig: {
				border: 1
			},
			store: Ext.create("Ext.ux.stackorganizer.store.Tree", {
				fields: i_self.fields,
				root: o_stack
			}),
			rootVisible: false,
			lines: false
		});

		var i_toolbar = Ext.widget("toolbar", {
			dock: "top",
			items: [
				{
					xtype: "splitbutton",
					text: ip2.i18n({
						da: "Tilføj",
						en: "Add"
					}),
					iconCls: "pf-add",
					menu: i_self.getCreateMenu()
				}
			]
		});

		var i_store = i_stacktree.getStore();
		i_store.on({
			datachanged: {
				fn: function(store, a_nodes) {

					var a_items = store.data.items;
					Ext.Array.each(a_items, function(i_node) {
						i_node.set("leaf", true);
						i_node.set("iconCls", "x-tree-no-icon");
					});
				}
			}
		});

		i_stacktree.addDocked(i_toolbar);

		i_west.add(i_stacktree);

		// Add and create the content component
		i_center.add({
			xtype: "stackcontentaccordion",
			border: 0,
			xpd: i_self.xpd,
			supportXpd: i_self.supportXpd,
			tokenKey: i_self.tokenKey,
			collectionId: i_self.collectionId,
			stack: o_stack,
			fields: i_self.fields/*,
			dragConfig: {
				dragGroup: "stackDD",
				enableDrag: true,
				enableDrop: false
			}*/
		});

		// Create the context menu for the stack tree
		i_self.stackContextMenu = Ext.create("Ext.menu.Menu", {
			renderTo: Ext.getBody(),
			itemId: "stackcontextmenu",
			items: [
				{
					xtype: "menuitem",
					iconCls: "pf-navigate_cross",
					text: ip2.i18n({
						da: "Fjern",
						en: "Remove"
					}),
					itemId: "remove"
				},
				{
					xtype: "menuitem",
					iconCls: "pf-edit",
					text: ip2.i18n({
						da: "Rediger toplink",
						en: "Edit Toplink"
					}),
					itemId: "edit"
				},
				{
					xtype: "menuitem",
					iconCls: "pf-edit",
					text: ip2.i18n({
						da: "Rediger siden",
						en: "Edit Page"
					}),
					itemId: "editpage"
				}
			]
		});
		i_self.getStackContextMenu = function () {
			return this.stackContextMenu;
		};

		// Set the original value of this component now
		var o_value = i_self.getValue();
		i_self.originalValue = o_value;

		return i_self;
	},

	getCreateMenu: function() {

		var i_self = this;
		var o_xpd = i_self.xpd;
		var o_supportXpd = i_self.supportXpd;
		var o_collections = o_xpd.collections;
		var a_items = [];

		ip2.each(o_collections, function(o_collection, s_key) {

			var b_allow = (function () {

				var b_allow = false;
				var parents = o_collection.allowedparents;
				var n_id = i_self.collectionId;

				// Parents is an array
				// If array is empty or collectionId is in the allowedparent array
				// it is allowed
				if (Ext.isArray(parents)) {

					if (!parents.length) {
						b_allow = true;
					}
					else {
						b_allow = (Ext.Array.indexOf(parents, n_id) >= 0);
					}
				}

				return b_allow;
			})();

			if (b_allow) {
				var o_supportXpd = i_self.sanitizeXpdValue(o_collection.xpd);
				var i_menuitem = Ext.widget("menuitem", {
					text: ip2.xpd.translate(o_xpd, o_collection.title, ip2.session.getLanguage()),
					itemId: "collection-" + o_collection.id,
					stackId: o_collection.id,
					collection: o_collection,
					supportXpd: o_supportXpd,
					handler: function(item) {

						var i_grid = i_self.getAccordion().getStackById(item.stackId);
						var i_model = i_grid.getStore().getModel();

						var i_record = i_model.create({
							__cid__: item.supportXpd.collections[item.collection.ptype].id
						});

						var s_event = "entityupdate:" + item.collection.entity;
						var o_event = {};
						o_event[s_event] = {
							fn: function(i_record, s_action) {
								i_grid.refreshData(i_record);
							},
							single: true
						};

						var o_size = Ext.ux.file.util.Handler.getWindowSize();

						var i_window = Ext.widget("window", {
							modal: false,
							closable: true,
							collapsible: true,
							resizable: true,
							width: o_size.width * 0.9,
							height: o_size.height * 0.9,
							layout: "fit"
						});

						ip2.addChild(i_window, i_record, "create", item.collection);

						i_self.mon(ip2.App, o_event);

						i_window.show();
					}
				});
				a_items.push(i_menuitem);
			}
		});

		var i_menu = Ext.widget("menu", {
			items: a_items
		});
		return i_menu;
	},

	fetchStack: function(n_cid, f_callback) {

		if (!n_cid) {
			throw new Error("Ext.ux.stackorganizer.Panel: I really need a cid! (Listen to my needcid event and call my setCid to help me)");
		}

		var i_self = this;

		// Load the stack data and add the initialize the components
		Ext.Ajax.request({
			url: "/wsh-services/wshproxy.aspx",
			params: {
				xpd: i_self.supportXpd._path,
				stackxpd: i_self.xpd._path,
				token: i_self.getToken(),
				action: "getpage",
				environment: "treestore",

				// TODO: Get this from pages.xpd (pageLang.widget)
				cid: n_cid
			},
			success: function (o_response) {

				var o_xpd = i_self.xpd;
				var n_id;
				var o_stack = {};

				try {
					o_stack = Ext.decode(o_response.responseText);
				}
				catch (err) {
					console.log("TODO: Error handling for stack on loading data");
				}

				o_stack.children || (o_stack.children = []);

				i_self.sanitizeStackValue(o_stack, true);

				f_callback && f_callback(o_stack);
			}
		});

		return i_self;
	},

	stackRemove: function () {

		var i_self = this;
		var i_tree = i_self.getStackTree();
		var i_store = i_tree.getView().getStore();
		var a_selected = i_tree.getSelectionModel().getSelection();

		i_store.remove(a_selected);

		return i_self;
	},

	onCheckBoxChange: function (i_node, b_checked) {

		var i_self = this;
		var o_properties = i_node.get("properties");

		i_node.set({
			"toplink": b_checked,
			"checked": b_checked
		});

		if (o_properties) {
			o_properties.toplink = b_checked;
			i_node.set("properties", o_properties);
		}
		i_self.fireEvent("change", i_self);

		return i_self;
	},

	onStackAdd: function (i_grid, i_record, b_create) {

		var i_self = this;
		var i_tree = i_self.getStackTree();
		var i_store = i_tree.getStore();
		var i_root = i_store.getRootNode();
		var i_selected = i_tree.getLastSelectedNode();
		var o_stack;

		i_tree.cleanIndexes();

		if (b_create) {
			var i_node = i_root.createNode(i_record.data);
			var o_prop = i_record.get("properties");

			// Insert after last selected node in stacktree
			// unless last selected node is last node in stacktree
			if (i_selected) {

				var n_index = i_selected.get("index");

				i_root.insertChild(n_index + 1, i_node);
			}

			// No node selected, or last selected node is also last node in tree
			else {
				i_root.appendChild(i_node);
			}

			i_tree.cleanIndexes().getView().refresh();
			i_tree.setNodeFocus(i_node);
		}
		else {
			var a_removed = i_store.getRemovedRecords();
			ip2.each(a_removed, function(i_removed) {
				if (i_removed.get("token") == i_record.get("token")) {
					i_record.set(i_removed.data);
				}
			});
		}

		if (!i_record.get("title")) {
			var o_prop = i_record.get("properties");
			var title = o_prop.title || o_prop.header || o_prop.name;

			if (Ext.isString(title)) {
				if (ip2.isStringedObject(title)) {
					title = JSON.parse(title);
				}
				else {
					title = {
						da: title,
						en: "",
						fr: "",
						de: ""
					};
				}
			}

			i_record.set("title", title);
		}

		o_stack = i_self.getValue();

		// Set the new stack value on the grid so filter will update and the
		// grid will refresh itself
		i_grid.setStack(o_stack);

		i_self.fireEvent("change", i_self);

		return i_self;
	},

	onStackEdit: function (i_self, i_record) {

		var i_self = this;
		var o_title = i_self.getStackTitle(i_record);
		var b_checked = i_record.get("checked");
		var s_language = ip2.session.getLanguage();
		var i_window;

		i_window = Ext.widget("window", {
			renderTo: Ext.getBody(),
			closable: true,
			width: 600,
			layout: "fit",
			title: ip2.i18n(o_title),
			items: [
				{
					xtype: "form",
					itemId: "stackform",
					layout: "anchor",
					bodyPadding: 20,
					defaults: {
						anchor: "100%",
						labelWidth: 100
					},
					items: [
						{
							xtype: "i18ntextfield",
							name: "title",
							itemId: "title",
							preventI18nTrigger: true,
							defaultLanguage: s_language,
							languages: i_self.languages,
							fieldLabel: ip2.i18n({
								da: "Titel",
								en: "Title"
							}),
							value: o_title
						},
						{
							xtype: "checkbox",
							name: "checked",
							itemId: "checked",
							inputValue: "true",
							fieldLabel: ip2.i18n({
								da: "Toplink",
								en: "Toplink"
							}),
							checked: b_checked
						}
					],
					listeners: {
						dirtychange: {
							fn: function(i_form, b_dirty) {
								var i_owner = i_form.owner;
								var i_save = i_owner.down("#button-save");
								if (i_save) {
									if (b_dirty) {
										i_save.enable();
									}
									else {
										i_save.disable();
									}
								}
							}
						}
					},
					buttons: [
						{
							text: ip2.i18n("save"),
							action: "save",
							itemId: "button-save",
							disabled: true,
							handler: function () {

								var i_form = i_window.down("#stackform");
								var o_title = i_form.down("#title").getValue();
								var b_checked = i_form.down("#checked").getValue();

								i_record.set({
									title: o_title,
									checked: b_checked ? true : false,
									toplink: b_checked ? true : false
								});

								i_window.close();

								i_self.fireEvent("change", i_self);
							}
						},
						{
							text: ip2.i18n("cancel"),
							action: "cancel",
							handler: function () {
								i_window.close();
							}
						}
					]
				}
			]
		}).show();

		return i_self;
	},

	onStackRemove: function (i_record) {

		var i_self = this;
		var i_tree = i_self.getStackTree();
		var i_accordion = i_self.getAccordion();
		var i_grid = i_accordion.getStackById(i_record.get("stackId"));
		var o_stack = i_self.getValue();

		if (!i_grid) {
			i_accordion.refreshStackData(o_stack); // THIS WILL CAUSE A TOTAL REFRESH
		}
		else {
			i_grid.stack = o_stack;
			i_grid.refreshData();
		}

		return i_self;
	},

	onStackEditPage: function (i_tree, i_node, i_item, n_index, e, o_events) {

		var i_self = this;
		var o_xpd = ip2.xpd.flatten(i_self.xpd);
		var o_collections = o_xpd.collections;
		var o_collection = o_collections[i_node.get("stackId")];

		var i_el = Ext.get(i_item.id);

		var o_keys = {};
		var o_size = Portfolio.util.Handler.getWindowSize();
		var i_user = Portfolio.util.Handler.getUser();

		var s_entity = o_collection.xpd == "pages.xpd" ? "WSHPAGET00" : o_collection.entity;

		var o_config = {
			dmd: "dmd/webshop.dmd",
			entityName: s_entity,
			uiName: "portfolio",
			context: "form"
		};

		var i_model = ip2.model(o_config);

		var i_record = i_model.create();
		var s_key = i_record.idProperty;
		var n_token = i_node.get("token");

		i_record.set(s_key, n_token);
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		var i_window = Ext.widget("window", {
			modal: false,
			closable: true,
			collapsible: true,
			resizable: true,
			width: o_size.width * 0.9,
			height: o_size.height * 0.9,
			layout: "fit"
		});

		i_window.show();
		i_window.setLoading();

		var i_entitypanel = Ext.widget("portfolio-entity-form", {
			keys: o_keys,
			action: "update",
			dmd: o_config.dmd,
			entity: o_config.entityName,
			view: o_config.uiName,
			context: "form",
			language: i_user.get("USRLNG") || "en",
			languages: wsh.getLanguages(),
			closable: false,
			listeners: {
				contentReady: {
					fn: function(i_contentPanel, i_entitypanel) {

						var i_header = i_entitypanel.getHeader();
						i_header.hide();
					}
				}
			}
		});

		i_window.add(i_entitypanel);

		i_window.setLoading(false);
	},

	onStackContext: function (i_stack, i_node, i_item, n_index, e, o_events) {

		var i_self = this;
		var i_menu = i_self.getStackContextMenu();

		e.preventDefault();
		var a_xy = e.getXY();
		i_menu.showAt(a_xy[0], a_xy[1]);

		i_menu.down("#remove").handler = function () {
			i_node.remove(false);
			i_self.onStackRemove(i_node);
			i_self.fireEvent("change", i_self);
		};

		i_menu.down("#edit").handler = function () {
			i_self.onStackEdit(i_self, i_node);
		};

		i_menu.down("#editpage").handler = function () {
			i_self.onStackEditPage(i_self, i_node, i_item, n_index, e, o_events);
		};

		return i_self;
	},

	getStackTitle: function (i_record) {

		var s_title = "";
		var o_title = i_record.get("title") || {};
		var o_properties = i_record.get("properties") || {};
		var s_language = ip2.session.getLanguage();

		if (!Ext.isObject(o_title) && ip2.isStringedObject(o_title)) {
			o_title = Ext.decode(o_title);
		}

		if (!o_title || (o_title && !o_title[s_language])) {

			if (!Ext.isObject(o_title)) {
				o_title = {};
			}

			o_title[s_language] = o_properties.title || o_properties.header || "";
		}

		return o_title;
	},

	getToken: function () {

		var i_self = this;
		var i_parent = i_self.dataParent;
		var s_key = i_self.dataTokenKey;
		var o_keys = i_parent.getKeys();

		return o_keys[s_key];
	},

	getValue: function () {

		var i_self = this;
		var i_stackTree = i_self.getStackTree();
		var value = {};

		if (i_stackTree) {
			var i_root = i_stackTree.getStore().getRootNode();
			value = i_self.serializeNode(i_root, true);
		}

		return value;
	},

	setValue: function (o_value) {

		var i_self = this;
		var i_stackTree = i_self.getStackTree();
		var i_root;

		if (i_stackTree) {
			i_root = i_stackTree.getStore().getRootNode();
			i_root.set(o_value);
		}

		i_self.value = o_value;

		return i_self;
	},

	getOriginalValue: function () {

		return this.originalValue;
	},

	resetOriginalValue: function () {

		var i_self = this;

		i_self.originalValue = i_self.value = i_self.getValue();

		return i_self;
	},

	isDirty: function () {

		var i_self = this;
		var o_original = i_self.getOriginalValue() || {};
		var o_value = i_self.getValue() || {};

		if (o_original === null || o_value === null) {
			return false;
		}

		var s_original = JSON.stringify(o_original);
		var s_value = JSON.stringify(o_value);

		return s_original != s_value;
	},

	serializeNode: function (i_node, b_root) {

		var i_self = this;
		var a_fields = i_self.fields;
		var o_data = i_node.data;
		var o_node = {};

		Ext.Array.each(a_fields, function (s_field) {

			var value = o_data[s_field];

			if (value != null && value != undefined) {

				// Normalize toplink to boolean
				if (s_field == "toplink") {

					if (value == "false" || value === "") {
						value = false;
					}
				}

				o_node[s_field] = value;
			}
		});

		if (b_root) {
			o_node.children = [];
		}

		if (i_node.childNodes && i_node.childNodes.length) {

			o_node.children = [];

			Ext.Array.each(i_node.childNodes, function (i_child) {
				o_node.children.push(i_self.serializeNode(i_child));
			});
		}

		return o_node;
	},

	sanitizeStackValue: function (o_stack, b_root) {

		var i_self = this;

		Ext.Object.each(o_stack, function (s_key, value) {

			if (s_key == "children") {
				Ext.Array.each(value, function (o_child) {
					i_self.sanitizeStackValue(o_child);
				});
			}
			else if (s_key == "checked") {
				o_stack.toplink = value;
				if (o_stack.properties) {
					o_stack.properties.toplink = value;
				}
			}
			else if (s_key == "leaf" && b_root) {
				o_stack.leaf = false;
			}
		});
	},

	sanitizeXpdValue: function (xpd) {

		if (Ext.isString(xpd)) {
			xpd = ip2.resource.get(xpd, true);
		}

		return xpd;
	}
});
Ext.define('Ext.ux.stackorganizer.Field', {

	extend: 'Ext.form.FieldContainer',

	alias: ['widget.stackfield'],

	mixins: {
		field: 'Ext.form.field.Field',
		componentController: 'Ext.ux.util.ComponentController'
	},

	refs: [
		{
			ref: 'stackPanel',
			selector: 'stackpanel'
		}
	],

	config: {
		token: 0,
		tokenKey: '__cid__',
		xpd: null,
		supportXpd: null,
		cid: null
	},

	initComponent: function () {

		var i_cmp = this;
		var o_stack;

		i_cmp.initComponentController();

		o_stack = Ext.Object.merge({
			xtype: 'stackpanel',
			border: false
		}, i_cmp.initialConfig);

		var i_stack = Ext.widget("stackpanel", o_stack);
		i_stack.on({
			change: {
				fn: function(i_stack) {
					i_cmp.checkChange();
				}
			},
			doAfterLayout: {
				fn: function(i_stack) {
					var i_widget = i_cmp.up("ip2widget");
					if (i_widget) {
						Ext.Component.updateLayout(i_widget);
					}
				},
				single: true
			}
		});

		Ext.apply(i_cmp, {
			layout: 'fit',
			margin: 0,
			padding: 0
		});

		i_cmp.callParent();

		i_cmp.initField();

		i_cmp.add(i_stack);

		i_cmp.addControls();

		return i_cmp;
	},

	initValue: function () {

		var i_cmp = this;
		var value = i_cmp.value;

		i_cmp.originalValue = value;

		return i_cmp;
	},

	getToken: function () {

		return this.getStackPanel().getToken();
	},

	addControls: function () {

		var i_cmp = this;
		var i_stack = i_cmp.getStackPanel();

		i_stack.on('needcid', function () {
			i_cmp.fireEvent('needcid', i_cmp, i_stack);
		});

		return i_cmp;
	},

	getValue: function () {

		var i_cmp = this;
		var i_stack = i_cmp.getStackPanel();
		var o_value = i_stack.getValue();
		var s_value = i_cmp.rawToValue(o_value);

		return s_value;
	},

	setValue: function (value) {

		var i_cmp = this;
		var i_stack = i_cmp.getStackPanel();

		i_cmp.value = value;

		i_stack.setValue(value);

		return i_cmp;
	},

	valueToRaw: function (s_value) {

		s_value = s_value || "";

		var i_cmp = this;
		var o_value = {};

		if (s_value.length) {
			o_value = Ext.decode(s_value);
		}

		return o_value;
	},

	disable: function() {

		var i_self = this;
		i_self.callParent(arguments);
		if (i_self.isDisabled()) {
			var i_stack = i_self.getStackPanel();
			i_stack.disable();
		}
	},

	enable: function() {

		var i_self = this;
		i_self.callParent(arguments);
		if (!i_self.isDisabled()) {
			var i_stack = i_self.getStackPanel();
			i_stack.enable();
		}
	},

	rawToValue: function (o_value) {

		var i_cmp = this;
		var s_value = '';

		if (Ext.Object.getSize(o_value)) {
			s_value = Ext.encode(o_value);
		}

		return s_value;
	},

	resetOriginalValue: function () {

		var i_cmp = this;
		var i_stack = i_cmp.getStackPanel();
		i_stack.resetOriginalValue();
		i_cmp.originalValue = i_cmp.value = i_cmp.getValue();
	},
	isDirty: function () {

		var i_cmp = this;
		var i_stack = i_cmp.getStackPanel();

		return i_stack.isDirty();
	}
});
Ext.define("Ext.ux.gallery.view.DropBox", {
	extend: "Ext.container.Container",
	alias: "widget.gallerydropbox",

	extensions: "*",

	layout: "absolute",

	requires: [
		"Ext.ux.plugin.UploadDD"
	],

	initComponent: function () {

		var i_cmp = this;

		i_cmp.initConfig(i_cmp.initialConfig);

		Ext.apply(i_cmp, {
			dropText: {
				en: "Drag-and-drop your file(s) here",
				da: "Træk-og-slip dine file(r) her"
			},
			html: i_cmp.createDropText(),
			plugins: [
				{
					ptype: "uploadDD",
					extensions: i_cmp.extensions
				}
			]
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	},

	getDDPlugin: function () {

		var i_cmp = this;
		var s_key = "uploadDD";
		var i_found;

		Ext.Array.some(i_cmp.plugins, function (i_plugin) {
			if (i_plugin.pluginId == s_key) {
				i_found = i_plugin;
				return true;
			}
		});

		return i_found;
	},

	createDropText: function () {

		var i_cmp = this;

		return new Ext.XTemplate(
			"<div _type=\"dropbox\">",
				"<table style=\"height: 100%; width: 100%; padding: 2px;\">",
					"<tr style=\"vertical-align: middle;\">",
						"<td style=\"text-align: center; pointer-events:none;\">",
							ip2.i18n(i_cmp.dropText),
						"</td>",
					"</tr>",
				"</table>",
			"</div>"
		).html;
	}
});

Ext.define("Ext.ux.gallery.view.LinkPageGrid", {

	extend: "Ext.grid.Panel",

	alias: "widget.mediagallerylinkpagegrid",

	primaryId: null,
	primaryKey: null,
	titleId: null,
	titleKey: null,
	value: "",

	_touched: false,

	config: {
		entity: "",
		dmd: "",
		uiName: "",
		model: null,
		info: null,
		where: ""
	},

	initComponent: function () {

		var i_self = this;
		var s_dmd = i_self.getDmd();
		var s_entity = i_self.getEntity();
		var s_uiName = i_self.getUiName() || "portfolio";
		var o_dmd = ip2.resource.get(s_dmd);

		var i_model = ip2.model({
			dmd: o_dmd._path,
			entityName: s_entity
		});

		var o_Info = ip2.dmd.getInfo({
			dmd: s_dmd,
			view: s_uiName,
			entity: s_entity,
			context: "grid"
		});

		i_self.setInfo(o_Info);

		i_self.setModel(i_model);

		// Get the primary column ID from model
		i_self.primaryId = i_self.getPrimaryKey();

		// Get the title column ID from model
		i_self.titleId = i_self.getPrimaryTitleKey();

		// Get the title from entity for this grid
		var s_title = (function (o_entity) {
			return ip2.i18n(o_entity.title || "No title for this entity!!");
		})(i_model.prototype.entity);

		var i_store = Ext.create("Ext.data.BufferedStore", {
			model: i_model,
			proxy: ip2.getProxyByEntity({
				dmd: s_dmd,
				entity: s_entity,
				view: s_uiName
			}),
			remoteSort: true,
			autoSync: false,
			pageSize: 100,
			autoLoad: true
		});

		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		Ext.apply(o_extraParams, {
			action: "getRows",
			context: "grid",
			uiName: s_uiName,
			dmdFile: o_dmd._path
		});

		if (i_self.where) {
			o_extraParams.where = i_self.where;
		}

		Ext.apply(i_self, {
			title: s_title,
			selModel: Ext.create("Ext.selection.CheckboxModel", {
				mode: "SINGLE",
				allowDeselect: true
			}),
			store: i_store,
			columns: (function (i_model) {

				var a_column = [];
				var o_dmdInfo = o_Info;
				var o_entity = o_Info.entity;

				Ext.Array.each(o_entity.ui.grids[s_uiName].columns, function (o_field, n_index) {

					var s_name = o_field.name;
					var o_column = i_model.columns[s_name] || {};
					var o_config;

					o_config = Ext.Object.merge(o_column.column || {}, o_column, o_field);

					// THIS COULD BE A XPD FIELD - AND AS SUCH THE TITLE IS TO BE FOUND IN THE XPD
					if (o_config.xpd) {

						var o_xpdInfo = ip2.getFieldXpdInfo(s_name, o_dmdInfo.entity, o_config);

						if (o_xpdInfo) {
							ip2.applyFieldXpdInfo(o_config, o_xpdInfo);
						}
					}

					if (o_config.title && !o_config.header) {
						o_config.header = o_config.title;
					}

					o_config.header = ip2.i18n(o_config.header);

					if (!o_config.width) {
						o_config.flex = 2;
					}

					if (o_config.dataIndex == "PLGPROP___CID__") {

						o_config.flex = 1;

						o_config.renderer = function(value, meta, record, rowIndex, colIndex) {

							var o_xpd = ip2.resource.get("pages.xpd", true);
							var o_collection = o_xpd.collections;
							var s_title = "";

							if (o_collection[value]) {
								s_title = o_collection[value].title;
								s_title = ip2.xpd.translate(o_xpd, s_title);
							}

							return s_title;
						};
					}

					if (!o_config.dataIndex) {
						o_config.dataIndex = o_config.name;
					}

					a_column.push(o_config);
				});

				return a_column;
			})(i_model.prototype)
		});

		i_self.callParent(arguments);

		i_self.on({
			afterrender: {
				fn: function(i_self) {
					var i_selectionModel = i_self.getSelectionModel();
					if (i_selectionModel.mode == "SINGLE") {
						i_selectionModel.allowDeselect = true;
					}
				}
			},
			select: {
				fn: function () {
					i_self._touched = true;
				},
				single: true
			},
			deselect: {
				fn: function () {
					i_self._touched = true;
				},
				single: true
			}
		});

		i_self.onInitialize && i_self.onInitialize();

		return i_self;
	},

	getPrimaryTitleKey: function () {

		var i_self = this;
		var o_Info = i_self.getInfo();
		var o_entity = o_Info.entity;
		var s_uiName = i_self.getUiName();
		var s_id;
		var o_ui = o_entity.ui.grids[s_uiName];
		var b_found = false;

		Ext.Array.some(o_ui.columns, function (o_column, n_index) {
			if (o_column.isTitle) {

				if (o_column.isPrimaryTitle) {
					s_id = o_column.name;
					return true;
				}
				else {
					s_id = o_column.name;
				}
			}
		});

		return s_id;
	},
	getPrimaryKey: function () {

		var i_self = this;
		var o_Info = i_self.getInfo();
		var o_entity = o_Info.entity;

		return o_entity.idColumn;
	},

	getValue: function () {

		var i_self = this;
		var s_primaryId = i_self.primaryId;
		var s_titleId = i_self.titleId;
		var o_value;
		var i_record;

		var a_records = i_self.getSelectionModel().getSelection();

		if (a_records.length > 0) {

			i_record = a_records[0];

			o_value = {
				type: i_self.name,
				token: i_record.get(s_primaryId)
			};

			if (s_titleId && i_record.get(s_titleId)) {
				o_value.title = i_record.get(s_titleId);
			}
		}
		else if (!i_self._touched) {
			o_value = i_self.value;
		}
		else {
			o_value = "";
		}

		return o_value;
	},
	setValue: function (o_value) {

		var i_self = this;
		var s_primaryId = i_self.primaryId;
		var s_titleId = i_self.titleId;
		var i_store = i_self.getStore();
		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();
		var n_token = o_value.token;

		i_self.value = o_value;

		if (n_token) {

			i_self.primaryKey = n_token;
			i_self.titleKey = o_value.title || null;

			o_extraParams.union = Ext.encode([{
				property: s_primaryId,
				value: n_token
			}]);

			i_store.load();
		}

		return i_self;
	}
});

Ext.define('Ext.ux.gallery.view.LinkStackGrid', {
	extend: 'Ext.panel.Panel',
	alias: ['widget.mediagallerylinkstackgrid'],
	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent();

		return i_cmp;
	}
});
Ext.define("Ext.ux.gallery.view.MediaGrid", {

	extend: "Ext.grid.Panel",

	alias: ["widget.gallerymediagrid"],

	mixins: {
		keyMapping: "Ext.ux.util.KeyMapping"
	},
	
	config: {
		
		linkConfig: null,
		actionColumns: null,
		allowImageRender: 1,
		dcMap: null
	},

	initComponent: function () {

		var i_cmp = this;

		Ext.apply(i_cmp, {
			cls: "x-ux-imagegrid"
		});

		i_cmp.language = i_cmp.language || wsh.i18n.getPrimary();

		i_cmp.initColumns();

		i_cmp.callParent(arguments);

		i_cmp.initKeyMapping();

		i_cmp.enableBubble("datachange");

		return i_cmp;
	},

	initColumns: function () {

		var i_cmp = this;
		var o_actionColumns = i_cmp.actionColumns;
		var a_columns = [];

		i_cmp.dcMap = {};

		// Create the action columns from definition
		Ext.Object.each(o_actionColumns, function (s_key, o_config) {

			o_config._key = s_key;

			var f_behavior;
			switch (o_config.type) {
				case "radiocheckbox":
					f_behavior = i_cmp.applyRadioCheckboxBehavior;
					o_config.inputType = "radio";
					o_config.context || (o_config.context = "column");
				break;
				case "radio":
					f_behavior = i_cmp.applyRadioBehavior;
					o_config.inputType = "radio";
					o_config.context || (o_config.context = "column");
				break;
				case "checkbox":
					o_config.inputType = "checkbox";
					f_behavior = i_cmp.applyCheckboxbehavior;
				break;
				default:
					o_config.inputType = "checkbox";
					f_behavior = i_cmp.applyCheckboxbehavior;
				break;
			}

			var f_getMappedName = function (s_key) {

				var s_name = false;
				var o_map = {
					header: ["title"],
					dataGroup: ["group"]
				};

				ip2.each(o_map, function (a_val, s_map) {
					var n_index = ip2.indexOf(a_val, s_key);
					if (n_index > -1) {
						s_name = s_map;
						return false;
					}
				});

				return s_name;
			};

			var f_sanitize = function (value, s_key, o_context) {

				// Could be a title or tooltip or whatever - use ip2.i18n
				if (ip2.isObject(value)) {
					value = ip2.i18n(value);
				}

				// Special conditions
				switch (s_key) {

				case "context":
					o_context.dataGroup || (o_context.dataGroup = o_context.group);
					if (!o_context.dataGroup) {
						o_context.dataGroup = o_context.dataIndex || o_context.name;
					}
				break;

				default:
				break;
				}

				return value;
			};

			ip2.each(o_config, function (value, s_key, o_context) {

				// Could be this is an mapped key
				var s_map = f_getMappedName(s_key);
				if (s_map) {
					o_context[s_map] = f_sanitize(value, s_map, o_context);
					delete o_context[s_key];
				}
				else {
					o_context[s_key] = f_sanitize(value, s_key, o_context);
				}
			});

			var o_column = ip2.extend({
				header: "",
				width: 55
			}, o_config, {
				sortable: false,
				resizable: false,
				hideable: false,
				align: "center",
				menuDisabled: true,
				dataIndex: s_key,
				toolTip: ip2.i18n(o_config.toolTip) || ip2.i18n(o_config.header),
				renderer: function (b_value, o_meta, i_record, n_row, n_col, i_store, i_view) {

					var o_input = i_cmp.createSpecialColumnInput(i_record, o_config);
					f_behavior.call(i_cmp, o_input.id, o_config);

					return o_input.html;
				}
			});

			a_columns.push(o_column);
		});

		// Then concat the remaining columns
		a_columns = a_columns.concat([
			{
				hidden: true,
				dataIndex: "type",
				sortable: false,
				draggable: false,
				resizable: false,
				hideable: false,
				menuDisabled: true
			},
			{
				header: ip2.i18n({
					da: "Medie",
					en: "Media"
				}),
				toolTip: ip2.i18n({
					da: "Hvis muligt vises et preview af mediet",
					en: "If possible a preview of the media will be shown"
				}),
				align: "center",
				width: 100,
				dataIndex: "url",
				renderer: function (s_value, metaData, i_record) {

					var value = i_record.get("url");
					var s_url = value;
					var s_lang = i_cmp.language;
					if (Ext.isObject(value)) {
						s_url = value[s_lang];
						if (!s_url) {
							s_url = value.any || "";
						}
					}

					var s_dc = "?_dc=" + ip2.getDcTimestamp();

					var s_url = Ext.ux.file.util.Handler.getUrlByExtension(s_url, true);

					var s_html = [
						"<div style=\"height: 24px;\">",
							"<img ",
								"data-internalid=\"" + i_record.internalId + "\" ",
								"class=\"grid-preview\" ",
								"height=\"24\"",
								"src=\"" + s_url + s_dc + "\"",
							"/>",
						"</div>"
					].join("");

					return s_html;
				}
			},
			{
				header: ip2.i18n({
					da: "Navn",
					en: "Name"
				}),
				toolTip: ip2.i18n({
					da: "Navn",
					en: "Name"
				}),
				flex: 1,
				dataIndex: "url",
				renderer: function (s_value) {

					var value = s_value;
					var s_lang = i_cmp.language;
					if (Ext.isObject(value)) {
						s_value = value[s_lang];
						if (!s_value) {
							s_value = value.any || "";
						}
					}

					return s_value.split("/").pop();
				}
			},
			{
				header: ip2.i18n({
					da: "Overskrift",
					en: "Headline"
				}),
				toolTip: ip2.i18n({
					da: "Overskrift",
					en: "Headline"
				}),
				flex: 2,
				dataIndex: "title",
				renderer: function (s_value) {
					var value = s_value;
					var b_stringed = ip2.isStringedObject(value);
					if (b_stringed) {
						var o_value = JSON.parse(value);
						i_cmp.language = i_cmp.language || wsh.i18n.getPrimary();
						var s_lang = i_cmp.language;
						value = ip2.i18nWithLanguage(o_value, s_lang);
					}
					else {
						if (Ext.isObject(value)) {
							var o_value = value;
							i_cmp.language = i_cmp.language || wsh.i18n.getPrimary();
							var s_lang = i_cmp.language;
							value = ip2.i18nWithLanguage(o_value, s_lang);
						}
					}
					return value;
				}
			},
			{
				header: ip2.i18n({
					da: "Link",
					en: "Link"
				}),
				toolTip: ip2.i18n({
					da: "Link",
					en: "Link"
				}),
				flex: 2,
				dataIndex: "link",
				renderer: function (o_value, o_meta, i_record, n_row, n_col, i_store, i_view) {

					o_value = o_value || {};

					var s_return = "";
					var s_type = o_value.type;
					var o_i18n;
					var s_url;

					if (!s_type) {
						return s_return;
					}

					switch (s_type) {
					case "page":
						var s_token = o_value.token;
						var s_title = o_value.title;

						o_i18n = {
							da: "Side: ",
							en: "Page: "
						};

						if (s_token && !s_title) {
							o_i18n.da += "med token " + s_token;
							o_i18n.en += "with token " + s_token;
						}
						else if (s_title) {
							o_i18n.da += s_title;
							o_i18n.en += s_title;
						}

						s_return = ip2.i18n(o_i18n);
					break;

					case "stack":
						o_i18n = {
							da: "Stak:",
							en: "Stack:"
						};

						s_return = [ip2.i18n(o_i18n), o_value.title || o_value.token].join(" ");

					break;

					case "url":
						s_url = o_value.url;
						var b_external = ip2.isExternalUrl(s_url);

						o_i18n = {
							da: b_external ? "Ekstern URL:" : "Intern URL: ",
							en: b_external ? "Extern URL:" : "Intern URL:"
						};

						s_return = [ip2.i18n(o_i18n), s_url].join(" ");
					break;

					case "document":
						s_url = o_value.value.url;

						o_i18n = {
							da: "Dokument: ",
							en: "Document: "
						};

						s_return = [ip2.i18n(o_i18n), s_url].join(" ");
					break;

					default:
					break;
					}

					return s_return;
				},
				hidden: i_cmp.linkConfig ? false : true
			},
			{
				header: ip2.i18n({
					en: "Caption",
					da: "Billedunderrubrik"
				}),
				toolTip: ip2.i18n({
					en: "Caption",
					da: "Billedunderrubrik"
				}),
				flex: 4,
				dataIndex: "caption",
				hidden: true
			},
			{
				xtype: "actioncolumn",
				iconCls: "pf-navigate_cross",
				width: 80,
				sortable: false,
				draggable: false,
				resizable: false,
				hideable: false,
				menuDisabled: true,
				align: "center",
				handler: function (i_view, n_row) {
					this.up("gallerymediagrid").fireEvent("itemremove", n_row);
				}
			}
		]);

		Ext.apply(i_cmp, {
			columns: a_columns,
			_previewMap: {
				image: function (i_record) {
					return {
						xtype: "image",
						src: i_record.get("url"),
						height: 345,
						maxWidth: 420
					};
				},
				video: function (i_record) {

					var value = i_record.get("url");
					var s_url = value;
					if (Ext.isObject(value)) {
						s_url = value[i_cmp.language];
						if (!s_url) {
							s_url = value.any || "";
						}
					}
					var i_meta = ip2.mediaMeta.fromUrl(s_url);
					var o_config;

					if (i_meta && i_meta.getIframe()) {
						o_config = {
							xtype: "container",
							html: i_meta.getIframe(420, 345, true)
						};
					}

					return o_config;
				}
			},
			cls: "x-ux-imagegrid",
			listeners: {
				afterrender: {
					fn: function(i_self) {
						var i_header = i_self.headerCt;
						i_self.tip = Ext.create("Ext.tip.ToolTip", {
							target: i_header.el,
							delegate: ".x-column-header",
							trackMouse: true,
							renderTo: Ext.getBody(),
							listeners: {
								beforeshow: {
									fn: function(tip) {
										var i_column = i_header.down("gridcolumn[id=" + tip.triggerElement.id + "]");
										if (i_column && i_column.toolTip) {
											tip.update(ip2.i18n(i_column.toolTip));
										}
										else {
											return false;
										}
									}
								}
							}
						});
					}
				}
			}
		});

		return i_cmp;
	},

	changeLanguage: function(s_lang) {
		var i_self = this;
		i_self.language = s_lang;
		var i_view = i_self.getView();
		i_view.refresh();
	},

	createSpecialColumnInput: function (i_record, o_config) {

		var i_cmp = this;

		var s_recordId = i_record.internalId;
		var value = i_record.get(o_config._key);

		var s_checked = value ? "checked" : "";
		var s_inputType = o_config.inputType;

		var s_name = [
			o_config.dataGroup || o_config.dataIndex || o_config.name,
			i_cmp.id
		].join("-");

		var s_id = [
			o_config.dataIndex || o_config.dataGroup || o_config.name,
			s_recordId,
			ip2.unique()
		].join("-");

		if (o_config.context == "row" || o_config.context == null) {
			s_name = [s_name, s_recordId].join("-");
		}

		var s_html = Ext.create("Ext.XTemplate",
			"<table ",
				"class=\"x-ux-gallery-cell\"",
				"style=\"text-align: center;",
				"width: 100%;\"",
			">",
				"<tr>",
					"<td valign=\"middle\">",
						"<input ",
							"id=\"" + s_id + "\"",
							"type=\"" + s_inputType + "\"",
							"class=\"" + s_name + "\"",
							"name=\"" + s_name + "\"",
							"value=\"" + s_recordId + "\"",
							"key=\"" + o_config._key + "\"",
							s_checked,
						"/>",
					"</td>",
				"</tr>",
			"</table>").html;

		return {
			id: s_id,
			html: s_html
		};
	},

	// TODO: Optimize for row type context or none (radiobutton used as checkbox)
	applyRadioCheckboxBehavior: function (s_id, o_config) {

		var i_cmp = this;

		// We wrap in a timeout to get behind in the stack
		// form the renderer calling us - so the HTML can be
		// rendered
		setTimeout(function () {

			var i_el = Ext.get(s_id);

			if (i_el) {

				i_el.on("click", function (o_event, i_self) {
					var s_class = i_self.name;
					var a_group = i_cmp.getInputByClass(s_class);
					var s_key = s_class.split("-").shift();

					ip2.each(a_group, function (i_input) {

						var i_record = i_cmp.getRecordFromInput(i_input);
						var o_values = {};
						if (i_self.id != i_input.id) {
							o_values[s_key] = false;
						}
						else {
							o_values[s_key] = !i_record.get(s_key);
						}
						i_cmp.silentSet(i_record, o_values);
					});

					i_self._changeChecker = true;

					/*
						var s_key = i_self.name.split("-").pop();
						var i_record = i_cmp.getRecordFromInput(i_self);
						var b_selfChange = i_self._selfCheck;

						if ( !i_self._changeChecker ) {

							i_self.checked = false;

							i_cmp.allowImageRender--;
							i_record.set(s_key, false);
							i_cmp.allowImageRender++;
						}

						i_self._changeChecker = false;
					*/
				});
			}
		}, 4);
	},

	// TODO: Optimize for row type context
	applyRadioBehavior: function (s_id, o_config) {

		var i_cmp = this;
		var i_store = i_cmp.store;

		// We wrap in a timeout to get behind in the stack
		// form the renderer calling us - so the HTML can be
		// rendered
		setTimeout(function () {

			var i_el = Ext.get(s_id);

			if (i_el) {

				i_el.on("change", function (o_event, i_self) {

					var s_class = i_self.name;
					var a_group = [];

					// row context based behavior
					if (o_config.context == "row") {

						var o_values = {};

						a_group = i_cmp.getInputByClass(s_class);

						ip2.each(a_group, function (i_input) {

							var s_key = (function (a_attr) {
								var found;
								ip2.each(a_attr, function (attr, s_attr) {
									if (attr.name == "key") {
										found = attr.value;
									}
								});
								return found;
							})(i_input.attributes);

							o_values[s_key] = i_input.checked;

							//o_values[s_key] = i_input.id == s_id ? true : false;
						});

						var i_record = i_cmp.getRecordFromInput(i_self);
						i_cmp.silentSet(i_record, o_values);
					}

					// column context based behavior
					else {

						a_group = i_cmp.getInputByClass(s_class);

						ip2.each(a_group, function (i_input) {

							var s_key = i_input.name.split("-").shift();
							var i_record = i_cmp.getRecordFromInput(i_input);
							var o_values = {};

							o_values[s_key] = i_input.id == s_id ? true : false;
							i_cmp.silentSet(i_record, o_values);
						});
					}
				});
			}
		}, 4);
	},

	applyCheckboxbehavior: function (s_id, o_config) {

		var i_cmp = this;

		// We wrap in a timeout to get behind in the stack
		// form the renderer calling us - so the HTML can be
		// rendered
		setTimeout(function () {

			var i_el = Ext.get(s_id);

			if (i_el) {

				i_el.on("change", function (o_event, i_self) {

					var i_record = i_cmp.getRecordFromInput(i_self);
					var s_key = i_self.name.split("-").shift();
					var o_values = {};

					o_values[s_key] = i_self.checked;

					i_cmp.silentSet(i_record, o_values);
				});
			}
		}, 4);
	},

	onEnterKey: function (i_view, i_record) {

		var i_cmp = this;
		var i_store = i_cmp.getStore();
		var n_row;

		i_store.each(function (i_item, n_index) {
			if (i_item.internalId == i_record.internalId) {
				n_row = n_index;
			}
		});

		i_cmp.fireEvent("itemedit", n_row);

		return i_cmp;
	},

	onDeleteKey: function (i_view, i_record, i_node, n_index) {

		var i_cmp = this;

		i_cmp.fireEvent("deletekey", i_record, n_index);

		return i_cmp;
	},

	silentSet: function (i_record, o_values) {

		var i_cmp = this;
		var i_store = i_cmp.getStore();
		i_cmp.allowImageRender--;
		i_record.set(o_values);
		i_store.fireEvent("datachanged", i_store);
		i_cmp.allowImageRender++;

		return i_cmp;
	},

	getInputByClass: function (s_class) {

		var i_cmp = this;
		var i_el = i_cmp.getView().getEl();
		var a_input = i_el.query(".x-ux-gallery-cell input." + s_class);

		return a_input;
	},

	getColumnInputs: function (s_key) {

		var i_cmp = this;
		var i_el = i_cmp.getView().getEl();
		var a_input = i_el.query(".x-ux-gallery-cell input." + s_key);

		return a_input;
	},
	getRecordFromInput: function (i_input) {

		var i_cmp = this;
		var i_store = i_cmp.getStore();
		var s_id = i_input.value;
		var i_record;

		i_store.findBy(function (i_found) {
			if (i_found.internalId == s_id) {
				i_record = i_found;
				return true;
			}
		});

		return i_record;
	}
});
if (!Ext.ClassManager.isCreated("Ext.ux.data.model.WebBios")) {
	Ext.define("Ext.ux.data.model.WebBios", {
		extend: "Ext.data.Model",
		alias: [
			"model.webbios"
		],
		fields: [
			{
				name: "id",
				type: "string"
			},
			{
				name: "path",
				type: "string"
			},
			{
				name: "text",
				type: "string"
			},
			{
				name: "ext",
				type: "string"
			},
			{
				name: "cls",
				type: "string"
			},
			{
				name: "leaf",
				type: "boolean"
			},
			{
				name: "mtime",
				type: "string"
			},
			{
				name: "size",
				type: "int",
				digits: 15
			}
		]
	});
}
if (!Ext.ClassManager.isCreated("Ext.ux.data.model.EditCode")) {
	Ext.define('Ext.ux.data.model.EditCode', {

		extend: 'Ext.data.Model',

		alias: ['model.editcode'],

		fields: [
			{ name: 'key', type: 'string' },
			{ name: 'comma', type: 'string' },
			{ name: 'decimal', type: 'string' },
			{ name: 'sign', type: 'string' },
			{ name: 'sign', type: 'string' },
			{ name: 'blank', type: 'string' },
			{ name: 'iValue', type: 'string' },
			{ name: 'jValue', type: 'string' },
			{ name: 'zero', type: 'string' }
		]
	});
}

Ext.define('Ext.ux.data.store.EditCode', {

	extend: 'Ext.data.Store',

	model: 'Ext.ux.data.model.EditCode',

	data: [
		{
			editcode: "",
			comma: "Commas Displayed",
			decimal: "Decimal Points Displayed",
			sign: "Sign Displayed When Negative Value",
			blank: "Blank Value of QDECFMT System Value",
			iValu: "I Value of QDECFMT System Value",
			jValue: "J Value of QDECFMT System Value",
			zero: "Leading Zero Suppressed"
		},
		{
			editcode: "1",
			comma: "Yes",
			decimal: "Yes",
			sign: "No sign",
			blank: ".00 or 0",
			iValue: ",00 or 0",
			jValue: "0,00 or 0",
			zero: "Yes"
		},
		{
			editcode: "2",
			comma: "Yes",
			decimal: "Yes",
			sign: "No sign",
			blank: "Blanks",
			iValue: "Blanks",
			jValue: "Blanks",
			zero: "Yes"
		},
		{
			editcode: "3",
			comma: "",
			decimal: "Yes",
			sign: "No sign",
			blank: ".00 or 0",
			iValue: ",00 or 0",
			jValue: "0,00 or 0",
			zero: "Yes"
		},
		{
			editcode: "4",
			comma: "",
			decimal: "Yes",
			sign: "No sign",
			blank: "Blanks",
			iValue: ",Blanks",
			jValue: "Blanks",
			zero: "Yes"
		},
		{
			editcode: "A",
			comma: "Yes",
			decimal: "Yes",
			sign: "CR",
			blank: ".00 or 0",
			iValue: ",00 or 0",
			jValue: "0,00 or 0",
			zero: "Yes"
		},
		{
			editcode: "B",
			comma: "Yes",
			decimal: "Yes",
			sign: "CR",
			blank: "Blanks",
			iValue: ",Blanks",
			jValue: "Blanks",
			zero: "Yes"
		},
		{
			editcode: "C",
			comma: "",
			decimal: "Yes",
			sign: "CR",
			blank: ".00 or 0",
			iValue: ",00 or 0",
			jValue: "0,00 or 0",
			zero: "Yes"
		},
		{
			editcode: "D",
			comma: "",
			decimal: "Yes",
			sign: "CR",
			blank: "Blanks",
			iValue: ",Blanks",
			jValue: "Blanks",
			zero: "Yes"
		},
		{
			editcode: "J",
			comma: "Yes",
			decimal: "Yes",
			sign: "-(Minus)",
			blank: ".00 or 0",
			iValue: ",00 or 0",
			jValue: "0,00 or 0",
			zero: "Yes"
		},
		{
			editcode: "K",
			comma: "Yes",
			decimal: "Yes",
			sign: "-(Minus)",
			blank: "Blanks",
			iValue: ",Blanks",
			jValue: "Blanks",
			zero: "Yes"
		},
		{
			editcode: "L",
			comma: "",
			decimal: "Yes",
			sign: "-(Minus)",
			blank: ".00 or 0",
			iValue: ",00 or 0",
			jValue: "0,00 or 0",
			zero: "Yes"
		},
		{
			editcode: "M",
			comma: "",
			decimal: "Yes",
			sign: "-(Minus)",
			blank: "Blanks",
			iValue: ",Blanks",
			jValue: "Blanks",
			zero: "Yes"
		},
		{
			editcode: "N",
			comma: "Yes",
			decimal: "Yes",
			sign: "-(Minus)",
			blank: ".00 or 0",
			iValue: ",00 or 0",
			jValue: "0,00 or 0",
			zero: "Yes"
		},
		{
			editcode: "O",
			comma: "Yes",
			decimal: "Yes",
			sign: "-(Minus)",
			blank: "Blanks",
			iValue: ",Blanks",
			jValue: "Blanks",
			zero: "Yes"
		},
		{
			editcode: "P",
			comma: "",
			decimal: "Yes",
			sign: "-(Minus)",
			blank: ".00 or 0",
			iValue: ",00 or 0",
			jValue: "0,00 or 0",
			zero: "Yes"
		},
		{
			editcode: "Q",
			comma: "",
			decimal: "Yes",
			sign: "-(Minus)",
			blank: "Blanks",
			iValue: ",Blanks",
			jValue: "Blanks",
			zero: "Yes"
		},
		{
			editcode: "W",
			comma: "",
			decimal: "",
			sign: "",
			blank: "",
			iValue: "",
			jValue: "",
			zero: "Yes"
		},
		{
			editcode: "Y",
			comma: "",
			decimal: "",
			sign: "",
			blank: "",
			iValue: "",
			jValue: "",
			zero: "Yes"
		},
		{
			editcode: "Z",
			comma: "",
			decimal: "",
			sign: "",
			blank: "",
			iValue: "",
			jValue: "",
			zero: "Yes"
		}
	]
});
if (!Ext.ClassManager.isCreated("Ext.ux.data.model.SnapOnIcon")) {
	Ext.define("Ext.ux.data.model.SnapOnIcon", {

		extend: "Ext.data.Model",

		alias: ["model.snaponicon"],

		fields: [
			{ name: "icon" },
			{ name: "score", type: "int" }
		],

		proxy: {
			type: "ajax",
			url: (ip2.isOffline) ? "ip2-services/ip2DmdProxy.php?action=snapOnIcons" : "/system/snapOnIcon.aspx?list=true",
			reader: {
				root: "rows"
			}
		}
	});
}

Ext.define('Ext.ux.data.store.SnapOnIcon', {

	extend: 'Ext.data.Store',

	model: 'Ext.ux.data.model.SnapOnIcon',

	sortRoot: 'score',

	listeners: {
		'beforeload': {
			fn: function(store, operation) {

				if (!operation.params.keyword.length) {
					operation.params.keyword = ' ';
				}
			}
		}
	}
});
Ext.define('Ext.ux.grid.Browser', {

	extend: 'Ext.grid.Panel',

	alias: 'widget.gridbrowser',

	mixins: {
		keyMapping: 'Ext.ux.util.KeyMapping'
	},

	extensions: '*',
	overwriteColumns: false,
	path: '/',
	service: null,

	pagebar: true,
	pagebarSizeEdit: true,
	pagebarSearch: true,
	pagebarSearchEmptyText: 'Search...',
	pagebarSearchWidth: 200,
	pagebarPosition: 'top',
	pageSize: 20,

	value: null,

	multiSelect: false,

	initComponent: function() {

		var i_cmp = this;
		var o_initial = i_cmp.initialConfig;

		var s_service = o_initial.service || (function () {
			var s_path = o_initial.path || i_cmp.path;
			return '/ip2-services/webbios.aspx?pathList=' + s_path + '&environment=gallery&omitList=system,_lock';
		})();

		var i_store = Ext.create('Ext.data.Store', {
			fields: ['name', 'path'],
			autoLoad: true,
			pageSize: o_initial.pageSize || i_cmp.pageSize,
			proxy: {
				type: 'ajax',
				url: s_service,
				reader: {
					type: 'json',
					root: 'rows',
					totalProperty: 'totalRows'
				},
				extraParams: {
					func: 'listDirByExtension',
					extnList: o_initial.extensions || i_cmp.extensions,
					metaData: true
				}
			}
		});

		// Prepare the default config object to apply
		var o_config = {
			cls: 'x-ux-imagegrid',
			store: i_store,
			listeners: {
				'itemdblclick': {
					fn: function () {
						i_cmp.doItemSelection();
					}
				}
			},
			columns: [
				{
					dataIndex: 'path',
					width: 70,
					renderer: function (s_path) {

						var s_height = 30;
						var b_image;

						b_image = (function (s_path) {

							var s_extension = s_path.split('.').pop().toLowerCase();
							var a_extension = ['gif', 'tiff', 'jpg', 'jpeg', 'tga', 'png', 'targa'];
							var b_image = Ext.Array.indexOf(a_extension, s_extension) > -1;

							return b_image;
						})(s_path);

						if (!b_image) {

							s_path = (function (s_path) {

								var a_file = s_path.split('.');
								var s_extension = a_file.pop();
								var a_extension = ['doc', 'docx', 'xls', 'xlsx', 'pdf', 'ppt'];
								var s_path;

								if (Ext.Array.indexOf(a_extension, s_extension) > -1) {
									s_path = '/portfolio/styles/icon/flatiu//media/' + s_extension + '.png';
								}
								else {
									s_path = '/portfolio/styles/icon/flatiu//media/generic-doc.png';
								}

								return s_path;
							})(s_path);
						}

						return '<img height="' + s_height + '" src="' + s_path + '">';
					}
				},
				{
					dataIndex: 'name',
					text: 'File',
					flex: 1
				}
			]
		};

		// Check to add pagingbar
		if (o_initial.pagingbar !== false) {
			o_config.dockedItems = Ext.Array.merge([], o_initial.dockedItems || [], [{
				xtype: 'extendedpagingtoolbar',
				itemId: 'pagingbar',
				store: i_store,
				dock: o_initial.pagebarPosition || i_cmp.pagebarPosition,
				pageSearch: o_initial.pagebarSearch || i_cmp.pagebarSearch,
				pageSearchWidth: o_initial.pagebarSearchWidth || i_cmp.pagebarSearchWidth,
				pageSearchEmptyText: o_initial.pagebarSearchEmptyText || i_cmp.pagebarSearchEmptyText,
				pageSizeEdit: o_initial.pagebarSizeEdit || i_cmp.pagebarSizeEdit
			}]);
		}

		// If we have columns passed in component configuration
		// And instanciator want to overwrite
		if (o_initial.columns && o_initial.overwriteColumns) {
			o_config.columns = o_initial.columns;
		}
		else if (o_initial.columns) {
			o_config.columns = Ext.Array.merge([], o_initial.columns || [], o_config.columns);
		}

		// Finally apply the configuration
		Ext.apply(i_cmp, o_config);

		// and call the parent constructor
		i_cmp.callParent();

		// Initialize any possible value(s) to place this/these item(s) first
		i_cmp.initValue();

		// Add Key navigation and interaction
		i_cmp.initKeyMapping();

		return i_cmp;
	},

	onEnterKey: function (i_record, n_index, e) {

		var i_cmp = this;

		i_cmp.doItemSelection();

		return i_cmp;
	},
	onRightKey: function (i_record, n_index, e) {

		var i_cmp = this;
		var b_pagingbar = i_cmp.pagebar;

		if (b_pagingbar) {
			i_cmp.down('#pagingbar').moveNext();
		}

		return i_cmp;
	},
	onLeftKey: function (i_record, n_index) {

		var i_cmp = this;
		var b_pagingbar = i_cmp.pagebar;

		if (b_pagingbar) {
			i_cmp.down('#pagingbar').movePrevious();
		}

		return i_cmp;
	},

	doItemSelection: function () {

		var i_cmp = this;
		var a_selected = i_cmp.getItemSelection();

		i_cmp.fireEvent('itemselect', i_cmp, a_selected);

		return i_cmp;
	},
	getItemSelection: function () {

		return this.getSelectionModel().getSelection();
	},

	initValue: function () {

		var i_cmp = this;
		var value = i_cmp.initialConfig.value;

		if (value) {
			i_cmp.setValue(value);
		}

		return i_cmp;
	},
	getValue: function () {

		return this.value;
	},
	setValue: function (value) {

		var i_cmp = this;
		var a_value = i_cmp.sanitizeValue(value);

		i_cmp.value = a_value;

		// Update the store proxy to handle a union of selected values
		i_cmp.updateStoreProxy();

		return i_cmp;
	},
	sanitizeValue: function (value) {

		var a_value = [];

		if (value) {
			a_value = (Ext.isArray(value)) ? value : [value];
		}

		return a_value;
	},

	updateStoreProxy: function () {

		var i_cmp = this;
		var i_store = i_cmp.getStore();
		var a_value = i_cmp.getValue();
		var a_union = [];

		Ext.Array.each(a_value, function (s_path, n_index) {
			a_union.push({
				property: 'path',
				value: s_path
			});
		});

		if (a_union.length) {
			i_store.proxy.extraParams.union = Ext.encode(a_union);
		}
		else {
			delete i_store.proxy.extraParams.union;
		}

		return i_cmp;
	}
});
Ext.define("Ext.ux.gallery.view.MediaEditor", {

	extend: "Ext.window.Window",

	alias: ["widget.gallerymediaeditor"],

	mixins: {
		componentController: "Ext.ux.util.ComponentController"
	},

	refs: [
		{
			ref: "tabpanel",
			selector: "tabpanel"
		},
		{
			ref: "form",
			selector: "form"
		},
		{
			ref: "picker",
			selector: "#uploadpicker"
		},
		{
			ref: "linkPanel",
			selector: "#linkpanel"
		},
		{
			ref: "layoutPanel",
			selector: "#layoutpanel"
		},
		{
			ref: "editorTabPanel",
			selector: "#editorTabPanel"
		}
	],

	layout: "fit",

	config: {
		_initialized: false,
		extensions: null,
		path: "",
		activeTab: null,
		type: "image",
		record: null,
		linkConfig: null,
		layoutConfig: null,
		ignoreStaticDir: false,
		originalValue: null,
		action: "add",
		mediaType: ""
	},

	save: function() {
		var i_self = this;
		var i_form = i_self.down("form").getForm();
		if (i_form.isValid() && i_self.fireEvent("beforesave", i_self)) {
			return i_self.doSave();
		}
		return false;
	},

	doSave: function() {
		var i_self = this;
		var el = i_self.getEl();

		var o_form = i_self.down("form");
		var delayCounter = 0;
		var b_doSave = true;

		var pop = function(status) {
			if (status === false) {
				b_doSave = status;
			}
			delayCounter--;

			if (delayCounter === 0) {
				if (b_doSave) {
					i_self._doSave(function() {
						el.unmask();
					});
				}
				else {
					el.unmask();
				}
			}
		};

		el.mask(ip2.i18n({
			da: "Gemmer...",
			en: "Saving..."
		}));
		var b_found = false;
		if (o_form) {
			var i_form = o_form.getForm();
			var o_fields = i_form.getFields();
			var a_fields = o_fields.items;

			Ext.Array.each(a_fields, function(i_field) {
				if (i_field.doSave && Ext.isFunction(i_field.doSave)) {
					delayCounter++;
					i_field.doSave(pop);
					b_found = true;
				}
			});
		}
		if (!b_found) {
			i_self._doSave();
		}
	},

	_doSave: function(fn) {
		var i_self = this;
		var o_values = this.getValues();
		var i_record = this.record;

		if (i_record) {
			i_self.fireEvent("update", o_values, i_record);
		}
		else {
			i_self.fireEvent("create", o_values);
		}
		// TODO: Make this callback fire when we are actually done with the submit
		fn && fn.call(i_self);
		i_self.fireEvent("aftersave", i_self, i_self.getRecord());
		i_self.destroy();
	},

	getRecord: function() {
		return this.record;
	},

	initComponent: function () {

		var i_cmp = this;
		var o_initial = i_cmp.initialConfig;
		i_cmp.initComponentController();

		Ext.apply(i_cmp, {
			extensions: o_initial.extensions,
			path: o_initial.path || i_cmp.path,
			ignoreStaticDir: o_initial.ignoreStaticDir || i_cmp.ignoreStaticDir,
			buttons: [
				{
					text: ip2.i18n({
						en: "OK",
						da: "OK"
					}),
					itemId: "okbutton",
					disabled: true,
					handler: function () {

						i_cmp.save();
					}
				},
				{
					text: ip2.i18n({
						en: "Cancel",
						da: "Annuller"
					}),
					handler: function () {

						i_cmp.fireEvent("cancel", i_cmp, i_cmp.getRecord());
						i_cmp.destroy();
					}
				}
			]
		});

		i_cmp.callParent(arguments);

		i_cmp.createLayout();

		i_cmp.control({
			form: {
				activate: i_cmp.onPropertiesActivate,
				afterrender: i_cmp.onPropertiesAfterrender
			},
			picker: {
				activate: i_cmp.onImagePickerActivate,
				itemselect: i_cmp.onImageSelect
			}
		});

		i_cmp.on({
			afterrender: {
				fn: i_cmp.onAfterRender
			}
		});

		return i_cmp;
	},

	createTabpanel: function(o_config) {
		var i_cmp = this;
		var activeTab = o_config.activeTab || 0;
		var i_tabpanel = Ext.widget("tabpanel", {
			xtype: "tabpanel",
			itemId: "editorTabPanel",
			border: false,
			activeTab: activeTab,
			layout: "fit",
			items: [i_cmp.createForm()]
		});
		return i_tabpanel;
	},

	createForm: function(o_config) {
		var i_cmp = this;
		var i_record = i_cmp.getRecord();
		var s_value = i_record ? i_record.get("url") : null;

		var a_items = i_cmp.createFormItems(o_config);

		a_items.push(i_cmp.createPickerField(o_config));

		var i_form = Ext.widget("form", {
			title: ip2.i18n({
				da: "Medie",
				en: "Media"
			}),
			itemId: "mediaproperties",
			layout: "anchor",
			bodyPadding: 15,
			fieldDefaults: {
				anchor: "100%",
				labelWidth: 100
			},
			trackResetOnLoad: true,
			listeners: {
				dirtychange: {
					fn: function (i_self, b_dirty) {
						i_cmp.checkChange();
					}
				},
				validitychange: {
					fn: function (i_self, b_valid) {
						if (!b_valid) {
							i_cmp.down("#okbutton").disable();
						}
						else {
							i_cmp.checkChange();
							i_cmp.down("#okbutton").enable();
						}
					}
				}
			},
			items: a_items
		});
		return i_form;
	},

	createFormItems: function(o_config) {
		var i_cmp = this;
		var a_items = [];
		a_items.push({
			xtype: "hidden",
			name: "type"
		},
		{
			xtype: "i18ntextfield",
			itemId: "title",
			name: "title",
			fieldLabel: ip2.i18n({
				da: "Overskrift",
				en: "Headline"
			}),
			emptyText: ip2.i18n({
				da: "Overskrift til mediet",
				en: "Headline for the media"
			}),
			userChange: false,
			listeners: {
				change: {
					fn: function(item, value) {
						if (!i_cmp.systemSet) {
							item.userChange = true;
						}
						if (!item.isDirty()) {
							item.userChange = false;
						}
					}
				}
			}
		},
		{
			xtype: "i18ntextmarkdownfield",
			fieldLabel: ip2.i18n({
				da: "Tekst",
				en: "Text"
			}),
			emptyText: ip2.i18n({
				da: "Indtast en kort tekst som underbygger overskriften og mediet",
				en: "Enter a short text that supports the headline and the media"
			}),
			name: "caption",
			height: 100,
			userChange: false,
			listeners: {
				change: {
					fn: function(item, value) {
						if (!i_cmp.systemSet) {
							item.userChange = true;
						}
						if (!item.isDirty()) {
							item.userChange = false;
						}
					}
				}
			}
		});
		return a_items;
	},

	createPickerField: function(o_config) {
		var i_cmp = this;
		var i_picker = Ext.widget("uploadpicker", {
			itemId: "uploadpicker",
			name: "url",
			path: i_cmp.path,
			extensions: i_cmp.extensions,
			ignoreStaticDir: i_cmp.ignoreStaticDir,
			allowBlank: true,
			userChange: false,
			submitRaw: false,
			fieldLabel: ip2.i18n({
				da: "Medie",
				en: "Media"
			}),
			emptyText: ip2.i18n({
				da: "Sti til lokalt medie eller URL til eksternt medie",
				en: "Path to local media or URL to external media"
			})
		});
		return i_picker;
	},

	createLinkStacks: function(o_linkConfig) {
		var i_cmp = this;
		var i_record = i_cmp.getRecord();
		var s_value = i_record ? i_record.get("url") : null;
		var o_stackPanel = ip2.extend({
			xtype: "ip2TreeSelector",
			wrapper: {
				getRecord: function () {
					return {
						data: {}
					};
				}
			},
			itemId: "linktypestack",
			name: "stack",
			title: ip2.i18n({
				da: "Stakke",
				en: "Stacks"
			}),
			omitChild: false,
			expandRootNode: false,
			multiSelect: false,
			extraColumns: [
				{
					text: {
						da: "Sidetype",
						en: "Page type"
					},
					dataIndex: "__cid__",
					uitype: "xpdCollectionTitle",
					flex: 1
				}
			],
			addToAllChildren: {
				allow: false
			},
			listeners: {
				change: {
					fn: function (i_self, a_checked) {
						if (!a_checked.length) {
							i_cmp.onLinkTypeDeselect("linktypestack");
						}
						else {
							i_cmp.onLinkTypeSelect("linktypestack");
						}
						i_cmp.checkChange();
					}
				}
			},
			getValue: function () {

				var i_self = this;
				var i_checked = i_self.getChecked()[0];

				if (!i_checked) {
					return "";
				}

				var o_values;
				var o_properties = Ext.decode(i_checked.get("extraProps"), true).properties;

				if (i_checked.parentNode && !i_checked.parentNode.isRoot()) {

					var i_parentNode = i_checked.parentNode;
					var o_parent = Ext.decode(i_parentNode.get("extraProps"), true).properties;

					o_values = {
						page: {
							hash: o_parent.seourl,
							token: o_parent.token
						},
						token: o_properties.token,
						title: o_properties.title,
						type: "stack"
					};
				}
				else {
					o_values = {
						type: "stack",
						token: o_properties.token,
						title: o_properties.title
					};
				}

				return o_values;
			},
			setValue: function (o_value) {

				o_value = o_value || {};

				var i_self = this;
				var i_store = i_self.getStore();
				var n_token = Number(o_value.token);
				var n_parentToken;
				var s_path;
				var a_path;

				if (!n_token) {
					return;
				}

				var b_parent = (function (o_config) {
					return (o_config && o_config.token);
				})(o_value.page);

				a_path = ["/0"];

				if (b_parent) {
					a_path.push(o_value.page.token);
					n_parentToken = o_value.page.token;

					// n_parentToken = Number(o_value.page.token); // TODO: Why was this here?
				}

				a_path.push(n_token);

				s_path = a_path.join("/");

				// Path is sorted, now wait on the rendering and
				// store loading

				i_store.on({
					load: {
						fn: function(i_store, a_records) {
							if (b_parent) {
								Ext.Array.each(a_records, function(i_record) {

									var o_properties = Ext.decode(i_record.get("extraProps"), true) || {};

									if (o_properties.token == n_parentToken) {
										i_record.expand();
										b_parent = false;
										delete n_parentToken;
									}
								});

								i_self.selectPath(s_path);
							}
							else {
								if (n_token) {
									Ext.Array.each(a_records, function(i_record) {

										var o_properties = Ext.decode(i_record.get("extraProps"), true) || {};

										if (o_properties.token == n_token) {
											var i_selectionModel = i_self.getSelectionModel();
											i_record.set("checked", true);
											i_selectionModel.select(i_record);
											delete n_token;
										}
									});
								}
							}
						}
					}
				});

				return i_self;
			}
		}, o_linkConfig.stacks);

		return o_stackPanel;
	},

	createLinkPages: function(o_linkConfig) {

		var i_cmp = this;
		var i_record = i_cmp.getRecord();
		var s_value = i_record ? i_record.get("url") : null;

		if (o_linkConfig.pages.view) {

			o_linkConfig.pages.uiName = o_linkConfig.pages.view;
			delete o_linkConfig.pages.view;
		}

		var o_info = {
			dmd: {
				path: o_linkConfig.pages.dmd,
				entityName: o_linkConfig.pages.entity || o_linkConfig.pages.entityName
			}
		};

		var o_pagePanel = ip2.extend({
			title: ip2.i18n({
				da: "Side",
				en: "Page"
			}),
			xtype: "entity.grid",
			name: "page",
			itemId: "linktypepage",
			selModel: {
				selType: "checkboxmodel", 
				mode: "SINGLE",
				allowDeselect: true
			},
			autoSelect: false,
			searchCombo: false,
			getValue: function () {

				var i_self = this;
				var s_titleId = i_self.titleId;

				var o_value = "";

				var i_record;
		
				var a_records = i_self.getSelectionModel().getSelection();
		
				if (a_records.length > 0) {
		
					i_record = a_records[0];
		
					o_value = {
						type: i_self.name,
						token: i_record.get(i_record.idProperty)
					};
		
					if (s_titleId && i_record.get(s_titleId)) {
						o_value.title = i_record.get(s_titleId);
					}
				}
		
				return o_value;
			},
			setValue: function (o_value) {
		
				var i_self = this;
				var i_store = i_self.getStore();
				var i_model = i_store.getModel();
				var i_proxy = i_store.getProxy();
				var s_primaryId = i_model.idProperty;

				var o_extraParams = i_proxy.getExtraParams();
				var n_token = o_value.token;
		
				i_self.value = o_value;
		
				if (n_token) {
		
					i_self.primaryKey = n_token;
					i_self.titleKey = o_value.title || null;
		
					o_extraParams.union = Ext.encode([{
						property: s_primaryId,
						value: n_token
					}]);
		
					i_store.load();
				}
		
				return i_self;
			}
		}, o_linkConfig.pages);

		Ext.apply(o_pagePanel, o_info);

		var i_linkGrid = Ext.widget("entity.grid", o_pagePanel);

		i_linkGrid.events.selectionchange.clearListeners();
		i_linkGrid.events.itemdblclick.clearListeners();
		i_linkGrid.events.itemcontextmenu.clearListeners();

		i_linkGrid.on({
			select: {
				fn: function (i_self, i_record) {

					var i_grid = i_self.view.up();
					var i_store = i_grid.getStore();
					var i_model = i_store.getModel();
					var s_primaryId = i_model.idProperty;
					var n_key = i_record.get(s_primaryId);

					i_grid.primaryKey = n_key;
					i_grid._record = i_record;

					var i_proxy = i_store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();

					o_extraParams.union = Ext.encode([{
						property: s_primaryId,
						value: n_key
					}]);

					i_cmp.checkChange();

					i_cmp.onLinkTypeSelect("linktypepage");
				}
			},
			deselect: {
				fn: function (i_self) {

					var i_grid = i_self.view.up();
					var i_store = i_grid.getStore();

					var i_proxy = i_store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();

					delete o_extraParams.union;

					i_grid.primaryKey = null;
					i_grid._record = null;

					i_cmp.checkChange();

					i_cmp.onLinkTypeDeselect();
				}
			}
		});

		var i_store = i_linkGrid.getStore();

		i_store.on({
			load: {
				fn: function(i_store, a_records) {
					
					if (i_linkGrid.value) {

						var n_token = i_linkGrid.value.token;

						var i_found = Ext.Array.findBy(a_records, function(i_record) {
							return i_record.get(i_record.idProperty) == n_token;
						});

						if (i_found) {
							var i_view = i_linkGrid.getView();
							i_view.select([i_found]);
						}
					}
				}
			}
		});

		return i_linkGrid;
	},

	createLinkDocuments: function(o_linkConfig) {
		var i_cmp = this;
		var i_record = i_cmp.getRecord();
		var s_value = i_record ? i_record.get("url") : null;
		var o_documentsGallery = ip2.extend({
			xtype: "mediagallery",
			itemId: "documentgallery",
			listeners: {
				afterrender: {
					fn: function (i_self) {

						i_self.on({
							create: {
								fn: function () {
									i_cmp.checkChange();
									i_cmp.onLinkTypeSelect("linktypedocument");
								}
							},
							empty: {
								fn: function () {
									i_cmp.checkChange();
									i_cmp.onLinkTypeDeselect("linktypedocument");
								}
							}
						});
					}
				}
			}
		}, o_linkConfig.documents);

		var o_documentPanel = ip2.extend({
			xtype: "panel",
			title: ip2.i18n({
				da: "Dokument",
				en: "Document"
			}),
			itemId: "linktypedocument",
			name: "document",
			items: [ o_documentsGallery ],
			getValue: function () {

				var i_self = this;
				var i_document = i_self.down("#documentgallery");
				var o_value = i_document.getValue();

				return {
					type: "document",
					value: o_value
				};
			},
			setValue: function (o_value) {

				var i_self = this;
				var i_document = i_self.down("#documentgallery");

				i_document.setValue(o_value.value);
			}
		});

		return o_documentPanel;
	},

	createLinkPanel: function() {
		var i_cmp = this;
		var i_record = i_cmp.getRecord();
		var s_value = i_record ? i_record.get("url") : null;
		var o_linkPanel = {
			xtype: "form",
			itemId: "linktypeurl",
			name: "url",
			title: ip2.i18n({
				da: "URL",
				en: "URL"
			}),
			layout: "anchor",
			bodyPadding: 15,
			getValue: function () {

				var i_self = this;
				var i_input = i_self.down("#linktypeurlvalue");
				var o_values;
				var value = i_input.getValue();

				if (value) {
					o_values = {
						type: i_self.name,
						url: i_input.getValue()
					};
				}
				else {
					o_values = "";
				}

				return o_values;
			},
			setValue: function (o_values) {

				var i_self = this;
				var i_input = i_self.down("#linktypeurlvalue");
				var s_value = o_values.url;

				i_input.setValue(s_value);

				return i_self;
			},
			items: [
				{
					xtype: "textfield",
					itemId: "linktypeurlvalue",
					name: "value",
					anchor: "100%",
					isFormField: false,
					fieldLabel: ip2.i18n({
						da: "Indtast URL",
						en: "Enter URL"
					}),
					listeners: {
						change: {
							fn: function (i_self, s_value) {
								if (s_value.length) {
									i_cmp.onLinkTypeSelect("linktypeurl");
								}
								else {
									i_cmp.onLinkTypeDeselect();
								}

								i_cmp.checkChange();
							}
						}
					}
				}
			]
		};
		return o_linkPanel;
	},

	createLayout: function() {
		var i_cmp = this;
		var o_initial = i_cmp.initialConfig;
		var i_tabpanel = i_cmp.createTabpanel(o_initial);
		i_cmp.add(i_tabpanel);

		var o_linkConfig = i_cmp.linkConfig;

		if (o_linkConfig) {

			var a_linkItems = [];

			if (o_linkConfig.stacks) {
				a_linkItems.push(i_cmp.createLinkStacks(o_linkConfig));
			}

			if (o_linkConfig.pages) {

				a_linkItems.push(i_cmp.createLinkPages(o_linkConfig));
			}

			if (o_linkConfig.documents) {
				a_linkItems.push(i_cmp.createLinkDocuments(o_linkConfig));
			}

			a_linkItems.push(i_cmp.createLinkPanel(o_initial));

			var o_linkPanel = ip2.extend({}, o_linkConfig, {
				xtype: "tabpanel",
				itemId: "linkpanel",
				layout: "fit",
				title: ip2.i18n({
					da: "Link",
					en: "Link"
				}),
				getValue: function () {

					var i_self = this;
					var i_activeTab = i_self.activeTab;
					var o_values;

					if (i_activeTab) {
						o_values = i_activeTab.getValue();
					}

					return o_values;
				},
				setValue: function (o_value) {

					var i_self = this;
					var s_type = o_value.type;
					var i_tab = i_self.down("[name=" + s_type + "]");

					i_cmp.onLinkTypeSelect(i_tab.itemId);

					i_tab.setValue(o_value);

					return i_self;
				},
				items: a_linkItems
			});

			i_cmp.getEditorTabPanel().add(o_linkPanel);

			// If we have a linkConfig then we will add a combo that will
			// allow us to pick how this link should behave
			i_cmp.down("#mediaproperties").add({
				xtype: "combo",
				name: "target",
				fieldLabel: ip2.i18n({
					da: "Åben indhold i",
					en: "Open contents in"
				}),
				displayField: "value",
				valueField: "key",
				value: "parent",
				store: {
					fields: ["key", "value"],
					data: [
						{
							key: "parent",
							value: ip2.i18n({
								da: "Samme vindue (Normal)",
								en: "Same window (Normal)"
							})
						},
						{
							key: "blank",
							value: ip2.i18n({
								da: "Nyt vindue",
								en: "New window"
							})
						},
						{
							key: "lightbox",
							value: ip2.i18n({
								da: "Lightbox",
								en: "Lightbox"
							})
						}
					]
				}
			});
		}

		// If layout object config then add to tabpanel
		var o_layoutConfig = i_cmp.layoutConfig;

		if (o_layoutConfig) {
			var value = o_layoutConfig.value || {};
			if (i_cmp.record.get("layout")) {
				value = i_cmp.record.get("layout");
			}
			var o_xpdConfig = ip2.extend({}, o_layoutConfig, {
				xtype: "xpdfield",
				itemId: "layoutXpd",
				anchor: "100%",
				value: JSON.stringify(value),
				listeners: {
					dirtychange: {
						fn: function (i_self, b_dirty) {
							i_cmp.checkChange();
						}
					},
					validitychange: {
						fn: function (i_self, b_valid) {
							if (!b_valid) {
								i_cmp.down("#okbutton").disable();
							}
							else {
								i_cmp.checkChange();
								i_cmp.down("#okbutton").enable();
							}
						}
					}
				}
			});

			i_cmp.getEditorTabPanel().add({
				xtype: "panel",
				itemId: "layoutpanel",
				title: ip2.i18n({
					da: "Layout",
					en: "Layout"
				}),
				border: false,
				bodyPadding: 15,
				autoScroll: true,
				layout: "anchor",
				items: [o_xpdConfig],
				getXpdField: function () {
					return this.down("xpdfield");
				},
				resetOriginalValue: function () {

					var i_self = this;
					var i_xpd = i_self.getXpdField();

					i_xpd.resetOriginalValue();

					return i_self;
				},
				getValue: function () {

					var i_self = this;
					var i_xpd = i_self.getXpdField();
					var s_value = i_xpd.getValue();

					return JSON.parse(s_value);
				},
				setValue: function (o_value) {

					var i_self = this;
					var i_xpd = i_self.getXpdField();
					var s_value = JSON.stringify(o_value);

					i_xpd.setValue(s_value);

					return i_self;
				}
			});
		}
	},

	onAfterRender: function () {

		var i_cmp = this;
		var i_form = i_cmp.getForm();
		var i_linkPanel = i_cmp.getLinkPanel();
		var i_layoutPanel = i_cmp.getLayoutPanel();
		var i_picker = i_cmp.getPicker();
		var s_type = i_cmp.type;
		var i_record = i_cmp.record;

		// If we have a record - then we are editing
		// Load it into the form
		if (i_record) {

			i_form.loadRecord(i_record);

			// The link tab needs special treatment
			var o_link = i_record.get("link");
			if (o_link && i_linkPanel) {
				i_linkPanel.setValue(o_link);
				i_cmp._link = o_link;
			}

			// The layout tab needs special treatment
			var o_layout = i_record.get("layout");
			if (o_layout && i_layoutPanel) {
				i_layoutPanel.setValue(o_layout);
				i_layoutPanel.resetOriginalValue();
				i_cmp._layout = o_layout;
			}
		}

		i_cmp.originalValue = i_cmp.getValues();

		i_cmp._initialized = true;

		return i_cmp;
	},

	onPropertiesAfterrender: function () {

		var i_cmp = this;
		var i_form = i_cmp.getForm();

		i_form.getEl().on("keydown", function (e, i_htmlNode, eOpts) {

			var b_enter = e.browserEvent.keyIdentifier == "Enter";
			var b_shift = e.shiftKey;

			if (b_enter && !b_shift) {
				//i_cmp.save();
			}
		});

		return i_cmp;
	},

	onPropertiesActivate: function () {

		var i_cmp = this;

		setTimeout(function () {
			i_cmp.down("#uploadpicker").focus();
			i_cmp.down("#title").focus();
		}, 100);

		return i_cmp;
	},

	onImagePickerActivate: function () {

		var i_cmp = this;
		var	i_picker = i_cmp.getPicker();
		var	i_selectionModel = i_picker.getSelectionModel();

		setTimeout(function () {
			var selected = i_selectionModel.getSelection();
			if (!selected.length) {
				selected = i_picker.getStore().getAt(0);
			}
			i_picker.getView().focus();
			i_selectionModel.select(selected);
		}, 100);

		return i_cmp;
	},

	onImageSelect: function (i_grid, a_records) {

		var i_cmp = this;
		var i_form = i_cmp.getForm();
		var i_url = i_form.down("[name=url]");
		var i_record = a_records[0];
		var s_url = i_record.get("path");

		s_url = ip2.cleanPath("/" + s_url);

		i_url.setValue(s_url);

		i_form.show();

		return i_cmp;
	},

	onLinkTypeSelect: function (s_itemId) {

		var i_cmp = this;
		var i_linkPanel = i_cmp.getLinkPanel();

		i_linkPanel.items.each(function (i_item) {
			if (i_item.itemId != s_itemId) {
				i_item.disable();
			}
			else {
				i_item.enable();
				i_linkPanel.setActiveTab(i_item);
			}
		});

		return i_cmp;
	},
	onLinkTypeDeselect: function () {

		var i_cmp = this;
		var i_linkPanel = i_cmp.getLinkPanel();

		i_linkPanel.items.each(function (i_item) {
			i_item.enable();
		});

		return i_cmp;
	},

	getValues: function () {

		var i_cmp = this;
		var i_form = i_cmp.getForm();
		i_form = i_form.getForm();

		var o_formValues = i_form.getFieldValues();
		var o_values = o_formValues || {};

		var i_linkPanel = i_cmp.getLinkPanel();

		if (i_linkPanel) {
			o_values.link = i_linkPanel.getValue();
			if (o_values.link) {
				o_values.link.target = o_values.target;
			}
		}

		var i_layoutPanel = i_cmp.getLayoutPanel();

		if (i_layoutPanel) {
			o_values.layout = i_layoutPanel.getValue();
		}

		return o_values;
	},

	getPath: function () {

		return this.initialConfig.path || this.path;
	},

	checkChange: function () {

		var i_cmp = this;
		var i_button = i_cmp.down("#okbutton");
		var value = i_cmp.getValues();
		var originalValue = i_cmp.originalValue;

		if (!ip2.isEqual(value, originalValue) && i_cmp._initialized) {
			//i_button.enable();
		}
		else {
			//i_button.disable();
		}

		return i_cmp;
	}
});
Ext.define("Ext.ux.gallery.Media", {

	extend: "Ext.panel.Panel",

	alias: ["widget.mediagallery"],

	mixins: {
		componentController: "Ext.ux.util.ComponentController"
	},

	refs: [
		{
			ref: "dropbox",
			selector: "gallerydropbox"
		},
		{
			ref: "grid",
			selector: "gallerymediagrid"
		},
		{
			ref: "toolbar",
			selector: "#gallerytoolbar"
		}
	],

	border: true,
	config: {
		galleryGrid: null,
		store: null,
		addButton: null,
		pageSize: 0,
		path: "",
		maxItems: -1,
		layoutConfig: null,
		linkConfig: null,
		editorConfig: null,
		extensions: "*",
		dragText: "",
		dropText: "",
		confirmRemoveRowText: "",
		confirmRemoveRowsText: "",
		ignoreStaticDir: false,
		itemCreateText: "",
		itemEditText: "",
		itemRemoveText: "",
		itemCreateTitle: "",
		itemEditTitle: "",
		actionColumns: null,
		dropzone: null,
		contextMenu: null,
		fields: null,
		uploading: false,
		isValueInit: false,
		mediaType: ""
	},

	initComponent: function () {

		var i_self = this;
		var o_config = i_self.initialConfig;

		// Apply non-primitive configurations defaults
		Ext.apply(i_self, {
			linkConfig: o_config.linkConfig || i_self.linkConfig,
			layoutConfig: o_config.layoutConfig || i_self.layoutConfig,
			actionColumns: o_config.actionColumns || {},
			ignoreStaticDir: o_config.ignoreStaticDir || i_self.ignoreStaticDir,
			dragText: o_config.dragText || {
				en: "Drag and drop a row to reorder",
				da: "Slip for at re-arrangere rækkefølge"
			},
			dropText: o_config.dropText || {
				en: "Drag-and-drop your images here",
				da: "Træk-og-slip dine billeder her"
			},
			confirmRemoveRowText: o_config.confirmRemoveRowText || {
				da: "Ønsker du virkelig at fjerne denne række?",
				en: "Do you really wish to remove this row?"
			},
			confirmRemoveRowsText: o_config.confirmRemoveRowsText || {
				da: "Ønsker du virkelig at fjerne de valgte rækker?",
				en: "Do you really wish to remove the selected rows?"
			},
			itemCreateTitle: o_config.itemCreateTitle || {
				da: "Tilføj nyt emne",
				en: "Add new item"
			},
			itemEditTitle: o_config.itemEditTitle || {
				da: "Rediger",
				en: "Edit"
			},
			itemCreateText: o_config.itemCreateText || {
				da: "Tilføj",
				en: "Add"
			},
			itemEditText: o_config.itemEditText || {
				da: "Rediger",
				en: "Edit"
			},
			itemRemoveText: o_config.itemRemoveText || {
				da: "Fjern",
				en: "Remove"
			},
			bodyStyle: {
				"background-color": "white"
			},
			editorConfig: {
				renderTo: Ext.getBody(),
				width: "60%",
				height: "60%",
				autoShow: true,
				linkConfig: i_self.linkConfig,
				layoutConfig: i_self.layoutConfig,
				path: i_self.path,
				extensions: i_self.extensions,
				ignorestaticdir: i_self.ignoreStaticDir,
				modal: false,
				mediaType: i_self.getMediaType(),
				listeners: {
					update: {
						fn: i_self.updateData,
						scope: i_self
					},
					create: {
						fn: i_self.createData,
						scope: i_self
					},
					destroy: {
						fn: i_self.refocusGrid,
						scope: i_self
					}
				}
			}
		});

		// Initialize the component controller utility mixin
		i_self.initComponentController();

		// Call the parent class for the class chain
		i_self.callParent(arguments);

		i_self.addStore();

		// Add the needed store and components
		i_self.addComponents();

		// Add the control object for event handling
		i_self.addControls();

		i_self.initValue();

		return i_self;
	},

	initValue: function () {

		var i_self = this;
		var value = i_self.value;

		i_self.setValue(value);
		i_self.originalValue = value;
		i_self.isValueInit = true;

		return i_self;
	},

	// Add the store, components and the control objects for components
	addStore: function () {

		var i_self = this;
		var o_actionColumns = i_self.actionColumns;

		var a_fields = [
			{ name: "RELCHDTKN", type: "int" },
			{ name: "_id", type: "string" },
			{ name: "url", type: "auto", defaultValue: "" },
			{ name: "name", type: "string", defaultValue: "" },
			{ name: "sequence", type: "int" },
			{ name: "layout", type: "auto", defaultValue: "" },
			{ name: "link", type: "auto", defaultValue: "" },
			{ name: "title", type: "auto", defaultValue: "" },
			{ name: "caption", type: "auto", defaultValue: "" },
			{ name: "type", type: "string", defaultValue: "image" },
			{ name: "target", type: "string", defaultValue: "" }
		];

		i_self.fields = a_fields;

		// Add the action columns (all boolean)
		Ext.Object.each(o_actionColumns, function (s_key, o_config) {
			a_fields.push({
				name: s_key,
				type: "boolean",
				defaultValue: false
			});
		});

		var i_store = Ext.create("Ext.data.Store", {
			fields: a_fields,
			proxy: {
				type: "memory",
				reader: {
					type: "json",
					rootProperty: "images"
				}
			}
		});

		i_self.setStore(i_store);

		return i_self;
	},

	addComponents: function () {

		var i_self = this;
		var o_initial = i_self.initialConfig;
		var i_store = i_self.getStore();
		

		var i_galleryGrid = Ext.widget("gallerymediagrid", {
			store: i_store,
			multiSelect: true,
			linkConfig: i_self.linkConfig,
			actionColumns: i_self.actionColumns,
			viewConfig: {
				plugins: [
					{
						ptype: "gridviewdragdrop",
						dragText: ip2.i18n(o_initial.dragText || i_self.dragText)
					}
				],
				listeners: {
					beforedrop: {
						fn: function(node, data, overRecord, position) {
							var i_store = data.view.ownerCt.getStore();
							i_store.fireEvent("beforereorder", i_store);
						}
					},
					drop: {
						fn: function(node, data, overRecord, position) {
							var i_store = data.view.ownerCt.getStore();
							var a_data = i_store.data.items;
							var n_index = 0;
							var b_found = false;
							Ext.Array.each(a_data, function(i_record) {
								if (i_record.get("RELCHDTKN") == data.records[0].get("RELCHDTKN")) {
									b_found = true;
								}
								if (!b_found) {
									n_index++;
								}
							});
							if (!b_found) {
								n_index = 0;
							}
							i_store.fireEvent("reorder", i_store, data.records, n_index);
						}
					}
				}
			},
			listeners: {
				afterrender: {
					fn: function(i_grid) {

						var i_store = i_grid.getStore();

						var a_records = i_store.getRange();

						i_galleryGrid[Ext.isEmpty(a_records) ? "hide" : "show"]();
					}
				}
			}
		});

		i_store.on({
			datachanged: {
				fn: function(i_store) {

					var a_records = i_store.getRange();

					i_galleryGrid[Ext.isEmpty(a_records) ? "hide" : "show"]();
				}
			}
		});

		var i_addButton = Ext.widget("button", {
			itemId: "createButton",
			text: ip2.i18n(i_self.itemCreateText),
			handler: function () {
				i_self.onCollectionItemAdd();
			}
		});

		i_self.add([
			{
				xtype: "container",
				layout: {
					type: "hbox",
					align: "center"
				},
				style: {
					"background-color": "white",
					"padding": "7px"
				},
				defaults: {
					margin: "0px 10px 0px 0px"
				},
				items: [
					i_addButton,
					{
						xtype: "gallerydropbox",
						extensions: o_initial.extensions || i_self.extensions,
						dropText: o_initial.dropText || i_self.dropText,
						flex: 1,
						padding: 2,
						maxItems: i_self.maxItems,
						margin: "0px 0px 0px 0px"
					}
				]
			},
			i_galleryGrid
		]);

		i_self.contextMenu = Ext.widget("menu", {
			renderTo: Ext.getBody(),
			items: [
				{
					xtype: "menuitem",
					itemId: "editButton",
					text: ip2.i18n(i_self.itemEditText),
					iconCls: "pf-edit"
				},
				{
					xtype: "menuitem",
					itemId: "removeButton",
					text: ip2.i18n(i_self.itemRemoveText),
					iconCls: "pf-delete"
				},
				{
					xtype: "menuitem",
					itemId: "previewButton",
					text: ip2.i18n({
						da: "Preview",
						en: "Preview"
					}),
					iconCls: "pf-eye"
				}
			]
		});

		i_self.setGalleryGrid(i_galleryGrid);
		i_self.setAddButton(i_addButton);

		return i_self;
	},

	addControls: function () {

		var i_self = this;

		i_self.on({
			afterrender: {
				fn: function (i_self) {
					i_self.syncButtons();
				},
				single: true
			},
			create: {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			},
			update: {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			},
			remove: {
				fn: function (i_self) {
					i_self.checkAutoSelectColumns();
					i_self.syncButtons();
				}
			},
			empty: {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			}
		});

		i_self.control({
			"grid": {
				itemedit: i_self.onCollectionItemEdit,
				itemdblclick: i_self.onCollectionItemEdit,
				itemremove: i_self.onCollectionItemRemove,
				deletekey: i_self.onCollectionItemRemove,
				itemcontextmenu: i_self.onCollectionContext,
				scope: i_self
			},
			"dropbox": {
				drop: i_self.onDrop,
				beforedrop: i_self.onBeforeDrop,
				dragenter: i_self.onDragEnter
			}
		});

		return i_self;
	},

	openItemEditor: function (i_record) {

		var i_self = this;
		var o_defaults = i_self.editorConfig;

		var o_config = {
			title: i_record ?
				[
					ip2.i18n(i_self.itemEditTitle),
					i_record.get("url")
				].join(" ")
				:
				ip2.i18n(i_self.itemCreateTitle),
			record: i_record,
			ignoreStaticDir: i_self.ignoreStaticDir,
			type: i_record ? i_record.get("type") : "image",
			activeTab: "mediaproperties"
		};

		Ext.apply(o_config, o_defaults);

		var i_window = Ext.widget("gallerymediaeditor", o_config);

		i_window.on("aftersave", function(item, record) {
			i_self.createData([record], true);
		});

		return i_self;
	},

	// Component control event handling methods
	onDragEnter: function (i_dropbox, o_event) {

		var i_self = this;

		var i_plugin = i_dropbox.getDDPlugin();
		var b_valid = i_self.validateDrop(o_event);

		if (!b_valid) {
			i_dropbox.addCls(i_plugin.failureCls);
		}
	},

	onBeforeDrop: function (i_dropbox, i_files, o_event) {

		var i_self = this;
		var b_valid = i_self.validateDrop(o_event);

		return b_valid;
	},

	onDrop: function (i_dropbox, i_files) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_el = i_self.getEl();
		var a_concat = [];
		var s_path = "";

		var s_preset = ip2.preset.staticPath || "pp-static";

		if (i_self.ignoreStaticDir) {
			s_path = i_self.path;
		}
		else {
			s_path = ip2.cleanPath([s_preset, i_self.path].join("/"));
		}

		var msg = ip2.i18n({
			da: "Kontrolerer filer....",
			en: "Checking files..."
		});
		i_el.mask(msg);

		Ext.ux.file.util.Handler.checkFiles(s_path, i_files, function(o_result) {

			i_el.unmask();
			var a_update = o_result.update;
			var a_create = o_result.create;
			var b_update = false;
			var b_cancel = false;
			var b_create = false;
			var msg;

			if (a_update.length > 0) {
				b_update = true;
				var b_override = false;
				var b_rename = false;
				Ext.ux.file.util.Handler.getUIConflickWindow(
					i_el.el,
					i_self,
					s_path,
					a_update,
					function(cancel, a_override, a_rename) {

						b_cancel = cancel;
						if (a_override.length > 0) {
							b_override = true;
							msg = ip2.i18n({
								da: "Overskriver filer....",
								en: "Overriding files..."
							});
							i_el.mask(msg);
							var a_files = [];
							Ext.Array.each(a_override, function(o_file) {
								a_files.push(o_file.file);
							});
							if (Ext.ux.file.util.Handler.hasFileManager()) {
								var a_names = [];
								Ext.Array.each(a_files, function(o_file) {
									a_names.push(o_file.name);
								});
								var s_url = path = ip2.cleanPath(s_path) + "/";
								Ext.ux.file.util.Handler.getRecordsByName(s_url, a_names, function(a_records) {
									if (a_records.length === 0) {
										Ext.ux.file.util.Handler.createRecords(s_path, a_files, false, function(a_records) {
											a_concat = a_concat.concat(a_files);
											b_override = false;
											if (!b_rename && !b_create) {
												i_el.unmask();
												i_self.createFromFiles(a_concat, s_path, true);
											}
										});
									}
									else {
										var a_create = [];
										Ext.Array.each(a_files, function(o_file) {
											var b_found = false;
											Ext.Array.each(a_names, function(s_name) {
												if (s_name == o_file.name) {
													b_found = true;
												}
											});
											if (!b_found) {
												a_create.push(o_file);
											}
										});
										if (a_create.length > 0) {
											Ext.ux.file.util.Handler.createRecords(s_path, a_create, false, function(a_records) {
												a_concat = a_concat.concat(a_files);
												b_override = false;
												if (!b_rename && !b_create) {
													i_el.unmask();
													i_self.createFromFiles(a_concat, s_path, true);
												}
											});
										}
										else {
											a_concat = a_concat.concat(a_files);
											b_override = false;
											if (!b_rename && !b_create) {
												i_el.unmask();
												i_self.createFromFiles(a_concat, s_path, true);
											}
										}
									}
								});
							}
							else {
								Ext.ux.file.util.Handler.uploadFiles(s_path, a_files, false, function(a_records) {
									a_concat = a_concat.concat(a_files);
									b_override = false;
									if (!b_rename && !b_create) {
										i_el.unmask();
										i_self.createFromFiles(a_concat, s_path, true);
									}
								});
							}
						}
						if (a_rename.length > 0) {
							b_rename = true;
							if (!b_override) {
								msg = ip2.i18n({
									da: "Opretter filer....",
									en: "Creating files..."
								});
								i_el.mask(msg);
							}
							if (Ext.ux.file.util.Handler.hasFileManager()) {
								Ext.ux.file.util.Handler.createRecords(s_path, a_rename, true, function(a_records) {
									a_concat = a_concat.concat(a_rename);
									b_rename = false;
									if (!b_override && !b_create) {
										i_el.unmask();
										i_self.createFromFiles(a_concat, s_path, true);
									}
								});
							}
							else {
								Ext.ux.file.util.Handler.uploadFiles(s_path, a_rename, true, function(a_records) {
									a_concat = a_concat.concat(a_rename);
									b_rename = false;
									if (!b_override && !b_create) {
										i_el.unmask();
										i_self.createFromFiles(a_concat, s_path, true);
									}
								});
							}
						}
						if (!b_override && !b_rename) {
							if (!b_create) {
								i_el.unmask();
								i_self.createFromFiles(a_concat, s_path, true);
							}
							else {
								msg = ip2.i18n({
									da: "Opretter filer....",
									en: "Creating files..."
								});
								i_el.mask(msg);
							}
						}
					}, false);
			}
			if (a_create.length > 0) {
				b_create = true;
				if (!b_update) {
					i_el.unmask();
					msg = ip2.i18n({
						da: "Opretter filer....",
						en: "Creating files..."
					});
					i_el.mask(msg);
				}
				if (Ext.ux.file.util.Handler.hasFileManager()) {
					Ext.ux.file.util.Handler.createRecords(s_path, a_create, false, function(a_records) {
						a_concat = a_concat.concat(a_create);
						b_create = false;
						if (!b_update || b_cancel) {
							i_el.unmask();
							i_self.createFromFiles(a_concat, s_path, true);
						}
					});
				}
				else {
					Ext.ux.file.util.Handler.uploadFiles(s_path, a_create, false, function(a_records) {
						a_concat = a_concat.concat(a_create);
						b_create = false;
						if (!b_update || b_cancel) {
							i_el.unmask();
							i_self.createFromFiles(a_concat, s_path, true);
						}
					});
				}
			}
		});
	},

	createFromFiles: function(a_files, s_path, b_append) {

		var i_self = this;
		var a_result = [];
		Ext.Array.each(a_files, function(i_file) {
			var o_file = i_file.file || i_file;
			var s_name = i_file.suggestedName || o_file.name;
			var s_url = [s_path, s_name].join("/");
			var o_record = {
				name: s_name,
				url: s_url
			};
			a_result.push(o_record);
		});
		i_self.createData(a_result, b_append);
	},

	onCollectionItemAdd: function () {

		var i_self = this;
		var i_grid = i_self.getGrid();
		var i_store = i_grid.getStore();
		var i_model = i_store.model.create();
		i_self.openItemEditor(i_model);

		return i_self;
	},

	onCollectionItemEdit: function (n_row, i_record) {

		var i_self = this;
		var i_store = i_self.getStore();

		// Delegator is either a doubleclick or itemcontextmenu handler
		// So we get the record by row number
		if (Ext.isNumber(n_row)) {
			i_record = i_store.getAt(n_row);
		}

		i_self.openItemEditor(i_record);

		return i_self;
	},

	onCollectionItemRemove: function (toRemove) {

		var i_self = this;
		var i_store = i_self.getStore();
		var s_message;

		// If toRemove is a number, then it is the row to remove
		if (Ext.isNumber(toRemove)) {

			s_message = ip2.i18n(i_self.confirmRemoveRowText);

			i_self.throwMessage(s_message, function () {
				i_self.removeData(toRemove);
			});
		}

		if (!toRemove) {

			var i_grid = i_self.getGrid();
			var a_selected = i_grid.getSelectionModel().getSelection();
			var n_selected = a_selected.length;

			if (n_selected) {

				s_message = n_selected > 1 ? i_self.confirmRemoveRowsText : i_self.confirmRemoveRowText;
				s_message = ip2.i18n(s_message);

				i_self.throwMessage(s_message, function () {
					i_self.removeData(a_selected);
				});
			}
		}
	},

	onCollectionContext: function (i_media, i_record, i_item, n_index, o_event) {

		o_event.preventDefault();

		var i_self = this;
		var i_store = i_self.getStore();
		var i_menu = i_self.contextMenu;
		var b_allowAdd = i_self.allowAdd();
		var a_xy = o_event.getXY();

		var i_remove = i_menu.items.get("removeButton");
		var i_edit = i_menu.items.get("editButton");
		var i_preview = i_menu.items.get("previewButton");

		if (i_remove) {
			i_remove.handler = function () {
				i_self.onCollectionItemRemove();
			};
		}

		if (i_edit) {
			i_edit.handler = function () {
				i_self.onCollectionItemEdit(n_index);
			};
		}

		if (i_preview) {
			i_preview.handler = function () {

				var o_size = ip2.getWindowSize();

				var s_extension = i_record.get("name") || i_record.get("url");

				s_extension = s_extension.split(".").pop();

				var a_extension_image = ["jpg","jpeg","png","gif", "bmp"];

				s_extension = s_extension.toLowerCase();

				var i_window = Ext.widget("window", {
					layout: "fit",
					title: "Preview - " + (i_record.get("name") || i_record.get("title")),
					width: o_size.width * 0.6,
					height: o_size.height * 0.8,
					listeners: {
						afterrender: {
							fn: function() {
								Ext.GlobalEvents.fireEvent("applyContextMenu");
							}
						},
						destroy: {
							fn: function() {

								var i_globalWindow = Ext.get(window.document);
								i_globalWindow.events.contextmenu.clearListeners();

								Ext.GlobalEvents.fireEvent("removeContextMenu");
							}
						}
					}
				});

				var a_items = [];

				if (Ext.Array.contains(a_extension_image, s_extension)) {

					var i_canvas = Ext.widget("component", {
						autoEl: {
							tag: "canvas"
						}
					});

					var i_container = Ext.widget("container", {
						itemId: "canvas-container",
						items: [
							i_canvas
						],
					});

					var i_image = new Image();

					i_image.onload = function() {
						i_container.fireEvent("resize", i_container, i_container.getWidth(), i_container.getHeight());
					};

					i_container.on({
						resize: {
							fn: function(i_wrapper) {

								var i_canvasEl = i_canvas.getEl();
								var i_canvasDom = i_canvasEl.dom;
								var n_width = i_wrapper.getWidth();
								var n_height = i_wrapper.getHeight();

								var i_context = i_canvasDom.getContext("2d");

								i_context.clearRect(0, 0, n_width, n_height);

								i_canvasDom.width = n_width;
								i_canvasDom.height = n_height;

								i_context.drawImage(i_image, 10, 10, n_width - 20, n_height -20);
								
							},
							buffer: 100
						}
					});

					a_items.push(i_container);

					i_image.src = i_record.get("url");
				}
				else {
					var i_iframe = Ext.widget("containeriframe", {
						src: i_record.get("url")
					});
					a_items.push(i_iframe);
				}

				i_window.add(a_items);

				i_window.show();
			};
		}

		i_menu.showAt(a_xy[0], a_xy[1]);
	},

	createData: function (data, b_append) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_model = i_store.getModel();
		var a_data = Ext.Array.from(data);

		// If we have nothing in store, and we have actionColumns applied
		// then we need to apply default autoSelect values to first dataset in a_data
		var n_store = i_store.getCount();
		var o_actionColumns = i_self.actionColumns;

		// Check autoSelect defaults for row context groups in actionColumns
		Ext.Array.each(a_data, function (o_data, n_index) {

			// Get row context based default values for autoSelect
			var o_defaults = i_self.getAutoSelectDefaults("row");

			// If store is empty then we need to apply column context defaults
			if (!n_store && n_index === 0 && i_self.isValueInit) {
				var o_columnDefaults = i_self.getAutoSelectDefaults("column");
				Ext.apply(o_defaults, o_columnDefaults);
			}

			if (o_data.isModel) {
				if (o_data.phantom !== null && o_data.modified !== null) {
					o_data.set(o_defaults);
				}
			}
			else {
				Ext.apply(o_data, o_defaults);
			}
		});

		i_store.loadData(a_data, b_append);

		i_self.fireEvent("create", i_self);

		return i_self;
	},

	updateData: function (data, i_record) {

		var i_self = this;
		var i_store = i_self.getStore();
		var a_data = Ext.Array.from(data);
		var a_records = [];

		Ext.Array.each(a_data, function (o_data) {

			if (!i_record) {
				i_record = i_self.findRecordByData(o_data);
			}

			if (i_record) {

				a_records.push(i_record);

				i_record.set(o_data);

				// Only refresh the row we messed with
				var n_index = i_store.indexOf(i_record);
				if (n_index > -1) {
					i_self.getGrid().getView().refreshNode(n_index);
				}
			}
		});

		return i_self;
	},

	removeData: function (toRemove) {

		// toRemove can be one of the following
		// - record
		// - object/values
		// - index (in store)
		var i_self = this;
		var i_store = i_self.getStore();
		var a_remove = Ext.Array.from(toRemove);
		var a_records = [];

		Ext.Array.each(a_remove, function (item) {

			var i_record;

			if (Ext.isNumber(item)) {
				i_record = i_store.getAt(item);
			}
			if (Ext.isObject(item)) {

				// Is a record?
				if (item.store && item.store.model && item instanceof item.store.model) {
					i_record = item;
				}
				else {
					i_record = i_self.findRecordByData(item);
				}
			}

			a_records.push(i_record);
		});

		// Our records to remove array is ready
		i_store.remove(a_records);
		if (i_store.getData().length === 0) {
			i_self.fireEvent("empty", i_self);
		}
		else {
			i_self.fireEvent("datachanged", i_self);
		}
	},

	emptyData: function () {

		var i_self = this;
		var i_store = i_self.getStore();

		i_store.removeAll();

		i_self.fireEvent("empty", i_self);

		return i_self;
	},

	loadData: function (data, b_append) {

		var i_self = this;
		var i_store = i_self.getStore();
		var a_data = Ext.Array.from(data);
		i_store.removeAll(true);
		i_store.loadData(a_data);
		return i_self;
	},

	createFileData: function (o_file) {

		var i_self = this;
		var s_path = i_self.path;
		var s_name = o_file.name;

		var s_url = [s_path, s_name].join(""/"");

		s_url = ip2.cleanPath(s_url);

		return {
			name: s_name,
			url: s_url
		};
	},

	humanFileSize: function (bytes) {
		return ip2.humanFileSize(bytes);
	},

	syncButtons: function () {

		var i_self = this;

		i_self.syncAddButton();

		return i_self;
	},
	syncAddButton: function () {

		var i_self = this;
		var n_max = i_self.maxItems;
		var i_button = i_self.getAddButton();
		var value = i_self.getValue();

		if (n_max === 0) {
			i_button.disable();
		}
		else if (n_max == 1 && Ext.Object.getSize(value)) {
			i_button.disable();
		}
		else if (value && n_max > value.length) {
			i_button.disable();
		}
		else {
			i_button.enable();
		}

		return i_self;
	},

	syncRemoveButton: function () {

		var i_self = this;
		var i_toolbar = i_self.getToolbar();
		var i_button = i_toolbar.down("#removeButton");
		var n_max = i_self.maxItems;
		var value = i_self.getValue();

		if (n_max === 0) {
			i_button.disable();
		}
		else if (Ext.Object.getSize(value) || (Ext.isArray(value) && value.length)) {
			i_button.enable();
		}
		else {
			i_button.disable();
		}

		return i_self;
	},

	// Value handling
	getValue: function () {

		var i_self = this;
		var i_store = i_self.getStore();
		var b_single = (i_self.maxItems == 1) ? true : false;
		var a_value = [];
		var o_value = {};
		var a_records = i_store.data.items.slice(0);

		Ext.Array.each(a_records, function(i_record, n_index) {
			var o_data = ip2.clone(i_record.data);

			if (b_single) {
				o_value = o_data;
			}
			else {
				o_data.sequence = n_index;

				a_value.push(o_data);
			}
		});

		if (a_value.length && b_single) {
			o_value = value.length ? a_value[0] : {};
		}

		if (b_single) {
			o_value = trim(o_value);
		}
		else {
			Ext.Array.each(a_value, function (o_value, n_index) {
				a_value[n_index] = trim(o_value);
			});
		}

		function trim (o_value) {
			var o_return = {};
			Ext.Object.each(o_value, function (s_key, value) {
				if (value === null) {
					o_return[s_key] = "";
				}
				else {
					o_return[s_key] = value;
				}
			});
			return o_return;
		}

		return b_single ? o_value : a_value;
	},

	setValue: function (value) {

		var i_self = this;
		var i_store = i_self.getStore();

		var a_values = Ext.Array.from(value);

		if (Ext.isString(value)) {

			a_values = Ext.decode(value, true) || [];
		}

		if (a_values.length > 0) {
			i_self.loadData(a_values);
		}
		else {
			i_self.emptyData();
		}

		i_self.value = a_values;

		return i_self;
	},

	// Utility methods
	refocusGrid: function () {
		var i_self = this;
		var i_grid = i_self.getGrid();

		// Make sure the previously selected rows are once again selected
		var a_selected = i_grid.getSelectionModel().getSelection();

		i_grid.getView().focus();
		i_grid.getSelectionModel().select(a_selected);

		return i_self;
	},

	getAutoSelectDefaults: function (s_context) {

		var i_self = this;
		var o_columns = i_self.actionColumns || {};

		var o_defaults = {};

		// AutoSelect columns come in 2 contexts, column or row
		// - Column context ('column') = radio or radiocheckbox
		// - Row context ('row') = radio, radiocheckbox or checkbox
		Ext.Object.each(o_columns, function (s_key, o_config) {

			var b_select = o_config.autoSelect;

			if (b_select && o_config.context == s_context) {
				o_defaults[s_key] = b_select;
			}
		});

		return o_defaults;
	},

	checkAutoSelectColumns: function () {

		var i_self = this;
		var i_store = i_self.getStore();
		var o_columns = i_self.actionColumns;

		if (o_columns) {

			var o_map = {};

			// Create the initial map to check for flags
			Ext.Object.each(o_columns, function (s_key, o_column) {
				if (o_column.autoSelect) {
					o_map[s_key] = false;
				}
			});

			// Check each record and set flag to true if an value was found
			i_store.each(function (i_record) {
				Ext.Object.each(o_map, function (s_key, value) {
					if (i_record.get(s_key)) {
						o_map[s_key] = true;
					}
				});
			});

			// Check first record in store - if value is false, then check
			// first record
			Ext.Object.each(o_map, function (s_key, value) {
				if (!value) {
					var i_record = i_store.getAt(0);
					if (i_record) {
						i_record.set(s_key, true);
					}
				}
			});
		}

		return i_self;
	},

	validateDrop: function (o_event) {

		var i_self = this;
		var b_valid = true;

		var o_datatransfer = o_event.dataTransfer;
		var a_files = o_datatransfer.items || o_datatransfer.files;

		var n_transfer = a_files.length;
		var n_max = i_self.maxItems;
		var n_count = i_self.getStore().getCount();

		// Only check conditions if this is not a limitless list
		if (n_max != -1) {
			// Do not allow if more files are being uploaded than list holds
			if (n_count + n_transfer > n_max) {
				b_valid = false;
			}
		}

		return b_valid;
	},

	findRecordByData: function (o_data) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_found;

		i_store.data.each(function (i_record) {

			if (i_record.get("name") == o_data.name) {
				i_found = i_record;
			}
		});

		return i_found;
	},

	hasRecord: function (o_data) {

		var i_self = this;
		var i_store = i_self.getStore();
		var b_hasRecord = false;

		i_store.data.each(function (i_record) {

			if (i_record.get("name") == o_data.name) {
				b_hasRecord = true;
			}
		});

		return b_hasRecord;
	},

	allowAdd: function () {

		var i_self = this;
		var b_allow = true;

		var n_max = i_self.maxItems;
		var n_count = i_self.getStore().getCount();

		if (n_max != -1 && n_count >= n_max) {
			b_allow = false;
		}

		return b_allow;
	},

	// Message handling
	throwMessage: function (o_message, f_confirm, f_cancel) {

		f_confirm = f_confirm || Ext.emptyFn;
		f_cancel = f_cancel || Ext.emptyFn;

		var o_config = {
			message: ip2.i18n(o_message),
			width: 400,
			yesText: ip2.i18n({
				da: "Ja",
				en: "Yes"
			}),
			noText: ip2.i18n({
				da: "Nej",
				en: "No"
			}),
			yesFn: function () {
				f_confirm();
			},
			noFn: function () {
				f_cancel();
			}
		};

		ip2.messageBox(o_config);
	},

	isDirty: function () {

		var i_self = this;
		var i_grid = i_self.getGrid();
		var b_dirty = i_grid.isDirty();

		return b_dirty;
	},

	changeLanguage: function(s_language) {
		var i_self = this;
		var i_grid = i_self.getGrid();
		i_grid.changeLanguage(s_language);
	}
});
Ext.define("Ext.ux.gallery.Field", {

	extend: "Ext.form.FieldContainer",

	alias: ["widget.mediagalleryfield"],

	mixins: {
		field: "Ext.form.field.Field"
	},

	requires: [
		"Ext.ux.gallery.Media",
		"Ext.ux.gallery.view.MediaGrid",
		"Ext.ux.gallery.view.DropBox",
		"Ext.ux.gallery.view.MediaEditor",
		"Ext.ux.themed.ActionColumn"
	],

	config: {
		path: null,
		pageSize: null,
		maxItems: -1,
		linkConfig: null,
		layoutConfig: null,
		editorConfig: null,
		extensions: null,
		dragText: null,
		dropText: null,
		ignoreStaticDir: false,
		progressUploadText: "",
		progressDoneText: "",
		progressCheckText: "",
		progressCheckDoneText: "",
		progressFailText: "",
		confirmRemoveRowText: "",
		confirmRemoveRowsText: "",
		itemCreateText: "",
		itemEditText: "",
		itemRemoveText: "",
		itemCreateTitle: "",
		itemEditTitle: "",
		actionColumns: null,
		galleryAlias: "mediagallery",
		language: "",
		mediaType: "",
		gallery: null
	},

	initComponent: function() {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;

		i_cmp.callParent(arguments);

		var i_gallery = Ext.widget(o_config.galleryAlias || i_cmp.galleryAlias, {
			path: o_config.path || i_cmp.path,
			maxItems: o_config.maxItems || i_cmp.maxItems,
			extensions: o_config.extensions || i_cmp.extensions,
			editorConfig: o_config.editorConfig || i_cmp.editorConfig,
			layoutConfig: o_config.layoutConfig || i_cmp.layoutConfig,
			linkConfig: o_config.linkConfig || i_cmp.linkConfig,
			pageSize: o_config.pageSize || i_cmp.pageSize,
			value: o_config.value || i_cmp.value,
			actionColumns: o_config.actionColumns || {},
			dragText: o_config.dragText || i_cmp.dragText,
			dropText: o_config.dropText || i_cmp.dropText,
			progressUploadText: o_config.progressUploadText,
			progressDoneText: o_config.progressDoneText,
			progressCheckText: o_config.progressCheckText,
			progressCheckDoneText: o_config.progressCheckDoneText,
			progressFailText: o_config.progressFailText,
			confirmRemoveRowText: o_config.confirmRemoveRowText,
			confirmRemoveRowsText: o_config.confirmRemoveRowsText,
			itemCreateTitle: o_config.itemCreateTitle,
			itemEditTitle: o_config.itemEditTitle,
			itemCreateText: o_config.itemCreateText,
			itemEditText: o_config.itemEditText,
			itemRemoveText: o_config.itemRemoveText,
			ignoreStaticDir: o_config.ignoreStaticDir || i_cmp.ignoreStaticDir,
			parentEntity: o_config.parentEntity || i_cmp.parentEntity,
			parentEnumType: o_config.parentEnumType || i_cmp.parentEnumType,
			childEntity: o_config.childEntity || i_cmp.childEntity,
			childEnumType: o_config.childEnumType || i_cmp.childEnumType,
			mediaType: i_cmp.getMediaType()
		});

		i_cmp.add(i_gallery);

		i_cmp.setGallery(i_gallery);

		i_cmp.initField();

		i_cmp.initEvents();

		return i_cmp;
	},

	initEvents: function () {

		var i_cmp = this;
		var i_gallery = i_cmp.getGallery();
		var i_store = i_gallery.getStore();

		i_store.on({
			datachanged: {
				fn: function () {
					i_cmp.checkChange();
				}
			},
			update: {
				fn: function () {
					i_cmp.checkChange();
				}
			}
		});

		return i_cmp;
	},

	initValue: function () {

		var i_cmp = this;
		var i_gallery = i_cmp.getGallery();
		var value = i_gallery.getValue();
		var b_empty = i_cmp.isEmptyValue(value);

		if (b_empty) {
			value = "";
		}

		i_cmp.value = value;

		i_cmp.mixins.field.initValue.call(i_cmp);
	},

	getValue: function () {

		var i_cmp = this;
		var i_gallery = i_cmp.getGallery();
		var value = i_gallery.getValue();
		var b_empty = i_cmp.isEmptyValue(value);

		if (i_cmp.isEmptyValue(value)) {
			value = "";
		}

		return value;
	},

	getSubmitValue: function () {

		var i_cmp = this;

		var value = i_cmp.getValue();

		if (Ext.isString(value)) {
			value = Ext.decode(value, true) || [];
		}

		return value;
	},

	setValue: function (value) {

		var i_cmp = this;
		var i_gallery = i_cmp.getGallery();

		i_gallery.setValue(value);

		i_cmp.value = value;

		i_cmp.checkChange();

		return i_cmp;
	},

	isEmptyValue: function (value) {

		var i_cmp = this;

		if (!value) {
			return true;
		}

		if (Ext.isObject(value) && !Ext.Object.getSize(value)) {
			return true;
		}

		if (Ext.isArray(value) && !value.length) {
			return true;
		}

		return false;
	},

	resetOriginalValue: function (value) {

		var i_cmp = this;
		var i_gallery = i_cmp.getGallery();
		var b_emptyValue;

		value = value || i_cmp.getValue();

		b_emptyValue = i_cmp.isEmptyValue(value);

		if (b_emptyValue) {
			value = '';
		}

		i_cmp.originalValue = value;

		return i_cmp;
	},

	checkChange: function () {

		if (!this.suspendCheckChange) {

			var c = this;
			var b = c.getValue();
			var a = c.lastValue;

			var a_stringed = Ext.encode(a);
			var b_stringed = Ext.encode(b);

			if (!c.isEqual(b_stringed, a_stringed) && !c.isDestroyed) {
				c.lastValue = b;
				c.fireEvent("change", c, b, a);
				c.onChange(b, a);
			}
		}
	},

	disable: function() {

		var i_self = this;
		i_self.callParent(arguments);
		var i_gallery = i_self.getGallery();
		if (i_self.isDisabled()) {
			i_gallery.disable();
		}
	},

	enable: function() {

		var i_self = this;
		i_self.callParent(arguments);
		var i_gallery = i_self.getGallery();
		if (!i_self.isDisabled()) {
			i_gallery.enable();
		}
	},

	isDirty: function() {

		var i_self = this;
		var i_gallery = i_self.getGallery();
		var originalValue = "";
		var value = i_gallery.getValue();

		if (i_gallery.maxItems == 1) {
			originalValue = i_self.originalValue || {};
		}
		else {
			originalValue = i_self.originalValue || [];
		}

		var s_originalValue = "";
		var s_value = "";

		try {
			s_originalValue = Ext.encode(originalValue);
			s_value = Ext.encode(value);
		}
		catch (err) {}
		var b_dirty = s_originalValue != s_value;
		return b_dirty;
	},

	changeLanguage: function(s_language) {
		var i_self = this;
		var i_gallery = i_self.getGallery();
		i_gallery.changeLanguage(s_language);
	}
});
Ext.define('Ext.ux.gallery.MediaRelation', {

	extend: 'Ext.ux.gallery.Media',

	alias: ['widget.mediagalleryrelation'],

	parentStore: null,

	// Object with the serverParams set to pass on
	// directly to the service
	// Will be gotten from the following 4 values from XPD
	serverParams: null,

	// These 4 values will be added to the serverParams config
	// object used for the service
	parentEntity: '',
	parentEnumType: '',
	childEntity: '',
	childEnumType: '',
	records: null,

	initComponent: function () {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;

		Ext.apply(i_cmp, {
			serverParams: o_config.serverParams || {
				parentEntity: null,
				parentToken: null,
				parentType: null,
				childEntity: null,
				childType: null,
				language: null,
				action: 'getJoinedRelation'
			},
			parentEntity: o_config.parentEntity != null ? o_config.parentEntity : i_cmp.parentEntity,
			parentEnumType: o_config.parentEnumType != null ? o_config.parentEnumType : i_cmp.parentEnumType,
			childEntity: o_config.childEntity != null ? o_config.childEntity : i_cmp.childEntity,
			childEnumType: o_config.childEnumType != null ? o_config.childEnumType : i_cmp.childEnumType
		});

		i_cmp.callParent(arguments);
		i_cmp.records = {};
		i_cmp.on({
			'afterrender': {
				fn: i_cmp.onAfterRender,
				scope: i_cmp
			}
		});
		i_cmp.enableBubble("reset");

		return i_cmp;
	},

	initValue: function () {

		var i_cmp = this;
		var value = i_cmp.value;

		//i_cmp.setValue(value);
		i_cmp.originalValue = value;
		i_cmp.isValueInit = true;

		return i_cmp;
	},

	createParentStore: function () {

		var i_cmp = this;
		var s_dmdProxy = '/ip2-services/ip2dmdproxy.aspx?model=WSHRELET00&uiName=portfolio&context=grid&dmdFile=dmd/webshop.dmd';
		var i_model;
		if (Ext.ClassManager.isCreated("ip2.temp.Model")) {
			i_model = Ext.ClassManager.get("ip2.temp.Model");
		}
		else {
			i_model = Ext.define('ip2.temp.Model', {
				extend: "Ext.data.Model",
				fields: [
					'_id',
					'RELRELTKN', 'RELPNTTYP', 'RELPNTTKN', 'RELPNTLNG', 'RELCHDTYP', 'RELCHDTKN', 'RELCHDPROP',
					'FILFILTKN', 'FILCREATE', 'FILMODIFY', 'FILCRTBY', 'FILMEDIA', 'FILNAME', 'FILHEAD', 'FILSUB', 'FILPATH',
					'FILORIPATH', 'FILEXT', 'FILWIDTH', 'FILHEIGHT', 'FILSIZE', 'FILTAG', 'FILREL', 'FILEXTERNAL'
				],
				idProperty: "RELRELTKN"
			});
		}
		return i_cmp.parentStore = Ext.create('Ext.data.Store', {
			model: i_model,
			autoLoad: true,
			proxy: {
				type: 'ajax',
				api: {
					'read': '/ip2-services/wshproxy.aspx',
					'create': s_dmdProxy + '&action=upsert',
					'update': s_dmdProxy + '&action=upsert',
					'delete': s_dmdProxy + '&action=delete'
				},
				reader: {
					type: 'json',
					rowProperty: "rows",
					totalProperty: 'totalRows'
				}
			},
			listeners: {
				beforeload: {
					fn: function(store) {
						var i_proxy = store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();
						Ext.apply(o_extraParams, i_cmp.serverParams);
					}
				}
			}
		});
	},

	getParentStore: function () {

		return this.parentStore;
	},

	onAfterRender: function () {

		var i_cmp = this;
		var i_parent;

		var s_primaryKey;
		var n_primaryKey;
		var s_languageKey;

		var getDataParent = function (i_parent) {

			while (i_parent && !i_parent.dataParent) {
				i_parent = i_parent.up();
			}

			return i_parent.dataParent;
		};

		var getDataLanguage = function (i_parent) {

			while (i_parent && !i_parent.language) {
				i_parent = i_parent.up();
			}

			return i_parent.language;
		};

		// Prepare the params object to pass to the service
		// which will be saved on i_cmp.serverParams
		i_cmp.serverParams.parentEntity = i_cmp.parentEntity;
		i_cmp.serverParams.childEntity = i_cmp.childEntity;

		if (!i_cmp.primaryKey || !i_cmp.languageKey) {

			i_parent = getDataParent(i_cmp);

			s_primaryKey = i_parent.dmdInfo.entity.idColumn;
			n_primaryKey = i_parent.keys[s_primaryKey];

			if (i_parent.language) {
				s_languageKey = i_parent.language;
			}
			else {
				s_languageKey = getDataLanguage(i_cmp);
			}

			i_cmp.oldLang = s_languageKey;
		}

		if (!i_cmp.primaryKey) {

			i_cmp.serverParams.parentToken = n_primaryKey;
		}
		if (!i_cmp.languageKey && s_languageKey) {

			i_cmp.serverParams.language = s_languageKey;
		}

		// Deal with ENUM of parentEnumType=>parentType
		// Deal with ENUM of childEnumType=>childType
		i_cmp.serverParams.parentType = i_cmp.getTypeEnumValue('parentRelationTypes', i_cmp.parentEnumType);
		i_cmp.serverParams.childType = i_cmp.getTypeEnumValue('childRelationTypes', i_cmp.childEnumType);
		i_cmp.serverParams.childEntity = i_cmp.serverParams.childEntity + "_GRID_PORTFOLIO";

		i_cmp.createParentStore();

		i_cmp.bindStores();
	},

	addControls: function () {

		var i_cmp = this;

		i_cmp.on({
			'afterrender': {
				fn: function (i_self) {
					i_self.syncButtons();
				},
				single: true
			},
			'create': {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			},
			'update': {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			},
			'remove': {
				fn: function (i_self) {
					i_self.checkAutoSelectColumns();
					i_self.syncButtons();
				}
			},
			'empty': {
				fn: function (i_self) {
					i_self.syncButtons();
				}
			}
		});

		i_cmp.control({
			'grid': {
				itemedit: i_cmp.onCollectionItemEdit,
				itemdblclick: i_cmp.onCollectionItemEdit,
				itemremove: i_cmp.onCollectionItemRemove,
				deletekey: i_cmp.onCollectionItemRemove,
				itemcontextmenu: i_cmp.onCollectionContext,
				scope: i_cmp
			},
			'dropbox': {
				dragenter: i_cmp.onDragEnter,
				afterrender: function(item) {
					i_cmp.dropzone = Ext.widget("filedropzone", {
						animateTarget: item.getEl(),
						extensions: i_cmp.extensions,
						dropFn: function(a_records) {
							i_cmp.onDrop(a_records);
						}
					});
				}
			}
		});

		return i_cmp;
	},

	onDragEnter: function (i_dropbox, o_event) {

		var i_cmp = this;
		i_cmp.dropzone.show();
	},

	onDrop: function(a_records) {
		var i_cmp = this;
		var a_models = [];
		var i_parentStore = i_cmp.getParentStore();
		var n_childenum = i_cmp.serverParams.childType;
		var n_parentenum = i_cmp.serverParams.parentType;
		var n_primaryKey = i_cmp.serverParams.parentToken;

		ip2.each(a_records, function(i_record) {
			var i_model = i_parentStore.model.create(i_record.data);
			i_model.set({
				RELCHDTYP: n_childenum,
				RELPNTTYP: n_parentenum,
				RELPNTTKN: n_primaryKey,
				RELCHDTKN: i_record.get("FILFILTKN")
			});
			a_models.push(i_model);
		});
		i_parentStore.add(a_models);
	},

	bindStores: function() {

		var i_cmp = this;
		var i_parentStore = i_cmp.getParentStore();
		var i_gridStore = i_cmp.getStore();
		i_cmp.isDropping = false;

		i_parentStore.on({
			load: {
				fn: function(store, a_records) {

					var i_entityform = i_cmp.up("entityform");
					var a_result = [];
					var a_all = [];

					if (i_entityform && i_entityform.action == "copy") {
						Ext.Array.each(a_records, function(i_record) {
							i_record.set(i_record.idProperty, null);
						});
					}

					Ext.Array.each(a_records, function(i_record) {
						var i_gridrecord = initParentRecord(i_record);
						a_result.push(i_gridrecord);
					});

					if (a_result.length > 0) {
						i_cmp.createData(a_result, {
							addRecords: true
						});
					}

					i_parentStore.each(function(i_record, n_index) {
						a_all.push(i_record.data);
					});

					i_cmp.records[i_cmp.serverParams.language] = a_all;

					i_cmp.fireEvent("reset");
				}
			},
			add: {
				fn: function(i_store, a_records) {
					var a_result = [];
					var a_all = [];
					Ext.Array.each(a_records, function(i_record) {
						var i_gridrecord = initParentRecord(i_record);
						a_result.push(i_gridrecord);
					});
					i_cmp.createData(a_result, {
						addRecords: true
					});
					i_parentStore.each(function(i_record, n_index) {
						a_all.push(i_record.data);
					});
					i_cmp.records[i_cmp.serverParams.language] = a_all;
				}
			}
		});

		i_gridStore.on({
			remove: {
				fn: function(store, a_records) {
					if (i_cmp.isDropping) {
						return;
					}
					var a_all = [];
					ip2.each(a_records, function(i_record) {
						var i_parentRecord = i_parentStore.findRecord('_id', i_record.get('_id'));
						i_parentStore.remove(i_parentRecord);
					});
					i_parentStore.each(function(i_record, n_index) {
						a_all.push(i_record.data);
					});
					i_cmp.records[i_cmp.serverParams.language] = a_all;
				}
			},
			beforereorder: {
				fn: function(store) {
					i_cmp.isDropping = true;
				}
			},
			reorder: {
				fn: function(store, a_records, n_index) {
					i_cmp.isDropping = false;
				}
			}
		});

		function initParentRecord(i_parentRecord) {

			if (!i_parentRecord.get("_id")) {
				i_parentRecord.set('_id', ip2.unique('tmp-'));
			}
			var o_relProp = i_parentRecord.get('RELCHDPROP');
			if (!Ext.isObject(o_relProp)) {
				o_relProp = {};
			}
			else {
				if (!o_relProp.type) {
					o_relProp.type = "image";
				}
			}
			var o_gridRecord = ip2.extend({}, o_relProp, i_cmp.parent2grid(i_parentRecord, i_parentRecord.data));

			var i_gridRecord = i_gridStore.model.create(o_gridRecord);

			var systemSet = false;

			// TODO: Don't overridee set methods, now even when you want a record change event!
			i_gridRecord.set = (function(orig) {
				return function() {
					var ret = orig.apply(this, arguments);
					if (!systemSet) {
						systemSet = true;
						var changes = ip2.clone(this.data);
						if (!Ext.Object.isEmpty(changes)) {
							var i_parentRecord = i_parentStore.findRecord('_id', this.get('_id'));
							if (i_parentRecord) {
								i_parentRecord.set(i_cmp.grid2parent(this, changes));
							}
							else {
								console.log('parentRecord is missing');
							}
						}
						systemSet = false;
					}
					return ret;
				};
			})(i_gridRecord.set);

			i_parentRecord.set = (function(orig) {
				return function() {
					var ret = orig.apply(this, arguments);
					if (!systemSet) {
						systemSet = true;
						var changes = ip2.clone(this.data);
						if (!Ext.Object.isEmpty(changes)) {
							var i_gridRecord = i_gridStore.findRecord('_id', this.get('_id'));
							if (i_gridRecord) {
								i_gridRecord.set(i_cmp.parent2grid(this, changes));
							}
							else {
								console.log('gridRecord is missing');
							}
						}
						systemSet = false;
					}
					return ret;
				};
			})(i_parentRecord.set);
			return i_gridRecord;
		}
	},

	parent2grid: function(i_parentRecord, changes) {
		var o_set = {};

		if (changes.RELCHDPROP) {
			ip2.extend(o_set, changes.RELCHDPROP);
		}

		if (changes.RELCHDTKN) {
			o_set.RELCHDTKN = changes.RELCHDTKN;
		}
		if (changes._id) {
			o_set._id = changes._id;
		}

		if (changes.FILNAME || changes.FILPATH) {
			if (i_parentRecord.get("FILEXTERNAL")) {
				o_set.url = i_parentRecord.get("FILORIPATH");
			}
			else {
				o_set.url = i_parentRecord.get("FILPATH") + i_parentRecord.get("FILNAME");
			}
		}
		if (changes.FILNAME) {
			o_set.name = changes.FILNAME;
		}

		return o_set;
	},

	grid2parent: function(i_gridRecord, changes) {
		var o_set = {};

		o_set.RELCHDPROP = ip2.clone(i_gridRecord.data);
		delete o_set.RELCHDPROP.RELCHDTKN;

		if (changes.RELCHDTKN) {
			o_set.RELCHDTKN = changes.RELCHDTKN;
		}
		if (changes._id) {
			o_set._id = changes._id;
		}

		return o_set;
	},

	getTypeEnumValue: function (s_key, enumValue) {

		var i_cmp = this;
		var s_lang = wsh.i18n.getPrimary();

		var i_ns = ip2.resource.get('adm.ns', true);
		var o_value = i_ns.getEnumValue(s_key + '~' + enumValue);

		return o_value[s_lang];
	},

	onCollectionItemAdd: function () {

		var i_cmp = this;
		i_cmp.openItemEditor();

		return i_cmp;
	},

	openItemEditor: function (i_gridRecord) {

		var i_cmp = this;
		var o_defaults = i_cmp.editorConfig;
		var i_parentStore = i_cmp.getParentStore();
		var i_parentRecord;

		var o_config = {
			type: 'image',
			ignoreStaticDir: i_cmp.ignoreStaticDir,
			activeTab: 'mediaproperties'
		};

		var isEdit = i_gridRecord ? true : false;

		if (isEdit) {
			i_parentRecord = i_parentStore.findRecord('_id', i_gridRecord.get('_id'));

			o_config.action = 'edit';
			o_config.type = i_gridRecord.get('type') || o_config.type;
			o_config.record = i_gridRecord;
			o_config.title = [ip2.i18n(i_cmp.itemEditTitle), i_parentRecord.get('FILNAME')].join(' ');
		}
		else {

			i_parentRecord = i_parentStore.model.create();
			i_parentRecord.set({ _id: ip2.unique('tmp-') });
			o_config.record = Ext.create('Ext.data.Store', { fields: [] }).model.create();
			o_config.action = 'add';
			o_config.title = ip2.i18n(i_cmp.itemCreateTitle);
		}

		Ext.apply(o_config, o_defaults);

		var i_window = Ext.widget('mediaeditorrelation', o_config);

		i_window.on('aftersave', function(item, record) {

			if (!isEdit) {
				i_parentRecord.set(i_cmp.grid2parent(record, ip2.extend({ type: o_config.type }, record.data)));
				i_parentRecord = i_parentStore.add(i_parentRecord.data)[0];
			}
			else {
				i_gridRecord.set('type', o_config.type);
			}

			var i_combo = item.down('[name="RELCHDTKN"]');
			var i_fileRecord = i_combo.getRecord();

			// If fileRecord is null it means that we didnt change the image:
			if (i_fileRecord) {
				i_parentRecord.set(i_fileRecord.data);
			}
		});

		return i_cmp;
	},

	createData: function (data, o_options) {

		var i_cmp = this;
		var i_store = i_cmp.getStore();
		var a_data = Ext.Array.from(data);

		// If we have nothing in store, and we have actionColumns applied
		// then we need to apply default autoSelect values to first dataset in a_data
		var n_store = i_store.getCount();
		var o_actionColumns = i_cmp.actionColumns;

		// Check autoSelect defaults for row context groups in actionColumns
		ip2.each(a_data, function (i_data, n_index, a_context) {

			// Get row context based default values for autoSelect
			var o_defaults = i_cmp.getAutoSelectDefaults('row');

			// If store is empty then we need to apply column context defaults
			if (!n_store && n_index == 0 && i_cmp.isValueInit) {
				var o_columnDefaults = i_cmp.getAutoSelectDefaults('column');
				ip2.extend(o_defaults, o_columnDefaults);
			}
			if (i_data.phantom != null && i_data.modified != null) {
				i_data.set(o_defaults);
			}
			else {
				a_context[n_index] = ip2.defaults(i_data, o_defaults);
			}
		});
		var a_result = [];
		ip2.each(a_data, function(i_record) {
			a_result.push(i_record.data);
		});

		i_store.loadRecords(a_data, o_options);

		i_cmp.fireEvent("create", i_cmp);

		return i_cmp;
	},

	doSave: function(f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_cmp = this;
		var i_parentStore = i_cmp.getParentStore();

		if (i_parentStore) {
			var a_records = i_parentStore.getData().items.slice(0);
			var a_return = [];
			ip2.each(a_records, function(i_record) {
				var o_clone = ip2.clone(i_record.data);
				var i_model = i_parentStore.model.create(o_clone);
				var a_keys = Ext.Object.getKeys(i_model.data);
				ip2.each(a_keys, function(s_key) {
					if (s_key.slice(0, 3) != 'REL' && s_key != "_id") {
						delete i_model.data[s_key];
					}
				});
				a_return.push(i_model);
			});
			i_cmp.doSync(a_return, f_callback);
		}
		else {
			f_callback();
		}
	},

	getBatches: function(a_records) {

		var i_self = this;
		var i_entityform = i_self.up("entityform");
		var n_tkn = i_self.serverParams.parentToken;

		if (i_entityform) {
			var i_entityRecord = i_entityform.getForm().getRecord();
			n_tkn = i_entityRecord.get(i_entityRecord.idProperty);
			i_self.serverParams.parentToken = n_tkn;
		}

		var i_parentStore = i_self.getParentStore();
		var a_languages = wsh.getLanguages();
		var a_batch = [];
		var a_deleted = i_parentStore.getRemovedRecords();
		var a_gridRecords = i_self.getStore().data.items;
		var i_dummy = i_parentStore.model.create();

		var a_sorted = [];

		ip2.each(a_records, function(i_record) {
			ip2.each(a_gridRecords, function(i_gridRecord, n_index) {
				if (i_gridRecord.get("RELCHDTKN") == i_record.get("RELCHDTKN")) {
					i_record.set("RELCHDSEQ", n_index);
				}
			});
		});

		ip2.each(a_records, function (i_record) {
			if (!Ext.isNumber(i_record)) {
				var key = {};
				i_record.set({
					RELCHDTYP: i_self.serverParams.childType,
					RELPNTTYP: i_self.serverParams.parentType,
					RELPNTTKN: n_tkn,
					RELPNTLNG: i_self.serverParams.language
				});
				key[i_record.idProperty] = i_record.get(i_record.idProperty) || 0;
				a_batch.push({
					type: 'upsert',
					dmd: 'dmd/webshop.dmd',
					entity: "WSHRELET00",
					key: key,
					row: i_record.data
				});
			}
		});

		ip2.each(a_deleted, function (i_record) {
			var s_language = i_record.get("RELPNTLNG");
			if (s_language == i_self.serverParams.language) {
				var i_parentRecord = i_parentStore.findRecord(i_record.idProperty, i_record.get(i_record.idProperty));
				if (!i_parentRecord) {
					var key = {};
					key[i_record.idProperty] = i_record.get(i_record.idProperty);
					a_batch.push({
						type: 'delete',
						dmd: 'dmd/webshop.dmd',
						entity: "WSHRELET00",
						key: key,
						row: i_record.data
					});
				}
			}
		});

		ip2.each(a_languages, function(s_lang) {

			if (s_lang != i_self.serverParams.language) {
				var a_langRecords = i_self.records[s_lang] || [];
				var a_records = a_langRecords.slice(0);
				ip2.each(a_records, function(o_record) {
					var i_model = i_parentStore.model.create(o_record);
					var a_keys = Ext.Object.getKeys(i_model);
					ip2.each(a_keys, function(s_key) {
						if (s_key.slice(0, 3) != 'REL') {
							delete i_model.data[s_key];
						}
					});
					var key = {};
					i_model.RELCHDTYP = i_self.serverParams.childType;
					i_model.RELPNTTYP = i_self.serverParams.parentType;
					i_model.RELPNTTKN = n_tkn;
					i_model.RELPNTLNG = s_lang;
					key[i_dummy.idProperty] = i_model.get(i_dummy.idProperty) || 0;
					a_batch.push({
						type: 'upsert',
						dmd: 'dmd/webshop.dmd',
						entity: "WSHRELET00",
						key: key,
						row: i_model.data
					});
				});
			}
		});

		return a_batch;
	},

	doSync: function(a_records, f_callback) {

		var i_self = this;
		var a_batch = i_self.getBatches(a_records);
		var i_gridStore = i_self.getStore();
		var i_grid = i_self.getGrid();

		Ext.Ajax.request({
			url: '/ip2-Services/ip2dmdproxy.aspx',
			jsonData: {
				transaction: {
					batch: a_batch
				}
			},
			success: function (xhr) {
				var o_resp = JSON.parse(xhr.responseText);
				i_gridStore.removeAll(true);
				i_grid.getView().refresh();
				i_self.parentStore.load();
				f_callback();
			}
		});
	},

	changeLanguage: function(s_lang) {
		var i_self = this;
		var i_parent = i_self;
		if (i_self.parentStore) {
			var i_gridStore = i_self.getStore();
			var i_grid = i_self.getGrid();
			var a_values = i_self.getValues();
			i_self.records[i_self.serverParams.language] = a_values;
			var a_records = i_self.records[s_lang];
			i_self.serverParams.language = s_lang;
			i_self.parentStore.proxy.api.read = '/ip2-services/wshproxy.aspx?' + Ext.Object.toQueryString(i_self.serverParams);
			if (a_records == undefined) {
				i_gridStore.removeAll(true);
				i_grid.getView().refresh();
				i_self.parentStore.load();
			}
			else {
				i_gridStore.removeAll(true);
				i_grid.getView().refresh();
				i_self.parentStore.removeAll(true);
				i_self.parentStore.add(a_records);
			}
		}
	},

	getValues: function() {
		var i_self = this;
		var a_return = [];
		var i_parentStore = i_self.parentStore;
		var i_gridStore = i_self.getStore();
		if (i_gridStore && i_parentStore) {
			var a_records = i_parentStore.data.items.slice(0);
			i_gridStore.each(function(i_record) {
				ip2.each(a_records, function(i_parentRecord) {
					if (i_parentRecord.get("_id") == i_record.get("_id")) {
						var o_model = ip2.clone(i_parentRecord.data);
						var o_data = ip2.clone(i_record.data);
						o_model.RELCHDPROP = o_data;
						delete o_data._id;
						delete o_model._id;
						a_return.push(o_model);
					}
				});
			});
		}
		return a_return;
	}
});
Ext.define('Ext.ux.gallery.FieldRelation', {

	extend: 'Ext.ux.gallery.Field',

	alias: ['widget.mediagalleryfieldrelation'],

	// Object with the serverParams set to pass on
	// directly to the service
	// Will be gotten from the following 4 values from XPD
	serverParams: null,

	// These 4 values will be added to the serverParams config
	// object used for the service
	parentEntity: '',
	parentEnumType: '',
	childEntity: '',
	childEnumType: '',
	records: null,
	language: '',

	galleryAlias: 'mediagalleryrelation',

	initComponent: function () {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;
		i_cmp.records = {};
		i_cmp.language = wsh.getLanguages()[0];
		Ext.apply(i_cmp, {
			parentEntity: o_config.parentEntity || i_cmp.parentEntity,
			parentEnumType: o_config.parentEnumType || i_cmp.parentEnumType,
			childEntity: o_config.childEntity || i_cmp.childEntity,
			childEnumType: o_config.childEnumType || i_cmp.childEnumType
		});

		i_cmp.callParent(arguments);

		i_cmp.on({
			reset: function() {
				i_cmp.doReset();
			}
		});

		return i_cmp;
	},

	doSave: function (f_callback) {

		return this.getGallery().doSave(f_callback);
	},

	isDirty: function () {

		var i_self = this;
		var b_dirty = false;
		var a_language = wsh.getLanguages();
		var i_gallery = i_self.getGallery();
		var value = i_gallery.getValues();

		var o_value = i_self.records[i_self.language] || {
			originalValue: [],
			value: [],
			dirty: false,
			wasDirty: false
		};

		var originalValue = o_value.originalValue;
		var s_originalValue = "";
		var s_value = "";

		try {
			s_originalValue = Ext.encode(originalValue);
			s_value = Ext.encode(value);
		}
		catch (err) {}

		b_dirty = s_originalValue != s_value;

		return b_dirty;
	},

	changeLanguage: function(s_lang) {

		var i_self = this;
		var i_gallery = i_self.getGallery();
		var value = i_gallery.getValues();
		var b_dirty = i_self.isDirty();
		i_self.suspendCheckChange++;

		var o_language = i_self.records[i_self.language];
		o_language.dirty = b_dirty;
		o_language.value = value;

		i_self.language = s_lang;
		i_gallery.changeLanguage(s_lang);

		i_self.suspendCheckChange--;
		i_self.checkDirty();
	},

	checkChange: function () {

		var i_cmp = this;
		i_cmp.callParent(arguments);

		return i_cmp.isDirty();
	},

	checkDirty: function() {
		var i_self = this;
		var isDirty = i_self.isDirty();
		if (isDirty !== i_self.wasDirty) {
			i_self.fireEvent('dirtychange', i_self, isDirty);
			i_self.onDirtyChange(isDirty);
			i_self.wasDirty = isDirty;
		}
	},

	getValue: function() {

		var i_self = this;
		var i_gallery = i_self.getGallery();
		var value = i_gallery.getValues();
		var b_empty = i_self.isEmptyValue(value);

		if (i_self.isEmptyValue(value)) {
			value = '';
		}

		return value;
	},

	setValue: function(value) {

		var i_self = this;
		i_self.value = value;
	},

	doReset: function() {

		var i_self = this;
		var i_gallery = i_self.getGallery();
		var value = i_gallery.getValues();
		i_self.records[i_self.language] = {
			originalValue: value,
			value: value,
			dirty: false,
			wasDirty: false
		};

		i_self.resetOriginalValue();
		i_self.wasDirty = true;
		i_self.fireEvent("change", i_self, value);
		i_self.checkDirty();
	},

	resetOriginalValue: function() {

		var i_self = this;
		i_self.originalValue = i_self.value = i_self.getValue();
	}
});
Ext.define('Ext.ux.gallery.view.MediaEditorRelation', {
	extend: "Ext.ux.gallery.view.MediaEditor",
	alias: "widget.mediaeditorrelation",

	initComponent: function () {

		var i_cmp = this;
		i_cmp.callParent(arguments);
	},

	createPickerField: function(o_config) {
		var i_cmp = this;
		var i_picker = Ext.widget("uploadpickermanager", {
			itemId: 'uploadpicker',
			name: 'RELCHDTKN',
			path: i_cmp.path,
			extensions: i_cmp.extensions,
			ignoreStaticDir: i_cmp.ignoreStaticDir,
			allowBlank: false,
			userChange: false,
			submitRaw: false,
			fieldLabel: ip2.i18n({
				da: 'Medie',
				en: 'Media'
			}),
			emptyText: ip2.i18n({
				da: 'Sti til lokalt medie eller URL til eksternt medie',
				en: 'Path to local media or URL to external media'
			}),
			listeners: {
				select: {
					fn: function(item, a_records) {
						if (i_cmp.action == "add") {
							var o_record = a_records[0];
							var i_form = item.up("form");
							var i_fieldhead = i_form.down('[name="title"]');
							var i_fieldsub = i_form.down('[name="caption"]');

							i_cmp.systemSet = true;

							if (!i_fieldhead.userChange) {
								i_fieldhead.setValue(o_record.get("FILHEAD"));
							}
							if (!i_fieldsub.userChange) {
								i_fieldsub.setValue(o_record.get("FILSUB"));
							}

							i_cmp.systemSet = false;
						}
					}
				}
			}
		});
		return i_picker;
	}

});
Ext.define('Ext.ux.folderorganizer.DmdEditor', {

	extend: 'Ext.window.Window',
	height: 400,
	width: 600,
	autoScroll: true,
	closable: false,
	collapsible: true,
	layout: {
		type: 'fit'
	},
	initComponent: function() {

		var me = this;

		var model = me.store.model;

		var editor = Ext.create('Ext.ux.entity.Form', {
			model: me.store.model,
			action: me.action,
			keys: ip2.extractKeys(me.store.model, me.record),
			dataParent: me.wrapper,
			preventHeader: true,
			listeners: {
				'storewrite': {
					fn: function(self, operation, record) {
						me.fireEvent('datachanges', operation.action, record);
					}
				},
				'removed': function(win) {
					me.close();
				},
				'recordloaded': function(form, record) {
					if (me.action != 'new') {
						me.setTitle(form.getFormTitles());
					}
				}
			}
		});

		me.items = editor;

		me.callParent();
	}
});

Ext.define("Ext.ux.folderorganizer.Tree", {
	extend: "Ext.tree.Panel",
	collapsible: false,
	useArrows: true,
	rootVisible: false,
	multiSelect: true,
	singleExpand: false,
	border: false,
	region: "center",
	/**
	 * @cfg expandToLevel
	 * Set what level to expand to initially
	 */
	expandToLevel: 0,

	/**
	 * @cfg levelSelectFirst
	 * Set what on what level to autoselect first node in
	 */
	levelSelectFirst: false,

	config: {
		searchValue: null,
		xpdEditorConfig: null
	},

	requires: [
		"Ext.ux.folderorganizer.Util"
	],

	initComponent: function(config) {

		var i_self = this;

		var o_config = Ext.apply({}, i_self.initialConfig);
		var i_store = i_self.getStore();
		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();
		var i_model = i_store.model;
		var i_record = i_model.create({});
		var i_wrapper = i_self.wrapper;
		var o_viewConfig;

		Ext.apply(o_extraParams, {
			displayCheckbox: i_self.displayCheckbox
		});

		var n_expandToLevel = i_self.expandToLevel;

		i_store.on({
			load: {
				fn: function (i_store, a_nodes) {
					if (n_expandToLevel) {
						i_self.expandTree(i_self, a_nodes);
					}
				},
				single: true
			}
		});

		i_store.on({
			load: {
				fn: function (i_store, a_nodes) {
					Ext.Array.each(a_nodes, function(i_node) {
						if (i_node.get("ID") == -1) {
							i_node.set("allowDrop", false);
						}
						if (i_node.get("iconCls").indexOf("parent") != -1) {
							i_node.set("leaf", false);
							i_node.commit(true);
						}
						else {
							i_node.set("appendOnly", true);
						}
					});
				}
			}
		});

		// is association specified, then setup
		i_self.hasAssociation = (i_self.wrapper) ? true : false;
		if (i_self.hasAssociation) {
			i_self.setupAssociation();
		}

		// is writer model specified, then create writer store
		if (!i_self.writerStore && i_model.prototype.writerModel) {
			i_self.writerStore = Ext.create("Ext.data.Store", {
				model: i_model.prototype.writerModel,
				autoSync: false
			});

			var i_writeStore = i_self.writerStore;

			var i_writeProxy = i_writeStore.getProxy();
			var o_writerParams = i_writeProxy.getExtraParams();

			Ext.apply(o_writerParams, {
				uiName: "portfolio",
				context: "form"
			});
		}

		// create tree grid
		var a_columns = i_self.columns || [];
		var a_modelColumns = i_self.getModelColumns();
		var a_extra = i_self.extraColumns || [];

		a_columns = a_columns.concat(a_modelColumns.concat(a_extra));

		i_self.hideHeaders = a_columns.length == 1;

		if (i_self.hasAssociation) {
			// tree grid view

			var b_dragAndDrop = ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".update");

			o_viewConfig = {
				rootVisible: i_self.rootVisible,
				plugins: {
					ptype: "treeviewdragdrop",
					dragGroup: "organizerItems",
					dropGroup: "organizerItems",
					enableDrag: b_dragAndDrop,
					enableDrop: b_dragAndDrop,
					appendOnly: false,
					onViewRender: function(view) {
						var dnd = this;

						if (dnd.enableDrag) {
							dnd.dragZone = Ext.create("Ext.tree.ViewDragZone", {
								view: view,
								ddGroup: dnd.dragGroup || dnd.ddGroup,
								dragText: dnd.dragText,
								repairHighlightColor: dnd.nodeHighlightColor,
								repairHighlight: dnd.nodeHighlightOnRepair
							});
						}

						if (dnd.enableDrop) {
							dnd.dropZone = Ext.create("Ext.tree.ViewDropZone", {
								view: view,
								ddGroup: dnd.dropGroup || dnd.ddGroup,
								allowContainerDrops: dnd.allowContainerDrops,
								appendOnly: dnd.appendOnly,
								allowParentInserts: dnd.allowParentInserts,
								expandDelay: dnd.expandDelay,
								dropHighlightColor: dnd.nodeHighlightColor,
								dropHighlight: dnd.nodeHighlightOnDrop,
								isValidDropPoint: function(node, position, dragZone, e, data) {
									return i_self.validateDropPoint(this, node, data, position);
								},
								onNodeDrop: function(node, dragZone, e, data) {
									var dropZone = this;
									var dropped = false;
									var record = data.records[0];
									var processDrop = function () {
										dropZone.invalidateDrop();
										if (record.isNode) {
											dropZone.handleNodeDrop(data, dropZone.overRecord, dropZone.currentPosition);
											if (dropZone.currentPosition == "append") {
												dropZone.overRecord.set("leaf", false);
											}
										}
										dropped = true;
										dropZone.fireViewEvent("drop", node, data, dropZone.overRecord, dropZone.currentPosition);
									};
									performOperation = false;

									if (dropZone.valid) {
										performOperation = dropZone.fireViewEvent("beforedrop", node, data, dropZone.overRecord, dropZone.currentPosition, processDrop);
										if (performOperation !== false) {
											if (!dropped) {
												processDrop();
											}
										}
									}
									return performOperation;
								}
							});
						}
					}
				},
				listeners: {
					beforedrop: {
						fn: function(node, data, targetNode, dropPosition, dropFunction, eOpts) {
							var record = data.records[0];
							if (record.isNode && i_self.hasSequenceProperty(record)) {
								i_self.calculateNewSequence(this, node, data, targetNode, dropPosition);
							}
						}
					},
					drop: {
						fn: function(node, data, targetNode, dropPosition, eOpts) {

							var record = data.records[0];
							if (record.isNode && i_self.hasSequenceProperty(record)) {
								i_self.resequenceNode(this, node, data, targetNode, dropPosition);
							}
							else {
								i_self.addAssociation(targetNode, data.records, true);
							}
						}
					}
				}
			};
		}

		// XpdEditor window config
		i_self.xpdEditorConfig = {
			height: "90%",
			width: 700,
			collapsible: true,
			listeners: {
				show: {
					fn: function (i_window) {

						var i_form = i_window.down("form").getForm();
						var a_items = i_form.getFields();
						var i_xpdfield = a_items.items[0];

						var a_fields = i_xpdfield.query("field");

						Ext.Array.each(a_fields, function(i_field, n_index) {
							if (!i_field.isDisabled() && !i_field.readOnly) {
								i_field.focus(true, 10);
								return false;
							}
						});
					}
				}
			}
		};

		Ext.Object.merge(i_self, o_config, {
			idCount: 0,
			node: {},
			name: i_self.namePrefix + ".,tree",
			mode: i_self.mode || "model",
			viewConfig: o_viewConfig,
			listeners: {
				afterrender: {
					fn: function() {
						i_self.deselect();
						var i_root = i_self.getRootNode();
						if (i_self.view.rootVisible) {
							i_root.set("allowDrop", true);
						}
					}
				},
				beforeitemexpand: {
					fn: function(node) {
						i_self.beforeItemExpand(node);
					}
				},
				checkchange: {
					fn: function(node, checked) {
						i_self.nodeCheckChange(node, checked);
					}
				},
				select: {
					fn: function(view, node, index, e) {
						i_self.wrapper.fireEvent("nodeselection", node);
						Ext.ux.folderorganizer.Util.setCollectionColumnHeader(i_self, node);
					}
				},

				foldercreate: {
					fn: function(parentNode, properties) {
						i_self.folderCreate(parentNode, properties);
					}
				},
				rowselection: {
					fn: function(cid, records) {
						i_self.hasmanySelectionChange(records);
					}
				},
				propertychange: {
					fn: function(record, action, node) {
						i_self.save(record, action, node);
					}
				},
				itemcontextmenu: {
					fn: function(view, node, item, index, e) {
						e.stopEvent();

						i_self.getSelectionModel().select(node);
						var el = Ext.get(item);
						var coords = e.getXY();

						// row menu
						var items = [];
						if (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".create")) {

							var i_toolbar = i_self.up("panel").down("toolbar");
							var i_buttonAdd = i_toolbar.getComponent("add");

							if (i_buttonAdd && !i_buttonAdd.disabled) {
								if (!i_buttonAdd.menu) {
									var o_config = i_buttonAdd.initialConfig;
									o_config.icon = "";
									o_config.iconCls = "pf-add";
									var i_item  = Ext.widget("menuitem", o_config);
									items.push(i_item);
								}
								else {
									var i_menu = i_buttonAdd.menu;
									var a_items = i_menu.items.items;
									var a_menuitems = [];
									var parentCollection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(i_toolbar, node);
									if (parentCollection) {
										ip2.each(parentCollection.allowedchilds, function(n_cid) {
											ip2.each(a_items, function(i_button) {
												if (i_button.itemId == "add" + n_cid) {
													var o_config = i_button.initialConfig;
													var i_item = Ext.widget("menuitem", o_config);
													a_menuitems.push(i_item);
												}
											});
										});
									}
									else {
										ip2.each(a_items, function(i_button) {
											var o_config = i_button.initialConfig;
											var i_item = Ext.widget("menuitem", o_config);
											a_menuitems.push(i_item);
										});
									}
									var i_menuadd = Ext.widget("menuitem", {
										text: ip2.i18n({
											da: "Tilføj",
											en: "Add"
										}),
										iconCls: "pf-add",
										menu: {
											items: a_menuitems
										}
									});
									items.push(i_menuadd);
								}
							}
						}

						if (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".update")) {
							items.push({
								xtype: "menuitem",
								allowOtherMenus: false,
								text: ip2.i18n({
									da: "Rediger menupunkt",
									en: "Edit menuitem"
								}),
								itemId: "update",
								iconCls: "pf-edit",
								handler: function() {
									i_self.updateRow(i_self.node);
								}
							});
						}
						var o_properties = Ext.decode(node.get("PROPERTIES"), true) || {};
						if (o_properties.itemnumber || o_properties.pagetoken) {
							if (i_self.entity == "WSHMNUET00" || i_self.entity == "WSHFLDET00") {
								var s_type = ip2.i18n({
									da: i_self.entity == "WSHMNUET00" ? "side" : "produkt",
									en: i_self.entity == "WSHMNUET00" ? "page" : "product"
								});
								var b_get = true;
								switch (i_self.entity) {
									case "WSHMNUET00":
										b_get = (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data.WSHPAGET00.update") ||
												ip2.isAccessible("app." + i_wrapper.dmdProject + ".data.WSHPAGET00.read"));
										break;
									case "WSHFLDET00":
										b_get = (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data.WSHITMET00.update") ||
												ip2.isAccessible("app." + i_wrapper.dmdProject + ".data.WSHITMET00.read"));
										break;
								}
								if (b_get) {
									items.push({
										xtype: "menuitem",
										iconCls: "pf-edit",
										itemId: "edit",
										text: ip2.i18n({
											da: "Rediger " + s_type,
											en: "Edit " + s_type
										}),
										handler: function() {

											var s_entity = "";

											// TODO: Get this info from XPD.
											if (i_self.entity == "WSHMNUET00") {
												s_entity = "WSHPAGET00";
												s_tkn = o_properties.pagetoken;
											}

											if (i_self.entity == "WSHFLDET00") {
												s_entity = "WSHITMET00";
												s_tkn = o_properties.itemnumber;
											}

											var i_model = ip2.model({
												dmd: i_self.dmd,
												entityName: s_entity,
												context: "grid",
												uiName: "portfolio"
											});
											var o_config = {
												dmd: i_self.dmd,
												entityName: s_entity
											};
											var i_record = i_model.create();
											i_record.set(i_record.idProperty, s_tkn);

											var o_size = Ext.ux.file.util.Handler.getWindowSize();

											var wnd = Ext.widget("window", {
												modal: false,
												closable: true,
												collapsible: true,
												resizable: true,
												width: o_size.width * 0.9,
												height: o_size.height * 0.9,
												layout: "fit"
											});

											ip2.addChild(wnd, i_record, "update", o_config);

											var s_event = "entityupdate:" + s_entity;
											var o_event = {};

											o_event[s_event] = {
												fn: function(i_record) {
													var i_store = i_self.store;
													i_parentnode = node.parentNode;
													i_parentnode.removeAll(false);
													i_store.load({
														node: i_parentnode
													});
												},
												single: true
											};

											i_self.mon(ip2.App, o_event);
											wnd.show();
										}
									});
								}
							}
						}
						if (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".delete")) {
							items.push({
								xtype: "menuitem",
								itemId: "remove",
								text: i_self.getI18N("remove"),
								iconCls: "pf-delete",
								handler: function() {
									i_self.removeRow(i_self.node);
								}
							});
						}
						if (i_self.allowExpandChildren && !node.isLeaf()) {
							items.push({
								xtype: "menuitem",
								itemId: "expand",
								text: i_self.getI18N("expand"),
								iconCls: "pf-navigate_expand",
								handler: function() {
									i_self.expandChildren(i_self.node);
								}
							});
						}
						if (i_self.allowExport) {
							items.push({
								xtype: "menuitem",
								itemId: "export",
								text: i_self.getI18N("eksport"),
								iconCls: "pf-cloud_download",
								handler: function() {
									i_self.exportRow(i_self.node);
								}
							});
						}
						if (!node.get("leaf")) {
							items.push({
								xtype: "menuitem",
								iconCls: "pf-refresh",
								itemId: "icon-reload",
								text: ip2.i18n({
									da: "Genindlæs",
									en: "Reload"
								}),
								handler: function() {
									var i_store = i_self.store;
									node.removeAll(false);
									i_store.load({
										node: node
									});
								}
							});
						}

						var menu = Ext.widget("menu", {
							items: items
						});

						menu.showAt([coords[0], coords[1]]);

						if (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".update") ||
							ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".read")) {
							if (node.get("allowEdit") && i_self.checkAllowEdit(node)) {
								menu.down("#update").enable();
								i_self.node = node;
							}
							else {
								menu.down("#update").disable();
							}
						}

						if (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".delete")) {
							if (node && !node.isRoot()) {
								if (node.get("allowRemove")) {
									menu.down("#remove").enable();
									i_self.node = node;
								}
							}
							else {
								menu.down("#remove").disable();
							}
						}
					}
				},
				itemdblclick: {
					fn: function(view, node, item, index, e) {
						if (ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".update") ||
							ip2.isAccessible("app." + i_wrapper.dmdProject + ".data." + i_self.entity + ".read")) {
							if (node.get("allowEdit") && i_self.checkAllowEdit(node)) {
								i_self.updateRow(node);
							}
						}
					}
				}
			},
			displayCheckbox: Ext.isBoolean(i_self.displayCheckbox) ? i_self.displayCheckbox : true,
			allowEdit: (i_self.menus.indexOf("edit") == -1) ? false : true,
			allowRemove: (i_self.menus.indexOf("remove") == -1) ? false : true,
			allowExport: i_self.allowExport !== undefined ? i_self.allowExport : true,
			allowExpandChildren: (i_self.menus.indexOf("expandChildren") == -1) ? false : true,
			addToAllChildren: i_self.addToAllChildren || { allow: false },
			previousNodeCid: 0,
			searchValue: "",
			languageService: i_self.languageService || "",
			expandToLevel: o_config.expandToLevel || i_self.expandToLevel,
			levelSelectFirst: o_config.levelSelectFirst || i_self.levelSelectFirst,
			columns: a_columns,
			selMol: o_config.selMol !== undefined ? o_config.selMol : Ext.create("Ext.ux.folderorganizer.TreeSelModel")
		});

		i_self.callParent();

		if (i_self.addToAllChildren && i_self.addToAllChildren.multiChoiceDialog) {
			var mcd = i_self.addToAllChildren.multiChoiceDialog;

			i_self.questions = [];
			for (var i = 0; i < mcd.questions.length; i++) {
				i_self.questions.push({
					answer: i,
					question: ip2.i18n(mcd.questions[i])
				});

				switch (i) {
					case 0:
						i_self.questions[i].icon = "/system/images/icons/16x16/check2.png";
						break;
					case 1:
						i_self.questions[i].icon = "/system/images/icons/16x16/checks.png";
						break;
					case 2:
						i_self.questions[i].icon = "/system/images/icons/16x16/undo.png";
						break;
				}
			}
		}

		if (i_self.rootVisible) {
			var i_root = i_self.getRootNode();
			i_root.set("TITLE", "...");
			i_root.commit();
			i_root.expand();
		}

		return i_self;
	},

	/* ----------------------------------------------------------------------------------------------------
			Expand the treegrid
		 ---------------------------------------------------------------------------------------------------- */
	expandTree: function (i_self, a_node) {
		var me = this;

		if (me.el && me.el.dom) {
			me.expandTreeToLevel(a_node, 0, function (i_node, a_node) {
				// Callback pr. expand
			});
		}
		else {
			me.on({
				"afterrender": {
					fn: function () {
						me.expandTreeToLevel(a_node, 0, function (i_node, a_node) {
							// Callback pr. expand
						});
					},
					single: true
				}
			});
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Expand the treegrid to a certain level down, and also select first node at certain level
			if config options expandToLevel and levelSelectFirst are set
		 ---------------------------------------------------------------------------------------------------- */
	expandTreeToLevel: function (a_node, n_level, f_callback) {

		f_callback = f_callback || Ext.emptyFn;
		var me = this;

		if (a_node) {
			if (a_node.length === undefined) {
				a_node = [];
			}
		}

		var i_cmp = this;
		var i_tree = i_cmp;
		var i_store = i_cmp.store;
		var n_expandToLevel = i_cmp.expandToLevel;
		var n_selectLevel = i_cmp.levelSelectFirst;

		if (n_expandToLevel > n_level) {
			Ext.Array.each(a_node, function (i_node) {
				i_store.on({
					"load": {
						fn: function (i_self, a_node) {
							i_cmp.expandTreeToLevel(a_node, n_level, f_callback);

							if (n_selectLevel && n_selectLevel == n_level && a_node && a_node[0]) {
								i_tree.getSelectionModel().select(a_node[0]);
								me.wrapper.fireEvent("nodemouseup", a_node[0]);
							}

							f_callback(i_node, a_node);
						},
						single: true
					}
				});
				i_node.expand();
			});
			n_level++;
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Expand the treegrid to specified node
		 ---------------------------------------------------------------------------------------------------- */
	expandTreeToNode: function (array, selectedTreeNode, propertyField, propertyName) {
		var me = this;
		var node;
		var propertyValue = Ext.decode(selectedTreeNode.data[propertyField])[propertyName];

		me.expandTreeNodeInArray(0, array, node, function(parentNode) {
			me.getSelectionModel().select(me.findChildByProperty(parentNode, propertyField, propertyName, propertyValue));
		});
	},

	/* ----------------------------------------------------------------------------------------------------
			Expand the treegrid to specified node
		 ---------------------------------------------------------------------------------------------------- */
	expandTreeNodeInArray: function (counter, array, node, callback) {

		callback = callback || Ext.emptyFn;

		var me = this;

		if (counter >= array.length) {
			callback(node);
		}
		else {
			var nodeId = parseInt(array[counter]);
			var node = me.store.getNodeById(nodeId);
			counter++;
			if (node.isLeaf()) {
				me.expandTreeNodeInArray(counter, array, node, callback);
			}
			else if (node.isExpanded()) {
				me.expandTreeNodeInArray(counter, array, node, callback);
			}
			else if (node.isLoaded()) {
				node.on({
					"expand": {
						fn: function (node) {
							me.expandTreeNodeInArray(counter, array, node, callback);
						},
						single: true
					}
				});
				node.expand();
			}
			else {
				me.store.on({
					"load": {
						fn: function (store, a_record, success, operation, node) {
							var node = operation.node;
							me.expandTreeNodeInArray(counter, array, node, callback);
						},
						single: true
					}
				});
				node.expand();
			}
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Check tree node allow edit according xpd collection
		 ---------------------------------------------------------------------------------------------------- */
	findChildByProperty: function(node, propertyField, propertyName, value) {
		var cs = node.childNodes;
		var len = cs.length;
		var i = 0;
		var n;

		for (; i < len; i++) {
			n = cs[i];
			if (Ext.decode(n.data[propertyField])[propertyName] == value) {
				return n;
			}
		}

		return null;
	},

	/* ----------------------------------------------------------------------------------------------------
			Check tree node allow edit according xpd collection
		 ---------------------------------------------------------------------------------------------------- */
	checkAllowEdit: function(node) {
		var me = this;

		var collection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(me, node);

		return collection !== null ? (collection.disallowedit) ? false : true : false;
	},

	/* ----------------------------------------------------------------------------------------------------
			Validate drop point
		 ---------------------------------------------------------------------------------------------------- */
	validateDropPoint: function(treegrid, node, data, position) {

		var me = this;
		var b_allowed = false;
		var dragNode = data.records[0];
		var i_store = dragNode.getTreeStore ? dragNode.getTreeStore() : dragNode.store;
		var targetNode = treegrid.view.getRecord(node);

		if (!targetNode.get("allowDrop")) {
			return false;
		}

		if (targetNode.parentNode) {
			if (ip2.isEqual(targetNode.parentNode.data, dragNode.data)) {
				return false;
			}
		}

		// drag from folder property grid
		if (i_store.model && i_store.model.owner && i_store.model.owner.xtype == "folderorganizerFolderPropertyGrid") {
			b_allowed = false;
		}

		if (dragNode.get("cid")) {
			// cid specified in model
			b_allowed = me.validateDropPointXpd(dragNode, targetNode, position);
		}
		if (me.isTreeNodeDrag(dragNode)) {
			// leaf node DnD in tree grid
			if (targetNode.id == dragNode.id) {
				b_allowed = false;
			}
			else {
				b_allowed = me.validateDropPointXpd(dragNode, targetNode, position);
				if (dragNode.get("PARENTID") == targetNode.get("ID")) {
					b_allowed = false;
				}
				else {
					if (dragNode.get("PARENTID") != targetNode.get("PARENTID")) {
						if (me.isLeaf(targetNode)) {
							b_allowed = false;
						}
						else {
							if (position != "append") {
								b_allowed = false;
							}
						}
					}
					else {
						if (position == "before") {
							if (dragNode.nextSibling) {
								if (dragNode.nextSibling.get("ID") == targetNode.get("ID")) {
									b_allowed = false;
								}
							}
						}
						else if (position == "after") {
							if (dragNode.previousSibling) {
								if (dragNode.previousSibling.get("ID") == targetNode.get("ID")) {
									b_allowed = false;
								}
							}
						}
					}
				}
			}
		}
		else {
			if (!ip2.isEqual(dragNode.data, targetNode.data)) {
				b_allowed = true;
			}
		}

		if (b_allowed && targetNode.childNodes && targetNode.childNodes.length > 0) {
			var a_children = targetNode.childNodes;
			ip2.each(a_children, function(i_node) {
				if (i_node.get("token")) {
					var n_token = i_node.get("token");
					if (n_token == dragNode.get(dragNode.idProperty)) {
						b_allowed = false;
					}
				}
				else {
					if (i_node.get("rowProps") || i_node.get("PROPERTIES")) {

						var o_prop;
						var n_token;
						var s_idProperty = dragNode.idProperty;

						if (i_node.get("rowProps")) {
							o_prop = Ext.decode(i_node.get("rowProps"));
							n_token = o_prop.token;
							if (n_token == dragNode.get(dragNode.idProperty)) {
								b_allowed = false;
							}
						}
						if (b_allowed && i_node.get("PROPERTIES")) {
							o_props = Ext.decode(i_node.get("PROPERTIES"));
							if (s_idProperty == "ITMITMTKN") {
								n_token = o_props.itemnumber;
							}
							else if (s_idProperty == "PAGPAGTKN") {
								n_token = o_props.pagetoken;
							}

							if (n_token == dragNode.get(dragNode.idProperty)) {
								b_allowed = false;
							}
						}
					}
				}
			});
		}
		else {
			if (b_allowed && targetNode.parentNode) {
				var a_children = targetNode.parentNode.childNodes;
				ip2.each(a_children, function(i_node) {
					if (i_node.get("token")) {
						var n_token = i_node.get("token");
						if (n_token == dragNode.get(dragNode.idProperty)) {
							b_allowed = false;
						}
					}
					else {
						if (i_node.get("rowProps") || i_node.get("PROPERTIES")) {

							var o_prop;
							var n_token;
							var s_idProperty = dragNode.idProperty;

							if (i_node.get("rowProps")) {
								o_prop = Ext.decode(i_node.get("rowProps"));
								n_token = o_prop.token;
								if (n_token == dragNode.get(dragNode.idProperty)) {
									b_allowed = false;
								}
							}
							if (b_allowed && i_node.get("PROPERTIES")) {
								o_props = Ext.decode(i_node.get("PROPERTIES"));
								if (s_idProperty == "ITMITMTKN") {
									n_token = o_props.itemnumber;
								}
								else if (s_idProperty == "PAGPAGTKN") {
									n_token = o_props.pagetoken;
								}

								if (n_token == dragNode.get(dragNode.idProperty)) {
									b_allowed = false;
								}
							}
						}
					}
				});
			}
		}

		return b_allowed;
	},

	/* ----------------------------------------------------------------------------------------------------
			Check tree node drop according xpd rules (allow parent & childs)
		 ---------------------------------------------------------------------------------------------------- */
	validateDropPointXpd: function(dragNode, targetNode, position) {

		var me = this;
		var b_allowed = false;
		var parentCid = Ext.ux.folderorganizer.Util.getXpdCollectionId(me, targetNode);
		var parentCollection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(me, targetNode);
		var childCollection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(me, dragNode);

		if (parentCollection && !Ext.isEmpty(parentCollection.childlimit) && targetNode.childNodes.length >= parentCollection.childlimit) {
			b_allowed = false;
		}
		else if (childCollection.id == parentCid) {
			b_allowed = true;
		}
		else if (childCollection.allowedparents && childCollection.allowedparents.length > 0) {
			b_allowed = (childCollection.allowedparents.indexOf(parentCid) == -1) ? false : true;
		}
		else if (!parentCollection.allowedchilds) {
			// if no allowedchild specified - then allow drop
			b_allowed = true;
		}
		else {
			var cid = Ext.ux.folderorganizer.Util.getXpdCollectionId(me, dragNode);
			b_allowed = (parentCollection.allowedchilds.indexOf(cid) == -1) ? false : true;
		}

		return b_allowed;
	},

	/* ----------------------------------------------------------------------------------------------------
			Is it a tree drag from one tree node to another
		 ---------------------------------------------------------------------------------------------------- */
	isTreeNodeDrag: function(i_node) {

		var i_self = this;
		var b_isNode = i_node.isNode;

		if (b_isNode) {
			b_isNode = i_node.get("PARENTID") ? true : false;
			if (b_isNode) {
				return b_isNode;
			}
		}

		var o_dragData = i_node.get("dragData");

		if (o_dragData) {

			var o_view = o_dragData.view;

			if (o_view) {
				b_isNode = o_dragData.view.xtype == "treeview";
			}
		}

		return b_isNode;
	},

	/* ----------------------------------------------------------------------------------------------------
			Check if node has sequence property in column PROPERTIES
		 ---------------------------------------------------------------------------------------------------- */
	hasSequenceProperty: function(node) {
		if (!node.data || !node.data.PROPERTIES) {
			return false;
		}

		var props = Ext.decode(node.data.PROPERTIES);
		if (props.__cid__) {
			var collection = this.wrapper.xpd.flatten.collections[props.__cid__];
			if (collection && collection.properties.seq) {
				return true;
			}
		}

		return false;
	},

	/* ----------------------------------------------------------------------------------------------------
			Resequence node
		 ---------------------------------------------------------------------------------------------------- */
	calculateNewSequence: function(treegrid, node, data, targetNode, position) {
		var me = this;

		if (!data.records || !data.records[0]) {
			return;
		}

		var dragNode = data.records[0];

		var afterSeq;
		var beforeSeq;

		switch (position) {
			case "append":
				afterSeq = 0;
				if (targetNode.childNodes && targetNode.childNodes[0]) {
					beforeSeq = me.getSequenceFromProperties(targetNode.childNodes[0]);
				}
				else {
					beforeSeq = 2.0;
				}
				break;
			case "after":
				afterSeq = me.getSequenceFromProperties(targetNode);
				if (targetNode.nextSibling) {
					beforeSeq = me.getSequenceFromProperties(targetNode.nextSibling);
				}
				else {
					beforeSeq = afterSeq + 2.0;
				}
				break;
			case "before":
				if (targetNode.previousSibling) {
					afterSeq = me.getSequenceFromProperties(targetNode.previousSibling);
				}
				else {
					afterSeq = 0;
				}
				beforeSeq = me.getSequenceFromProperties(targetNode);
				break;
		}

		var props = Ext.decode(dragNode.data.PROPERTIES);
		var seq = (afterSeq + beforeSeq) / 2;

		if (Ext.isNumeric(seq)) {
			if (seq === 0) {
				dragNode.data.reseqAllSiblings = true;
			}
			else {
				dragNode.data.reseqAllSiblings = false;
				props.seq = seq.toString();
				dragNode.data.PROPERTIES = Ext.encode(props);
			}
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Resequence node
		 ---------------------------------------------------------------------------------------------------- */
	resequenceNode: function(treegrid, node, data, targetNode, position) {
		var me = this;

		if (!data.records || !data.records[0]) {
			return;
		}

		if (data.records[0].data.reseqAllSiblings) {
			me.resequenceAllChildrenNodes(targetNode.parentNode);
		}
		else {
			me.getRecord({
				node: data.records[0],
				success: function(args) {
					me.updateRowProperties(args.record, args.node, args.node.data.PROPERTIES, false);
				}
			});
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Resequence all children nodes
		 ---------------------------------------------------------------------------------------------------- */
	resequenceAllChildrenNodes: function(parentNode) {
		var me = this;
		var nextSeq = 0;

		for (var i = 0; i < parentNode.childNodes.length; i++) {
			var node = parentNode.childNodes[i];
			nextSeq += 10;

			var props = Ext.decode(node.data.PROPERTIES);
			props.seq = nextSeq;
			node.data.PROPERTIES = Ext.encode(props);

			me.getRecord({
				node: node,
				success: function(args) {
					me.updateRowProperties(args.record, args.node, args.node.data.PROPERTIES, false);
				}
			});
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Get sequence from properties
		 ---------------------------------------------------------------------------------------------------- */
	getSequenceFromProperties: function(node) {
		props = Ext.decode(node.data.PROPERTIES);

		return parseFloat(props.seq) || 0;
	},

	/* ----------------------------------------------------------------------------------------------------
			Add new row
		 ---------------------------------------------------------------------------------------------------- */
	addRow: function(collection) {
		var me = this;

		if (!me.writerStore) {
			Ext.ux.folderorganizer.Alert({
				title: me.getI18N("invalidConfig"),
				msg: me.getI18N("missingConfigOptions")
			});
			return;
		}

		if (collection) {
			me.addRowProperties(collection);
		}
		else {
			var key = {};
			key[me.propertyNameMapping.ID] = 0;
			me.writerStore.proxy.extraParams.key = Ext.encode(key);

			var model = me.writerStore.proxy.getModel();
			var record = model.create();
			me.writerStore.insert(0, record);
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Add row properties using XPD
		 ---------------------------------------------------------------------------------------------------- */
	addRowProperties: function(collection) {

		var me = this;

		var parentNode = me.node;

		var i_tree = this;
		var i_root = i_tree.getRootNode();
		var i_store = i_tree.getStore();
		var i_model = i_store.getModel();
		var b_parent = !Ext.Object.getSize(parentNode) ? false : true;

		var record = { data: {} };
		record.data[me.propertyNameMapping.PROPERTIES] = "{\"__cid__\":" + collection.id + "}";
		record = i_model.create(record.data);

		var o_config = Ext.apply({
			title: me.getI18N("create") + " \"" + ip2.xpd.translate(me.wrapper.xpd, collection.title, ip2.session.getLanguage()) + "\"",
			xpd: me.wrapper.xpd,
			collection: collection,
			record: record,
			environment: me.environment,
			propertyNameMapping: me.propertyNameMapping,
			action: "create",
			entity: me.wrapper.entity,
			dmdFile: me.writerStore.model.dmdFile,
			languageService: collection.languageService || me.languageService || "",
			preSave: me.preSave || function(a_modifed, f_callback) {
				f_callback();
			},
			doSave: function(record, node, properties, f_callback) {

				// MODIFIED BY ISJ

				// Deal with mapping values
				var o_data = {};
				o_data[me.propertyNameMapping.ID] = 0;
				o_data[me.propertyNameMapping.PARENTID] = b_parent ? (parentNode.data.ID > 0 ? parentNode.data.ID : 0) : 0;

				if (b_parent) {
					var o_props = Ext.decode(properties, true) || {};
					if (Ext.isEmpty(o_props.seq)) {
						me.setSequenceProperty(parentNode, o_props);
						properties = Ext.encode(o_props); // TODO: Why do this when o_props has not been touched?
					}
				}
				o_data[me.propertyNameMapping.PROPERTIES] = properties;

				// Deal with the record
				var i_record = me.writerStore.model.create(o_data);
				var i_node;
				var o_nodeData;
				var i_child;

				var i_created = Ext.create(me.store.model.$className, {
					ID: o_data[me.propertyNameMapping.ID],
					PARENTID: o_data[me.propertyNameMapping.PARENTID],
					TITLE: "",
					PROPERTIES: o_data[me.propertyNameMapping.PROPERTIES],
					leaf: me.setLeafForCollection(properties),
					allowEdit: true,
					allowRemove: true,
					loaded: true
				});
				o_nodeData = me.titlePropertyRenderer(i_created);
				i_created.set("TITLE", o_nodeData.title);
				i_created.set("icon", o_nodeData.icon);
				if (!o_nodeData.icon) {
					i_created.set("iconCls", "webshop-parent-node");
				}

				var f_loadParent = function(i_node, f_callback) {

					if (i_node) {
						i_node.collapse();
						i_node.removeAll(false);
						me.store.load({
							node: i_node,
							callback: function() {
								i_node.expand();
								f_callback();
							}
						});
					}
				};

				// Create key for store and save record
				i_record.phantom = true;

				me.saveRow(i_record, function(b_created, i_record) {

					if (b_created) {
						me.wrapper.fireEvent("nodeadded", i_created);
						f_loadParent(parentNode, function() {
							f_callback(i_record);
						});
					}
					else {
						if (f_callback) {
							f_callback(false, o_error);
						}
					}
				});

				delete me.writerStore.proxy.extraParams.key;

				var o_createdProperties = Ext.decode(i_created.getData("PROPERTIES"), true) || {};
				var o_parentProperties = Ext.decode(parentNode.getData("PROPERTIES"), true) || {};

				var childCid = o_createdProperties.__cid__;
				var parentCid = o_parentProperties.__cid__;

				if (childCid == 1 && parentCid == 2) {
					Ext.Ajax.request({
						url: me.proxy,
						params: {
							action: "setFolderCid",
							token: parentNode.get("ID"),
							cid: 1
						}
					});
					o_parentProperties.__cid__ = 1;
					parentNode.set("PROPERTIES", Ext.encode(o_parentProperties));
				}
			}
		}, me.xpdEditorConfig);

		i_window = Ext.create("Ext.ux.folderorganizer.XpdEditor", o_config);

		i_window.show();
		i_window.expand();
	},

	/* ----------------------------------------------------------------------------------------------------
			Update existing row
		 ---------------------------------------------------------------------------------------------------- */
	updateRow: function(node) {
		var me = this;

		if (!me.writerStore) {
			Ext.ux.folderorganizer.Alert({
				title: me.getI18N("invalidConfig"),
				msg: me.getI18N("missingConfigOptions")
			});
			return;
		}

		if (!node) {
			var nodes = me.getSelectionModel().getSelection();
			node = nodes[0];
		}

		if (node.data.allowEdit) {
			me.getRecord({
				node: node,
				success: function(args) {
					if (me.mode == "folder") {
						var collection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(me, args.record);
						if (collection) {
							me.updateRowUsingXpdEditor(args.record, args.node);
						}
						else {
							me.wrapper.fireEvent("nodestartedit", args.record);
						}
					}
				}
			});
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Update row properties using XPD
		 ---------------------------------------------------------------------------------------------------- */
	updateRowUsingXpdEditor: function(record, node) {

		var i_cmp = this;

		var i_window;

		if (!i_window) {

			var o_idColumn = (function () {

				var i_store = i_cmp.writerStore;
				var i_model = i_store.getModel();
				var o_model = i_model.prototype.dmdModel;
				var a_entities = o_model.entities;

				var o_entity = Ext.Array.findBy(a_entities, function(o_value) {
					return o_value.name == i_cmp.wrapper.entity;
				});

				var s_idColumn = o_entity.idColumn;

				var a_columns = [];

				if (Ext.isArray(o_entity.columns)) {
					a_columns = Ext.Array.slice(o_entity.columns);
				}
				else {
					Ext.Object.each(o_entity.columns, function(s_key, o_value) {
						o_value.name = s_key;
						a_columns.push(o_value);
					});
				}

				var o_return;

				Ext.Array.each(a_columns, function(o_column) {
					if (o_column.name == s_idColumn) {
						o_return = o_column;
						return false;
					}
				});

				return o_return;
			})();

			var s_title = (function () {

				var s_title = node.data.TITLE;
				var	o_xpd = i_cmp.wrapper.xpd;
				var	s_language = ip2.session.getLanguage();
				var	s_update = i_cmp.getI18N("update");

				s_title = ip2.xpd.translate(o_xpd, s_title, s_language);

				return [s_update, s_title].join(" ");
			})();

			var o_properties = Ext.decode(record.get(i_cmp.propertyNameMapping.PROPERTIES), true) || {};
			var o_collection = {};

			if (i_cmp.xpd.flatten.collections[o_properties[i_cmp.xpd.idProperty]]) {
				o_collection = i_cmp.xpd.flatten.collections[o_properties[i_cmp.xpd.idProperty]];
			}

			var o_config = Ext.apply({
				title: s_title,
				xpd: i_cmp.wrapper.xpd,
				environment: i_cmp.environment,
				propertyNameMapping: i_cmp.propertyNameMapping,
				idColumn: o_idColumn,
				node: node,
				record: record,
				action: "update",
				entity: i_cmp.wrapper.entity,
				dmdFile: i_cmp.writerStore.model.dmdFile,
				languageService: o_collection.languageService || i_cmp.languageService || "",
				preSave: i_cmp.preSave || function(a_modifed, f_callback) {
					f_callback();
				},
				doSave: function(record, node, properties, f_callback) {
					i_cmp.updateRowProperties(record, node, properties, true, function(i_node, o_error) {
						f_callback(i_node, o_error);
					});
				}
			}, i_cmp.xpdEditorConfig);

			i_window = Ext.create("Ext.ux.folderorganizer.XpdEditor", o_config);
		}

		i_window.show();
		i_window.expand();
	},

	/* ----------------------------------------------------------------------------------------------------
			Get row title
		 ---------------------------------------------------------------------------------------------------- */
	updateRowProperties: function(i_record, i_node, o_properties, b_updateNode, f_callback) {

		var i_self = this;

		if ((i_record.get(i_self.propertyNameMapping.PARENTID) !== undefined) && (i_node.parentNode.data.ID !== undefined)) {
			i_record.set(i_self.propertyNameMapping.PARENTID, (i_node.parentNode.get("ID") > 0 ? i_node.parentNode.get("ID") : 0));
		}
		i_record.set(i_self.propertyNameMapping.PROPERTIES, o_properties);

		var a_batch = [];
		var o_keys = {};

		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		var o_batch = {
			type: "upsert",
			dmd: i_self.dmd,
			entity: i_self.entity,
			transactiontype: i_self.entity,
			key: o_keys,
			row: i_record.getData()
		};

		a_batch.push(o_batch);

		Ext.Ajax.request({
			url: i_self.writerStore.proxy.url,
			jsonData: {
				transaction: {
					batch: a_batch
				}
			},
			success: function(i_repsonse, i_operation) {

				var o_result = Ext.decode(i_repsonse.responseText, true) || [{}];
				var o_record = o_result.batch[0].row;

				i_record.set(i_record.idProperty, o_record[i_record.idProperty]);

				if (i_record.get(i_self.propertyNameMapping.PARENTID) === 0) {
					i_self.wrapper.fireEvent("noderemoved", i_node);
				}
				else {
					i_node.set("PARENTID", i_record.get(i_self.propertyNameMapping.PARENTID));
				}
				if (f_callback) {
					f_callback(i_node);
				}
			},
			failure: function(o_error) {
				if (f_callback) {
					f_callback(false, o_error);
				}
			},
			getRecords: function() {
				return [i_record];
			}
		});

		// update node
		if (i_node && b_updateNode) {
			i_node.set("PROPERTIES", o_properties);
			var nodeData = i_self.titlePropertyRenderer(i_node);
			if (nodeData.title && nodeData.title.length > 0) {
				i_node.set("TITLE", nodeData.title);
				i_node.set("icon", nodeData.icon);
			}

			i_self.wrapper.fireEvent("nodechanged", i_node);
		}
	},

	saveRow: function(i_record, f_callback) {

		var i_self = this;
		f_callback = f_callback || Ext.emptyFn;

		var o_keys = {};
		var a_batch = [];
		var o_data = i_record.getData();
		o_keys[i_self.propertyNameMapping.ID] = o_data[i_self.propertyNameMapping.ID] || null;

		var o_batch = {
			type: "upsert",
			dmd: i_self.dmd,
			entity: i_self.entity,
			transactiontype: i_self.entity,
			key: o_keys,
			row: o_data
		};

		a_batch.push(o_batch);

		Ext.Ajax.request({
			url: i_self.writerStore.proxy.getUrl(),
			jsonData: {
				transaction: {
					batch: a_batch
				}
			},
			success: function(i_repsonse, i_operation) {

				var o_result = Ext.decode(i_repsonse.responseText, true) || [{}];
				var o_record = o_result.batch[0].row;

				Ext.Object.each(o_record, function(s_key, value) {
					i_record.set(s_key, value);
				});

				f_callback(true, i_record);
			},
			failure: function(o_error) {
				if (f_callback) {
					f_callback(true, o_error);
				}
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
			Set leaf for collection
		 ---------------------------------------------------------------------------------------------------- */
	setLeafForCollection: function(properties) {
		var me = this;

		var props = Ext.decode(properties),
		collection = Ext.ux.folderorganizer.Util.getXpdCollection(me, props.__cid__);

		if (collection.allowedchilds && collection.allowedchilds.length > 0) {
			return false;
		}
		else {
			return true;
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Remove existing row
		 ---------------------------------------------------------------------------------------------------- */
	removeRow: function(node) {
		var me = this;

		node = node || this.node;

		var collection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(me, node);

		if (!node.isLeaf()) {
			if (collection && collection.organizer && collection.organizer.prompt && collection.organizer.prompt.removeChildren) {
				Ext.create("Ext.ux.folderorganizer.MultiChoice", {
					title: ip2.i18n(
						{ da: "Sletning af afdeling og personer." },
						{ en: "What to delete ?" }
					),
					questions: [{
						answer: 0,
						question: ip2.i18n(
							{ da: "Slet afdelingen samt alle personer i denne!" },
							{ en: "This row, and all children." }
						),
						icon: "/system/images/icons/16x16/row_delete.png"
					},{
						answer: 1,
						question: ip2.i18n(
							{ da: "Slet afdelingen på uden af slette personerne." },
							{ en: "Only this row." }
						),
						icon: "/system/images/icons/16x16/row_delete.png"
					},{
						answer: 2,
						question: ip2.i18n(
							{ da: "Fortryd." },
							{ en: "Cancel." }
						),
						icon: "/system/images/icons/16x16/undo.png"
					}],
					guideLine: ip2.i18n(
						{ da: "Vælg, hvad der skal slettes:" },
						{ en: "Choose what to delete." }
					),
					modal: true,
					node: node,
					handler: function(answer) {
						var msgbox = this;

						switch (answer) {
							case 0:
								me.doDelete(msgbox.node, "allchildren");
								break;
							case 1:
								me.doDelete(msgbox.node, "onlyparent");
								break;
							case 2:
								break;
						}
					}
				}).show();
			}
			else {
				Ext.MessageBox.show({
					title: me.getI18N("confirmDeleteTitle"),
					msg: me.getI18N("confirmDelete").toString(),
					buttons: Ext.MessageBox.YESNOCANCEL,
					fn: function(btn, text) {
						switch (btn) {
							case "yes":
								me.doDelete(node);

								break;
							case "no":
								break;
							default:
								break;
						}
					},icon: Ext.MessageBox.QUESTION
				});
			}
		}
		else {
			if (collection && collection.organizer && collection.organizer.prompt && collection.organizer.prompt.removeRow) {
				Ext.create("Ext.ux.folderorganizer.MultiChoice", {
					title: ip2.i18n(
						{ da: "Sletning af person." },
						{ en: "What to delete ?" }
					),
					questions: [{
						answer: 0,
						question: ip2.i18n(
							{ da: "Slet personen!" },
							{ en: "Reference to above row and this row." }
						),
						icon: "/system/images/icons/16x16/row_delete.png"
					},{
						answer: 1,
						question: ip2.i18n(
							{ da: "Slet tilknytning til afdelingen." },
							{ en: "Only reference to above row." }
						),
						icon: "/system/images/icons/16x16/row_delete.png"
					},{
						answer: 2,
						question: ip2.i18n(
							{ da: "Fortryd." },
							{ en: "Cancel." }
						),
						icon: "/system/images/icons/16x16/undo.png"
					}],
					guideLine: ip2.i18n(
						{ da: "Vælg, hvad der skal slettes:" },
						{ en: "Choose what to delete." }
					),
					modal: true,
					node: node,
					handler: function(answer) {
						var msgbox = this;

						switch (answer) {
							case 0:
								me.doDelete(msgbox.node, "");
								break;
							case 1:
								me.doDelete(msgbox.node, "onlyreference");
								break;
							case 2:
								break;
						}
					}
				}).show();
			}
			else {
				me.doDelete(node);
			}
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Expand all children
		 ---------------------------------------------------------------------------------------------------- */
	expandChildren: function(node) {

		var me = this;
		node = node || me.node;

		node.expand(true);
	},

	/* ----------------------------------------------------------------------------------------------------
			Confirm export
		 ---------------------------------------------------------------------------------------------------- */
	exportRow: function(node) {

		var me = this;
		node = node || me.node;

		Ext.MessageBox.show({
			title: me.getI18N("confirmExportTitle"),
			msg: me.getI18N("confirmExport") + " <b>" + node.data.TITLE + "</b>",
			buttons: Ext.MessageBox.YESNO,
			fn: function(btn, text) {
				switch (btn) {
					case "yes":
						me.doExport(node);
						break;
					case "no":
						break;
					default:
						break;
				}
			},
			icon: Ext.MessageBox.QUESTION
		});
	},

	/* ----------------------------------------------------------------------------------------------------
			Export
		 ---------------------------------------------------------------------------------------------------- */
	doExport: function(node) {
		var me = this;

		var loadingMask = new Ext.LoadMask(
			Ext.getBody(),
			{
				msg: me.getI18N("pleaseWait")
			}
		);
		loadingMask.show();

		Ext.Ajax.request({
			url: "/wsh-services/wshExpFld.aspx?folderToken=" + node.data.ID,
			node: node,
			loadingMask: loadingMask,
			success: function(response, request) {
				request.loadingMask.hide();
				var result = Ext.decode(response.responseText);
				if (result.success) {
					var msg = me.getI18N("exportInformation");
					msg = msg.replace("&title", node.data.TITLE);
					msg = msg.replace("&folder", result.folder);
					Ext.MessageBox.show({
						title: me.getI18N("information"),
						msg: msg,
						buttons: Ext.MessageBox.OK,
						icon: Ext.MessageBox.INFORMATION
					});
				}
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
			DMD editor
		 ---------------------------------------------------------------------------------------------------- */
	dmdEditor: function(store, record, node, action) {
		var me = this;

		var win = Ext.create("Ext.ux.folderorganizer.DmdEditor", {
			wrapper: this,
			store: store,
			record: record,
			action: action,
			title: (action == "new") ? me.getI18N("create") : me.getI18N("update"),
			listeners: {
				datachanges: function(writeaction, record) {
					if (writeaction == "create") {
						var childNode = me.createNewNode(record, node);
						var parentNode = node || me.store.getRootNode();
						if (parentNode && parentNode.isLoaded()) {
							parentNode.insertChild(0, childNode);
						}
					}
					else if (writeaction == "update") {
						node.set("GROUP", record.data.NAME);
					}
					else if (writeaction == "destroy") {
						me.doDelete(node);
					}
				}
			}
		});
		win.show();
	},

	/* ----------------------------------------------------------------------------------------------------
			Create new node
		 ---------------------------------------------------------------------------------------------------- */
	createNewNode: function(record, node) {
	},

	/* ----------------------------------------------------------------------------------------------------
			Get the record for a tree node
		 ---------------------------------------------------------------------------------------------------- */
	getRecord: function(args) {
		var me = this;

		if (!me.writerStore) {
			return;
		}

		var i_node = args.node;

		// get record by ip2 model and use model writer to sync with server

		var i_store = me.writerStore;

		var i_proxy = me.writerStore.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		Ext.apply(o_extraParams, {
			action: "getRow",
			dmdFile: me.writerStore.model.dmdFile,
			uiName: "portfolio",
			context: "form",
			key: Ext.encode(me.getKey(args.node)),
			args: args
		});

		i_store.load(function(a_records, i_operation, success) {

			var i_request = i_operation.getRequest();
			var o_parmas = i_request.getParams();
			var args = o_parmas.args;

			if (Ext.isFunction(args.success) && !args.success.fired) {
				args.success.fired = true;
				args.record = a_records[0];
				args.success.call(this, args);
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
			get key values from node
		 ---------------------------------------------------------------------------------------------------- */
	getKey: function(node) {
		var me = this;

		key = {};
		if (node) {
			key[me.propertyNameMapping.ID] = node.data.ID;
		}
		return key;
	},

	/* ----------------------------------------------------------------------------------------------------
			Save
		 ---------------------------------------------------------------------------------------------------- */
	save: function(record, action, node) {
		var me = this;

		if (!action || Ext.isObject(action)) {
			action = "update";
		}

		// find node, if not passed
		if (action == "update" && !node) {
			node = me.store.getNodeById(record.data[me.propertyNameMapping.ID]);

			// if still no node, because off an error in extjs. nodeHash array not correct updated !
			// -then check if editing selected node
			var nodes = me.getSelectionModel().getSelection();
			if (nodes && nodes[0].data.ID == record.data[me.propertyNameMapping.ID]) {
				node = nodes[0];
			}
		}

		if (action == "update" && node) {

			for (var key in record.data) {
				if (node.data[me.propertyNameMappingReverse[key]]) {
					node.set(me.propertyNameMappingReverse[key], record.data[key]);
				}
			}

			if (me.mode == "folder" && record.data[me.propertyNameMapping.PROPERTIES]) {
				me.setNodeTitle(node, record.data[me.propertyNameMapping.PROPERTIES]);
			}
		}

		if (me.writerStore) {
			me.writerStore.proxy.extraParams.action = "updateRow";
			me.writerStore.proxy.extraParams.dmdFile = me.writerStore.model.dmdFile;
			record.save({
				success: function(record, operation) {
					if (operation.action == "add") {
						this.refresh();
					}
				},
				action: action,
				scope: me
			});
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Refresh the tree view
		 ---------------------------------------------------------------------------------------------------- */
	refresh: function(clear) {
		var me = this;

		var root = me.store.getRootNode();
		root.removeAll();

		if (Ext.isBoolean(clear)) {
			delete me.store.proxy.extraParams.search;
		}

		me.store.load({
			scope: this,
			callback: function(records, operation, success) {
				me.expandTree(this, records[0], records);
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
			Search
		 ---------------------------------------------------------------------------------------------------- */
	search: function(searchValue) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_root = i_self.getRootNode();
		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		o_extraParams.search = searchValue;

		i_root.collapse();
		i_root.removeAll();

		i_store.load({
			scope: this,
			callback: function(a_records, operation, success) {
				i_root.expand();
				i_self.expandTree(i_self, a_records);
			}
		});
	},

	/* ----------------------------------------------------------------------------------------------------
			Refresh the tree view
		 ---------------------------------------------------------------------------------------------------- */
	deselect: function() {
		var me = this;

		me.getSelectionModel().deselectAll();

		if (!me.cid) {
			return;
		}

		var node = me.getRootNode();
		if (Ext.isEmpty(node.data.PROPERTIES)) {
			var props = {
				__cid__: me.cid
			};
			node.set("PROPERTIES", Ext.encode(props));
		}
		me.getSelectionModel().select(node);
	},

	/* ----------------------------------------------------------------------------------------------------
			Before expanding a tree node
		 ---------------------------------------------------------------------------------------------------- */
	beforeItemExpand: function(node) {
		var me = this;

		//me.getSelectionModel().select(node);

		if (node.hasChildNodes()) {
			var childNode = node.getChildAt(0);
			if (childNode.isLeaf()) {
				var getAssociation = (Ext.isBoolean(childNode.getAssociation)) ? childNode.getAssociation : true;
				if (getAssociation) {
					for (var c in node.childNodes) {
						me.getAssociationNode(node.childNodes[c]);
					}
				}
			}
		}
		else if (me.isLeaf(node)) {
			return false;
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Set tree node title depending on the property data
		 ---------------------------------------------------------------------------------------------------- */
	setNodeTitle: function(node, properties) {
		var data = (Ext.isString(properties)) ? Ext.decode(properties) : properties;
		if (data.title) {
			node.set("TITLE", data.title);
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			The checkbox for a node is changed
		 ---------------------------------------------------------------------------------------------------- */
	isForeignRelation: function(node) {
		var me = this;

		var collection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(me, node);
		if (collection && collection.entity) {
			return true;
		}
		else {
			return false;
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			The checkbox for a node is changed
		 ---------------------------------------------------------------------------------------------------- */
	nodeCheckChange: function(node, checked) {
		var me = this;

		if (me.hasAssociation) {
			// validate: "hasMany" (itemgrid) has an selection
			var selection = me.wrapper.hasMany.panel.getSelectionModel().getSelection();
			if (selection.length === 0) {
				Ext.ux.folderorganizer.Alert({
					title: me.getI18N("message"),
					msg: me.getI18N("hasManySelectionMissing")
				});
				node.set("checked", !checked); // swap check mark back
				return;
			}

			me.changeAssociation(node, selection, checked, false);
		}
	},

	/* ----------------------------------------------------------------------------------------------------
			Get the association nodes
		 ---------------------------------------------------------------------------------------------------- */
	getAssociationNode: function(node) {
		var me = this;

		node.set("allowEdit", true);

		if (me.hasAssociation && me.wrapper.association && me.wrapper.association.name && me.mode != "folder") {
			node[me.wrapper.association.name]().load({
				callback: function(records) {
					// change node from leaf to parent node
					if (records.length > 0) {
						node.set("leaf", false);
					}

					// get associated nodes
					for (var i = 0; i < records.length; i++) {
						var childNode = me.createAssociationNode(node, records[i], false, false);
					}
				}
			});
		}
	},

	addAssociation: function(node, selection, dropped) {
		this.changeAssociation(node, selection, true, dropped);
	},

	removeAssociation: function(node, selection) {
		this.changeAssociation(node, selection, false, false);
	},

	changeAssociation: function(node, selection, checked, dropped) {
		var me = this;

		if (!me.hasAssociation) {
			return;
		}

		if (Ext.isBoolean(node.data.allowDrop) && node.data.allowDrop) {
			me.changeAssociationSelection(node, selection, checked, dropped);
		}
		else if (node.hasChildNodes()) {
			var childNode = node.getChildAt(0);
			if (me.isLeaf(childNode)) {
				me.changeAssociationSelection(node, selection, checked, dropped);
			}
			else {
				me.traverseChildren(node, selection, checked, dropped);
			}
		}
		else {
			me.changeAssociationSelection(node, selection, checked, dropped);
		}
	},

	traverseChildren: function(node, selection, checked, dropped) {
		var me = this;

		var children = node.childNodes;
		for (var i = 0; i < children.length; i++) {
			if (children[i].hasChildNodes()) {
				me.traverseChildren(children[i], selection, checked, dropped);
			}
			else {
				me.changeAssociationSelection(children[i], selection, checked, dropped);
			}
		}
	},

	changeAssociationSelection: function(node, selection, checked, dropped) {
		if (checked) {
			this.appendAssociationSelection(node, selection, dropped);
		}
		else {
			this.removeAssociationSelection(node, selection);
		}
	},

	appendAssociationSelection: function(node, selection, dropped) {
		var me = this;

		if (!me.hasAssociation) {
			return;
		}

		var record = {};
		for (var i = 0; i < selection.length; i++) {
			var duplicate = false;
			if (me.many2many && !me.many2many.allowDuplicateRecords) {
				duplicate = me.checkDuplicateAssociation(node, selection[i]);
			}
			if (!duplicate) {
				if (me.addToAllChildren.allow && node.data.hasSubFolders) {

					// params for the YES button function
					var params = {
						node: node,
						selection: selection[i],
						dropped: dropped
					};

					// Traverse all node children thru and add selection
					var updateAllChildren = function(params) {
						var properties = me.buildProperties(params.selection);
						Ext.Ajax.request({
							url: me.proxy,
							params: {
								action: "addItemToAllChildren",
								folder: params.node.data.ID,
								item: properties.keyValue,
								cid: params.selection.data.cid,
								xpd: me.wrapper.xpdPath
							},
							success: function(response, request) {
								if (request.node) {
									// remove all children
									if (request.node.childNodes) {
										var children = request.node.childNodes;
										var len = children.length;
										for (var i = 0; i < len; i++) {
											children[0].remove(true);
										}
									}

									// refresh this node
									me.store.load({
										node: request.node
									});
								}
							},
							node: params.node
						});
					};

					if (me.addToAllChildren.warning && me.questions) {
						Ext.create("Ext.ux.folderorganizer.MultiChoice", {
							title: ip2.i18n(me.addToAllChildren.multiChoiceDialog.title),
							questions: me.questions,
							guideLine: ip2.i18n(me.addToAllChildren.multiChoiceDialog.guideLine),
							modal: true,
							params: params,
							handler: function(answer) {
								switch (answer) {
									case 0:
										me.doCreate(this.params.node, this.params.selection, true, this.params.dropped);
										break;
									case 1:
										updateAllChildren(this.params);
										break;
									case 2:
										break;
								}
							}
						}).show();
					}
					else {
						updateAllChildren(params);
					}
				}
				else {
					me.doCreate(node, selection[i], true, dropped);
				}
			}
		}

		// parent node not a leaf any more
		node.set("leaf", false);
	},

	removeAssociationSelection: function(node, selection) {
		var me = this;

		if (!me.hasAssociation) {
			return;
		}

		var children = node.childNodes;
		var removeCnt = 0;
		var noOfChildren = children.length;

		// finding all children for this node matching a selection
		for (var c = 0; c < noOfChildren; c++) {
			var child = children[c];
			for (var i = 0; i < selection.length; i++) {
				var sID = selection[i].data.ID;
				var keys = me.getKeysFromNode(child);
				if (sID == keys.hasMany.ID) {
					removeCnt++;

					// remove record in many - many store
					var record = me.findMany2ManyRecord(keys);
					if (record !== null) {
						me.doDeleteRelation(record);
					}

					// remove this tree node
					child.remove(true);
				}
			}
		}

		if (removeCnt > 0) {
			if (removeCnt == children.length) {
				node.set("leaf", true);
			}
		}
	},

	createMany2ManyRecord: function(parentNode, item) {
		var me = this;

		var data = me.buildMany2ManyData(parentNode, item);

		return me.many2many.store.model.create(data);
	},

	buildMany2ManyData: function(i_parent, i_node) {

		var i_self = this;

		var o_data = {};

		if (i_self.wrapper.xpd) {

			o_data[i_self.propertyNameMapping.PARENTID] = i_parent.get("ID");

			if (i_node.get("cid")) {

				var o_build = i_self.buildProperties(i_node);
				var o_properties = o_build.properties;

				if (Ext.isEmpty(o_properties.seq)) {

					i_self.setSequenceProperty(i_parent, o_properties);
				}

				o_data[i_self.propertyNameMapping.PROPERTIES] = Ext.encode(o_properties);

				// kopi data from original
				var o_collection = Ext.ux.folderorganizer.Util.getXpdCollection(i_self, i_node.get("cid"));

				if (o_collection.organizer && o_collection.organizer.copyOriginalWhenDropped) {

					o_data[i_self.propertyNameMapping.PROPERTIES] = i_node.get(i_self.propertyNameMapping.PROPERTIES);

					if (!o_data[i_self.propertyNameMapping.PROPERTIES]) {

						var o_key = {};
						o_key[i_self.propertyNameMapping.ID] = i_node.get(i_self.propertyNameMapping.ID);

						var rs = ip2.sajax.request({
							url: "/ip2-services/ip2dmdProxy.aspx?model=" + i_self.entity + "&action=getRow&dmdFile=" + i_self.writerStore.model.dmdFile + "&key=" + Ext.encode(o_key),
							method: "GET",
							asJson: true
						});

						o_data[i_self.propertyNameMapping.PROPERTIES] = rs.rows[0][i_self.propertyNameMapping.PROPERTIES];
					}
				}

				if (o_collection && o_collection.titleColumns) {

					var a_titles = o_collection.titleColumns.split(",");

					Ext.Array.each(a_titles, function(s_title, n_index) {
						o_data.TITLE = i_self.concatTitle(o_data.TITLE, i_node.get(s_title.trim()));
					});
				}
			}
		}
		else {
			var belongToKey;
			if (Ext.isFunction(i_parent.get("ID").substring) && i_parent.get("ID").substring(0, 11) == "association") {
				belongToKey = i_parent.get("parentId");
			}
			else {
				belongToKey = i_parent.get("ID");
			}
			o_data[i_self.wrapper.belongTo.foreignKey] = belongToKey;
			o_data[i_self.wrapper.hasMany.foreignKey] = i_node.get("ID");
		}

		return o_data;
	},

	isLeaf: function(i_node) {

		var b_leaf = i_node.isLeaf();

		if (Ext.isBoolean(i_node.get("isHasManyNode")) && i_node.get("isHasManyNode")) {
			b_leaf = true;
		}

		return b_leaf;
	},

	isNode: function(i_record) {
		return i_record.isNode ? true : false;
	},

	buildProperties: function(item) {

		var me = this;
		var cid = item.data.cid;
		var properties = {};
		var property;
		var props = {};
		var keyValue;

		if (item.data.PROPERTIES) {
			props = Ext.decode(item.data.PROPERTIES);
		}
		Ext.apply(props, item.data);

		if (cid === undefined) {
			cid = props.__cid__;
		}

		var collection = Ext.ux.folderorganizer.Util.getXpdCollection(me, cid);
		for (var key in collection.properties) {
			if (collection.properties[key].isKey) {
				property = collection.properties[key].databasebind;
				if (props[property] === undefined) {
					property = key;
				}
				properties[key] = props[property];
				keyValue = props[property];
			}
			else if (collection.properties[key].databasebind) {
				var dataexclude = Ext.isBoolean(collection.properties[key].dataexclude) ? collection.properties[key].dataexclude : false;
				if (!dataexclude) {
					if (Ext.isArray(collection.properties[key].databasebind)) {
						Ext.Array.each(collection.properties[key].databasebind, function(property) {
							if (props[property]) {
								properties[key] = props[property];
							}
							else {
								property = property;
								if (props[property]) {
									properties[key] = props[property];
								}
							}
						});
					}
					else {
						property = collection.properties[key].databasebind;
						property = property;
						properties[key] = props[property] || "";
					}
				}
			}
			else if (collection.properties[key].value) {
				properties[key] = collection.properties[key].value;
			}
			else {
				properties[key] = props[key] || "";
			}
		}
		properties.__cid__ = cid;

		if (!keyValue) {
			if (props[me.propertyNameMapping.ID]) {
				keyValue = props[me.propertyNameMapping.ID];
			}
			else if (item.data.ID) {
				keyValue = item.data.ID;
			}
		}

		return { keyValue: keyValue, properties: properties };
	},

	/* ----------------------------------------------------------------------------------------------------
			Get next sequence number for properties
		 ---------------------------------------------------------------------------------------------------- */
	setSequenceProperty: function(parentNode, properties) {
		var seq = 20;
		if (parentNode.hasChildNodes() && parentNode.firstChild) {
			var props = (parentNode.firstChild.data.PROPERTIES) ? Ext.decode(parentNode.firstChild.data.PROPERTIES) : { seq: 20 };
			if (!Ext.isNumber(props.seq)) {
				seq = parseFloat(props.seq);
				if (isNaN(seq)) {
					seq = 20;
					props.seq = seq;
				}
				else {
					props.seq = seq;
				}
			}
			else {
				seq = props.seq;
			}
		}

		seq = seq / 2;
		properties.seq = seq;
	},

	checkDuplicateAssociation: function(node, selection) {
		var me = this;
		var keys;

		// child node it self
		if (Ext.isFunction(node.data.ID.substring) && node.data.ID.substring(0, 11) == "association") {
			keys = me.getKeysFromNode(node);
			if (keys.hasMany.ID == selection.data.ID) {
				return true;
			}
		}

		// parent node without any children
		if (!node.hasChildNodes()) {
			return false;
		}

		// parent node with children, check all children
		var children = node.childNodes;
		for (var i = 0; i < children.length; i++) {
			keys = me.getKeysFromNode(children[i]);
			if (keys.hasMany.ID == selection.data.ID) {
				return true;
			}
		}
	},

	createAssociationNode: function(i_parent, i_record, setChecked, b_dropped) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_model = i_store.getModel();
		var s_title = "";
		var ID;

		if (!i_self.hasAssociation) {
			return;
		}

		if (b_dropped) {
			s_title = i_self.getAssociationNodeTitle(i_record);
			ID = i_parent.get("ID") + "_" + i_record.get(i_record.idProperty);
		}
		else {
			if (i_self.wrapper.hasMany.foreignKey) {
				var hasManyRecord;
				hasManyRecord = i_self.wrapper.hasMany.store.getById(i_record.data[i_self.wrapper.hasMany.foreignKey]);
				if (!hasManyRecord) {
					hasManyRecord = i_self.wrapper.hasMany.store.getById(i_record.get("ID"));
				}
				if (hasManyRecord) {
					s_title = i_self.getAssociationNodeTitle(hasManyRecord);
					ID = i_parent.get("ID") + "_" + hasManyRecord.get("ID");
				}
			}
		}

		var i_node;

		if (i_record.isNode) {
			i_node = i_record;
		}
		else {
			i_node = Ext.create(i_model.$className, {
				ID: "association_" + ID
			});
		}

		// node.set(i_model.treeColumnName, title);
		i_node.set("leaf", true);
		i_node.set("isHasManyNode", true);
		i_node.set("allowEdit", i_self.allowEdit);
		i_node.set("allowRemove", i_self.allowRemove);

		var o_data = i_self.buildMany2ManyData(i_parent, i_record);

		if (o_data) {

			Ext.Object.each(o_data, function(s_key, value) {
				i_node.set(i_self.propertyNameMappingReverse[s_key], value);
			});
		}

		i_node.getAssociation = false; // prevent this leaf node from trigger "getAssociation"

		if (i_self.displayCheckbox) {

			i_parent.set("checked", setChecked);
		}

		var o_render = i_self.titlePropertyRenderer(i_node);

		if (s_title && s_title.length > 0) {
			o_render.title = s_title;
		}
		i_node.set(i_model.treeColumnName, o_render.title);
		i_node.set("icon", o_render.icon);

		return i_node;
	},

	getAssociationNodeTitle: function(record) {
		var me = this;
		var title = "";

		// get title using the description in xpd
		if (me.wrapper.xpd) {
			if (record.data.cid) {
				var cid = record.data.cid;
				var collection = Ext.ux.folderorganizer.Util.getXpdCollection(me, cid);
				if (collection.titleColumns) {
					var titles = collection.titleColumns.split(",");
					for (var i = 0; i < titles.length; i++) {
						title = me.concatTitle(title, record.data[titles[i].trim()]);
					}
				}
				else if (collection.properties) {
					for (var name in collection.properties) {
						if (collection.properties[name].isTitle) {
							var props = record.data;
							if (record.data.PROPERTIES) {
								Ext.apply(props, Ext.decode(record.data.PROPERTIES));
							}
							if (Ext.isArray(collection.properties[name].databasebind)) {
								Ext.Array.each(collection.properties[name].databasebind, function(name) {
									if (props[name]) {
										title = me.concatTitle(title, props[name]);
										return false;
									}
								});
							}
							else {
								if (props[collection.properties[name]]) {
									title = me.concatTitle(title, props[collection.properties[name].databasebind]);
								}
							}
						}
					}
				}
			}
		}
		else {
			var fields = me.wrapper.hasMany.titleFields || record.store.model.prototype.fields.keys;
			for (var i = 0; i < fields.length; i++) {
				title += ((title.length === 0) ? "" : ", ") + record.data[fields[i]];
			}
		}

		return title;
	},

	concatTitle: function(title, value) {
		return (title) ? title + " " + ip2.i18n(value) : ip2.i18n(value);
	},

	getKeysFromNode: function(node) {
		var keys = {};
		keys.belongTo = {};
		keys.hasMany = {};

		if (Ext.isFunction(node.data.ID.indexOf)) {
			var temp = node.data.ID.substring(node.data.ID.indexOf("_") + 1);
			keys.belongTo.ID = Number(temp.substring(0, temp.indexOf("_")));
			keys.hasMany.ID = Number(temp.substring(temp.indexOf("_") + 1));
		}
		else {
			keys.belongTo.ID = node.data.ID;
			keys.hasMany.ID = node.data.ID;
		}

		return keys;
	},

	findMany2ManyRecord: function(keys) {
		var me = this;

		var record;
		var cnt = 0;

		record = me.many2many.store.findRecord(me.wrapper.hasMany.foreignKey, keys.hasMany.ID, 0);
		while (record) {
			if (record.data[me.wrapper.belongTo.foreignKey] == keys.belongTo.ID) {
				return record;
			}
			record = me.many2many.store.findRecord(me.wrapper.hasMany.foreignKey, keys.hasMany.ID, ((record.index) ? record.index + 1 : cnt++));
		}

		return null;
	},
	hasmanySelectionChange: function(selection) {
		var me = this;

		if (!me.displayCheckbox) {
			return;
		}

		me.setNodesUnchecked();

		if (selection && selection[0]) {
			me.setNodesChecked(selection);
		}
	},

	setNodesChecked: function(selection) {

		var i_self = this;

		var i_store = i_self.getStore();

		var i_many2manyStore = i_self.many2many.store;
		var i_model = i_many2manyStore.getModel();
		var i_proxy = i_model.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		var a_filter = [];


		for (var i = 0; i < selection.length; i++) {
			o_option.property = i_self.wrapper.hasMany.foreignKey;
			o_option.value = selection[i].data.ID;
			o_option.operator = "OR";
			filter.push(o_option);
			delete o_option;
		}

		var oldAction = o_extraParams.action;
		o_extraParams.action = "getRows";
		o_extraParams.filter = Ext.encode(a_filter);


		i_many2manyStore.on({
			load: {
				fn: function(i_manyStore, a_records, b_successful, i_operation) {

					o_extraParams.action = oldAction;
					delete o_extraParams.filter;

					Ext.Array.each(a_records, function(i_record) {

						var i_belongToRecord = i_store.getNodeById(i_record.get(i_self.wrapper.belongTo.foreignKey));

						if (i_self.displayCheckbox && i_belongToRecord) {
							i_belongToRecord.set("checked", true);
						}
					});
				}
			}
		});

		i_many2manyStore.load();
	},

	setNodesUnchecked: function() {

		var i_self = this;

		var i_store = i_self.getStore();

		var i_many2manyStore = i_self.many2many.store;

		var a_records = i_many2manyStore.getRange();

		Ext.Array.each(a_records, function(i_record) {

			var i_belongToRecord = i_store.getNodeById(i_record.get(i_self.wrapper.belongTo.foreignKey));

			if (i_self.displayCheckbox && i_belongToRecord) {
				i_belongToRecord.set("checked", false);

				if (i_belongToRecord.parentNode) {
					i_belongToRecord.parentNode.set("checked", false);
				}

			}
		});
	},

	getModelColumns: function() {

		var i_self = this;
		var a_columns = [];

		var i_store = i_self.getStore();
		var i_model = i_store.getModel();
		var a_fields = i_model.getFields();

		Ext.Array.each(a_fields, function(i_field) {

			var o_column;
			var s_columnTitel;

			s_columnTitel = ip2.i18n(i_field.title);

			if (!s_columnTitel) {
				s_columnTitel = ip2.i18n(i_field.name);
			}

			if (i_field.isTitle) {

				o_column = {
					title: s_columnTitel,
					text: s_columnTitel,
					dataIndex: i_field.name,
					flex: i_field.flex ? i_field.flex : 1,
					renderer: Ext.isFunction(i_field.renderer) ? i_field.renderer :
						function(value, meta, record) {

							var s_title = value;
							var nodeData = i_self.titlePropertyRenderer(record);
							var s_value = nodeData.title;

							var s_search = i_self.getSearchValue();

							if (s_value) {
								s_title = s_value;
							}
							else {
								s_title = ip2.i18n(value);
							}
							if (s_search) {
								var s_searchLower = s_search.toLowerCase();
								var s_titleLower = s_title.toLowerCase();
								if (s_titleLower.indexOf(s_searchLower) > -1) {
									var n_start = s_titleLower.indexOf(s_searchLower);
									var n_end = n_start + s_searchLower.length;
									s_title = s_title.substring(0, n_start) +
									"<span style=\"background-color:yellow;n_\">" +
									s_title.substring(n_start, n_end) +
									"</span>" + s_title.substring(n_end);
								}
							}
							return s_title;
						},
					scope: i_self
				};

				// first column
				if (Ext.isEmpty(a_columns)) {
					o_column.xtype = "treecolumn";
					o_column.flex = 2;
					delete o_column.width;
					i_model.treeColumnName = i_model.treeColumnName || o_column.dataIndex;
				}

				a_columns.push(o_column);
			}
			else if (i_field.isOrganizer) {

				o_column = {
					header: s_columnTitel,
					text: s_columnTitel,
					title: s_columnTitel,
					dataIndex: i_field.name,
					flex: i_field.flex ? i_field.flex : 1,
					renderer: function(value, i_meta, i_record, n_index) {
						return value;
					},
					scope: i_self
				};

				a_columns.push(o_column);
			}
		});

		// if columns still empty, use all fields
		if (Ext.isEmpty(a_columns)) {
			Ext.Array.each(a_fields, function(i_field) {
				var o_column = {
					text: Ext.util.Format.capitalize(Ext.util.Format.lowercase(i_field.name)),
					dataIndex: i_field.name
				};

				// first column
				if (Ext.isEmpty(a_columns)) {
					o_column.xtype = "treecolumn";
					i_model.treeColumnName = i_model.treeColumnName || o_column.dataIndex;
				}
				a_columns.push(o_column);
			});
		}

		if (i_self.wrapper.xpd) {
			a_columns =	Ext.ux.folderorganizer.Util.addCollectionColumns(i_self, a_columns);
		}

		return a_columns;
	},
	/* -------------------------------------------------------------------------------------------------------------------
			Add columns dynamic depending on the collection
		 ------------------------------------------------------------------------------------------------------------------- */
	titlePropertyRenderer: function(i_record) {

		var i_self = this;

		var o_data = {
			title: "",
			icon: ""
		};

		var s_icon = i_record.get("icon");

		var o_collection = Ext.ux.folderorganizer.Util.getXpdCollectionByNode(i_self, i_record);

		if (!o_collection) {
			return o_data;
		}

		if (o_collection.icon) {
			o_data.icon = (i_self.wrapper.xpd.iconPath ? i_self.wrapper.xpd.iconPath + "/" : "") + o_collection.icon;
		}

		if (o_collection) {
			if (o_collection.properties) {

				var s_properties = i_record.get("PROPERTIES");

				var o_properties = Ext.decode(s_properties, true) || {};

				// Apply values from row properties, if not already exists or is empty
				var s_rowProperties = i_record.get("rowProps");

				if (s_rowProperties) {
					var o_rowPropperties = Ext.decode(s_rowProperties, true) || {};
					if (o_rowPropperties.properties) {
						o_rowPropperties = o_rowPropperties.properties;
					}

					Ext.apply(o_properties, o_rowPropperties);
				}

				var o_collectionProperties = o_collection.properties;

				Ext.Object.each(o_collectionProperties, function(s_key, value) {
					if (o_properties.hasOwnProperty(s_key) && value.isTitle) {
						o_data.title = i_self.concatTitle(o_data.title, o_properties[s_key]);
					}
				});

				if (o_data.title.length === 0) {
					var o_title = o_collectionProperties.title;

					if (o_title && o_title.databasebind) {
						var a_titleFields = Ext.isArray(o_title.databasebind) ? o_title.databasebind : [o_title.databasebind];
						Ext.Array.each(a_titleFields, function(s_field) {
							if (o_properties[field]) {
								o_data.title = o_properties[field];
								return false;
							}
						});
					}
					else if (o_properties.title) {
						o_data.title = ip2.i18n(o_properties.title);
					}

					if (s_icon.indexOf(o_properties.icon) > 0) {
						i_record.set("icon", "");
						i_record.commit(true);
					}
				}
			}
		}

		if (!Ext.isString(o_data.title)) {
			o_data.title = o_data.title + " ";
		}

		return o_data;
	},

	expandSelectedNodes: function() {
		var me = this;

		var nodes = me.getSelectionModel().getSelection();
		for (var i = 0; i < nodes.length; i++) {
			nodes[i].expand();
		}
	},

	doCreate: function(parentNode, selection, setChecked, dropped) {
		var me = this;

		// Warning for copy from original
		if (selection.data.cid && dropped) {
			var collection = Ext.ux.folderorganizer.Util.getXpdCollection(me, selection.data.cid);

			if (collection.organizer &&
				collection.organizer.copyOriginalWhenDropped &&
				collection.organizer.prompt &&
				collection.organizer.prompt.copyOriginal) {

				if (selection.data[me.propertyNameMapping.PARENTID] > 0) {
					Ext.create("Ext.ux.folderorganizer.MultiChoice", {
						title: ip2.i18n(
							{ da: "Personen er tilknyttet en anden afdeling." },
							{ en: "Copy from original ?" }
						),
						questions: [{
							answer: 0,
							question: ip2.i18n(
								{ da: "Lav en kopi af personen og tilknyt denne i stedet." },
								{ en: "Continue to copy this row." }
							),
							icon: "/system/images/icons/16x16/copy.png"
						},{
							answer: 1,
							question: ip2.i18n(
								{ da: "Fortryd." },
								{ en: "Cancel." }
							),
							icon: "/system/images/icons/16x16/undo.png"
						}],
						guideLine: ip2.i18n(
							{ da: "Vælg, hvad der skal ske:" },
							{ en: "This row already belong to an other parent." }
						),
						modal: true,
						parentNode: parentNode,
						selection: selection,
						setChecked: setChecked,
						dropped: dropped,
						handler: function(answer) {
							var msgbox = this;

							switch (answer) {
								case 0:
									me.createNodeAndRecord(msgbox.parentNode, msgbox.selection, msgbox.setChecked, msgbox.dropped, false);
									break;
								case 1:
									break;
							}
						}
					}).show();
				}
				else {
					me.createNodeAndRecord(parentNode, selection, setChecked, dropped, true);
				}
			}
			else {
				me.createNodeAndRecord(parentNode, selection, setChecked, dropped, false);
			}
		}
		else {
			me.createNodeAndRecord(parentNode, selection, setChecked, dropped, false);
		}
	},

	createNodeAndRecord: function(i_parent, i_selection, setChecked, b_dropped, b_keepOriginal) {

		var i_self = this;
		var i_many2manyStore = i_self.many2many.store;

		// Sync many to many relation
		var i_record = i_self.createMany2ManyRecord(i_parent, i_selection);
		if (b_keepOriginal) {
			i_record.set(i_self.propertyNameMapping.ID, i_selection.get(i_self.propertyNameMapping.ID));
		}

		i_many2manyStore.insert(0, i_record);

		// create new child node
		var i_child;
		var o_childProp;
		var o_parentProp;

		if (i_parent.isLoaded()) {
			i_child = i_self.createAssociationNode(i_parent, i_selection, setChecked, b_dropped);
		}

		// If parent node do not have any folder as children, but has product as children. Set parent as cid 2 = product folder
		var s_childValue = i_record.get(i_self.propertyNameMapping.PROPERTIES);
		var s_parentValue = i_parent.get("PROPERTIES");
		var n_childCid = 0;
		var n_parentCid = 0;

		if (s_childValue) {

			o_childProp = Ext.decode(s_childValue);
			n_childCid = o_childProp.__cid__;
		}
		if (s_parentValue) {

			o_parentProp = Ext.decode(s_parentValue);
			n_parentCid = o_parentProp.__cid__;
		}

		if (n_childCid == 3 && n_parentCid == 1) {
			if (!i_self.hasChildnodesWithCid(i_parent, 1) && !i_self.hasChildnodesWithCid(i_parent, 2)) {
				Ext.Ajax.request({
					url: i_self.proxy,
					params: {
						action: "setFolderCid",
						token: i_parent.get("ID"),
						cid: 2
					}
				});
				var o_properties = Ext.decode(i_parent.get("PROPERTIES"));
				o_properties.__cid__ = 2;
				i_parent.set("PROPERTIES" ,Ext.encode(o_properties));
			}
		}
		// Sync with server
		i_self.doCreateRelation(i_record, i_child, i_parent, b_keepOriginal);
	},

	doCreateRelation: function(i_record, i_child, i_parent, b_keepOriginal) {

		var i_self = this;

		var i_store = i_self.getStore();

		var i_many2manyStore = i_self.many2many.store;
		var i_model = i_many2manyStore.getModel();
		var i_proxy = i_model.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		var s_oldAction = o_extraParams.action;

		var key = {};
		if (b_keepOriginal) {
			key[i_self.propertyNameMapping.ID] = i_record.get(i_self.propertyNameMapping.ID);
		}
		else {
			key[i_self.propertyNameMapping.ID] = 0;
		}

		o_extraParams.action = "updateRow";
		o_extraParams.key = Ext.encode(key);

		i_self.saveRow(i_record, function(b_created, i_record) {

			if (b_created) {

				var s_properties = i_record.get(i_self.propertyNameMapping.PROPERTIES);

				if (s_properties) {

					var data = Ext.decode(s_properties, true) || {};

					if (data.__cid__ == 3) {

						Ext.Ajax.request({
							url: i_self.proxy,
							params: {
								action: "checkProductCatalogLocation",
								folderToken: i_record.get(i_self.propertyNameMapping.ID)
							}
						});
					}
				}

				if (i_parent) {

					i_parent.removeAll(false);

					i_store.load({
						node: i_parent
					});
				}
			}
		});

		o_extraParams.action = s_oldAction;
		delete o_extraParams.key;
	},

	doUpdateRelation: function(i_parent) {

		var i_self = this;

		var i_many2manyStore = i_self.many2many.store;
		var i_model = i_many2manyStore.getModel();
		var i_proxy = i_model.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		var oldAction = o_extraParams.action;

		var o_key = {};
		var o_parentKey = i_parent.get("key");
		if (o_parentKey) {
			o_key = o_parentKey;
		}
		else {
			o_key[i_self.propertyNameMapping.ID] = i_parent.get("ID");
		}

		o_extraParams.action = "updateRow";
		o_extraParams.key = Ext.encode(o_key);
		i_many2manyStore.sync();
		o_extraParams.action = oldAction;
		delete o_extraParams.key;
	},

	doDelete: function(i_node, s_action) {

		var i_self = this;

		var i_parent = i_node.parentNode;

		if (i_node.get("allowRemove")) {
			Ext.Ajax.request({
				url: i_self.proxy,
				node: i_node,
				params: {
					action: "removefolder",
					subaction: s_action || "allchildren",
					ID: i_node.get("ID"),
					entity: i_self.entity,
					idField: i_self.propertyNameMapping.ID,
					parentidField: i_self.propertyNameMapping.PARENTID,
					propertiesField: i_self.propertyNameMapping.PROPERTIES,
					dataLibrary: (Ext.isFunction(i_self.wrapper.getDataLibrary)) ? i_self.wrapper.getDataLibrary() : ""
				},
				success: function(response, request) {
					i_self.wrapper.fireEvent("noderemoved", request.node);
				}
			});
		}

		var o_parentProp = Ext.decode(i_parent.get("PROPERTIES"), true) || {};

		var n_parentCid = o_parentProp.__cid__;

		var n_cid = -1;

		i_node.remove();


		if (n_parentCid == 2 && !i_self.hasChildnodesWithCid(i_parent, 3)) {

			n_cid = 1;
		}
		else if (n_parentCid == 1 &&
				(
					!i_self.hasChildnodesWithCid(i_parent, 1) ||
					!i_self.hasChildnodesWithCid(i_parent, 2)
				) && i_self.hasChildnodesWithCid(i_parent, 3)
			) {

			n_cid = 1;
		}

		if (n_cid > -1)  {

			o_parentProp.__cid__ = n_cid;

			Ext.Ajax.request({
				url: i_self.proxy,
				params: {
					action: "setFolderCid",
					token: i_parent.get("ID"),
					cid: n_cid
				}
			});
		}

		i_parent.set("PROPERTIES", Ext.encode(o_parentProp));

		if (i_parent && i_parent.hasChildNodes && Ext.isFunction(i_parent.hasChildNodes)) {
		}
		else {
			i_parent.set("leaf", true);
		}
	},

	doDeleteRelation: function(i_node) {

		var i_self = this;

		var i_many2manyStore = i_self.many2many.store;
		var i_model = i_many2manyStore.getModel();
		var i_proxy = i_model.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		var oldAction = o_extraParams.action;

		var o_key = {};
		o_key[i_self.propertyNameMapping.ID] = i_node.get("ID");

		i_many2manyStore.remove(i_node);

		o_extraParams.action = "deleteRow";
		o_extraParams.key = Ext.encode(o_key);
		i_many2manyStore.sync();
		o_extraParams.action = oldAction;
		delete o_extraParams.key;
	},

	setFocus: function(component) {
		var me = this;

		if (component == "tree") {
			me.getSelectionModel().select(0);
			me.getView().focus();
		}
		else {
			if (!me[component]) return false; // component does not exists
			me[component].focus();
		}

		return true; // set focus successed
	},
	setupAssociation: function() {
		var me = this;

		// add listeners to many - many store. Set id
		if (me.many2many && me.many2many.store) {
			me.many2many.store.on("write", function(store, operation) {
				var response;
				var newId;
				var o_resp = operation.getResponse();
				if (o_resp.responseText) {
					response = Ext.decode(o_resp.responseText);
					if (response.success) {
						if (response.rows) {
							// new records, set id and commit
							for (var i = 0; i < operation.records.length; i++) {
								if (Ext.isObject(response.rows)) {
									newId = response.rows.ID;
								}
								else {
									newId = (response.rows[i].ID) ? response.rows[i].ID : 0;
								}
								operation.records[i].set("ID", newId);
								operation.records[i].commit();

								// update many - many store
								var record = me.many2many.store.getById(newId);
								record.set(me.wrapper.belongTo.foreignKey, operation.records[i].data[me.wrapper.belongTo.foreignKey]);
								record.set(me.wrapper.hasMany.foreignKey, operation.records[i].data[me.wrapper.hasMany.foreignKey]);
							}
						}
						else {
							for (var i = 0; i < operation.records.length; i++) {
								operation.records[i].commit();
							}
						}
					}
				}
			});
		}
	},
	getI18N: function(key) {
		var value = ip2.folderorganizer.getTextValue(key);
		if (Ext.isObject(value)) {
			value = value[ip2.folderorganizer.getLanguage()];
		}
		return value;
	},

	/* ----------------------------------------------------------------------------------------------------
			Has node children with specified cid
		 ---------------------------------------------------------------------------------------------------- */
	hasChildnodesWithCid: function(node, cid) {
		var me = this;

		for (var i = 0; i < node.childNodes.length; i++) {
			if (Ext.decode(node.childNodes[i].data.PROPERTIES).__cid__ == cid) {
				return true;
			}
		}

		return false;
	}
});
  Ext.define('Ext.ux.folderorganizer.Organizer', {

	extend: 'Ext.panel.Panel',

	layout: {
		type: 'border'
	},

	border: false,

	initComponent: function() {

		var me = this;
		me.dmdProject = me.dmd.split("/").pop().split(".").shift();
		me.setupI18N();

		Ext.tip.QuickTipManager.init();

		me.listeners = me.listeners || {};
		me.contentEvents = ['foldercreate', 'rowselection', 'propertychange'];
		me.focusNo = 1;

		if (me.folder) {
			me.initFolder();
		}
		else {
			me.initBelongTo();
		}

		me.listeners = Ext.apply(me.listeners, {
			afterrender: function() {
				me.setFocus();
				me.enableFocusManager();
			}
		});

		me.title = null,
		me.preventHeader = true;

		me.callParent(arguments);

		return me;
	},
	/* ---------------------------------------------------------------------------------------------
		  initialize folder method
		 --------------------------------------------------------------------------------------------- */
	initFolder: function() {

		var me = this;

		me.items = [];

		me.folder.cid = me.folder.cid || '';
		me.folder.displayRootNode = (Ext.isBoolean(me.folder.displayRootNode)) ? me.folder.displayRootNode : true;
		me.folder.expandRootNode = (Ext.isBoolean(me.folder.expandRootNode)) ? me.folder.expandRootNode : false;
		me.folder.hasRootCid = (Ext.isBoolean(me.folder.hasRootCid)) ? me.folder.hasRootCid : true;
		me.folder.multiAddChoice = (Ext.isBoolean(me.folder.multiAddChoice)) ? me.folder.multiAddChoice : true;
		me.folder.orderBy = me.folder.orderBy || '';
		me.folder.extraProps = me.folder.extraProps || '';
		me.folder.buttons = Ext.Array.filter(me.folder.buttons, function(s_button) {
			var b_allowed = true;
			switch (s_button) {
				case "add":
					b_allowed = ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".create");
					break;
				case "edit":
					b_allowed = (ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".update") ||
								ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".read"));
					break;
				case "remove":
					b_allowed = ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".delete");
					break;
			}
			return b_allowed;
		});

		me.folder.allowExport = ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".export.definitions");

		if (!me.folder.propertyNameMapping) {
			if (me.folder.entity && me.folder.entity == 'WSHNAMET00') {
				me.folder.propertyNameMapping = {
					ID: 'NAMNAMTKN',
					PARENTID: 'NAMPNTTKN',
					PROPERTIES: 'NAMPROP'
				};
			}
			else if (me.folder.entity && me.folder.entity == 'WSHMNUET00') {
				me.folder.propertyNameMapping = {
					ID: 'MNUMNUTKN',
					PARENTID: 'MNUPNTTKN',
					PROPERTIES: 'MNUPROP'
				};
			}
			else {
				me.folder.propertyNameMapping = {
					ID: 'FLDFLDTKN',
					PARENTID: 'FLDPNTTKN',
					PROPERTIES: 'FLDPROP'
				};
			}
		}
		me.folder.propertyNameMappingReverse = {};
		for (var key in me.folder.propertyNameMapping) {
			me.folder.propertyNameMappingReverse[me.folder.propertyNameMapping[key]] = key.toString();
		}

		me.dmdName = me.folder.dmd;
		me.dmdPath = me.dmdName;
		me.xpdName = me.xpd;
		me.xpdPath = me.xpdName;

		// get xpd definition
		me.xpd = ip2.resource.get(me.xpdName);

		// flatten xpd, if passed
		if (me.xpd) {
			me.xpd.flatten = ip2.xpd.flatten(me.xpd);
			ip2.each(me.xpd.flatten.collections, function(collection) {
				collection.uiName = 'portfolio';
			});
		}
		var model = {};

		if (Ext.ClassManager.isCreated("folder-" + me.entity)) {

			model = Ext.ClassManager.get("folder-" + me.entity);

			var i_proxy = model.getProxy();
			var o_extraParams = i_proxy.getExtraParams();

			Ext.apply(o_extraParams, {
				action: 'treeStore',
				entity: me.folder.entity,
				dataLibrary: me.getDataLibrary(),
				menus: Ext.encode(me.folder.menus),
				displayRootNode: me.folder.displayRootNode,
				hasRootCid: me.folder.hasRootCid,
				orderBy: me.folder.orderBy,
				extraProps: me.folder.extraProps,
				cid: me.folder.cid,
				xpd: me.xpdPath,
				dmd: me.dmdPath,
				language: ip2.session.getLanguage(),
				idField: me.folder.propertyNameMapping.ID,
				parentidField: me.folder.propertyNameMapping.PARENTID,
				propertiesField: me.folder.propertyNameMapping.PROPERTIES
			});
		}
		else {
			var a_fields = [
				{ name: 'TITLE', type: 'string', isTitle: true, title: 'Folder' },
				{ name: 'ID' },
				{ name: 'PARENTID', type: 'int' },
				{ name: 'PROPERTIES', type: 'string' },
				{ name: 'rowProps', type: 'string' },
				{ name: 'hasSubFolders', type: 'bool' },
				{ name: 'allowEdit', type: 'bool' },
				{ name: 'allowRemove', type: 'bool' },
				{ name: 'highlight', type: 'bool' }
			];

			var a_extra = me.getModelFields();
			a_fields = a_fields.concat(a_extra);

			model = Ext.define('folder-' + me.entity, {
				extend: 'Ext.data.Model',
				fields: a_fields,
				idProperty: 'ID',
				proxy: {
					type: 'ajax',
					url: me.folder.proxy,
					extraParams: {
						action: 'treeStore',
						entity: me.folder.entity,
						dataLibrary: me.getDataLibrary(),
						menus: Ext.encode(me.folder.menus),
						displayRootNode: me.folder.displayRootNode,
						hasRootCid: me.folder.hasRootCid,
						orderBy: me.folder.orderBy,
						extraProps: me.folder.extraProps,
						cid: me.folder.cid,
						xpd: me.xpdPath,
						dmd: me.dmdPath,
						language: ip2.session.getLanguage(),
						idField: me.folder.propertyNameMapping.ID,
						parentidField: me.folder.propertyNameMapping.PARENTID,
						propertiesField: me.folder.propertyNameMapping.PROPERTIES
					}
				}
			});
		}

		me.store = Ext.create('Ext.data.TreeStore', {
			model: model,
			clearOnLoad: true,
			root: {
				ID: 0,
				PARENTID: 0,
				PROPERTIES: "",
				rowProps: ""
			}
		});

		// add writer store
		if (me.folder.menus && me.folder.menus.length > 0) {

			var i_writerModel = ip2.model({
				dmd: me.dmdPath,
				entityName: me.folder.entity,
				context: "form"
			});

			var i_writerStore = Ext.create('Ext.data.Store', {
				model: i_writerModel,
				autoSync: false,
				proxy: ip2.getProxyByEntity({
					dmd: me.dmdPath,
					entityName: me.folder.entity,
					dataLibrary: me.getDataLibrary()
				})
			});

			var i_writerProxy = i_writerStore.getProxy();
			var o_writerParams = i_writerProxy.getExtraParams();

			Ext.apply(o_writerParams, {
				storeId: ip2.storeId(),
				uiName: me.dmdProject || "portfolio",
				context: 'form'
			});

			me.writerModel = i_writerModel;
			me.writerStore = i_writerStore;
		}

		// relation between folder and content
		me.many2many = {};

		me.many2many.model = ip2.model({
			dmd: me.dmdPath,
			entityName: me.folder.entity,
			dataLibrary: me.getDataLibrary()
		});

		me.many2many.store = Ext.create('Ext.data.Store', {
			model: me.many2many.model,
			proxy: ip2.getProxyByEntity({
				dmd: me.dmdPath,
				entityName: me.folder.entity,
				dataLibrary: me.getDataLibrary()
			})
		});

		Ext.apply(me.many2many.store.getProxy().getExtraParams(), {
			dmdFile: me.dmdPath,
			uiName: me.folder.uiName || 'organizer',
			context: 'grid',
			action: 'getRows'
		});

		me.many2many.root = 'rows';
		me.many2many.allowDuplicateRecords = true;

		me.belongTo = {};
		me.belongTo.foreignKey = me.folder.propertyNameMapping.ID;
		me.hasMany = {};
		me.hasMany.foreignKey = me.folder.propertyNameMapping.ID;

		var o_layout = {
			type: "vbox",
			align: "stretch"
		};
		if (me.folder.entity == "WSHMNUET00") {
			o_layout = {
				type: "border"
			};
			me.displayFilterField = true;
		}
		var folderPanel = Ext.create('Ext.panel.Panel', {
			flex: 1,
			border: true,
			region: "center",
			layout: o_layout,
			split: true,
			items: []
		});

		// Toolbar
		var tb = Ext.create('Ext.ux.folderorganizer.Toolbar', {
			wrapper: me,
			border: false,
			namePrefix: 'folder',
			propertyNameMapping: me.folder.propertyNameMapping
		});
		delete me.folder.buttons;
		if (tb.items.items && tb.items.items.length > 0) {
			folderPanel.addDocked(tb);
			tb.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved', 'nodestartedit', 'nodeloaded', 'nodemouseup']);
		}

		// Breadcrumb
		if (me.showFolderBreadcrumb) {
			me.productCatalogLocation = Ext.create('Ext.ux.folderorganizer.FolderProductLocation', {
				itemId: 'productCatalogLocation',
				wrapper: me,
				listeners: {
					nodeselection: function(node) {
						// prevent firing twice
						if (node.internalId == me.productCatalogLocation.internalId) {
							return false;
						}
						me.productCatalogLocation.internalId = node.internalId;

						if (me.productCatalogLocation.rendered) {
							var key = me.treegrid.buildProperties(node);
							if (key.keyValue) {
								var keyField = (key.properties.__cid__ == 3) ? 'item' : 'folder';
								me.productCatalogLocation.store.proxy.extraParams[keyField] = key.keyValue;
								me.productCatalogLocation.store.load();
								me.productCatalogLocation.store.on('load', function(store, records) {
									if (records.length > 1) {
										me.productCatalogLocation.show();
									}
								});
								delete me.productCatalogLocation.store.proxy.extraParams[keyField];
							}
						}
					}
				}
			});
			folderPanel.add(me.productCatalogLocation);

			me.productCatalogLocation.relayEvents(
				me, [
					'nodeselection',
					'nodeadded',
					'nodechanged',
					'noderemoved',
					'nodestartedit',
					'nodeloaded',
					'nodemouseup'
				]);
		}

		// Folder Tree
		// TODO: This really should be an applyIf - there is no chance of changing these
		// TODO values at all when you do it like this
		var cfg = Ext.apply(me.folder, {
			flex: 1,
			wrapper: me,
			namePrefix: 'belongTo',
			displayCheckbox: false,
			mode: 'folder',
			xpd: me.xpd,
			xpdName: me.xpdName,
			xpdPath: me.xpdPath,
			store: me.store,
			many2many: me.many2many,
			environment: me.environment || 'folderorganizer',
			showFolderBreadcrumb: me.showFolderBreadcrumb || false,
			displayRootNode: true,
			languageService: me.folder.languageService || ""
		});

		if (cfg.title && Ext.isObject(cfg.title)) {
			cfg.title = ip2.i18n(cfg.title);
		}

		if (me.writerStore) {
			cfg.writerStore = me.writerStore;
		}
		me.treegrid = Ext.create('Ext.ux.folderorganizer.Tree', cfg);
		me.treegrid.flex = 3;
		me.treegrid.relayEvents(me, me.contentEvents);
		if (!me.dataParent) {
			if (me.folder.entity == "WSHMNUET00") {
				me.treegrid.on({
					select: {
						fn: function(i_tree, node) {
							var i_stacktree = me.down("#stacktree");
							if (node.get("PROPERTIES")) {
								i_stacktree.clear();
								var o_properties = Ext.decode(node.get("PROPERTIES"));
								var o_rowprops = node.get("rowProps") ? Ext.decode(node.get("rowProps")) : {};
								if (o_rowprops.__cid__ == 13 || o_rowprops.__cid__ == 14) {
									i_stacktree.reload(node, o_properties, o_rowprops);
								}
								if (o_properties.__cid__ && o_properties.__cid__ != 2) {
									var s_title = o_properties.title || node.get("TITLE") || "";
									s_title = ip2.i18n(s_title);
									i_stacktree.setTitle(ip2.i18n({
										da: "Side elementer: " + s_title,
										en: "Page elements: " + s_title
									}));
								}
							}
							else {
								i_stacktree.clear();
							}
						}
					}
				});
			}
		}
		folderPanel.add(me.treegrid);
		if (!me.dataParent) {
			if (me.folder.entity == "WSHMNUET00") {
				var i_south = Ext.widget("treepanel", {
					layout: "fit",
					iconCls: 'ip2-tree-application-group',
					rootVisible: false,
					animate: false,
					useArrows: true,
					collapsible: true,
					viewConfig: {
						loadMask: false
					},
					split: true,
					itemId: "stacktree",
					region: "south",
					flex: 1,
					title: ip2.i18n({
						da: "Side elementer: ",
						en: "Page elements: "
					}),
					hidden: false,
					clear: function() {
						var i_self = this;
						var i_root = i_self.getRootNode();
						i_root.removeAll(false);
						i_self.setTitle("");
					},
					reload: function(node, o_properties, o_rowprops)	{
						var i_tree = this;
						var i_root = i_tree.getRootNode();
						var i_store = i_tree.getStore();
						var i_model = i_store.model.create(node.data);
						i_root.removeAll(false);
						var s_title = "";
						if (o_properties.title) {
							s_title = ip2.i18n(o_properties.title);
						}
						else {
							s_title = node.get("TITLE");
						}
						i_model.set("text", s_title);
						i_model.set("token", o_rowprops.token);
						var i_node = i_root.appendChild(i_model);
						i_node.commit();
						i_tree.getStackItems(i_node, o_rowprops);
					},
					listeners: {
						itemcontextmenu: function(view, node, item, index, e) {
							var i_self = this;
							var coords = e.getXY();
							var a_items = [];

							e.stopEvent();
							if (ip2.isAccessible("app." + me.dmdProject + ".data.WSHPAGET00.update") ||
								ip2.isAccessible("app." + me.dmdProject + ".data.WSHPAGET00.read")) {
								a_items.push({
									xtype: "menuitem",
									iconCls: 'pf-edit',
									itemId: "edit",
									text: ip2.i18n({
										da: "Rediger side",
										en: "Edit page"
									}),
									handler: function() {

										var s_entity = 'WSHPAGET00';
										var s_tkn = node.get("token");

										var i_model = ip2.model({
											dmd: me.dmd,
											entityName: "WSHPAGET00",
											context: 'grid',
											uiName: "portfolio"
										});
										var o_config = {
											dmd: me.dmd,
											entityName: "WSHPAGET00"
										};
										var i_record = i_model.create();
										i_record.set(i_record.idProperty, s_tkn);

										var o_size = Ext.ux.file.util.Handler.getWindowSize();

										var wnd = Ext.widget("window", {
											modal: false,
											closable: true,
											collapsible: true,
											resizable: true,
											width: o_size.width * 0.9,
											height: o_size.height * 0.9,
											layout: "fit"
										});
										ip2.addChild(wnd, i_record, 'update', o_config);
										wnd.show();
									}
								});

								var menu = Ext.widget("menu", {
									items: a_items
								});

								menu.showAt([coords[0], coords[1]]);
							}
						}
					},
					getStackItems: function(i_node, o_rowprops) {
						var i_tree = this;
						var i_store = i_tree.getStore();
						var o_stack_xpd = ip2.resource.get("stack.xpd", true);
						var o_pages_xpd = ip2.resource.get("pages.xpd", true);
						Ext.Ajax.request({
							url: '/wsh-services/wshproxy.aspx',
							params: {
								xpd: o_pages_xpd.path,
								stackxpd: o_stack_xpd.path,
								token: o_rowprops.token,
								action: 'getpage',
								environment: 'treestore'
							},
							success: function (o_response) {

								var o_stack = {};

								try {
									o_stack = Ext.decode(o_response.responseText);
								}
								catch (err) {
									console.log('TODO: Error handling for stack on loading data');
								}

								o_stack.children || (o_stack.children = []);
								if (o_stack.children.length > 0) {
									var a_nodes = [];
									ip2.each(o_stack.children, function(o_item) {
										var i_model = i_store.model.create();
										var s_title = + o_item.token;
										if (Ext.isObject(o_item.title)) {
											s_title = s_title + " - " + ip2.i18n(o_item.title);
										}
										else {
											if (o_item.title) {
												if (o_item.title.substring(0, 1) == "{") {
													var o_title = Ext.decode(o_item.title);
													s_title = s_title + " - " + ip2.i18n(o_item.title);
												}
												else {
													s_title = s_title + " - " + o_item.title;
												}
											}
										}
										i_model.set("TITLE", s_title);
										i_model.set("text", s_title);
										i_model.set("allowDrag", false);
										i_model.set("allowDrop", false);
										i_model.set("checked", null);
										i_model.set("ptype", "stack");
										i_model.set("leaf", true);
										i_model.set("token", o_item.token);
										i_model.set("__cid__", o_item.__cid__);
										a_nodes.push(i_model);
									});
									i_node.set("leaf", false);
									if (i_node.childNodes == null) {
										i_node.childNodes = [];
									}
									i_node.appendChild(a_nodes);
									i_node.expand();
								}
							}
						});
					}
				});
				folderPanel.add(i_south);
			}
		}

		// Folder Property Grid
		if (me.showFolderProperty) {
			me.familyPropertyGrid = Ext.widget('folderorganizerFolderPropertyGrid', {
				title: ip2.i18n(me.getI18N('productFamilyHeaderTitle')),
				itemId: 'familyPropertyGrid',
				action: 'getProductInFamily',
				wrapper: me,
				hidden: true,
				flex: 1,
				listeners: {
					nodeselection: function(node) {
						// prevent firing twice
						if (node.internalId == me.familyPropertyGrid.internalId) {
							return false;
						}
						me.familyPropertyGrid.internalId = node.internalId;

						me.familyPropertyGrid.selectedFolderToken = node.data.ID;

						node.data.cid = 0;

						var props = Ext.decode(node.data.PROPERTIES);
						if (props.__cid__) {
							node.data.cid = props.__cid__;
						}

						if (me.familyPropertyGrid.rendered) {
							if (node.data.cid == 3) {
								me.familyPropertyGrid.show();
								me.familyPropertyGrid.store.removeAll();
								var key = me.treegrid.buildProperties(node);
								if (key.keyValue) {
									me.familyPropertyGrid.store.proxy.extraParams.item = key.keyValue;
									me.familyPropertyGrid.store.load();
								}
							}
							else {
								me.familyPropertyGrid.hide();
							}
						}
					}
				},
				folderPropertyAdded: function(data) {
					me.fireEvent('nodeadded', data);
				},
				folderPropertyRemoved: function(data) {
					me.fireEvent('noderemoved', data);
				},
				getFamilyStatus: function(record) {
					var dnd = this;

					if (record.data.cid != 3) {
						return;
					}

					if (dnd.dragedRecord == record) {
						return;
					}

					dnd.dragedRecord = record;

					Ext.Ajax.request({
						url: me.proxy,
						params: {
							action: 'getProductFamilyStatus',
							item: record.data.ITMITMTKN
						},
						record: record,
						success: function(response, request) {
							var result = Ext.decode(response.responseText);
							request.record.familyStatus = result.familyStatus;
						}
					});
				}
			});

			me.familyPropertyGrid.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved', 'nodestartedit', 'nodeloaded', 'nodemouseup']);

			me.relatedPropertyGrid = Ext.widget('folderorganizerFolderPropertyGrid', {
				title: ip2.i18n(me.getI18N('productRelationHeaderTitle')),
				itemId: 'relatedPropertyGrid',
				action: 'getProductInRelation',
				wrapper: me,
				hidden: false,
				flex: 1,
				listeners: {
					nodeselection: function(node) {
						// prevent firing twice
						if (node.internalId == me.relatedPropertyGrid.internalId) {
							return false;
						}
						me.relatedPropertyGrid.internalId = node.internalId;

						me.relatedPropertyGrid.selectedFolderToken = node.data.ID;

						node.data.cid = 0;

						var props = Ext.decode(node.data.PROPERTIES);
						if (props.__cid__) {
							node.data.cid = props.__cid__;
						}

						if (me.relatedPropertyGrid.rendered) {
							var key = me.treegrid.buildProperties(node);
							if (key.keyValue) {
								me.relatedPropertyGrid.store.proxy.extraParams.token = key.keyValue;
								me.relatedPropertyGrid.store.proxy.extraParams.type = (node.data.cid == 3) ? 'rel' : 'cat';
								me.relatedPropertyGrid.store.load();
							}
						}
					}
				}
			});

			me.relatedPropertyGrid.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved', 'nodestartedit', 'nodeloaded', 'nodemouseup']);

			me.familyPropertyGrid.dependcy = {
				store: me.relatedPropertyGrid.store
			};
			me.relatedPropertyGrid.dependcy = {
				store: me.familyPropertyGrid.store
			};
			folderPanel.add(me.familyPropertyGrid);
			folderPanel.add(me.relatedPropertyGrid);
		}

		me.items.push(folderPanel);

		// Add Content grid ?
		if (!me.content) {
			return;
		}

		var cfg = Ext.apply(me.content, {
			flex: 1,
			wrapper: me,
			xpd: me.xpd,
			uiName: me.folder.uiName || 'portfolio',
			copyNode: (me.copyNode === true) ? true : false,
			alwaysShowGrid: (me.showFolderProperty === true) ? true : false,
			region: "east",
			split: true
		});
		if (cfg.title && Ext.isObject(cfg.title)) {
			cfg.title = ip2.i18n(cfg.title);
		}

		me.contentCt = Ext.create('Ext.ux.folderorganizer.Content', cfg);
		me.items.push(me.contentCt);

		me.relayEvents(me.contentCt, me.contentEvents);

		// Pass event further to child components (relay events)
		me.contentCt.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved', 'nodestartedit', 'nodeloaded']);
	},

	getModelFields: function() {

		var i_self = this;
		var a_fields = [];

		var o_dmd = ip2.resource.get(i_self.dmdPath);

		var o_model = o_dmd.model;
		var a_entities = o_model.entities;
		var o_entity = Ext.Array.findBy(a_entities, function(o_value) {
			return o_value.name == i_self.entity;
		});

		if (o_entity) {

			var s_view = i_self.uiName || "portfolio";

			var o_view = o_entity.ui.grids[s_view];

			var a_columns = [];
			var viewColumns = o_view.columns;

			if (Ext.isArray(viewColumns)) {
				a_columns = Ext.Array.slice(viewColumns);
			}
			else if (Ext.isObject(viewColumns)) {

				Ext.Object.each(viewColumns, function(s_key, o_value) {
					o_value.name = s_key;
					a_columns.push(o_value);
				});
			}

			Ext.Array.each(a_columns, function(o_column) {

				if (o_column.isOrganizer) {

					var o_field = {
						type: "auto",
						name: o_column.name,
						title: o_column.title || o_column.name,
						flex: o_column.flex || 1,
						isOrganizer: true
					};

					a_fields.push(o_field);
				}
			});
		}

		return a_fields;
	},

	/* ---------------------------------------------------------------------------------------------
		  initialize 'old' method (belongTo -and hasMany method)
		 --------------------------------------------------------------------------------------------- */
	initBelongTo: function() {
		var me = this;

		if (!me.belongTo || !me.hasMany) {
			Ext.ux.folderorganizer.Alert({
				title: me.getI18N('invalidConfig'),
				msg: me.getI18N('missingConfigOptions')
			});
			return;
		}

		// set defaults
		me.belongTo.title = me.belongTo.title || null;
		me.belongTo.displayCheckbox = Ext.isBoolean(me.belongTo.displayCheckbox) ? me.belongTo.displayCheckbox : true;
		me.belongTo.displayFilterField = Ext.isBoolean(me.belongTo.displayFilterField) ? me.belongTo.displayFilterField : true;
		me.belongTo.displayRootNode = (Ext.isBoolean(me.belongTo.displayRootNode)) ? me.belongTo.displayRootNode : true;
		me.belongTo.expandRootNode = (Ext.isBoolean(me.belongTo.expandRootNode)) ? me.belongTo.expandRootNode : false;
		me.belongTo.menus = me.belongTo.menus || [];

		me.hasMany.title = me.hasMany.title || null;
		me.hasMany.displayColumns = me.hasMany.displayColumns ? me.hasMany.displayColumns : [];
		me.hasMany.displayFilterField = Ext.isBoolean(me.hasMany.displayFilterField) ? me.hasMany.displayFilterField : true;

		me.tabSequence = me.tabSequence || [
			{
				parent: 'belongTo',
				child: 'tree'
			},
			{
				parent: 'belongTo',
				child: 'filterField'
			},
			{
				parent: 'hasMany',
				child: 'filterField'
			},
			{
				parent: 'hasMany',
				child: 'grid'
			}
		];

		// setup "Belong-To" store and panel
		me.belongTo.store = Ext.create('Ext.data.TreeStore', {
			model: me.belongTo.model,
			clearOnLoad: false
		});
		var belongToCfg = Ext.apply(me.belongTo, {
			flex: 1,
			store: me.belongTo.store,
			wrapper: me,
			region: "center",
			split: true,
			namePrefix: 'belongTo'
		});

		// setup "Many to many" store and panel
		if (me.many2many) {
			me.many2many.allowDuplicateRecords = Ext.isBoolean(me.many2many.allowDuplicateRecords) ? me.many2many.allowDuplicateRecords : true;

			me.many2many.store = Ext.create('Ext.data.Store', {
				model: me.many2many.model
			});

			// create association between "belong to" -and "has many"
			me.association = Ext.create('Ext.data.HasManyAssociation', {
				associatedModel: me.many2many.model,
				ownerModel: me.belongTo.model,
				associationKey: me.many2many.root,
				foreignKey: me.belongTo.foreignKey,
				primaryKey: (me.belongTo.store.model.prototype.idProperty) ? me.belongTo.store.model.prototype.idProperty : 'id',
				name: 'getOrganizedItems'
			});

			belongToCfg.many2many = {
				store: me.many2many.store
			};
		}

		belongToCfg.writerStore = Ext.create('Ext.data.Store', {
			model: belongToCfg.writerModel
		});
		belongToCfg.writerStore.model.dmdFile = belongToCfg.writerStore.model.dmdFile;

		me.belongTo.panel = Ext.create('Ext.ux.folderorganizer.Tree', belongToCfg);

		// setup "Has many" store and panel

		if (Ext.isArray(me.hasMany.items)) {
			me.hasMany.panel = Ext.create('Ext.panel.Panel', {
				split: true,
				flex: 1,
				width: (ip2.body.init().getWidth() / 2),
				layout: 'accordion',
				region: "east"
			});
			for (var i = 0; i < me.hasMany.items.length; i++) {
				var item = me.hasMany.items[i];
				item.name = item.name || 'accordion-panel-' + i;
				item.store = Ext.create('Ext.data.Store', {
					model: item.model,
					remoteSort: true,
					autoSync: false,
					name: item.name
				});
				var cfg = Ext.apply(item, {
					flex: 1,
					store: item.store,
					wrapper: me,
					namePrefix: 'hasMany',
					copyNode: (me.copyNode === true) ? true : false
				});
				me.hasMany[item.name] = Ext.create('Ext.ux.folderorganizer.Itemgrid', cfg);
				me.hasMany.panel.add(me.hasMany[item.name]);
			}
		}
		else {
			me.hasMany.store = Ext.create('Ext.data.Store', {
				model: me.hasMany.model,
				remoteSort: true,
				autoSync: false
			});
			var cfg = Ext.apply(me.hasMany, {
				flex: 1,
				split: true,
				store: me.hasMany.store,
				wrapper: me,
				namePrefix: 'hasMany',
				copyNode: (me.copyNode === true) ? true : false,
				region: "center"
			});
			me.hasMany.panel = Ext.create('Ext.ux.folderorganizer.Itemgrid', cfg);
		}

		me.items = [
			me.belongTo.panel,
			me.hasMany.panel
		];

		// Pass event further to child components (relay events)
		me.belongTo.panel.relayEvents(me, me.contentEvents);
		me.hasMany.panel.relayEvents(me, ['nodeselection', 'nodeloaded']);
	},
	getDataLibrary: function() {
		return this.folder.dataLibrary || '';
	},
	enableFocusManager: function() {
		var me = this;

		//Ext.FocusManager.enable({focusFrame: this.focusFrame});

		// Ext.FocusManager.addListener({
		// 	componentfocus: function(fm, cmp, previousCmp, eOpts) {
		// 		var name = (cmp.panel) ? cmp.panel.name : cmp.name;
		// 		me.focusNo = me.getFocusNo(name);
		// 	}
		// });
	},

	setFocus: function(direction) {
	var me = this;

	if (!me.tabSequence) {
		return;
	}

	var component;
	var loop = 0;

	var setParameters = function() {
		if (direction == 'forward') {
			me.focusNo++;
		}
		else if (direction == 'backward') {
			me.focusNo--;
		}
		else {
			direction = 'forward';
		}

		if (me.focusNo >= me.tabSequence.length) {
			me.focusNo = 0;
		}
		else if (me.focusNo < 0) {
			me.focusNo = me.tabSequence.length - 1;
		}

		component = me.tabSequence[me.focusNo];
	};

	setParameters();
	while (!me.setChildComponentFocus(component)) {
		loop++;
		if (loop > 10) {
			break;
		}
		setParameters();
	}
  },
	setChildComponentFocus: function(component) {
		var me = this;

		// stop loop
		if (!me[component.parent] || !me[component.parent].panel || !Ext.isFunction(me[component.parent].panel.setFocus)) {
			return true;
		}

		return me[component.parent].panel.setFocus(component.child);
	},
	getFocusNo: function(field) {
		var me = this;

		if (!field || !me.tabSequence) {
			return 0;
		}

		var parent = field.split('.')[0];
		var child = field.split('.')[1];

		for (var i = 0; i < me.tabSequence.length; i++) {
			if (me.tabSequence[i].parent == parent && me.tabSequence[i].child == child) {
				return i;
			}
		}

		return 0;
	},
	setupI18N: function() {
		var texts = {
			ns: 'IP2',
			lang: ['da', 'en'],
			enums: {},
			text: {
				add: {
					value: { da: 'Tilføj', en: 'Add' }
				},
				addTips: {
					value: { da: 'Tryk ctrl+a for at tilføje ny række', en: 'Presse ctrl+a to add new row' }
				},
				refresh: {
					value: { da: 'Opfrisk', en: 'Refresh' }
				},
				refreshTips: {
					value: { da: 'Press F5 to refresh the list', en: 'Press F5 to refresh the list' }
				},
				create: {
					value: { da: 'Opret ny', en: 'Create new' }
				},
				update: {
					value: { da: 'Rediger', en: 'Edit' }
				},
				updateTips: {
					value: { da: 'Tryk ctrl+e for at editere en eksisterende række', en: 'Presse ctrl+e to exit an existing row' }
				},
				remove: {
					value: { da: 'Fjern', en: 'Remove' }
				},
				removeTips: {
					value: { da: 'Will remove a item from the folder', en: 'Will remove a item from the folder' }
				},
				eksport: {
					value: { da: 'Eksport', en: 'Export' }
				},
				confirmExportTitle: {
					value: { da: 'Bekræft eksport', en: 'Confirm export' }
				},
				confirmExport: {
					value: { da: 'Bekræft venligst eksport af : ', en: 'Please confirm export of : ' }
				},
				information: {
					value: { da: 'Information', en: 'Information' }
				},
				exportInformation: {
					value: { da: '<b>"&title"</b> er eksporteret til folder: <b>"&folder"</b>', en: '<b>"&title"</b> has been exported to folder: <b>"&folder"</b>' }
				},
				deselect: {
					value: { da: 'Fravælg', en: 'Deselect' }
				},
				deselectTips: {
					value: { da: 'Fravælg alle valgte rækker', en: 'Deselect all selected rows' }
				},
				confirmDeleteTitle: {
					value: { da: 'Bekræft sletning', en: 'Confirm deleting' }
				},
				confirmDelete: {
					value: { da: 'Vil du slette denne ?', en: 'Do you  want to delete it ?' }
				},
				save: {
					value: { da: 'Gem', en: 'Save' }
				},
				cancel: {
					value: { da: 'Annuller', en: 'Cancel' }
				},
				expand: {
					value: { da: 'Udvid', en: 'Expand' }
				},
				search: {
					value: { da: 'Søg', en: 'Search' }
				},
				searchText: {
					value: { da: 'Søg (min. 3 karakter)', en: 'Search (min. 3 characters)' }
				},
				min3characters: {
					value: { da: 'Indtast minimum 3 karakter', en: 'Enter minimum 3 characters' }
				},
				addPropertiesTitle: {
					value: { da: 'Opret ny properties', en: 'Add new properties' }
				},
				editPropertiesTitle: {
					value: { da: 'Ændre properties', en: 'Edit properties' }
				},
				noRecords: {
					value: { da: 'Ingen rækker blev fundet', en: 'No rows found' }
				},
				message: {
					value: { da: 'Meddelelse', en: 'Message' }
				},
				hasManySelectionMissing: {
					value: { da: 'Has many selection missing !', en: 'Has many selection missing !' }
				},
				invalidConfig: {
					value: { da: 'Invalid config options', en: 'Invalid config options' }
				},
				missingConfigOptions: {
					value: { da: 'Required config options are missing !', en: 'Required config options are missing !' }
				},
				addToAllChildrenTitle: {
					value: { da: 'Tilføj valgte på alle underliggende rækker ?', en: 'Add selected on all children' }
				},
				addToAllChildren: {
					value: {
						da: 'Klik JA for at oprette på alle underliggende rækker<br /><br />Klik på NEJ for kun at oprette på dette niveau',
						en: 'Click YES to add on all children<br /><br />Click NO to only add at this level'
					}
				},
				productFamilyHeaderTitle: {
					value: { da: 'Produktvarianter', en: 'Product variants' }
				},
				productRelationHeaderTitle: {
					value: { da: 'Relaterede produkter', en: 'Related products' }
				},
				product: {
					value: { da: 'Produkt', en: 'Product' }
				},
				name: {
					value: { da: 'Navn', en: 'Name' }
				},
				title: {
					value: { da: 'Titel', en: 'Title' }
				},
				breadcrumb: {
					value: { da: 'Breadcrumb', en: 'Breadcrumb' }
				},
				productCatalogLocationHeaderTitle: {
					value: { da: 'Produktets placering i kataloget', en: 'The products catalog location' }
				},
				primary: {
					value: { da: 'Primær', en: 'Primary' }
				},
				pleaseWait: {
					value: { da: 'Venligst...', en: 'Please wait...' }
				}
			}
		};

		ip2.namespace('ip2.folderorganizer');
		ip2.folderorganizer = new ip2.DynamicNS(texts);
		ip2.folderorganizer.setLanguage(ip2.session.getLanguage());
	},
	getI18N: function(key) {
		return ip2.folderorganizer.getTextValue(key);
	}
});
Ext.define('Ext.ux.folderorganizer.FamilyOrganizer', {
	extend: 'Ext.ux.folderorganizer.Organizer',
	initComponent: function() {
		var me = this;

		me.models = {};
		me.counter = 0;

		var dmdName = me.dmd;
		var dmdPath = me.dmd;
		var xpdName = me.xpd;
		var xpdPath = me.xpd;

		// family
		// ------
		Ext.define('family', {
			extend: 'Ext.data.Model',
			fields: [
			{ name: 'ID', type: 'string' },
			{ name: 'KEY', type: 'string' },
			{ name: 'GROUP', type: 'string', title: 'Group', flex: 1, groupColumn: true },
			{ name: 'leaf', type: 'boolean' },
			{ name: 'allowDrag', type: 'boolean' },
			{ name: 'allowDrop', type: 'boolean' },
			{ name: 'allowEdit', type: 'boolean' },
			{ name: 'allowRemove', type: 'boolean' },
			{ name: 'iconCls', type: 'string' }
			],
			idProperty: 'ID',
			proxy: {
				type: 'ajax',
				url: me.serviceUrl,
				extraParams: {
					action: 'familyTreeStore',
					displayRootNode: true,
					dmd: dmdPath,
					xpd: xpdPath,
					entity: 'WSHITMET00',
					uiName: 'portfolio',
					titleColumns: Ext.encode(me.titleColumns)
				}
			}
		});
		me.belongTo.model = 'family';
		me.belongTo.propertyNameMapping = {
			ID: 'IFMIFMTKN',
			PARENTID: 'IFMPNTTKN',
			NAME: 'IFMNAM',
			SHARED: 'IFMSHRPROP'
		};

		// writer model (used to add/update)
		// ---------------------------------
		me.models.writer = ip2.model({
			dmd: dmdName,
			entityName: 'WSHIFMET00'
		});
		me.belongTo.writerModel = me.models.writer.modelName;
		me.belongTo.cid = (me.cid) ? me.cid : [];

		// vare propertites
		// ----------------
		me.models.item = ip2.model({
			dmd: dmdName,
			entityName: 'WSHITMET00'
		});
		Ext.apply(me.models.item.proxy.extraParams, {
			dmdFile: dmdPath,
			uiName: 'portfolio',
			context: 'grid',
			action: 'getRows'
		});
		me.hasMany.model = me.models.item.modelName;
		if (Ext.isArray(me.hasMany.items)) {
			for (var i = 0; i < me.hasMany.items.length; i++) {
				me.hasMany.items[i].model = me.models.item.modelName;
				me.hasMany.items[i].displayColumns = me.titleColumns;
				me.hasMany.items[i].displayFilterField = true;
				me.hasMany.items[i].buttons = ['refresh'];
			}
		}

		me.belongTo.doCreate = function(parentNode, selection, setChecked, dropped) {
			// call per dropped item
			var me = this;

			var childNode;
			var params = {};

			var action = 'add';
			var dragFrom = 'family2family';

			if (selection.store && selection.store.name) {
				dragFrom = selection.store.name;
			}
			else if (selection.childNodes) {
				if (selection.data.ID.substring(0, 4) == 'item') {
					action = 'update';
					dragFrom = 'familyProductGrid';
				} if (selection.data.ID.substring(0, 4) == 'prel') {
					action = 'update';
					dragFrom = 'relatedProductGrid';
				}
			}

			// if dragged record from grid (not tree grid), create new childnode
			if (!selection.childNodes && parentNode.isLoaded()) {
				childNode = me.createNewNode(selection, parentNode, dragFrom);
				if (parentNode && parentNode.isLoaded()) {
					parentNode.insertChild(0, childNode);
				}
			}

			// dragged from family to family
			if (dragFrom == 'family2family') {
				params = {
					action: 'updateFamily',
					ID: selection.data.KEY,
					PARENTID: parentNode.data.KEY
				};
				Ext.Ajax.request({
					url: me.wrapper.serviceUrl,
					params: params,
					node: selection,
					success: function(response, request) {
          }
				});

				// drag from product in family
			}
			else if (dragFrom == 'familyProductGrid') {
				// if existing record, move to new parent ?
				if (action == 'update') {
					params = {
						action: 'updateFamilyProduct',
						item: selection.data.KEY,
						family: parentNode.data.KEY
					};
				}
				else {
					params = {
						action: 'updateFamilyProduct',
						item: selection.data[selection.store.model.prototype.idProperty],
						family: parentNode.data.KEY
					};
				}
				Ext.Ajax.request({
					url: me.wrapper.serviceUrl,
					params: params,
					parentNode: parentNode,
					childNode: childNode,
					selection: selection,
					success: function(response, request) {
						var result = {};
						eval('result =' + response.responseText);
						if (result.success) {
							request.selection.store.remove(request.selection);
						}
					}
				});

				// add related product
			}
			else if (dragFrom == 'relatedProductGrid') {

				if (action == 'update') {
					selection.set('FAMILY', parentNode.data.KEY);
					params = {
						action: 'updateRelatedProduct',
						id: selection.data.KEY,
						family: parentNode.data.KEY
					};
				}
				else {
					params = {
						action: 'addRelatedProduct',
						item: selection.data.ITMITMTKN,
						family: parentNode.data.KEY
					};
				}
				Ext.Ajax.request({
					url: me.wrapper.serviceUrl,
					params: params,
					parentNode: parentNode,
					childNode: childNode,
					selection: selection,
					success: function(response, request) {
						var result = {};
						eval('result =' + response.responseText);
						if (result.success && result.newID) {
							if (request.childNode) {
								request.childNode.set('ID', 'prel.' + result.newID);
								request.childNode.set('KEY', result.newID);
							}
						}
					}
				});
			}
		};

		me.belongTo.doDelete = function(node) {
			// family
			if (node.data.ID.substring(0, 4) == 'fami') {
				// remove family
				Ext.Ajax.request({
					url: me.wrapper.serviceUrl,
					params: {
						action: 'removeFamily',
						family: node.data.KEY
					}
				});

				// reload grid store
				var grid = me.hasMany.familyProductGrid;
				if (grid) {
					grid.getStore().load();
				}
				// product in family
			}
			else if (node.data.ID.substring(0, 4) == 'item') {
				// remove family
				Ext.Ajax.request({
					url: me.wrapper.serviceUrl,
					params: {
						action: 'removeFamilyProduct',
						item: node.data.KEY
					}
				});

				// add node to product grid
				var grid = me.hasMany.familyProductGrid;
				if (grid) {
					var store = grid.getStore();

					// get data for single record that has been remove
					var filter = [{
						property: 'ITMITMTKN',
						value: node.data.KEY
					}];
					var params = {
						model: 'WSHITMET00',
						dmdFile: me.models.item.proxy.extraParams.dmdFile,
						uiName: me.models.item.proxy.extraParams.uiName,
						context: me.models.item.proxy.extraParams.context,
						action: me.models.item.proxy.extraParams.action,
						filter: Ext.encode(filter),
						language: me.models.item.proxy.extraParams.language,
						languageColumn: me.models.item.proxy.extraParams.languageColumn
					};
					Ext.Ajax.request({
						url: '/ip2-services/ip2dmdProxy.aspx',
						params: params,
						method: 'GET',
						success: function(response, request) {
							var result = {};
							eval('result =' + response.responseText);
							if (result.totalRows > 0) {
								var record = new store.model(result.rows[0]);
								store.insert(0, record);
							}
						}
					});
				}

				// else, product in relation
			}
			else if (node.data.ID.substring(0, 4) == 'prel') {
				// remove related product
				Ext.Ajax.request({
					url: me.wrapper.serviceUrl,
					params: {
						action: 'removeRelatedProduct',
						id: node.data.KEY
					}
				});
			}

			// remove node from product grid
			node.remove();
		};

		me.belongTo.addRow = function() {
			var me = this;

			var model = me.writerStore.proxy.getModel();
			var record = new model;

			var nodes = me.treegrid.getSelectionModel().getSelection();
			node = nodes[0];

			me.dmdEditor(me.writerStore, record, node, 'new');
		};

		me.belongTo.createNewNode = function(record, node, dragFrom) {
			var me = this;

			var data = me.buildNodeData(record, dragFrom);

			if (node && node.data.ID) {
				data.PARENTID = node.data.KEY;
				record.set('IFMPNTTKN', data.PARENTID);
				if (data.PARENTID == 0) {
					record.set('IFMSHRPROP', '{"format":{},"color":{"dep":"format"}}');
				}
				record.save({
					getRecords: function() {
						return [record];
					}
				});
			}

			return Ext.create(me.store.model.modelName, data);
		};

		me.belongTo.buildNodeData = function(record, dragFrom) {
			var me = this;

			var data = {
				leaf: false,
				allowDrag: true,
				allowDrop: true,
				allowEdit: true,
				allowRemove: true
			};

			if (dragFrom) {
				var title = '';
				data.KEY = record.data.ITMITMTKN || record.data.KEY;

				if (dragFrom == 'familyProductGrid') {
					data.ID = 'item.' + record.data.ITMITMTKN;
					data.iconCls = 'dpd-icon-family';
					data.leaf = true;
				}
				else if (dragFrom == 'relatedProductGrid') {
					data.ID = 'prel.' + record.data.ITMITMTKN;
					data.iconCls = 'dpd-icon-related';
					data.leaf = true;
				}

				var columns = me.titleColumns;
				if (columns) {
					for (var i = 0; i < columns.length; i++) {
						if (record.data[columns[i]]) {
							title = me.concatTitle(title, record.data[columns[i]]);
						}
					}
				}
				data.GROUP = title;
			}
			else {
				data.KEY = record.data.IFMIFMTKN || record.data.KEY;
				data.ID = 'fami.' + record.data.IFMIFMTKN;
				data.GROUP = record.data.IFMNAM || record.data.GROUP;
			}

			return data;
		};
		me.belongTo.updateRow = function(node) {
			var me = this;

			if (!node) {
				var nodes = me.treegrid.getSelectionModel().getSelection();
				node = nodes[0];
			}

			if (!node) {
				return;
			}

			if (node.data.allowEdit) {
				me.getRecord({
					node: node,
					success: function(args) {
						me.dmdEditor(me.writerStore, args.record, args.node, 'update');
					}
				});
			}
		};

		me.belongTo.isAddAllow = function(node) {
			if (node.data.ID.substring(0, 4) == 'item' || node.data.ID.substring(0, 4) == 'prel') {
				return false;
			}
			else {
				return true;
			}
		};

		me.belongTo.getKey = function(node) {
			key = {};
			if (node) {
				key.IFMIFMTKN = node.data.KEY;
			}
			return key;
		};

		me.belongTo.nodeDropPoint = function(dragNode, targetNode, position) {
			if (position == 'append') {
				return true;
			}
			else {
				return false;
			}
		};

		me.belongTo.isTreeNodeDrag = function(node) {
			if (this.isNode(node)) {
				if (node.data.ID.substring(0, 4) == 'fami' || node.data.ID.substring(0, 4) == 'item' || node.data.ID.substring(0, 4) == 'prel') {
					return true;
				}
				else {
					return false;
				}
			}
			else {
				return false;
			}
		};

		me.belongTo.hasSequenceProperty = function(node) {
			return false;
		};

		me.callParent();
	}
});

Ext.define("Ext.ux.widget.folderorganizer.Catalog", {

	extend: "Ext.ux.folderorganizer.Organizer",

	alias: ["widget.widgetcatalog"],

	initComponent: function () {

		var i_cmp = this,
			o_config = i_cmp.initialConfig,
			o_settings = {};

		var a_proxyMap = [
			"folderTitle", "folderUiName", "folderOrderBy",
			"folderKey", "propertyKey", "contentToken",
			"folderToken", "contentKey", "propertyKey",
			"contentTitle", "contentFilter",
			"folderDataLibrary", "folderUiName", "preSave"
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			"proxy", "dmd", "entity", "xpd", "extraProps", "environment",
			"menus", "buttons",	"expandToLevel", "levelSelectFirst",
			"folderMultiAddChoice", "folderChildCid"
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		o_settings.folderProperty = {
			ID: o_settings.folderKey || "FLDFLDTKN",
			PARENTID: o_settings.contentKey || "FLDPNTTKN",
			PROPERTIES: o_settings.propertyKey || "FLDPROP"
		};

		o_settings.folderToken += "";

		var o_organizer = {};

		Ext.apply(o_organizer, {
			xpd: o_settings.xpd || "folder.xpd",
			folder: {
				propertyNameMapping: o_settings.folderProperty,
				dmd: o_settings.dmd || "webshop.dmd",
				proxy: o_settings.proxy,
				entity: o_settings.entity || "WSHFLDET00",
				cid: o_settings.folderToken || "5",
				childCid: o_settings.folderChildCid || "2",
				multiAddChoice: o_settings.folderMultiAddChoice === false ? false : o_settings.folderMultiAddChoice || true,
				uiName: o_settings.folderUiName || "portfolio",
				menus: ["edit", "remove"],
				buttons: ["add", "edit", "remove", "refresh"],
				expandToLevel: o_settings.expandToLevel || 2,
				levelSelectFirst: o_settings.levelSelectFirst || 2,
				displayRootNode: true,
				title: o_settings.folderTitle === false ? false : o_settings.folderTitle || ip2.i18n({
					da: "Kataloger",
					en: "Catalogs"
				}),
				preSave: o_settings.preSave || function(a_modifed, f_callback) {
					f_callback();
				}
			},
			content: {
				title: o_settings.contentTitle === false ? false : o_settings.contentTitle || ip2.i18n({
					da: "Indhold til kataloger",
					en: "Catalog Content"
				})
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});

Ext.define("Ext.ux.widget.folderorganizer.Contact", {

	extend: "Ext.ux.folderorganizer.Organizer",

	alias: ["widget.widgetcontact"],

	initComponent: function () {

		var i_cmp = this,
			o_config = i_cmp.initialConfig,
			o_settings = {};

		var a_proxyMap = [
			"folderTitle", "folderUiName", "folderOrderBy",
			"folderKey", "propertyKey", "contentToken",
			"folderToken", "contentKey", "propertyKey",
			"contentTitle", "contentFilter",
			"folderDataLibrary", "folderUiName"
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			"proxy", "dmd", "entity", "xpd", "extraProps", "environment",
			"menus", "buttons",	"expandToLevel", "levelSelectFirst"
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		o_settings.folderProperty = {
			ID: o_settings.folderKey || "NAMNAMTKN",
			PARENTID: o_settings.contentKey || "NAMPNTTKN",
			PROPERTIES: o_settings.propertyKey || "NAMPROP"
		};

		o_settings.folderToken += "";

		var o_organizer = {};

		Ext.apply(o_organizer, {
			xpd: o_settings.xpd || "names.xpd",
			folder: {
				dmd: o_settings.dmd || "webshop.dmd",
				proxy: o_settings.proxy || "/wsh-services/wshProxy.aspx",
				entity: o_settings.entity || "WSHNAMET00",
				cid: o_settings.folderToken || "3",
				expandToLevel: o_settings.expandToLevel || 1,
				levelSelectFirst: o_settings.levelSelectFirst || 1,
				menus: ["edit", "remove"],
				buttons: ["add", "edit", "remove", "refresh"],
				displayRootNode: true,
				hasRootCid: false,
				multiAddChoice: true,
				propertyNameMapping: o_settings.folderProperty,
				title: o_settings.folderTitle === false ? false : o_settings.folderTitle || ip2.i18n({
					da: "Kontakter",
					en: "Contacts"
				})
			},
			content: {
				title: o_settings.contentTitle === false ? false : o_settings.contentTitle || ip2.i18n({
					da: "Kontaktpersoner",
					en: "Contact Persons"
				}),
				filter: o_settings.contentFilter || ""
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});

Ext.define("Ext.ux.widget.folderorganizer.Manufacturer", {

	extend: "Ext.ux.folderorganizer.Organizer",

	alias: ["widget.widgetmanufacturer"],

	initComponent: function () {

		var i_cmp = this,
			o_config = i_cmp.initialConfig,
			o_settings = {};

		var a_proxyMap = [
			"folderTitle", "folderUiName", "folderOrderBy",
			"folderKey", "propertyKey", "contentToken",
			"folderToken", "contentKey", "propertyKey",
			"contentTitle", "contentFilter",
			"folderDataLibrary", "folderUiName"
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			"proxy", "dmd", "entity", "xpd", "extraProps", "environment",
			"menus", "buttons",	"expandToLevel", "levelSelectFirst"
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		o_settings.folderProperty = {
			ID: o_settings.folderKey || "NAMNAMTKN",
			PARENTID: o_settings.contentKey || "NAMPNTTKN",
			PROPERTIES: o_settings.propertyKey || "NAMPROP"
		};

		o_settings.folderToken += "";

		var o_organizer = {};

		Ext.apply(o_organizer, {
			xpd: o_settings.xpd || "names.xpd",
			folder: {
				title: o_settings.folderTitle === false ? false : o_settings.folderTitle || {
					da: "Producenter",
					en: "Manufacturer"
				},
				propertyNameMapping: o_settings.folderProperty,
				cid: o_settings.folderToken || "1",
				childCid: o_settings.folderChildCid || "2",
				multiAddChoice: o_settings.folderMultiAddChoice === false ? false : o_settings.folderMultiAddChoice || true,
				dmd: o_settings.dmd || "webshop.dmd",
				proxy: o_settings.proxy,
				entity: o_settings.entity || "WSHNAMET00",
				orderBy: o_settings.folderOrderBy || "jsonGetStr(NAMPROP, \"name\")",
				menus: ["edit", "remove"],
				buttons: ["add", "edit", "remove", "refresh"],
				expandToLevel: o_settings.expandToLevel || 1,
				levelSelectFirst: o_settings.expandToLevel || 1,
				displayRootNode: true,
				rootVisible: true
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});
Ext.define('Ext.ux.widget.folderorganizer.Navigation', {

	extend: 'Ext.ux.folderorganizer.Organizer',

	alias: ['widget.widgetnavigation'],

	initComponent: function () {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;
		var o_settings = {};

		var a_proxyMap = [
			'folderTitle', 'folderUiName', 'folderOrderBy',
			'folderKey', 'propertyKey', 'contentToken',
			'folderToken', 'contentKey', 'propertyKey',
			'contentTitle', 'contentFilter',
			'folderDataLibrary', 'folderUiName',
			'statusTitle', 'publicationTitle'
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			'proxy', 'dmd', 'entity', 'xpd', 'extraProps', 'environment',
			'menus', 'buttons',	'expandToLevel', 'levelSelectFirst'
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		o_settings.folderProperty = {
			ID: o_settings.folderKey || 'NAMNAMTKN',
			PARENTID: o_settings.contentKey || 'NAMPNTTKN',
			PROPERTIES: o_settings.propertyKey || 'NAMPROP'
		};

		var o_organizer = {};

		Ext.apply(o_organizer, {
			xpd: o_settings.xpd || 'menus.xpd',
			environment: o_settings.environment || 'menuorganizer',
			folder: {
				dmd: o_settings.dmd || 'webshop.dmd',
				proxy: o_settings.proxy,
				entity: o_settings.entity || 'WSHMNUET00',
				menus: o_settings.menus || ['edit', 'remove', 'expandChildren'],
				buttons: o_settings.buttons || ['add', 'edit', 'remove', 'refresh'],
				propertyNameMapping: o_settings.folderProperty,
				displayRootNode: true,
				expandToLevel: o_settings.expandToLevel || 3,
				levelSelectFirst: o_settings.levelSelectFirst || 2,
				extraProps: o_settings.extraProps || 'page',
				extraColumns: [
					{
						header: o_settings.statusTitle ? ip2.i18n(o_settings.statusTitle) : ip2.i18n({
							da: 'Status',
							en: 'Status'
						}),
						width: 60,
						renderer: function(value, meta, record, rowIndex, colIndex) {
							if (record.data.rowProps && ip2.page) {
								return ip2.page.formatPublish(Ext.decode(record.data.rowProps).properties);
							}
							else {
								return '';
							}
						}
					},
					{
						header: o_settings.publicationTitle ? ip2.i18n(o_settings.publicationTitle) : ip2.i18n({
							da: 'Publikationsdatoer',
							en: 'Publication Dates'
						}),
						width: 260,
						renderer: function(value, meta, record, rowIndex, colIndex) {
							if (record.data.rowProps && ip2.page) {
								return ip2.page.formatPublishDate(Ext.decode(record.data.rowProps).properties);
							}
							else {
								return '';
							}
						}
					}
				],
				title: o_settings.folderTitle === false ? false : o_settings.folderTitle || ip2.i18n({
					da: 'Navigation',
					en: 'Navigation'
				})
			},
			content: {
				title: o_settings.contentTitle === false ? false : o_settings.contentTitle || ip2.i18n({
					da: 'Indhold',
					en: 'Content'
				})
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});

Ext.define('Ext.ux.widget.folderorganizer.Pages', {

	extend: 'Ext.ux.folderorganizer.Organizer',

	alias: ['widget.widgetpages'],

	initComponent: function () {

		var i_cmp = this,
			o_config = i_cmp.initialConfig,
			o_settings = {};

		var a_proxyMap = [
			'folderTitle', 'folderUiName', 'folderOrderBy',
			'folderKey', 'propertyKey', 'contentToken',
			'folderToken', 'contentKey', 'propertyKey',
			'contentTitle', 'contentFilter',
			'folderDataLibrary', 'folderUiName'
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			'proxy', 'dmd', 'entity', 'xpd', 'extraProps', 'environment',
			'menus', 'buttons',	'expandToLevel', 'levelSelectFirst'
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		var o_organizer = {};

		Ext.apply(o_organizer, {
			xtype: 'xpdlanguagespanel',
			keyMap: {
				relation: {
					child: o_config.relation.keys.foreign,
					parent: o_config.relation.keys.token
				},
				id: o_config.relation.keys.foreign
			},
			xpdId: '__cid__',
			name: o_config.field,
			panelPrefix: o_config.field + '_',
			languagePropertyName: o_config.relation.keys.on,
			propertiesPropertyName: o_config.relation.keys.properties,
			xpd: o_config.relation.xpd,
			dmd: {
				dmd: o_config.relation.dmd,
				entity: o_config.relation.entity,
				context: 'form'
			},
			trackerParent: i_dataTrackerParent.self,
			batchName: i_owner.initialConfig.batchName,
			updateTrackerRecord: function(data) {

				var self = this,
					keyMap = self.getKeyMap(),
					propertiesPropertyName = self.getPropertiesPropertyName(),
					id = data[keyMap.relation.child],
					dataTrack = self.getDataTrack(),
					properties = data[propertiesPropertyName],
					cid;

				properties = Ext.decode(properties);

				cid = String(properties.__cid__);

				dataTrack.each(function (parent) {

					// We do not wish to change the entityeditor as it will go dirty then!
					if (!parent.self.entityEditor) {

						var store = parent.getStore(),
							record = store.getById(id),
							s_pf = o_config.columnPrefix;

						if (!record) return false;

						ip2.each(properties, function (value, s_prop) {

							if (s_prop == '__cid__' && record.get(o_config.columnCid) != cid) {
								record.set(o_config.columnCid, cid);
							}
							else if (record.data[s_pf + s_prop] != null && record.data[s_pf + s_prop] != value) {
								record.set(s_pf + s_prop, value);
							}
						});
					}
				});
			},
			updateTrackerTitle: function (i_form, o_data) {

				// Get a title for the entity editor!
				var i_xpd = i_form.getXpdField(),
					i_editor = i_owner.up('[entityEditor=true]'),
					s_prop = o_data[s_properties],
					o_prop,
					s_title, s_type;

				try {
					o_prop = Ext.decode(s_prop)
				}
				catch (err) {}

				if (o_prop) {
					s_title = o_prop.title || o_prop.header;
					s_type = i_xpd.xpdData.collections[o_prop[i_xpd.xpd.idProperty]].title;

					s_type = ip2.xpd.translate(i_xpd.xpd, s_type);
					s_title = s_type + ': ' + s_title;
					i_editor.updateTitle(s_title);
				}
			},
			listeners: {
				'recordload': {
					fn: function (i_langPanel, i_form, i_record) {
						i_langPanel.updateTrackerTitle(i_form, i_record.data);
						ip2.waitMask.hide();
					}
				},
				'isready': {
					fn: function(self) {

						var master = self.getMaster(),
							xpdPanel = master.down('[name=' + s_properties + ']'),
							picker = xpdPanel.getCollectionPicker();

						// Run the picker change on init to make sure we dim
						// the needed other widgets in case we have first picker value
						// as our collection cid
						i_widget.onPickerChange(picker, picker.getValue());

						picker.on({
							'change': {
								fn: i_widget.onPickerChange,
								scope: i_widget
							}
						});
					},
					single: true
				},
				'xpdcreate': {
					fn: function(self, data) {
						self.updateTrackerRecord(data);
						self.updateTrackerTitle(self.getMaster(), data);
					}
				},
				'xpdupdate': {
					fn: function(self, data) {
						self.updateTrackerRecord(data);
						self.updateTrackerTitle(self.getMaster(), data);
					}
				}
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});
Ext.define('Ext.ux.widget.folderorganizer.PageNavigation', {

	extend: 'Ext.ux.folderorganizer.Organizer',

	alias: ['widget.widgetpagenavigation'],

	initComponent: function () {

		var i_cmp = this,
			o_config = i_cmp.initialConfig,
			o_settings = {};

		var a_proxyMap = [
			'folderTitle', 'folderUiName', 'folderOrderBy',
			'folderKey', 'propertyKey', 'contentToken',
			'folderToken', 'contentKey', 'propertyKey',
			'contentTitle', 'contentFilter',
			'folderDataLibrary', 'folderUiName'
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			'proxy', 'dmd', 'entity', 'xpd', 'extraProps', 'environment',
			'menus', 'buttons',	'expandToLevel', 'levelSelectFirst'
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		o_settings.folderProperty = {
			ID: o_settings.folderKey || 'MNUMNUTKN',
			PARENTID: o_settings.contentKey || 'MNUPNTTKN',
			PROPERTIES: o_settings.propertyKey || 'MNUPROP'
		};

		o_settings.contentFilter = (function () {

			var a_filter = [],
				o_keys = o_config.dataParent.getKeys();

			ip2.each(o_keys, function (value, s_key) {
				a_filter.push({
					property: s_key,
					value: value
				});
			});

			return Ext.encode(a_filter);
		})();

		var o_organizer = {};

		Ext.apply(o_organizer, {
			xpd: o_settings.xpd || 'menus.xpd',
			environment: o_settings.environment || 'menuorganizer',
			folder: {
				title: o_settings.folderTitle === false ? false : o_settings.folderTitle || ip2.i18n({
					da: 'Navigation',
					en: 'Navigation'
				}),
				dmd: o_settings.dmd || 'webshop.dmd',
				proxy: o_settings.proxy,
				entity: o_settings.entity || 'WSHMNUET00',
				menus: o_settings.menus || ['edit', 'remove', 'expandChildren'],
				buttons: o_settings.buttons || ['add', 'edit', 'remove', 'refresh'],
				expandToLevel: o_settings.expandToLevel || 3,
				levelSelectFirst: o_settings.levelSelectFirst || 2,
				displayRootNode: true
			},
			content: {
				title: o_settings.contentTitle === false ? false : o_settings.contentTitle || ip2.i18n({
					da: 'Indhold',
					en: 'Content'
				}),
				filter: o_settings.contentFilter
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});

Ext.define("Ext.ux.widget.folderorganizer.Partsplexer", {

	extend: "Ext.ux.folderorganizer.Organizer",

	alias: ["widget.widgetpartsplexer"],

	initComponent: function () {

		var i_cmp = this,
			o_config = i_cmp.initialConfig,
			o_settings = {};

		var a_proxyMap = [
			"folderTitle", "folderUiName", "folderOrderBy",
			"folderKey", "propertyKey", "contentToken",
			"folderToken", "contentKey", "propertyKey",
			"contentTitle", "contentFilter",
			"folderDataLibrary", "folderUiName"
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			"proxy", "dmd", "entity", "xpd", "extraProps", "environment",
			"menus", "buttons",	"expandToLevel", "levelSelectFirst"
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		o_settings.folderProperty = {
			ID: o_settings.folderKey || "FLDFLDTKN",
			PARENTID: o_settings.contentKey || "FLDPNTTKN",
			PROPERTIES: o_settings.propertyKey || "FLDPROP"
		};

		o_settings.folderToken += "";

		var o_organizer = {};

		Ext.apply(o_organizer, {
			xpd: o_settings.xpd || "folder.xpd",
			folder: {
				propertyNameMapping: o_settings.folderProperty,
				dmd: o_settings.dmd || "webshop.dmd",
				proxy: o_settings.proxy,
				entity: o_settings.entity || "WSHFLDET00",
				cid: o_settings.folderToken || "50",
				uiName: "portfolio",
				menus: ["edit", "remove"],
				buttons: ["add", "edit", "remove", "refresh"],
				expandToLevel: o_settings.expandToLevel || 1,
				levelSelectFirst: o_settings.levelSelectFirst || 1,
				displayRootNode: true,
				addToAllChildren: {
					allow: true,
					warning: true,
					multiChoiceDialog: {
						title: { da: "Sæt flueben", en: "Check checkboxes" },
						questions: [
						{ da: "Kun på denne række", en: "Check only on this row" },
						{ da: "På alle underliggende rækker", en: "Check all rows below this" },
						{ da: "Fortryd denne funktion", en: "Cancel this operation" }
						],
						guideLine: { da: "Hvor skal der sættes flueben ?", en: "Where to set check marks ?" }
					}
				},

				title: o_settings.folderTitle === false ? false : !Ext.isBoolean(o_settings.folderTitle) ? o_settings.folderTitle : ip2.i18n({
					da: "Modeller",
					en: "Models"
				})
			},
			content: {
				title: o_settings.contentTitle === false ? false : !Ext.isBoolean(o_settings.contentTitle) ? o_settings.contentTitle : ip2.i18n({
					da: "Produkter til modeller",
					en: "Products for models"
				})
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});

Ext.define("Ext.ux.widget.folderorganizer.PortfolioMenu", {

	extend: "Ext.ux.folderorganizer.Organizer",

	alias: ["widget.widgetportfoliomenu"],

	initComponent: function () {

		var i_cmp = this,
			o_config = i_cmp.initialConfig,
			o_settings = {};

		var a_proxyMap = [
			"folderTitle", "folderUiName", "folderOrderBy",
			"folderKey", "propertyKey", "contentToken",
			"folderToken", "contentKey", "propertyKey",
			"contentTitle", "contentFilter",
			"folderDataLibrary", "folderUiName"
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			"proxy", "dmd", "entity", "xpd", "extraProps", "environment",
			"menus", "buttons",	"expandToLevel", "levelSelectFirst"
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		o_settings.folderProperty = {
			ID: o_settings.folderKey || "MNUMNUTKN",
			PARENTID: o_settings.contentKey || "MNUPNTTKN",
			PROPERTIES: o_settings.propertyKey || "MNUPROP"
		};

		o_settings.folderToken += "";

		var o_organizer = {};
		Ext.apply(o_organizer, {
			xpd: o_settings.xpd || "navigation.xpd",
			folder: {
				title: o_settings.folderTitle === false ? false : o_settings.folderTitle || {
					da: "Menu",
					en: "Menu"
				},
				propertyNameMapping: o_settings.folderProperty,
				cid: o_settings.folderToken || "1",
				childCid: o_settings.folderChildCid || "2",
				multiAddChoice: o_settings.folderMultiAddChoice === false ? false : o_settings.folderMultiAddChoice || true,
				dmd: o_settings.dmd || "dmd/portfolio.dmd",
				proxy: o_settings.proxy,
				entity: o_settings.entity || "NAVMNUET00",
				orderBy: o_settings.folderOrderBy || "jsonGetNum(MNUPROP, \'seq\')",
				menus: ["edit", "remove"],
				buttons: ["add", "edit", "remove", "refresh"],
				expandToLevel: o_settings.expandToLevel || 1,
				levelSelectFirst: o_settings.expandToLevel || 1,
				displayRootNode: true,
				allowExport: false,
				extraColumns: [
					{
						header: o_settings.statusTitle ? ip2.i18n(o_settings.statusTitle) : ip2.i18n({
							da: "Url",
							en: "Url"
						}),
						flex: 1,
						renderer: function(value, meta, record, rowIndex, colIndex) {
							var s_prop = record.get("PROPERTIES") || "{}";
							var o_prop = JSON.parse(s_prop);
							return o_prop.url || "";
						}
					}
				]
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});
Ext.define("Ext.ux.widget.folderorganizer.Questionaries", {

	extend: "Ext.ux.folderorganizer.Organizer",

	alias: ["widget.widgetquestionaries"],

	initComponent: function () {

		var i_cmp = this,
			o_config = i_cmp.initialConfig,
			o_settings = {};

		var a_proxyMap = [
			"folderTitle", "folderUiName", "folderOrderBy",
			"folderKey", "propertyKey", "contentToken",
			"folderToken", "contentKey", "propertyKey",
			"contentTitle", "contentFilter",
			"folderDataLibrary", "folderUiName"
		];

		// Start building the settings object from the initialConfig
		Ext.apply(o_settings, ip2.pick(i_cmp.initialConfig, [
			"proxy", "dmd", "entity", "xpd", "extraProps", "environment",
			"menus", "buttons",	"expandToLevel", "levelSelectFirst"
		]));

		Ext.apply(o_settings, ip2.pick(o_config, a_proxyMap));

		o_settings.folderProperty = {
			ID: o_settings.folderKey || "QSTQSTTKN",
			PARENTID: o_settings.contentKey || "QSTPNTTKN",
			PROPERTIES: o_settings.propertyKey || "QSTPROP"
		};

		o_settings.folderToken += "";

		var o_organizer = {};
		Ext.apply(o_organizer, {
			xpd: o_settings.xpd || "questionaries.xpd",
			folder: {
				title: o_settings.folderTitle === false ? false : o_settings.folderTitle || {
					da: "Spørgsmål og svar",
					en: "Questionaries"
				},
				propertyNameMapping: o_settings.folderProperty,
				cid: o_settings.folderToken || "1",
				childCid: o_settings.folderChildCid || "2",
				multiAddChoice: o_settings.folderMultiAddChoice === false ? false : o_settings.folderMultiAddChoice || true,
				dmd: o_settings.dmd || "webshop.dmd",
				proxy: o_settings.proxy,
				entity: o_settings.entity || "WSHQSTET00",
				orderBy: o_settings.folderOrderBy || "jsonGetNum(QSTPROP, \'seq\')",
				menus: ["edit", "remove"],
				buttons: ["add", "edit", "remove", "refresh"],
				expandToLevel: o_settings.expandToLevel || 1,
				levelSelectFirst: o_settings.expandToLevel || 1,
				displayRootNode: true,
				allowExport: false
			},
			content: {
				title: o_settings.contentTitle === false ? false : o_settings.contentTitle || ip2.i18n({
					da: "Indhold til spørgsmål",
					en: "Questionaries Content"
				})
			}
		});

		Ext.apply(i_cmp, o_organizer);

		// Clean up;
		ip2.each(a_proxyMap, function (s_property) {
			delete i_cmp[s_property];
		});

		i_cmp.callParent(arguments);

		return i_cmp;
	}
});
Ext.define("Ext.ux.call2action.LinkTabpanel", {

	extend: "Ext.tab.Panel",

	alias: [
		"widget.ip2Call2ActionLinkTabpanel"
	],

	border: 0,

	layout: "fit",

	config: {
		stackSelector: null,
		pageGrid: null,
		filePanel: null,
		urlPanel: null,
		mediaGallery: null,
		linkTabs: {},
		tabStatus: [],
		selectedTab: 0
	},

	requires: [
		"Ext.ux.call2action.EntityGrid",
		"Ext.ux.gallery.Media",
		"Ext.ux.call2action.UrlPanel"
	],

	initComponent: function() {

		var i_self = this;

		var o_data = i_self.config.data;
		var o_linkTabs = i_self.getLinkTabs();

		i_self.data = o_data;

		Ext.apply(o_linkTabs, {
			stack: 0,
			page: 1,
			file: 2,
			url: 3,
			mediagallery: 4
		});

		var n_activeTab = 0;

		var a_actions = [false, false, false, false, false];

		i_self.setTabStatus(a_actions);

		if (o_data.link && o_data.link.type) {
			n_activeTab = o_linkTabs[o_data.link.type];
			a_actions = [true, true, true, true, true];
			a_actions[n_activeTab] = false;
		}

		i_self.setTabStatus(a_actions);

		i_self.setSelectedTab(n_activeTab);

		i_self.callParent(arguments);

		i_self.add(i_self.createItems());

		i_self.setActiveTab(n_activeTab);

		i_self.setSelectedTab(n_activeTab);
	},

	createItems: function() {

		var i_self = this;

		var a_actions = i_self.getTabStatus();

		var serviceUrl = "/wsh-services/wshproxy.aspx";

		var o_data = i_self.getData();
		var o_linkTabs = i_self.getLinkTabs();

		var a_items = [];

		var i_stackSelector = Ext.create("Ext.ux.folderorganizer.TreeSelector", {
			wrapper: i_self,
			title: ip2.i18n({
				da: "Stakke",
				en: "Stacks"
			}),
			dmd: "webshop.dmd",
			entity: "WSHSTCET00",
			xpd: "stack.xpd",
			proxy: serviceUrl,
			cid: 1,
			omitChild: false,
			expandRootNode: false,
			multiSelect: false,
			extraProps: "page",
			filter: "[{property: \"STCPNTTKN\", value:0}]",
			preventHeader: true,
			addToAllChildren: {
				allow: false
			},
			border: false,
			autoScroll: true,
			listeners: {
				change: {
					fn: function(i_selector, b_dirty) {

						var value = i_selector.getValue();

						if (value.ID.length > 0) {

							a_actions = [false, true, true, true, true];

							i_self.setTabStatus(a_actions);

							i_self.setPanelStatus();

							o_data.link = Ext.apply({}, {
								type: "stack",
								token: value.ID[0]
							});

							var a_nodes = i_selector.getSelection();

							Ext.Array.each(a_nodes, function(i_node) {

								var i_parent = i_node.parentNode;

								var s_properties = i_node.get("PROPERTIES");

								var o_properties = Ext.decode(s_properties);

								if (i_parent) {

									var s_parentprops = i_parent.get("PROPERTIES");

									if (s_parentprops) {

										var o_parentProperties = Ext.decode(s_parentprops);

										o_data.link.page = Ext.apply({}, {
											token: o_parentProperties.token,
											hash: o_properties.token
										});
									}
								}
								else {
									o_data.link.page = Ext.apply({}, {
										token: o_properties.token
									});
								}
							});
						}
						else {

							a_actions = [false, false, false, false, false];

							i_self.setTabStatus(a_actions);

							i_self.setPanelStatus();

							delete o_data.link;
						}
					}
				}
			},
			disabled: a_actions[0]
		});

		i_self.setStackSelector(i_stackSelector);

		var i_stackStore = i_stackSelector.getStore();

		i_stackStore.on({
			load: {
				fn: function (i_store, a_records) {
					var i_proxy = i_store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();
					delete o_extraParams.filter;
				}
			}
		});

		var i_pageGrid = i_self.createPageGrid();

		i_self.setPageGrid(i_pageGrid);

		var i_filePanel = Ext.create("Ext.ux.gallery.Media", {
			title: ip2.i18n({
				da: "Dokumenter",
				en: "Documents"
			}),
			path: "uploads/",
			extensions: "*",
			dropText: {
				en: "Drag-and-drop your files here",
				da: "Træk-og-slip dine filer her"
			},
			maxItems: 1,
			border: false,
			value: o_linkTabs.file == i_self.getSelectedTab() ? Ext.Array.from(o_data.link.items) : [],
			listeners: {
				create: {
					fn: function () {

						a_actions = [true, true, false, true, true];

						i_self.setTabStatus(a_actions);

						i_self.setPanelStatus();
						o_data.link = {
							type: "file"
						};
					},
					buffer: 100
				},
				empty: {
					fn: function () {

						a_actions = [false, false, false, false, false];

						i_self.setTabStatus(a_actions);

						i_self.setPanelStatus();

						delete o_data.link;
					},
					buffer: 100
				}
			},
			disabled: a_actions[2]
		});

		i_self.setFilePanel(i_filePanel);

		var i_urlPanel = Ext.create("Ext.ux.call2action.UrlPanel", {
			title: ip2.i18n({
				da: "URL",
				en: "URL"
			}),
			data: o_data,
			listeners: {
				dirtychange: {
					fn: function(panel, dirty) {
						if (dirty) {

							a_actions = [true, true, true, false, true];

							i_self.setTabStatus(a_actions);

							i_self.setPanelStatus();

							var i_urlPanel = i_self.getUrlPanel();

							o_data.link = i_urlPanel.getValue();
						}
						else {

							a_actions = [false, false, false, false, false];

							i_self.setTabStatus(a_actions);

							i_self.setPanelStatus();

							delete o_data.link;
						}
					}
				},
				isempty: {
					fn: function(panel, valid) {

						a_actions = [false, false, false, false, false];

						i_self.setTabStatus(a_actions);

						i_self.setPanelStatus();

						delete o_data.link;
					}
				},
				activate: {
					fn: function() {

						var i_urlPanel = i_self.getUrlPanel();
						var i_form = i_urlPanel.getForm();
						i_form.findField("title").focus(false, 50);
					}
				}
			},
			disabled: a_actions[3]
		});

		i_self.setUrlPanel(i_urlPanel);

		var i_mediaGallery = Ext.create("Ext.ux.gallery.Media", {
			path: "/images/page",
			extensions: "jpg,jpeg,gif,png",
			title: ip2.i18n({
				da: "Billeder",
				en: "Images"
			}),
			border: false,
			dropText: {
				en: "Drag-and-drop your files here<br><small>jpg,jpeg,gif,png</small>",
				da: "Træk-og-slip dine filer her<br><small>jpg,jpeg,gif,png</small>"
			},
			value: o_linkTabs.file == i_self.getSelectedTab() ? Ext.Array.from(o_data.link.items) : [],
			actionColumns: {
				primary: {
					type: "radiocheckbox",
					name: "primary",
					autoSelect: true,
					title: {
						da: "Primær",
						en: "Primary"
					},
					toolTip: {
						da: "Marker for at bruge dette på artikelbillede",
						en: "Select to use image in article"
					}
				}
			},
			listeners: {
				create: {
					fn: function () {

						a_actions = [true, true, true, true, false];

						i_self.setTabStatus(a_actions);

						i_self.setPanelStatus();

						o_data.link = {
							type: "mediagallery"
						};
					},
					buffer: 100
				},
				empty: {
					fn: function () {

						a_actions = [false, false, false, false, false];

						i_self.setTabStatus(a_actions);

						i_self.setPanelStatus();

						delete o_data.link;
					},
					buffer: 100
				}
			},
			disabled: a_actions[4]
		});

		i_self.setMediaGallery(i_mediaGallery);

		a_items.push(i_stackSelector);
		a_items.push(i_pageGrid);
		a_items.push(i_filePanel);
		a_items.push(i_urlPanel);
		a_items.push(i_mediaGallery);

		return a_items;
	},

	createPageGrid: function () {

		var i_self = this;

		var o_data = i_self.getData() || {};
		var a_actions = i_self.getTabStatus() || [];

		var i_pageGrid = Ext.create("Ext.ux.call2action.EntityGrid", {
			wrapper: i_self,
			title: ip2.i18n({
				da: "Sider",
				en: "Pages"
			}),
			preventHeader: true,
			border: false,
			dmd: {
				dmd: "webshop.dmd",
				entity: "WSHPAGET00",
				ui: "portfolio",
				columns: [
					{
						dataIndex: "PLGPROP_TITLE",
						flex: 2
					},
					{
						dataIndex: "PLGPROP___CID__",
						flex: 1
					}
				],
				filter: "[{\"property\":\"PLGPROP___CID__\", \"value\":\"13\", \"omit\": true}]",
				union: (o_data.link && o_data.link.type == "page") ? "[{\"property\":\"PAGPAGTKN\", \"value\":\"" + o_data.link.token + "\"}]" : ""
			},
			listeners: {
				selectionChange: {
					fn: function (view, a_records) {

						if (a_records.length > 0) {

							a_actions = [true, false, true, true, true];

							i_self.setTabStatus(a_actions);

							i_self.setPanelStatus();

							var i_record = a_records[0];

							o_data.link = Ext.apply({}, {
								type: "page",
								token: i_record.get("PAGPAGTKN")
							});
						}
						else {

							a_actions = [false, false, false, false, false];

							i_self.setTabStatus(a_actions);

							i_self.setPanelStatus();

							delete o_data.link;
						}
					}
				},
				activate: {
					fn: function () {

						var i_pageGrid = i_self.getPageGrid();
						var i_toolbar = i_pageGrid.getPagingBar();

						var i_field = i_toolbar.items.get("filterField");

						if (i_field) {
							i_field.focus(false, 50);
						}
					}
				}
			},
			disabled: a_actions[1]
		});

		return i_pageGrid;
	},

	/* ----------------------------------------------------------------------------------------------------
	    Get record, called by child components
	   ---------------------------------------------------------------------------------------------------- */
	setPanelStatus: function() {

		var i_self = this;

		var a_actions = i_self.getTabStatus();

		Ext.Array.each(a_actions, function(b_disabled, n_index) {

			var i_panel;

			switch (n_index) {
				case 0:
					i_panel = i_self.getStackSelector();
					break;
				case 1:
					i_panel = i_self.getPageGrid();
					break;
				case 2:
					i_panel = i_self.getFilePanel();
					break;
				case 3:
					i_panel = i_self.getUrlPanel();
					break;
				case 4:
					i_panel = i_self.getMediaGallery();
					break;
			}

			i_panel[b_disabled ? "disable" : "enable"]();
		});
	},

	/* ----------------------------------------------------------------------------------------------------
	    Get record, called by child components
	   ---------------------------------------------------------------------------------------------------- */
	getRecord: function(childComponent) {

		var i_self = this;
		var o_data = i_self.getData();

		var component = childComponent.getXType();
		var setData = true;

		var o_record = {
			data: {}
		};

		if (component == "ip2TreeSelector" && o_data.link.type != "stack") {
			setData = false;
		}

		if (setData) {
			o_record = {
				data: o_data
			};
		}

		return o_record;
	},

	getValue: function() {

		var i_self = this;
		var o_data = i_self.getData();
		return o_data.link;
	},

	/* ----------------------------------------------------------------------------------------------------
	    Validate and save form
	   ---------------------------------------------------------------------------------------------------- */
	doSave: function(args) {

		var i_self = this;
		var o_data = i_self.getData();

		if (o_data.link && o_data.link.type) {

			switch (o_data.link.type) {
				case "stack":
					if (o_data.link.linktype) {
						delete o_data.link.linktype;
					}
					break;
				case "page":
					if (o_data.link.linktype) {
						delete o_data.link.linktype;
					}
					break;
				case "file":
					if (o_data.link.linktype) {
						delete o_data.link.linktype;
					}
					o_data.link.items = i_self.filePanel.getValue();
					break;
				case "url":
					if (!i_self.urlPanel.isValid()) {
						i_self.setActiveTab(3);
						return;
					}
					else {
						o_data.link = i_self.urlPanel.getValue();
					}
					break;
				case "mediagallery":

					var i_gallery = i_self.getMediaGallery();
					var items = i_gallery.getValue();

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

					o_data.link.items = a_items;
					break;
			}

			if (Ext.isFunction(args.success)) {
				args.success.call();
			}
		}
		else {
			if (Ext.isFunction(args.failure)) {

				var errors = [{
					panel: "link",
					message: ip2.i18n("linkRequired")
				}];
				args.failure.call(i_self, errors);
			}
		}
	}

});
Ext.define("Ext.ux.call2action.Tabpanel", {

	extend: "Ext.tab.Panel",

	alias: [
		"widget.ip2Call2ActionTabpanel"
	],

	config: {
		generalPanel: null,
		LinkTabpanel: null
	},

	layout: "fit",

	requires: [
		"Ext.ux.call2action.GeneralPanel",
		"Ext.ux.call2action.LinkTabpanel"
	],

	initComponent: function() {

		var i_self = this;
		var o_data = i_self.config.data;
		i_self.data = o_data;

		var i_general = Ext.create("Ext.ux.call2action.GeneralPanel", {
			data: o_data,
			title: ip2.i18n({
				da: "Knap",
				en: "Button"
			}),
			listeners: {
				activate: {
					fn: function(i_panel) {

						var i_form = i_panel.getForm();
						var i_field = i_form.findField("buttontext");

						if (i_field) {
							i_field.focus(false, 50);
						}
					}
				}
			}
		});

		var i_linkpanel = Ext.create("Ext.ux.call2action.LinkTabpanel", {
			data: o_data,
			layout: "fit"
		});

		i_self.callParent();

		var i_linkContainer = Ext.widget("panel", {
			title: ip2.i18n({
				da: "Link til",
				en: "Link to"
			}),
			border: false,
			layout: "fit",
			items: [
				i_linkpanel
			]
		});

		i_self.add([
			i_general,
			i_linkContainer
		]);

		i_self.setGeneralPanel(i_general);
		i_self.setLinkTabpanel(i_linkpanel);

		i_self.setActiveTab(0);
	},

	doSave: function(args) {

		var i_self = this;

		var f_success = args.success || Ext.emptyFn;
		var f_faliure = args.failure || Ext.emptyFn;

		var i_general = i_self.getGeneralPanel();
		var i_linkpanel = i_self.getLinkTabpanel();

		i_self.messageSent = false;

		i_self.savecomplete = {
			generalPanel: false,
			LinkTabpanel: false
		};

		i_general.doSave({
			success: function() {
				i_self.savecomplete.generalPanel = true;
			},
			failure: function(errors) {
				i_self.setActiveTab(0);
				if (!i_self.messageSent && Ext.isArray(errors) && errors.length > 0) {
					i_self.messageSent = true;
					i_self.showMessage(errors);
				}
			}
		});

		i_linkpanel.doSave({
			success: function() {
				i_self.savecomplete.LinkTabpanel = true;
			},
			failure: function(errors) {
				i_self.setActiveTab(1);
				if (!i_self.messageSent && Ext.isArray(errors) && errors.length > 0) {
					i_self.messageSent = true;
					i_self.showMessage(errors);
				}
			}
		});

		if (i_self.savecomplete.generalPanel && i_self.savecomplete.LinkTabpanel) {
			f_success();
		}
		else {
			f_faliure();
		}
	},

	getValue: function() {

		var i_self = this;
		var o_data = i_self.getData();
		var i_general = i_self.getGeneralPanel();
		var i_linkpanel = i_self.getLinkTabpanel();

		var o_generalValues = i_general.getValue();
		var o_linkValues = i_linkpanel.getValue();

		Ext.apply(o_data, o_generalValues);

		o_data.link = o_linkValues;

		return o_data;
	},

	showMessage: function(a_error) {

		var o_error = a_error[0];

		if (o_error.message) {
			Ext.MessageBox.show({
				title: ip2.i18n("error"),
				msg: o_error.message,
				buttons: Ext.MessageBox.OK,
				icon: Ext.MessageBox.ERROR
			});
		}
	}
});
Ext.define("Ext.ux.call2action.Window", {

	extend: "Ext.window.Window",

	alias: [
		"widget.ip2Call2ActionWindow"
	],
	height: 501,

	width: 760,

	autoScroll: true,

	collapsible: true,

	layout: "fit",

	config: {
		record: null,
		okFn: Ext.emptyFn,
		success: Ext.emptyFn,
		data: {},
		tabpanel: null
	},

	initComponent: function() {

		var i_self = this;

		var i_record = i_self.getRecord();

		var o_data = Ext.apply({}, i_record.getData());

		var i_tabpanel = Ext.create("Ext.ux.call2action.Tabpanel", {
			wrapper: i_self,
			data: o_data || {},
			border: false,
			layout: "fit"
		});

		i_self.buttons = [{
			xtype: "themedbutton",
			text: ip2.i18n({
				da: "Ok",
				en: "Ok"
			}),
			handler: function() {
				i_tabpanel.doSave({
					success: function() {

						var i_record = i_self.getRecord();
						var i_tabpanel = i_self.getTabpanel();
						var o_data = i_tabpanel.getValue();

						var f_success = i_self.getSuccess();
						var f_okFn = i_self.getOkFn();

						i_record.set(o_data);
						i_record.commit();

						f_success(i_record);

						i_self.close();
						f_okFn();
					}
				});
			}
		},{
			text: ip2.i18n("cancel"),
			handler: function() {
				i_self.close();
			}
		}];

		i_self.callParent();

		i_self.setTabpanel(i_tabpanel);
		i_self.setData(o_data);

		i_self.add(i_tabpanel);
	}
});
Ext.define("Ext.ux.call2action.Grid", {

	extend: "Ext.grid.Panel",

	alias: [
		"widget.ip2Call2ActionGridGrid"
	],
	border: true,

	autoScroll: true,

	refreshCount: 0,

	viewConfig: {
		plugins: {
			ptype: "gridviewdragdrop"
		}
	},

	initComponent: function() {

		var i_self = this;

		i_self.buttonText = {};

		i_self.columns = [
			{
				text: ip2.i18n({
					da: "Design",
					en: "Design"
				}),
				flex: 1, dataIndex: "behaviour",
				renderer: i_self.wrapper.behaviours.renderer
			},
			{
				text: ip2.i18n({
					da: "Tekst",
					en: "Text"
				}),
				flex: 2,
				dataIndex: "buttontext",
				renderer: function (value) {

					var s_return = value;

					var s_lang = i_self.language;


					s_return = ip2.i18nWithLanguage(value, s_lang);

					return s_return;
				}
			},
			{
				text: ip2.i18n({
					da: "Linker til...",
					en: "Link to..."
				}),
				flex: 2,
				dataIndex: "link",
				renderer: function() {

					var a_copy = [].slice.call(arguments);

					if (!a_copy[1]) {

						var n_columnIndex = this.getIndex();
						var n_rowIndex = i_self.getStore().indexOf(a_copy[2]);

						a_copy[3] = n_rowIndex;
						a_copy[4] = n_columnIndex;
					}

					return i_self.linkRenderer.apply(i_self, a_copy);
				}
			},
			{
				text: ip2.i18n({
					da: "Åben indhold i",
					en: "Open contents in"
				}),
				flex: 2, dataIndex: "target",
				renderer: i_self.wrapper.targets.renderer
			},
			{
				xtype: "actioncolumn",
				iconCls: "pf-edit",
				handler: function(grid, rowIndex, colIndex) {
					var record = grid.getStore().getAt(rowIndex);
					i_self.doEdit(i_self.buttonText.edit, record);
				}
			},
			{
				xtype: "actioncolumn",
				iconCls: "pf-navigate_cross",
				handler: function(grid, rowIndex, colIndex) {
					var record = grid.getStore().getAt(rowIndex);
					i_self.doDelete(i_self.buttonText.remove, record);
				}
			}
		];

		var i_store  = Ext.create("Ext.data.Store", {
			fields: [
				{
					name: "behaviour",
					type: "auto"
				},
				{
					name: "buttontext",
					type: "auto"
				},
				{
					name: "target",
					type: "auto"
				},
				{
					name: "link",
					type: "auto"
				}
			],
			proxy: {
				type: "memory",
				reader: {
					type: "json",
					rootProperty: "relations"
				}
			},
			listeners: {
				add: {
					fn: function(store) {
						i_self.wrapper.checkChange();
					}
				},
				update: {
					fn: function(store) {
						i_self.wrapper.checkChange();
					}
				},
				remove: {
					fn: function(store) {
						i_self.wrapper.checkChange();
					}
				}
			}
		});

		var i_toolbar = Ext.widget("toolbar", {
			dock: "top",
			style: {
				"background-color": "white"
			},
			items: [
				{
					xtype: "button",
					text: ip2.i18n({
						da: "Tilføj",
						en: "Add"
					}),
					handler: function(button) {
						i_self.doAdd(i_self.buttonText.add);
					},
					listeners: {
						afterrender: function(button) {
							i_self.buttonText.add = button.getText();
						}
					}
				},
				{
					xtype: "button",
					text: ip2.i18n({
						da: "Rediger",
						en: "Edit"
					}),
					hidden: true,
					handler: function(button) {
						i_self.doEdit(i_self.buttonText.edit);
					},
					listeners: {
						afterrender: function(button) {
							i_self.buttonText.edit = button.getText();
						}
					}
				},
				{
					xtype: "button",
					text: ip2.i18n({
						da: "Slet",
						en: "Delete"
					}),
					hidden: true,
					handler: function(button) {
						i_self.doDelete(i_self.buttonText.remove);
					},
					listeners: {
						afterrender: function(button) {
							i_self.buttonText.remove = button.getText();
						}
					}
				}
			]
		});

		var i_menu = Ext.create("Ext.menu.Menu", {
			items: [
                {
					xtype: "menuitem",
					text: ip2.i18n({
						da: "Rediger",
						en: "Edit"
					}),
					iconCls: "pf-edit",
					handler: function () {
						i_self.doEdit(i_self.buttonText.edit);
					}
				},
				{
					xtype: "menuitem",
					text: ip2.i18n({
						da: "Slet",
						en: "Delete"
					}),
					iconCls: "pf-delete",
					handler: function () {
						i_self.doDelete(i_self.buttonText.remove);
					}
				}
            ]
		});

		i_self.store = i_store;

		i_self.callParent(arguments);

		i_self.addDocked(i_toolbar);

		i_self.on({
			afterrender: {
				fn: function() {

					var a_records = i_store.getRange();

					i_self.setHideHeaders(Ext.isEmpty(a_records));
				}
			},
			itemdblclick: {
				fn: function(i_view, i_record, i_element, n_index, i_event) {
					i_event.preventDefault();
					i_self.doEdit(i_self.buttonText.edit);
				}
			},
			itemcontextmenu: {
				fn: function(i_view, i_record, i_element, n_index, i_event) {
					i_event.stopEvent();
					i_menu.showAt(i_event.getXY());
				}
			}
		});

		i_store.on({
			datachanged: {
				fn: function() {
					var a_records = i_store.getRange();

					i_self.setHideHeaders(Ext.isEmpty(a_records));
				}
			}
		});

		if (i_self.data) {
			i_self.setValue(i_self.data);
		}

		return i_self;
	},

	changeLanguage: function(s_lang) {

		var i_self = this;
		var i_view = i_self.getView();
		i_self.language = s_lang;
		i_view.refresh();
	},

	/* ----------------------------------------------------------------------------------------------------
	    Edit a row
	   ---------------------------------------------------------------------------------------------------- */
	getPropertyValue: function(o_properties) {

		if (o_properties.header) {
			return o_properties.header;
		}
		else if (o_properties.name) {
			return o_properties.name;
		}
		else if (o_properties.title) {
			return o_properties.title;
		}
		else if (o_properties.metatitle) {
			return o_properties.metatitle;
		}
	},

	linkRenderer: function (value, meta, record, rowIndex, colIndex, store, view) {

		{

			var position = {
				row: rowIndex,
				column: colIndex
			};

			var data = record.getData();

			var s_return = "";

			if (data.link && data.link.type) {

				switch (data.link.type) {
					case "stack":
						if (data.link.token > 0) {
							Ext.Ajax.request({
								url: "/wsh-services/wshproxy.aspx",
								params: {
									action: "getStack",
									stacktoken: data.link.token,
									languagecode: ip2.session.getLanguage(),
									xpd: ip2.resource.getFullPath("pages.xpd")
								},
								position: position,
								view: view,
								success: function (response, request) {
									var result = {};
									eval("result = " + response.responseText);
									if (result.properties) {
										var title = i_self.getPropertyValue(result.properties);
										var cell = request.view.getCellByPosition(request.position);
										if (cell && cell.id) {
											document.getElementById(cell.id).innerHTML = "<div unselectable=\"on\" class=\"x-grid-cell-inner x-unselectable\" style=\"text-align: left;\">" + title + "</div>";
										}
									}
								}
							});
						}

						break;
					case "page":
						if (data.link.token > 0) {
							var key = {
								PLGPAGTKN: data.link.token
							};
							Ext.Ajax.request({
								url: "ip2-services/ip2dmdproxy.aspx",
								params: {
									action: "getRow",
									model: "WSHPLGET00",
									key: Ext.encode(key),
									dmdfile: ip2.resource.getFullPath("webshop.dmd")
								},
								position: position,
								view: view,
								success: function (response, request) {
									var result = {};
									eval("result = " + response.responseText);
									if (result.rows.length == 1) {
										var props = Ext.decode(result.rows[0].PLGPROP);
										if (props.title) {
											var cell = request.view.getCellByPosition(request.position);
											if (cell && cell.id) {
												document.getElementById(cell.id).innerHTML = "<div unselectable=\"on\" class=\"x-grid-cell-inner x-unselectable\" style=\"text-align: left;\">" + props.title + "</div>";
											}
										}
									}
								}
							});
						}

						break;
					case "file":

						var sep = "";

						if (data.link.items) {
							if (Ext.isArray(data.link.items)) {
								for (var i = 0; i < data.link.items.length; i++) {
									s_return += sep + ((data.link.items[i].name) ? data.link.items[i].name : data.link.items[i].url);
									sep = ", ";
								}
							}
							else {
								if (Ext.isObject(data.link.items)) {
									s_return += sep + ((data.link.items.name) ? data.link.items.name : data.link.items.url);
								}
							}
						}

						s_return.trim();
						break;

					case "url":

						if (data.link.title) {
							s_return = data.link.title;
						}

						break;

					case "mediagallery":

						s_return = ip2.i18n({
							da: "Billeder",
							en: "Images"
						});

						break;
				}
			}
			return s_return;
		}
	},

	/* ----------------------------------------------------------------------------------------------------
	    Edit a row
	   ---------------------------------------------------------------------------------------------------- */
	doAdd: function(s_buttonText) {

		var i_self = this;
		var i_store = i_self.getStore();

		var i_model = i_store.getModel();
		var a_fields = i_model.getFields();
		var i_record = i_model.create({});

		Ext.Array.each(a_fields, function(i_field) {
			if (!i_field.identifier) {
				i_record.set(i_field.name, "");
			}
		});

		var i_window = Ext.create("Ext.ux.call2action.Window", {
			title: ip2.i18n({
				da: "Opret Call2Action",
				en: "Create Call2Action"
			}),
			action: "create",
			actionText: s_buttonText,
			record: i_record,
			wrapper: i_self.wrapper,
			success: function(i_record) {
				i_store.insert(0, i_record);
			}
		});

		i_window.show();
	},

	/* ----------------------------------------------------------------------------------------------------
	    Edit a row
	   ---------------------------------------------------------------------------------------------------- */
	doEdit: function(s_buttonText, i_record) {

		var i_self = this;

		var a_records = i_record ? [i_record] : i_self.getSelection();
		if (a_records.length === 0) {
			Ext.MessageBox.show({
				msg: ip2.i18n({
					da: "Du skal vælge en række først.",
					en: "You have to select at least one row."
				}),
				icon: Ext.MessageBox.WARNING
			});

			setTimeout(function() {
				Ext.MessageBox.hide();
			}, 1000);
			return;
		}

		Ext.Array.each(a_records, function(i_record) {

			var i_window = Ext.create("Ext.ux.call2action.Window", {
				title: ip2.i18n({
					da: "Rediger Call2Action",
					en: "Edit Call2Action"
				}),
				action: "update",
				actionText: s_buttonText,
				record: i_record,
				wrapper: i_self.wrapper,
				okFn: function() {
					i_self.wrapper.checkChange();
				}
			});

			i_window.show();
		});
	},

	/* ----------------------------------------------------------------------------------------------------
	    Delete a row
	   ---------------------------------------------------------------------------------------------------- */
	doDelete: function(buttonText, i_record) {

		var i_self = this;
		var i_store = i_self.getStore();

		var a_records = i_record ? [i_record] : i_self.getSelection();
		if (a_records.length === 0) {
			Ext.MessageBox.show({
				msg: ip2.i18n({
					da: "Du skal vælge en række først.",
					en: "You have to select at least one row."
				}),
				icon: Ext.MessageBox.WARNING
			});

			setTimeout(function() {
				Ext.MessageBox.hide();
			}, 1000);
			return;
		}
		else {
			Ext.MessageBox.show({
				title: ip2.i18n("confirmDeleteTitle"),
				msg: ip2.i18n("confirmDelete"),
				buttons: Ext.MessageBox.OKCANCEL,
				fn: function(btn) {
					if (btn == "ok") {
						Ext.Array.each(a_records, function(record) {
							i_store.remove(record);
						});
						i_self.wrapper.checkChange();
					}
				},
				icon: Ext.MessageBox.WARNING
			});

			// Set owner container as dirty to trigger enable of save button
			i_self.wrapper.setDirty(true);
		}
	},

	/* ----------------------------------------------------------------------------------------------------
	    Get value
	   ---------------------------------------------------------------------------------------------------- */
	getValue: function () {

		var i_self = this;
		var value = i_self.getRawValue();

		return value;
	},

	/* ----------------------------------------------------------------------------------------------------
	    Get raw value
	   ---------------------------------------------------------------------------------------------------- */
	getRawValue: function () {

		var i_self = this;
		var a_value = [];

		var i_store = i_self.getStore();

		var a_records = i_store.getRange(0);

		Ext.Array.each(a_records, function(i_record) {

			var o_data = i_record.getData();

			var o_record = {
				ptype: "call2action"
			};

			Ext.apply(o_record, o_data);

			a_value.push(o_record);
		});

		return a_value;
	},

	/* ----------------------------------------------------------------------------------------------------
	    Set value
	   ---------------------------------------------------------------------------------------------------- */
	setValue: function (value) {

		var i_self = this;
		var i_store = i_self.getStore();

		// value can be a stringed array or array - normalize
		if (Ext.isString(value)) {
			if (value.length) {
				value = Ext.isString(value) ? Ext.decode(value) : value;
			}
			else {
				value = [];
			}
		}

		// We ended up with something else than an array - return false
		if (!Ext.isArray(value)) {
			value = [];
		}

		i_store.loadData(value);

		return i_self;
	}

});

Ext.define('Ext.ux.call2action.Field', {

	extend: 'Ext.form.FieldContainer',

	alias: ['widget.call2actionfield'],

	mixins: {
		field: 'Ext.form.field.Field'
	},

	grid: null,

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		i_cmp.initField();

		i_cmp.grid = i_cmp.add({
			xtype: 'ip2Call2ActionGridGrid',
			data: [],
			wrapper: i_cmp
		});

		return i_cmp;
	},

	initValue: function () {

		var i_cmp = this;
		var a_value = i_cmp.getValue();

		i_cmp.value = a_value;

		i_cmp.mixins.field.initValue.call(i_cmp);
	},

	getValue: function () {

		var i_cmp = this;
		var a_value = i_cmp.value;

		if (i_cmp.grid) {
			a_value = i_grid.getValue();
		}

		return a_value;
	},

	setValue: function (value) {

		var i_cmp = this;
		var i_grid = i_cmp.grid;
		var a_value;

		return i_cmp.mixins.field.setValue.call(i_cmp.value);
	},

	isDirty: function () {
	}
});
Ext.define("Ext.ux.call2action.Call2Action", {

	extend: "Ext.form.FieldContainer",

	mixins: {
		field: "Ext.form.field.Field"
	},

	alias: [
		"widget.ip2Call2ActionGrid"
	],

	originalValue: [],
	value: [],
	dirty: false,

	config: {
		behaviours: null,
		targets: null,
		grid: null
	},

	initComponent: function() {

		var i_self = this;
		var o_initialConfig = i_self.initialConfig;
		var value = o_initialConfig.value;

		Ext.tip.QuickTipManager.init();

		i_self.dirty = false;

		i_self.callParent();

		// create store for combobox, etc
		var i_behaviourStore = Ext.create("Ext.data.Store", {
			storeId: "call2action_behaviours",
			fields: ["key", "value"],
			data: [{
				key: "success",
				value: ip2.i18n({
					da: "Success",
					en: "Success"
				})
			},{
				key: "primary",
				value: ip2.i18n({
					da: "Primær",
					en: "Primary"
				})
			},{
				key: "default",
				value: ip2.i18n({
					da: "Neutral",
					en: "Neutral"
				})
			},{
				key: "info",
				value: ip2.i18n({
					da: "Info",
					en: "Info"
				})
			},{
				key: "inverse",
				value: ip2.i18n({
					da: "Negativ",
					en: "Inverse"
				})
			},{
				key: "whiteblack",
				value: ip2.i18n({
					da: "Hvid-BG / Sort-tekst",
					en: "White-BG / Black-text"
				})
			}],
			renderer: function(key) {
				var store = Ext.data.StoreManager.get("call2action_behaviours");
				var r = store.findRecord("key", key);
				return (r ? r.data.value : key);
			}
		});

		var i_targetsStore = Ext.create("Ext.data.Store", {
			storeId: "call2action_targets",
			fields: ["key", "value"],
			data: [{
				key: "parent",
				value: ip2.i18n({
					da: "Samme vindue (Normal)",
					en: "Same window (Normal)"
				})
			},{
				key: "blank",
				value: ip2.i18n({
					da: "Nyt vindue",
					en: "New window"
				})
			},{
				key: "lightbox",
				value: ip2.i18n({
					da: "Lightbox",
					en: "Lightbox"
				})
			}],renderer: function(key) {
				var store = Ext.data.StoreManager.get("call2action_targets");
				var r = store.findRecord("key", key);
				return (r ? r.data.value : key);
			}
		});

		i_self.setBehaviours(i_behaviourStore);
		i_self.setTargets(i_targetsStore);

		// Add grid with call-to-action rows
		var i_grid = Ext.widget("ip2Call2ActionGridGrid", {
			wrapper: i_self,
			data: value  || []
		});

		i_self.setGrid(i_grid);

		i_self.add(i_grid);

		// Bubble the "savecomplete" event up
		i_self.relayEvents(i_grid, ["savecomplete"]);

		i_self.initField();


		return i_self;
	},

	changeLanguage: function(s_lang) {

		var i_self = this;
		var i_grid = i_self.getGrid();
		i_grid.changeLanguage(s_lang);
	},

	/* ----------------------------------------------------------------------------------------------------
	    Get value
	   ---------------------------------------------------------------------------------------------------- */
	getValue: function() {

		var i_self = this;
		var i_grid = i_self.getGrid();
		var value;

		if (i_grid) {
			value = i_grid.getValue();
		}
		else {
			value = i_self.mixins.field.getValue.call(i_self);
		}
		if (value == "[]") {
			value = "";
		}

		return value;
	},

	/* ----------------------------------------------------------------------------------------------------
	    Get value for submit form
	   ---------------------------------------------------------------------------------------------------- */
	getSubmitValue: function() {

		var i_self = this;

		return i_self.getValue();
	},

	/* ----------------------------------------------------------------------------------------------------
	    Set value
	   ---------------------------------------------------------------------------------------------------- */
	setValue: function(value) {

		var i_self = this;
		var i_grid = i_self.getGrid();

		i_grid.setValue(value);

		i_self.value = value;
	},

	checkChange: function () {

		var i_self = this;

		var newVal = i_self.getValue();
		var oldVal = i_self.lastValue || [];

		if (!i_self.suspendCheckChange) {

			newVal = Ext.decode(newVal, true) || newVal;
			oldVal = Ext.decode(oldVal, true) || oldVal;

			var s_new = newVal;
			var s_old = oldVal;

			if (Ext.isObject(newVal)) {
				s_new = Ext.encode(newVal);
			}

			if (Ext.isObject(oldVal)) {
				s_old = Ext.encode(oldVal);
			}

			if (s_new != s_old) {
				i_self.lastValue = newVal;
				i_self.fireEvent('change', i_self, newVal, oldVal);
				i_self.onChange(newVal, oldVal);
			}
		}
	},

	disable: function() {

		var i_self = this;
		var i_grid = i_self.getGrid();

		i_self.callParent(arguments);

		if (i_self.isDisabled()) {

			i_grid.disable();
		}
	},

	enable: function() {

		var i_self = this;
		var i_grid = i_self.getGrid();

		i_self.callParent(arguments);

		if (!i_self.isDisabled()) {

			i_grid.enable();
		}
	},

	/* ----------------------------------------------------------------------------------------------------
	    Is Dirty (Children mark dirty)
	   ---------------------------------------------------------------------------------------------------- */
	isDirty: function() {

		var i_self = this;
		var i_grid = i_self.getGrid();

		var o_value = i_grid.getValue() || [];
		var o_originalValue = i_self.originalValue || [];
		var s_value = Ext.encode(o_value);
		var s_originalValue = Ext.encode(o_originalValue);

		return s_originalValue != s_value;
	},

	/* ----------------------------------------------------------------------------------------------------
	    Set Dirty - called from child components
	   ---------------------------------------------------------------------------------------------------- */
	setDirty: function(value) {
		return value
	},

	/* ----------------------------------------------------------------------------------------------------
	    Save every thing
	   ---------------------------------------------------------------------------------------------------- */
	doSave: function(f_callback) {
		//this.grid.doSave();
		if (f_callback) {
			f_callback();
		}
	}
});
Ext.define('Ext.ux.form.field.XidItemGrid', {

	extend: "Ext.form.FieldContainer",
	mixins: {
		field: 'Ext.form.field.Field'
	},

	alias: [
		'widget.xpditemgrid'
	],
	config: {
		dmd: "dmd/webshop.dmd",
		entity: "WSHITMET00",
		viewName: "portfolio",
		xpd: "product.xpd",
		context: "grid",
		model: null
	},

	changeListener: function() {

		var i_self = this;
		var a_value = [];

		var value = a_value = i_self.getValue();

		if (Ext.isString(value)) {
			a_value = Ext.decode(value, true) || [];
		}

		var a_columns = i_self.createColumns();
		var a_fields = [];
		var a_keys = [];

		var i_grid = Ext.widget("gridpanel", {
			minHeight: 500,
			store: {
				model: i_self.getModel(),
				proxy: {
					type: 'memory',
					reader: {
						type: 'json',
						rootProperty: 'rows'
					}
				}
			},
			columns: a_columns
		});

		var i_store = i_grid.getStore();

		i_self.add(i_grid);

		i_self.getData(a_value, function(a_records) {
			i_store.loadRecords(a_records, false);
		});
	},

	initComponent: function() {

		var i_self = this;

		i_self.callParent(arguments);
		i_self.createModel();
		i_self.changeListener();

		return this;
	},
	disable: function () {
		return this;
	},
	enable: function () {
		return this;
	},
	isDirty: function() {
		return false;
	},

	createModel: function() {

		var i_self = this;

		var i_model = i_self.getModel();

		if (!i_model) {

			var o_config = Ext.apply({}, {
				dmd: i_self.getDmd(),
				entityName: i_self.getEntity(),
				uiName: i_self.getViewName(),
				context: i_self.getContext()
			});

			i_model = ip2.model(o_config);

			i_self.setModel(i_model);
		}

		return i_model;
	},

	createColumns: function() {

		var i_self = this;
		var o_dmd = ip2.resource.get(i_self.getDmd());
		var o_xpd = ip2.resource.get(i_self.getXpd());
		var o_model = o_dmd.model;
		var s_entity = i_self.getEntity();
		var s_view = i_self.getViewName();
		var a_viewColumns = [];
		var a_entityColumns = [];
		var a_result = [];
		var i_model = i_self.getModel();
		var o_proto = i_model.prototype;

		var o_entity = Ext.Array.findBy(o_model.entities, function(o_value) {
			return o_value.name == s_entity;
		});

		if (o_entity) {

			a_entityColumns = a_entityColumns.concat(o_entity.columns);

			if (o_entity.ui.grids[s_view]) {

				var o_view = o_entity.ui.grids[s_view];

				var a_temp = Ext.Object.getValues(o_view.columns);

				Ext.Array.each(a_temp, function(o_value) {
					var o_clone = Ext.clone(o_value);
					a_viewColumns.push(o_clone);
				});
			}
		}

		var b_found = false;
		var o_uiTypes = ip2.getUiTypes();

		Ext.Array.each(a_viewColumns, function(o_viewColumn) {

			var o_clone = Ext.apply({}, o_viewColumn);

			if (!o_clone.hide) {

				Ext.Array.each(a_entityColumns, function(o_entityColumn) {
					if (o_clone.name == o_entityColumn.name) {
						Ext.apply(o_clone, o_entityColumn);
						return false;
					}
				});

				var o_protoColumn;

				if (Ext.isObject(o_proto.columns)) {
					o_protoColumn = o_proto.columns[o_clone.name];
				}
				else if (Ext.isArray(o_proto.columns)) {

					o_protoColumn = Ext.Array.findBy(o_proto.columns, function(o_column) {
						return o_column.name == o_clone.name;
					});
				}

				if (o_protoColumn) {
					Ext.applyIf(o_clone, o_protoColumn);
				}

				Ext.applyIf(o_clone, {
					dataIndex: o_clone.name,
					flex: o_clone.flex || 1
				});

				o_clone.header = ip2.i18n(o_clone.title) || ip2.i18n(o_clone.header);

				if (o_clone.uitype) {

					if (o_uiTypes.hasOwnProperty(o_clone.uitype)) {

						var o_uiType = o_uiTypes[o_clone.uitype];
						var o_grid = o_uiType.grid;

						var f_renderer = o_grid.renderer || function(value, i_meta, i_record) {
							return value;
						};

						o_clone.renderer = f_renderer;
					}
				}

				a_result.push(o_clone);
			}
		});

		return a_result;
	},

	getData: function(a_data, f_callback) {

		var i_self = this;
		var i_model = i_self.getModel();
		var a_batch = [];

		Ext.Array.each(a_data, function (o_value) {

			var o_keys = {};

			o_keys[i_model.idProperty] = o_value.itemToken;

			a_batch.push({
				type: 'get',
				dmd: i_self.getDmd(),
				entity: i_self.getEntity(),
				uiName: i_self.getViewName(),
				context: i_self.getContext(),
				key: o_keys
			});
		});

		Ext.Ajax.request({
			url: '/ip2-services/ip2dmdProxy.aspx',
			jsonData: {
				transaction: {
					batch: a_batch
				}
			},
			success: function (o_transaction) {

				var o_response = Ext.decode(o_transaction.responseText);
				var a_result = [];
				var a_records = [];

				Ext.Array.each(o_response.batch, function (o_batch) {

					if (o_batch.rows.length) {

						a_result = a_result.concat(o_batch.rows);
					}
				});

				Ext.Array.each(a_result, function(o_value) {
					var i_record = i_model.create(o_value);
					a_records.push(i_record);
				});

				f_callback(a_records);
			}
		});
	}
});
Ext.define("Ext.ux.file.proxy.TreeHive", {
	extend: "Ext.data.proxy.Ajax",
	alias: "proxy.hive",

	constructor: function (config) {
		var i_proxy = this;
		var b_system = config.useSystem != undefined ? config.useSystem : true;

		var o_proxy = Ext.Object.merge(config);
		o_proxy.reader = config.reader || {};

		o_reader = {
			type: 'json',
			$configStrict: false,
			useSystem: b_system,
			getData: function(dirs) {

				var hiveList = Ext.ux.file.util.Handler.getHives(null, null, true);

				var parent_path = this.__requests.shift();

				if (dirs.length) {

					Ext.Array.some(hiveList.slice().reverse(), function(hive) {
						if (dirs[0].path.indexOf(hive.path) === 0) {
							var dir = dirs[0];
							var a_path = dir.path.split('/');
							a_path.pop();
							var s_path = a_path.join('/');
							parent_path = s_path.replace(hive.path, hive.alias + "/");
							parent_path = ip2.cleanPath(parent_path);
							return true;
						};
					});
				}

				var hives = Ext.ux.file.util.Handler.getHives(parent_path, this.useSystem);

				if (dirs.length == 0) {
					ip2.each(hives, function(o_hive) {
						if (o_hive.type == "system") {
							o_hive.hasChild = false;
						}
					});
					return hives.slice();
				}

				return Ext.Array.map(dirs, function(dir) {

					var path = ip2.cleanPath('/' + parent_path + '/' + dir.path.split('/').pop()) + '/';

					for (var x = 0; x < hives.length; x++) {
						var hive = hives[x];

						if (path && path === hive.path) {
							hive.hasChild = dir.hasChild;
							return hive;
						}
					}

					dir.path = path;
					dir.iconCls = "x-ux-filemanager-images-default-collapsed";
					dir.allowImport = true;
					dir.allowAdd = true;

					return dir;
				});
			}
		};

		Ext.Object.merge(o_proxy.reader, o_reader);

		i_proxy.callParent([o_proxy]);

		return i_proxy;
	}
});
if (!Ext.ClassManager.isCreated('Ext.ux.file.model.TreeHive')) {
	Ext.define("Ext.ux.file.model.TreeHive", {
		extend: "Ext.data.Model",
		fields: [
			{ name: 'cls', type: "string" },
			{ name: 'ext', type: "string" },
			{ name: 'text', type: "string" },
			{ name: 'path', type: "string" },
			{ name: 'hasChild', type: "boolean" },
			{ name: 'leaf', type: "boolean" },
			{ name: 'isHive', type: "boolean" },
			{ name: 'type', type: "string" },
			{ name: "iconCls", type: "string" },
			{ name: "allowImport", type: "boolean" },
			{ name: "allowAdd", type: "boolean" }
		]
	});
}

Ext.define('Ext.ux.file.store.TreeHive', {
	extend: "Ext.data.TreeStore",

	model: 'Ext.ux.file.model.TreeHive',

	constructor: function (config) {

		var o_config = Ext.Object.merge(config);
		o_config.proxy = config.proxy || {};

		var i_store = this;
		var o_proxy = {
			$configStrict: false,
			type: "hive",
			url: '/ip2-Services/webbios.aspx',
			useSystem: config.useSystem != undefined ? config.useSystem : true
		};

		Ext.Object.merge(o_config.proxy, o_proxy);

		i_store.callParent([o_config]);
	},

	listeners: {
		beforeload: {
			fn: function(store, operation) {

				var node = operation.node;
				var i_proxy = store.getProxy();
				var o_params = operation.getParams();

				Ext.Object.merge(o_params, {
					func: "listdir",
					extension: "folder",
					path: node.get("path")
				});

				i_proxy.idParam = "path";

				store.proxy.reader.__requests || (store.proxy.reader.__requests = []);

				store.proxy.reader.__requests.push(node.get('path'));
				delete operation.node;
			}
		}
	}
});
Ext.define("Ext.ux.file.view.DropZone", {

	extend: "Ext.window.Window",
	alias: "widget.filedropzone",

	layout: "fit",
	treeHive: undefined,
	portletCount: 0,
	a_portlets: [],
	modal: true,
	constrain: true,
	resizable: false,
	preventHeader: false,
	closable: false,
	dropFn: undefined,
	overZone: false,
	closeAction: "hide",
	extensions: undefined,
	title: ip2.i18n({
		da: "Dropzone oversigt",
		en: "Dropzone overview"
	}),

	initComponent: function(config) {
		var i_self = this;
		i_self.addListners();
		i_self.callParent(config);
		i_self.portlet = i_self.createPortlet();
		i_self.add(i_self.portlet);
		i_self.createTreeHives(config);
	},

	createTreeHives: function () {
		var i_self = this;
		var stack = [];
		i_self.treeHive = Ext.ux.file.util.Handler.getUITree({
			useSystem: false
		});

		var store = i_self.treeHive.getStore();

		store.on({
			load: {
				fn: function(store, a_records, b_success) {
					ip2.each(a_records, function(o_record) {
						o_record.set("allowDrag", false);

						if (!o_record.get("hasChild")) {
							o_record.set("loaded", true);
						}
						else {
							stack.push(0);
							o_record.expand();
						}
					});
					stack.pop();
					if (stack.length == 0) {
						var root = i_self.treeHive.getRootNode();
						i_self.a_portlets = [];
						i_self.portletCount = 0;
						if (i_self.portlet.items) {
							i_self.portlet.removeAll(true);
						}
						root.cascadeBy(function(node) {
							if (!node.isRoot() && node.get("allowDrop")) {
								i_self.portletCount++;
								var s_path = ip2.cleanPath(node.get("path")) + "/";
								var text = "";
								if (!node.parentNode.isRoot()) {
									var parent = node.parentNode;
									while (!parent.isRoot() && parent.get("allowDrop")) {
										text = parent.get("text") + "/" + text;
										parent = parent.parentNode;
									}
									text = text + node.get("text");
								}
								else {
									text = node.get("text");
								}
								var item = i_self.createPortletItem(s_path, text);
								i_self.a_portlets.push(item);
							}
						});
						i_self.portlet.add(i_self.createColumns());
						i_self.addItems();
					}
				}
			}
		});
	},

	addItems: function() {
		var i_self = this;
		i_self.index = 0;
		var columns = i_self.portlet.items.items;
		ip2.each(i_self.a_portlets, function(item) {
			columns[i_self.index].add(item);
			i_self.index++;
			if (i_self.index == columns.length) {
				i_self.index = 0;
			}
		});
	},

	createColumns: function() {
		var i_self = this;
		var a_columns = [];

		if (i_self.portletCount % 2 == 0) {
			i_self.portletCount = Math.ceil(i_self.portletCount / 6);
		}
		else {
			i_self.portletCount = Math.ceil(i_self.portletCount / 5);
		}

		for (var i = 0; i < i_self.portletCount; i++) {
			var column = {
				xtype: "container",
				flex: 1,
				border: 0,
				layout: {
					type: "hbox",
					padding: 5,
					align: "stretch"
				},
				items: []
			};
			a_columns.push(column);
		}

		return a_columns;
	},

	createPortlet: function() {
		var i_portlet = Ext.widget("panel", {
			border: 0,
			layout: {
				type: "vbox",
				padding: 0,
				align: 'stretch'

			},
			style: {
				"position": "absolute",
				"padding": "5px",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"font-size": "5px"
			},
			items: []
		});
		return i_portlet;
	},

	createPortletItem: function(s_path, text) {
		var i_self = this;
		var item = {
			xtype: "container",
			border: 0,
			draggable: false,
			closable: false,
			collapsible: false,
			layout: "fit",
			flex: 1,
			items: [
				{
					xtype: "gallerydropbox",
					flex: 1,
					dropText: text + "</br><small><small>" + ip2.i18n({
						da: "Drop for at tilføje filer",
						en: "Drop to add files"
					}) + "</small></small>",
					path: s_path,
					extensions: i_self.extensions != undefined ? i_self.extensions : Ext.ux.file.util.Handler.extensions,
					maxItems: -1,
					style: {
						"position": "absolute",
						"padding": "5px",
						"top": "0px",
						"left": "0px",
						"right": "0px",
						"bottom": "0px",
						"font-size": "25px"
					},
					listeners: {
						drop: {
							fn: function(i_dropbox, a_files, o_event) {
								var plugin = i_dropbox.getDDPlugin();
								if (plugin.enableDrop) {
									var msg = ip2.i18n({
										da: "Kontrolerer filer....",
										en: "Checking files..."
									});
									i_self.setLoading(msg, true);
									Ext.ux.file.util.Handler.checkFiles(i_dropbox.path, a_files, function(o_result) {
										i_self.setLoading(false);
										var a_update = o_result.update;
										var a_create = o_result.create;
										var b_update = false;
										var b_cancel = false;
										var b_create = false;
										var a_result = [];
										if (a_update.length > 0) {
											b_update = true;
											Ext.ux.file.util.Handler.getUIConflickWindow(i_dropbox.getEl(), i_self, i_dropbox.path, a_update, function(cancel, a_records) {
												b_cancel = cancel;
												ip2.each(a_records, function(o_record) {
													a_result.push(o_record);
												});
												if (!b_create) {
													i_self.setLoading(false);
													i_self.onDrop(a_result);
												}
												else {
													var msg = ip2.i18n({
														da: "Opretter filer....",
														en: "Creating files..."
													});
													i_self.setLoading(msg, true);
												}
											});
										}
										if (a_create.length > 0) {
											b_create = true;
											if (!b_update) {
												i_self.setLoading(false);
												var msg = ip2.i18n({
													da: "Opretter filer....",
													en: "Creating files..."
												});
												i_self.setLoading(msg, true);
											}
											Ext.ux.file.util.Handler.createRecords(i_dropbox.path, a_create, false, function(a_records) {
												b_create = false;
												ip2.each(a_records, function(o_record) {
													a_result.push(o_record);
												});
												if (!b_update) {
													i_self.setLoading(false);
													i_self.onDrop(a_result);
												}
												if (b_cancel) {
													i_self.setLoading(false);
													i_self.onDrop(a_result);
												}
											});
										}
									});
								}
							}
						},
						dragenter: {
							fn: function(i_dropbox, o_event) {
								i_self.overZone = true;
								var plugin = i_dropbox.getDDPlugin();
								var items = o_event.dataTransfer.items || o_event.dataTransfer.files;
								if (i_dropbox.maxItems) {
									if (items.length > i_dropbox.maxItems && i_dropbox.maxItems != -1) {
										i_dropbox.addCls(plugin.failureCls);
										plugin.enableDrop = false;
									}
								}
							}
						},
						dragleave: {
							fn: function(i_dropbox, o_event) {
								var plugin = i_dropbox.getDDPlugin();
								plugin.enableDrop = true;
								i_self.overZone = false;
							}
						}
					}
				}
			]
		};
		return item;
	},

	onDrop: function(a_records) {
		var i_self = this;
		i_self.hide();
		i_self.dropFn(a_records);
	},

	addListners: function() {
		var i_self = this;
		Ext.Object.merge(i_self, {
			listeners: {
				afterrender: function(item) {
					i_self.dragging = 0;
					document.body.addEventListener('drop', function(o_event) {
						if (!i_self.overZone) {
							i_self.hide();
						}
					});
					i_self.mon(i_self.el, {
						dragenter: function (m_event) {
							i_self.dragging++;
						}
					});
					i_self.mon(i_self.el, {
						dragleave: function (m_event) {
							i_self.dragging--;
							if (i_self.dragging === 0) {
								if (i_self.dragging === 0) {
									i_self.hide();
								}
							}
						}
					});
				},
				beforeshow: function(item) {
					var o_size = Ext.ux.file.util.Handler.getWindowSize();
					o_size.width = o_size.width * 0.9;
					o_size.height = o_size.height * 0.9;
					i_self.setSize(o_size);

					var i_portlet = i_self.portlet;

					var f_layout = i_portlet.doLayout || i_portlet.updateLayout;

					f_layout.call(i_portlet);
				},
				show: function() {
					i_self.overZone = false;
					i_self.dragging = 0;
				}
			}
		});
	}
});
Ext.define("Ext.ux.file.view.Manager", {

	extend: "Ext.panel.Panel",

	alias: "widget.filemanager",

	treeDiskFolders: undefined,

	pnlWest: undefined,
	pnlCenter: undefined,
	border: false,
	grdStore: undefined,
	i_grid_memory: undefined,

	delayedTask: undefined,

	i_dropzone: undefined,

	toolbar: undefined,

	layout: "fit",

	sharedTreeStore: undefined,

	initComponent: function() {

		var i_self = this;
		i_self.dmdName = i_self.dmd.split("/").pop().split(".").shift();
		i_self.callParent();

		i_self.pnlContent = Ext.widget("panel", {
			layout: "border"
		});

		i_self.pnlWest = Ext.widget("panel", {
			width: 200,
			minWidth: 200,
			title: ip2.i18n({
				da: "Bibiliotek",
				en: "Library"
			}),
			layout: "fit",
			region: "west",
			border: false,
			split: true,
			collapsible: true,
			items: [
				i_self.createTreeDisk()
			]
		});

		i_self.pnlCenter = Ext.widget("panel", {
			flex: 1,
			title: ip2.i18n({
				da: "Filer",
				en: "Files"
			}),
			layout: "fit",
			region: "center",
			border: false,
			split: true
		});

		i_self.pnlCenter.add(i_self.createGrid());

		i_self.pnlContent.add(i_self.pnlWest);
		i_self.pnlContent.add(i_self.pnlCenter);

		i_self.add(i_self.pnlContent);

		return i_self;
	},

	createDropZone: function(grid) {
		var i_self = this;

		i_self.i_dropzone = Ext.widget("container", {
			layout: "fit",
			renderTo: Ext.getBody(),
			style: {
				"background-color": "white",
				"position": "absolute",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"display": "none",
				"opacity": "0.9"
			},
			items: [i_self.createPortlet()],
			listeners: {
				afterrender: function(item) {
					var i_dropzone = item;
					i_dropzone.dragging = 0;
					document.body.addEventListener("dragenter", function(o_event) {
						if (!i_dropzone.dragging || i_dropzone.dragging === 0) {
							var i_el = i_dropzone.getEl();
							if (i_el.dom) {
								i_el.setStyle("display", "inline");
								i_el.setStyle("z-index", "1");
								var size = item.getSize();
								i_self.portlet.setSize(size.width, size.height);

								var i_portlet = i_self.portlet;

								var f_layout = i_portlet.doLayout || i_portlet.updateLayout;

								f_layout.call(i_portlet);
							}
						}
						i_dropzone.dragging++;
					});

					document.body.addEventListener("dragleave", function(o_event) {
						i_dropzone.dragging--;
						var i_el = i_dropzone.getEl();
						if (i_el.dom && i_dropzone.dragging === 0) {
							i_el.setStyle("display", "none");
							i_el.setStyle("z-index", "0");
						}
					});

					document.body.addEventListener("drop", function(o_event) {
						var i_el = i_dropzone.getEl();
						if (i_el.dom) {
							i_el.setStyle("display", "none");
						}
						i_dropzone.dragging = 0;
					});
				}
			}
		});

		return i_self.i_dropzone;
	},

	createPortlet: function() {
		var i_self = this;
		var portlet = Ext.widget("panel", {
			border: 0,
			layout: {
				type: "vbox",
				padding: 5,
				align: "stretch"

			},
			style: {
				"position": "absolute",
				"padding": "5px",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"font-size": "5px"
			},
			items: []
		});
		i_self.portlet = portlet;
		return portlet;
	},

	createColumns: function() {
		var i_self = this;
		var columns = [];

		if (i_self.itemCount % 2 === 0) {
			i_self.itemCount = Math.ceil(i_self.itemCount / 6);
		}
		else {
			i_self.itemCount = Math.ceil(i_self.itemCount / 5);
		}

		for (var i = 0; i < i_self.itemCount; i++) {
			var column = {
				xtype: "container",
				flex: 1,
				border: 0,
				layout: {
					type: "hbox",
					padding: 5,
					align: "stretch"
				},
				items: []
			};
			columns.push(column);
		}

		return columns;
	},

	addItems: function() {
		var i_self = this;
		i_self.index = 0;
		var columns = i_self.portlet.items.items;
		i_self.portlet.tmp.forEach(function(item) {
			columns[i_self.index].add(item);
			i_self.index++;
			if (i_self.index == columns.length) {
				i_self.index = 0;
			}
		});
	},

	createPortletItem: function(s_path, text) {
		var i_self = this;
		var item = {
			xtype: "container",
			border: 0,
			draggable: false,
			closable: false,
			collapsible: false,
			layout: "fit",
			flex: 1,
			items: [
				{
					xtype: "gallerydropbox",
					flex: 1,
					dropText: [
					text,
					"</br><small><small>",
						ip2.i18n({
							da: "Drop for at tilføje filer",
							en: "Drop to add files"
						}),
					"</small></small>"
					].join(""),
					path: s_path,
					extensions: Ext.ux.file.util.Handler.extensions,
					maxItems: -1,
					style: {
						"position": "absolute",
						"padding": "5px",
						"top": "0px",
						"left": "0px",
						"right": "0px",
						"bottom": "0px",
						"font-size": "25px"
					},
					listeners: {
						drop: {
							fn: function(i_dropbox, a_files, o_event) {

								var i_plugin = i_dropbox.getDDPlugin();
								var s_message = "";

								if (i_plugin.enableDrop) {

									if (a_files.length == 1) {

										s_message = ip2.i18n({
											da: "Arbejder....",
											en: "Working...."
										});

										i_self.setLoading(s_message, true);

										Ext.ux.file.util.Handler.createRecordTemporary(i_dropbox.path, a_files[0], function(o_record) {

											i_self.setLoading(false);

											var i_store = i_self.grdStore;
											var i_window = i_self.createEditWindow(i_store, o_record, "new", o_record.uploadname);

											i_window.show();
										});
									}
									else {

										s_message = ip2.i18n({
											da: "Kontrolerer filer....",
											en: "Checking files..."
										});

										i_self.setLoading(s_message, true);

										Ext.ux.file.util.Handler.checkFiles(i_dropbox.path, a_files, function(o_result) {

											i_self.setLoading(false);

											var a_update = o_result.update;
											var a_create = o_result.create;
											var b_update = false;
											var b_cancel = false;
											var b_create = false;

											if (a_update.length > 0) {

												b_update = true;

												Ext.ux.file.util.Handler.getUIConflickWindow(
													i_self.getEl(),
													i_self, i_dropbox.path, a_update,
													function(cancel, a_records) {

														b_cancel = cancel;

														if (!b_create) {

															i_self.setLoading(false);
															i_self.grdStore.load();
														}
														else {

															s_message = ip2.i18n({
																da: "Opretter filer....",
																en: "Creating files..."
															});

															i_self.setLoading(s_message, true);
														}
													});
											}
											if (a_create.length > 0) {

												b_create = true;

												if (!b_update) {

													i_self.setLoading(false);

													s_message = ip2.i18n({
														da: "Opretter filer....",
														en: "Creating files..."
													});

													i_self.setLoading(s_message, true);
												}
												Ext.ux.file.util.Handler.createRecords(i_dropbox.path, a_create, false, function(a_records) {

													b_create = false;

													if (!b_update) {
														i_self.setLoading(false);
														i_self.grdStore.load();
													}
													if (b_cancel) {
														i_self.setLoading(false);
														i_self.grdStore.load();
													}
												});
											}
										});
									}
								}
							}
						},
						dragenter: {
							fn: function(i_dropbox, o_event) {

								var i_plugin = i_dropbox.getDDPlugin();

								if (!ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".create")) {
									i_dropbox.addCls(i_plugin.failureCls);
									i_plugin.enableDrop = false;
								}
							}
						},
						dragleave: {
							fn: function(i_dropbox, o_event) {
								var i_plugin = i_dropbox.getDDPlugin();
								i_plugin.enableDrop = true;
							}
						}
					}
				}
			]
		};
		return item;
	},

	createAddButton: function() {
		var i_self = this;
		var btnAdd = Ext.widget("splitbutton", {
			text: ip2.i18n({
				da: "Tilføj",
				en: "Add"
			}),
			listeners: {
				menuhide: function(item) {
					if (item.pressed) {
						item.toggle();
					}
				}
			},
			handler: function(item) {
				item.toggle();
				if (item.pressed) {
					item.showMenu();
				}
				else {
					item.hideMenu();
				}
			},
			menu: {
				xtype: "menu",
				minWidth: 150,
				height: 350,
				width: 200,
				autoScroll: true,
				enableKeyNav: false,
				onMouseOver: function() {},
				items: [
					i_self.createTreeAdd()
				]

			}
		});
		return btnAdd;
	},

	createTreeAdd: function() {
		var i_self = this;
		var i_tree = Ext.ux.file.util.Handler.getUITree({
			path: "$root$",
			useSystem: false,
			rootVisible: false,
			flex: 1,
			store: i_self.sharedTreeStore,
			listeners: {
				select: {
					fn: function(model, node) {
						var menu = i_self.treeAdd.up("menu");
						if (menu) {
							menu.hide();
							var i_view = i_self.treeAdd.getView();
							if (node.get("allowAdd")) {
								var i_store = i_self.grdStore;

								var o_record = i_self.grdStore.model.create();
								o_record.set("FILPATH", node.get("path"));
								o_record.set("FILORIPATH", node.get("path"));
								o_record.set("FILCRTBY", ip2.navigator.user.id);
								o_record.set("FILCREATE", ip2.createIsoTimeStamp());

								var wndEdit = i_self.createEditWindow(i_store, o_record, "new");
								wndEdit.show();
							}
							else {
								var title = ip2.i18n({
									da: "Fejl",
									en: "Error"
								});
								var msg = ip2.i18n({
									da: "Det ikke tilladt at oprette en fil på denne folder",
									en: "It is not allowed to create a file in this folder"
								});
								ip2.messageBox({
									icon: Ext.MessageBox.WARNING,
									title: title,
									closable: true,
									message: msg,
									yesText: ip2.i18n({
										da: "OK",
										en: "OK"
									}),
									noText: ip2.i18n({
										da: "Annuller",
										en: "Cancel"
									})
								});
							}
							i_view.deselect(node);
						}
					}
				}
			}
		});

		var store = i_tree.getStore();
		var i_view = i_tree.getView();

		store.on({
			load: {
				fn: function(store, a_records, success, operation, node) {
					ip2.each(a_records, function(o_record) {
						o_record.set("allowDrag", false);

						if (!o_record.get("hasChild")) {
							o_record.set("loaded", true);
						}
						else {
							o_record.expand();
						}
					});
					i_view.refresh();
					i_tree.setLoading(false);
				}
			}
		});
		i_self.treeAdd = i_tree;
		return i_tree;
	},

	createTreeDisk: function() {
		var i_self = this;
		stack = [];
		stack.push(0);

		var i_tree = Ext.ux.file.util.Handler.getUITree({
			path: "$root$",
			viewConfig: {
				plugins: {
					ptype: "treeviewdragdrop",
					enableDrag: false,
					enableDrop: true,
					dropGroup: "grid2tree",
					appendOnly: true
				},
				listeners: {
					beforedrop: {
						fn: function(node, data, overModel, dropPosition, dropHandler, e) {
							if (ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".create")) {
								var a_records = data.records;

								var s_fromPath = a_records[0].get("FILPATH");
								var s_toPath = ip2.cleanPath(overModel.get("path")) + "/";

								var msg = ip2.i18n({
									da: "Kontrolerer filer..",
									en: "Checking  files.."
								});
								i_self.setLoading(msg, true);
								Ext.ux.file.util.Handler.checkRecords(s_toPath, a_records, function(a_create, a_update) {
									var b_update = false;
									var b_cancel = false;
									var b_create = false;
									if (a_update.length > 0) {
										i_self.setLoading(false);
										b_update = true;
										ip2.each(a_update, function(o_update) {
											o_update.name = o_update.get("FILNAME");
											o_update.src = o_update.get("FILPATH") + o_update.get("FILNAME");
										});;
										var wnd = i_self.createConflickWindow(s_toPath, a_update, function(a_overwrite, a_rename) {
											if (a_rename.length > 0) {
												var a_records = [];
												ip2.each(a_rename, function(o_rename) {
													var o_record = o_rename.file;
													o_record.set("FILNAME", o_rename.suggestedName);
													a_records.push(o_record);
												});
												Ext.ux.file.util.Handler.moveRecords(s_toPath, a_records, function(a_records) {
													i_self.grdStore.load();
												});
											}
											if (a_overwrite.length > 0) {
												var a_records = [];
												var msg = ip2.i18n({
													da: "Flytter filer..",
													en: "Moving  files.."
												});
												i_self.setLoading(msg, true);
												ip2.each(a_overwrite, function(o_overwrite) {
													a_records.push(o_overwrite.file);
												});
												Ext.ux.file.util.Handler.moveAndDeleteOldRecords(s_toPath, a_records, function(a_records) {
													i_self.setLoading(false);
													i_self.grdStore.load();
												});
											}
											if (a_overwrite.length == 0 && a_rename.length == 0) {
												i_self.grdStore.load();
											}
										}, function() {
											b_cancel = true;
											if (!b_create) {
												i_self.grdStore.load();
											}
											else {
												var msg = ip2.i18n({
													da: "Flytter filer....",
													en: "Moving files..."
												});
												i_self.setLoading(msg, true);
											}
										});
										wnd.show();
									}
									if (a_create.length > 0) {
										b_create = true;
										if (!b_update) {
											i_self.setLoading(false);
											var msg = ip2.i18n({
												da: "Flytter filer..",
												en: "Moving  files.."
											});
											i_self.setLoading(msg, true);
										}
										Ext.ux.file.util.Handler.moveRecords(s_toPath, a_create, function(a_records) {
											b_create = false;
											if (!b_update) {
												i_self.setLoading(false);
												i_self.grdStore.load();
											}
											if (b_cancel) {
												i_self.setLoading(false);
												i_self.grdStore.load();
											}
										});
									}
								});
								data.records = [];
							}
							else {
								return false;
							}
						}
					},
					drop: {
						fn: function(node, data, overModel) {
							i_self.treeDiskFolders.getSelectionModel().select(overModel);
						}
					}
				}
			},
			listeners: {
				select: {
					fn: function(tree, node) {
						var title = ip2.i18n({
							da: "Filer - ",
							en: "Files - "
						});
						title += node.get("text");
						var path = "";
						if (node.isRoot()) {
							path = "/";
						}
						else {
							path = node.get("path");
						}

						i_self.pnlCenter.setTitle(title);

						if (node.get("type") == "system") {
							i_self.pnlCenter.setLoading(true);
							Ext.ux.file.util.Handler.getRecordListByPath(path, function(a_records) {
								if (i_self.i_grid_memory) {
									i_self.grid.hide();
									var i_memestore = i_self.i_grid_memory.getStore();
									i_memestore.loadData(a_records);
									i_memestore.loadPage(1);
									i_self.i_grid_memory.show();
								}
								else {
									i_self.grid.hide();
									i_self.i_grid_memory = i_self.createMemoryGrid(a_records);
									i_self.pnlCenter.add(i_self.i_grid_memory);
								}

								i_self.pnlCenter.setLoading(false);
							});
						}
						else {
							if (i_self.i_grid_memory) {
								i_self.i_grid_memory.hide();
								i_self.grid.show();
							}
							i_self.grdStore.proxy.extraParams.where = "FILPATH like '" + path + "%'";
							i_self.grdStore.currentPage = 1;
							i_self.grdStore.load();
						}

						i_self.treeDiskFolders.selected = node;
					}
				},
				itemcontextmenu: {
					fn: function(tree, node, html, index, event) {
						event.preventDefault();
						var theNode = node;
						var a_items = [];
						if (ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".createfolder")) {
							a_items.push({
								text: ip2.i18n({
									da: "Tilføj mappe",
									en: "Add folder"
								}),
								parent: node,
								disabled: (node.get("type") == "system") || node.isRoot(),
								handler: function(button) {
									var msg = ip2.i18n({
										da: "Skriv navnet på den nye mappe",
										en: "Write name on the new folder"
									});
									var title = ip2.i18n({
										da: "Ny mappe",
										en: "New folder"
									});
									Ext.Msg.prompt(title, msg, function(btn, text) {
										if (btn == "ok") {
											i_self.createDir(theNode, text);
										}
									});
								}
							});
						}
						if (ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".deletefolder")) {
							a_items.push({
								text: ip2.i18n({
									da: "Slet mappe",
									en: "Delete folder"
								}),
								parent: node,
								disabled: (node.get("isHive") || node.isRoot()) ? true : false,
								handler: function(button) {
									var msg = ip2.i18n({
										da: "Vil du slette mappen..?",
										en: "DO you want to delete the folder..?"
									});
									var title = ip2.i18n({
										da: "Slet",
										en: "Delete"
									});

									ip2.messageBox({
										icon: Ext.MessageBox.WARNING,
										title: title,
										closable: true,
										message: msg,
										yesText: ip2.i18n({
											da: "OK",
											en: "OK"
										}),
										yesFn: function () {
											i_self.deleteDir(theNode);
										},
										noText: ip2.i18n({
											da: "Annuller",
											en: "Cancel"
										})
									});
								}
							});
						}
						if (ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".syncfolder")) {
							a_items.push({
								text: ip2.i18n({
									da: "Synkroniser mappe",
									en: "synchronize folder"
								}),
								disabled: !node.get("allowImport"),
								handler: function(item) {
									var msg = ip2.i18n({
										da: "Synkroniserer filer",
										en: "synchronizing files"
									});
									i_self.setLoading(msg, true);

									Ext.ux.file.util.Handler.consulidateDirectory(node.get("path"), function(a_records, a_delete) {
										i_self.setLoading(false);
										if (a_records.length > 0) {
											i_self.addTags(a_records, function(a_records) {
												var title = ip2.i18n({
													da: "Success",
													en: "Success"
												});
												var msg = ip2.i18n({
													da: a_records.length + " filer blev tilføjet..",
													en: a_records.length + " files was added"
												});
												if (a_delete.length > 0) {
													msg = msg + ip2.i18n({
														da: "<br></br>" + a_delete.length + " referencer blev slettet",
														en: "<br></br>" + a_delete.length + " references was delete"
													});
												}
												ip2.messageBox({
													icon: Ext.MessageBox.INFO,
													title: title,
													closable: false,
													message: msg,
													yesFn: function() {
														i_self.grdStore.load();
													},
													noFn: function() {
														i_self.grdStore.load();
													},
													cancelFn: function() {
														i_self.grdStore.load();
													},
													yesText: ip2.i18n({
														da: "OK",
														en: "OK"
													}),
													noText: ip2.i18n({
														da: "Annuller",
														en: "Cancel"
													})
												});
											});
										}
										else {
											var title = ip2.i18n({
												da: "Success",
												en: "Success"
											});
											var msg = ip2.i18n({
												da: "Ingen nye filer..",
												en: "No new files.."
											});
											if (a_delete.length > 0) {
												msg = msg + ip2.i18n({
													da: "<br></br>" + a_delete.length + " referencer blev slettet",
													en: "<br></br>" + a_delete.length + " references was delete"
												});
											}
											if (a_delete.length == 0) {
												ip2.messageBox({
													icon: Ext.MessageBox.INFO,
													title: title,
													closable: false,
													message: msg,
													yesText: ip2.i18n({
														da: "OK",
														en: "OK"
													}),
													noText: ip2.i18n({
														da: "Annuller",
														en: "Cancel"
													})
												});
											}
											else {
												ip2.messageBox({
													icon: Ext.MessageBox.INFO,
													title: title,
													closable: false,
													message: msg,
													yesFn: function() {
														i_self.grdStore.load();
													},
													noFn: function() {
														i_self.grdStore.load();
													},
													cancelFn: function() {
														i_self.grdStore.load();
													},
													yesText: ip2.i18n({
														da: "OK",
														en: "OK"
													}),
													noText: ip2.i18n({
														da: "Annuller",
														en: "Cancel"
													})
												});
											}
										}
									});
								}
							});
						}
						a_items.push({
							text: ip2.i18n({
								da: "Genindlæs",
								en: "Reload"
							}),
							parent: node,
							handler: function(button) {
								i_self.reloadTrees(node, false);
							}
						});
						var menu = Ext.widget("menu", {
							allowOtherMenus: false,
							items: a_items
						});
						var a_xy = event.getXY();
						menu.showAt(a_xy[0], a_xy[1]);
					}
				}
			}
		});

		var i_view = i_tree.getView();
		var i_store = i_tree.getStore();

		i_self.sharedTreeStore = i_store;
		i_store.on({
			load: {
				fn: function(store, a_records, success, operation, node) {
					var i_tree = i_self.treeDiskFolders;
					if (!i_tree.selected) {
						var i_root = i_tree.getRootNode();
						var record = i_root.getChildAt(0);
						i_tree.selected = record;
						i_tree.getSelectionModel().select(record);
					}
					ip2.each(a_records, function(o_record) {
						o_record.set("allowDrag", false);

						if (!o_record.get("hasChild")) {
							o_record.set("loaded", true);
						}
						else {
							stack.push(0);
							o_record.expand();
						}
					});
					stack.pop();
					if (stack.length === 0) {
						var root = i_tree.getRootNode();
						i_self.portlet.tmp = [];
						i_self.itemCount = 0;
						if (i_self.portlet.items) {
							i_self.portlet.removeAll(true);
						}
						root.cascadeBy(function(node) {
							if (!node.isRoot() && node.get("allowDrop")) {
								i_self.itemCount++;
								var s_path = ip2.cleanPath(node.get("path")) + "/";
								var text = "";
								if (!node.parentNode.isRoot()) {
									var parent = node.parentNode;
									while (!parent.isRoot() && parent.get("allowDrop")) {
										text = parent.get("text") + "/" + text;
										parent = parent.parentNode;
									}
									text = text + node.get("text");
								}
								else {
									text = node.get("text");
								}
								var item = i_self.createPortletItem(s_path, text);
								i_self.portlet.tmp.push(item);
							}
						});
						i_self.portlet.add(i_self.createColumns());
						i_self.addItems();
						i_view.refresh();
						i_tree.setLoading(false);
					}
				}
			}
		});
		i_self.treeDiskFolders = i_tree;

		return i_tree;
	},

	addTags: function(a_records, f_callback) {
		var i_self = this;
		var title = ip2.i18n({
			da: "Nye filer",
			en: "New files"
		});
		var msg = ip2.i18n({ da: "Der er " + a_records.length + " nye filer", en: "There is " + a_records.length + " new files" }) + "</br>";
		msg += ip2.i18n({ da: "Tilføj tags", en: "Add tags" });

		Ext.Msg.prompt(title, msg, function(btn, text) {
			var msg = ip2.i18n({
				da: "Opretter filer...",
				en: "Creating files..."
			});
			i_self.setLoading(msg, true);
			if (btn == "ok") {
				Ext.ux.file.util.Handler.createTags(a_records, text, function(a_records) {
					i_self.setLoading(false);
					f_callback(a_records);
				});
			}
			else {
				Ext.ux.file.util.Handler.upsertRecords(a_records, function(a_records) {
					i_self.setLoading(false);
					f_callback(a_records);
				});
			}
		});
	},

	createDir: function(node, dir) {
		var i_self = this;
		var path = ip2.cleanPath(node.get("path")) + "/" + dir;
		var msg = ip2.i18n({
			da: "Opretter mappe",
			en: "Creating folder"
		});
		i_self.treeDiskFolders.setLoading(msg, true);
		Ext.ux.file.util.Handler.createDirectory(path, function(success) {
			if (success) {
				i_self.reloadTrees(node, false);
			}
			else {
				i_self.treeDiskFolders.setLoading(false);
				var title = ip2.i18n({
					da: "Fejl",
					en: "Error"
				});
				var msg = ip2.i18n({
					da: "Mappen kunne ikke oprettes",
					en: "The folder could not be created"
				});
				ip2.messageBox({
					icon: Ext.MessageBox.ERROR,
					title: title,
					closable: true,
					message: msg,
					yesText: ip2.i18n({
						da: "OK",
						en: "OK"
					}),
					noText: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					})
				});
			}
		});
	},

	reloadTrees: function(node, b_parent) {

		var i_self = this;
		i_self.treeDiskFolders.setLoading(true);
		i_self.treeDiskFolders.reload(node, b_parent, true);
	},

	deleteDir: function(node) {
		var i_self = this;
		var path = ip2.cleanPath(node.get("path"));
		var msg = ip2.i18n({
			da: "Sletter mappe",
			en: "Deleting folder"
		});
		i_self.treeDiskFolders.setLoading(msg, true);
		Ext.ux.file.util.Handler.deleteDirectory(path, function(success) {
			i_self.treeDiskFolders.setLoading(false);
			if (success) {
				i_self.reloadTrees(node, true);
			}
			else {
				var title = ip2.i18n({
					da: "Fejl",
					en: "Error"
				});
				var msg = ip2.i18n({
					da: "Sleting af mappen kunne ikke fortagets<br>mappen er ikke tom",
					en: "Removal of the folder could not be done<br>folder is not empty"
				});
				ip2.messageBox({
					icon: Ext.MessageBox.ERROR,
					title: title,
					closable: true,
					message: msg,
					yesText: ip2.i18n({
						da: "OK",
						en: "OK"
					}),
					noText: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					})
				});
			}
		});
	},

	createTooltip: function(view) {
		var i_self = view.up("filemanager");

		var tpl = new Ext.XTemplate(
			'<tpl for=".">',
				'<tpl if="values.FILEXTERNAL == true">',
				'<div style="width:250px;height:auto !important;">',
					'<div style="',
						'float: left;',
						'width: 25%;',
						'height: 100px;',
						'background-image: url({[this.getURL(values.FILEXTERNAL,values.FILEXT,values.FILORIPATH)]});',
						'background-repeat: no-repeat;',
						'background-size: contain;',
						'background-position: 50% 50%;',
					'"></div>',
					'<div style="',
						'float:right;',
						'padding:0px 0px 0px 10px;',
						'width:73%;',
						'height:100%;">',
						'<p><b>' + ip2.i18n({ da: "ID", en: "ID" }) + ' </b>: {FILFILTKN}</p>',
						'<p><b>' + ip2.i18n({ da: "Navn", en: "Name" }) + ' </b>: {FILNAME}</p>',
						'<p><b>' + ip2.i18n({ da: "Overskrift", en: "Header" }) + ' </b>: {FILHEAD}</p>',
						'<p><b>' + ip2.i18n({ da: "Overskrift 2", en: "Sub header" }) + '</b>: {FILSUB}</p>',
						'<p><b>' + ip2.i18n({ da: "Tag", en: "Tag" }) + ' </b>: {FILTAG}</p>',
						'<p><b>' + ip2.i18n({ da: "Relationer", en: "Relations" }) + ' </b>: {FILREL}</p>',
						'<p><b>' + ip2.i18n({ da: "Ekstern", en: "External" }) + ' </b>: [this.converTo(values.FILEXTERNAL)]</p>',
						'</div>',
					'<div style="clear:both"></div>',
					'</div>',
				'</tpl>',
				'<tpl if="values.FILEXTERNAL == false">',
					'<div style="width:250px;height:auto !important;">',
					'<div style="',
						'float: left;',
						'width: 25%;',
						'height: 100px;',
						'background-image: url({[this.getURL(values.FILEXTERNAL, values.FILEXT, values.FILPATH, values.FILNAME)]});',
						'background-repeat: no-repeat;',
						'background-size: contain;',
						'background-position: 50% 50%;',
					'"></div>',
					'<div style="',
						'float:right;',
						'padding:0px 0px 0px 10px;',
						'width:73%;',
						'height:100%;">',
						'<p><b>' + ip2.i18n({ da: "ID", en: "ID" }) + ' </b>: {FILFILTKN}</p>',
						'<p><b>' + ip2.i18n({ da: "Navn", en: "Name" }) + ' </b>: {FILNAME}</p>',
						'<p><b>' + ip2.i18n({ da: "Overskrift", en: "Header" }) + ' </b>: {FILHEAD}</p>',
						'<p><b>' + ip2.i18n({ da: "Overskrift 2", en: "Sub header" }) + '</b>: {FILSUB}</p>',
						'<p><b>' + ip2.i18n({ da: "Tag", en: "Tag" }) + ' </b>: {FILTAG}</p>',
						'<p><b>' + ip2.i18n({ da: "Relationer", en: "Relations" }) + ' </b>: {FILREL}</p>',
						'<p><b>' + ip2.i18n({ da: "Ekstern", en: "External" }) + ' </b>: {[this.converTo(values.FILEXTERNAL)]}</p>',
					'</div>',
					'<div style="clear:both;"></div>',
				'</div>',
				'</tpl>',
			'</tpl>',
			{
				converTo: function(value) {
					return value ? ip2.i18n({ da: "Ja", en: "Yes" }) : ip2.i18n({ da: "Nej", en: "No" });
				},
				getURL: function(b_external, s_ext, s_path, s_name) {
					var s_url = "";
					var a_extension_image = ["jpg","jpeg","png","gif", "bmp"];
					if (b_external) {
						if (a_extension_image.indexOf(s_ext.toLowerCase()) == -1) {
							s_url = Ext.ux.file.util.Handler.getUrlByExtension(s_url);
						}
						else {
							s_url = s_path;
						}
					}
					else {
						if (a_extension_image.indexOf(s_ext.toLowerCase()) == -1) {
							s_url = Ext.ux.file.util.Handler.getUrlByExtension(s_url);
						}
						else {
							s_url = s_path + s_name;
						}
					}
					var dc = new Date().getMilliseconds();
					return "\"" + s_url + "?_dc=" + dc + "\"";
				}
			}
        );

		view.tip = Ext.create("Ext.tip.ToolTip", {
			// The overall target element.
			target: view.el,

			// Each grid row causes its own seperate show and hide.
			delegate: view.itemSelector,

			// Moving within the row should not hide the tip.
			trackMouse: true,

			// Render immediately so that tip.body can be referenced prior to the first show.
			renderTo: Ext.getBody(),
			showDelay: 800,
			autoHide: false,
			listeners: {
				// Change content dynamically depending on which element triggered the show.
				beforeshow: function (tip) {
					var o_record = view.getRecord(tip.triggerElement);
					var div = document.createElement("div");
					var i_tpl = tpl.compile();
					i_tpl.overwrite(div, o_record.data);
					tip.update(div.innerHTML);
					delete div;
				}
			}
		});
		Ext.QuickTips.init();
	},

	createEditWindow: function(store, o_record, type, uploadname) {

		var i_self = this;
		var o_size = Ext.ux.file.util.Handler.getWindowSize();
		var title = "";
		if (type == "new") {
			title = ip2.i18n({
				da: "Ny fil",
				en: "New file"
			});
		}
		else {
			title = ip2.i18n({
				da: "Rediger " + o_record.get("FILNAME"),
				en: "Editing " + o_record.get("FILNAME")
			});
		}
		var wndEdit = Ext.widget("fileedit", {
			title: title,
			width: o_size.width * 0.9,
			height: o_size.height * 0.9,
			layout: "fit",
			constrain: true,
			modal: true,
			record: o_record,
			store: store,
			type: type,
			hasUploaded: uploadname != null ? true : false,
			uploadname: uploadname
		});
		return wndEdit;
	},

	createConflickWindow: function(pp_path, a_files, okFn, cancelFn) {
		var i_self = this;
		var wnd = Ext.widget("fileconflict", {
			files: a_files,
			path: pp_path,
			width: 900,
			height: 600,
			okFn: okFn || Ext.emptyFn,
			cancelFn: cancelFn || Ext.emptyFn
		});
		return wnd;
	},

	createGrid: function() {
		var i_self = this;

		var i_grid = Ext.ux.file.util.Handler.getUIGrid({
			autoLoad: false,
			viewConfig: {
				listeners: {
					render: i_self.createTooltip
				},
				plugins: {
					ptype: "gridviewdragdrop",
					enableDrop: false,
					dragGroup: "grid2tree"
				}
			}
		});

		i_grid.on({
			afterrender: {
				fn: function(i_grid) {

					var i_toolbar = i_grid.getToolbar();

					i_grid.events.itemdblclick.clearListeners();

					var index = i_toolbar.removeExport();

					i_toolbar.items.removeAt(index);

					index = i_toolbar.removeAdd();

					if (index && ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".create")) {
						i_toolbar.insert(index, i_self.createAddButton());
					}

					if (ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".update") ||
						ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".read")) {

						i_grid.on({
							"itemdblclick": {
								fn: function(grid, record, html, index) {
									var i_store = i_grid.getStore();
									var i_window = i_self.createEditWindow(i_store, record, "edit");
									i_window.show();
								}
							}
						});

						var i_menu = i_grid.getRowMenu();

						if (i_menu) {
							i_menu.items.removeAt(1, true);
							i_menu.items.items[0].handler = function(i_menu, event) {
								var i_store = i_grid.getStore();
								var i_record = i_grid.getSelection()[0];
								var i_window = i_self.createEditWindow(i_store, i_record, "edit");
								i_window.show();
							};
						}
					}

					var i_dropzone = i_self.createDropZone();

					var i_element = i_grid.getView().getEl();

					i_dropzone.getEl().insertBefore(i_element);

					i_grid.on({
						"afterdelete": {
							fn: function(store, records) {
								// TODO: Pipe yourself on the ip2.App event "entityupdate"
								// instead - the 2nd argument will be type (update, delete, create)
								// so we can deprecate the afterdelete event
								// By: ISJ
								Ext.ux.file.util.Handler.unlinkRecords(records, function() {});
							}
						}
					});
				}
			}
		});

		var i_store = i_grid.getStore();

		i_self.grid = i_grid;
		i_self.grdStore = i_store;

		i_store.on({
			beforeload: {
				fn: function(i_store, o_operation) {

					var i_selectedNode = i_self.treeDiskFolders.getSelection()[0];
					if (i_selectedNode) {
						var i_proxy = i_store.getProxy();
						var o_sorters = i_store.getSorters();
						var o_extraParams = i_proxy.getExtraParams();

						var s_path = "";

						if (i_selectedNode.isRoot()) {
							s_path = "/";
						}
						else {
							s_path = i_selectedNode.get("path");
						}

						s_path = "FILPATH like '" + s_path + "%'";
						var s_where = o_extraParams.where;
						if (!ip2.isEqual(s_where, s_path)) {
							if (s_where) {
								s_where = s_where + " AND " + s_path;
							}
							else {
								s_where = s_path;
							}
						}
						o_extraParams.where = s_where;
					}
				}
			}
		});

		return i_grid;
	},
	createMemoryGrid: function(a_records) {

		var i_self = this;
		var model = i_self.grdStore.model;
		var a_columns = i_self.grid.columns.slice();
		var a_result = [];
		ip2.each(a_columns, function(o_column) {
			a_result.push(o_column.initialConfig);
		});
		var a_data = [];
		ip2.each(a_records, function(o_record) {
			a_data.push(o_record.data);
		});
		var data = {
			"total": a_records.length,
			"rows": a_data
		};
		var i_store = Ext.create("Ext.data.Store", {
			model: model,
			sorters: [
				{
					property: "FILNAME",
					direction: "ASC"
				}
			],
			proxy: {
				type: "pagingmemory",
				reader: {
					type: "json",
					rootProperty: "rows",
					totalProperty: "total"
				}
			},
			pageSize: 50
		});

		i_store.loadRawData(data);

		var sm = Ext.create("Ext.selection.CheckboxModel", {
			mode: "MULTI",
			enableKeyNav: true
		});

		var i_grid = Ext.widget("gridpanel", {
			store: i_store,
			columns: a_result,
			selModel: sm,
			dockedItems: [{
				xtype: "pagingtoolbar",
				store: i_store,
				dock: "top",
				displayInfo: true,
				items: [
				"-",
				{
					xtype: "textfield",
					itemId: "txtsearch",
					labelWidth: 35,
					width: 250,
					isFormField: false,
					enableKeyEvents: true,
					triggers: {
						clear: {
							cls: "x-form-clear-trigger",
							scope: "this",
							hidden: true,
							handler: "onClear"
						},
						search: {
							cls: "x-form-search-trigger",
							scope: "this",
							handler: "onSearch"
						}
					},
					onClear: function(i_field) {
						i_field.setValue("");
						i_field.onSearch(i_field);
					},
					onSearch: function(i_field) {
						var value = i_field.getValue();
						var i_trigger = i_field.getTrigger("clear");
						if (value == "") {
							i_store.clearFilter();
							delete i_store.filterName;
							i_trigger.hide();
						}
						else {
							i_trigger.show();
							if (i_store.filterName) {
								i_store.clearFilter();
								delete i_store.filterName;
							}
							var i_filter = Ext.create("Ext.util.Filter", {
								id: "f_name",
								filterFn: function(o_record) {
									var a_keys = Object.keys(o_record.data);
									var s_value = "";
									var found = false;
									for (var i = 0; i < a_keys.length; i++) {
										var s_key = a_keys[i];
										var s_value = JSON.stringify(o_record.get(s_key));
										s_value = s_value.toLowerCase();

										if (s_value.indexOf(value.toLowerCase()) != -1) {
											found = true;
											break;
										}
									}
									return found;
								}
							});
							i_store.addFilter(i_filter);
						}
						i_store.loadPage(1);
					},
					listeners: {
						keydown: function(i_field, e) {
							if (e.keyCode == e.ENTER) {
								i_field.onSearch(i_field);
							}
						}
					}
				}
				]
			}],
			listeners: {
				afterrender: {
					fn: function(i_grid) {
						var i_store = i_grid.getStore();
						i_store.loadPage(1);
					}
				},
				itemdblclick: {
					fn: function(view, record, html, index) {
						if (ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".update") ||
							ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".read")) {
							var wnd = i_self.createPreviewWindow(record);
							wnd.show();
						}
					}
				},
				itemcontextmenu: {
					fn: function(view, record, item, index, event) {
						event.preventDefault();
						var selModel = i_grid.getSelectionModel();
						if (!selModel.isSelected(index)) {
							view.select(index);
						}
						event.stopEvent();
						if (ip2.isAccessible("app." + i_self.dmdName + ".data." + i_self.entity + ".delete")) {
							if (view.menu) {
								view.menu.hide();
								view.menu.destroy();
							}
							var i_menu = Ext.widget("menu", {
								items: [
								{
									text: ip2.i18n({
										da: "Slet",
										en: "Delete"
									}),
									iconCls: "ip2-icon-delete",
									handler: function(i_menuitem) {

										var a_records = i_grid.getSelectionModel().getSelection();

										var msg = a_records.length == 1 ? ip2.i18n({
											da: "Ønsker du virkelig at slette?",
											en: "Do you really wish to delete?"
										}) : ip2.i18n({
											da: "Ønsker du virkelig at slette de " + a_records.length + " valgte?",
											en: "Do you really wish to delete the " + a_records.length + " selected?"
										});
										var title = ip2.i18n({
											da: "Slet",
											en: "Delete"
										});

										ip2.messageBox({
											icon: Ext.MessageBox.WARNING,
											title: title,
											closable: true,
											message: msg,
											yesText: ip2.i18n({
												da: "OK",
												en: "OK"
											}),
											yesFn: function () {
												var msg = ip2.i18n({
													da: "Sletter...",
													en: "Deleting..."
												});
												i_self.setLoading(msg, true);

												Ext.ux.file.util.Handler.unlinkRecords(a_records, function() {
													var path = a_records[0].get("FILPATH");
													Ext.ux.file.util.Handler.getRecordListByPath(path, function(a_records) {
														if (i_self.i_grid_memory) {
															var i_memestore = i_self.i_grid_memory.getStore();
															i_memestore.loadData(a_records);
															i_memestore.loadPage(1);
														}
														i_self.setLoading(false);
													});
												});
											},
											noText: ip2.i18n({
												da: "Annuller",
												en: "Cancel"
											})
										});
									}
								}
								]
							});
							view.menu = i_menu;
							var a_xy = event.getXY();
							i_menu.showAt(a_xy[0], a_xy[1]);
						}
					}
				}
			}
		});
		return i_grid;
	},

	createPreviewWindow: function(o_record) {
		var wndPreview = Ext.widget("filepreview", {
			record: o_record
		});
		return wndPreview;
	}
});
Ext.define("Ext.ux.file.view.Edit", {

	extend: "Ext.window.Window",

	alias: "widget.fileedit",

	record: undefined,
	form: undefined,
	pnlInfo: undefined,
	pnlRelations: undefined,
	i_dropzone: undefined,
	type: undefined,
	extension: undefined,
	uploadname: undefined,
	layout: "fit",
	oldName: undefined,
	hasUploaded: false,

	initComponent: function(config) {

		var i_cmp = this;
		i_cmp.record = i_cmp.record || Ext.ux.file.util.Handler.createModel();
		var i_record = i_cmp.record;

		i_cmp.addListeners();
		i_cmp.callParent(config);

		var s_preset = ip2.preset.staticPath || "pp-static";

		if (!i_cmp.uploadname) {
			i_cmp.uploadname = ip2.cleanPath(s_preset + "/_upload" + ip2.getDcTimestamp());
		}

		if (i_cmp.type == "edit") {
			i_cmp.oldName = i_record.get("FILNAME");
		}

		i_cmp.form = i_cmp.add(i_cmp.createLayout());
		i_cmp.form.loadRecord(i_record);
		i_cmp.form.on({
			dirtychange: function(i_form, b_dirty) {
				i_cmp.setSavable(b_dirty);
			}
		});
	},

	addListeners: function(o_config) {
		var i_cmp = this;
		var i_record = i_cmp.record;

		Ext.Object.merge(i_cmp, {
			listeners: {
				beforeshow: function(i_item) {
					var i_grid = i_cmp.grid;
					var i_store = i_grid.getStore();
					i_store.load();
				},
				afterlayout: function() {
					if (i_cmp.type == "edit") {
						if (i_record.get("FILWIDTH") === 0 && i_record.get("FILHEIGHT") === 0 && !i_record.get("FILEXTERNAL")) {
							var absPath = i_record.get("FILPATH") + i_record.get("FILNAME");
							i_cmp.getImageInfo(absPath);
						}
					}
					else {
						if (i_cmp.uploadname.indexOf(".") != -1) {
							i_cmp.getImageInfo(i_cmp.uploadname);
						}
					}
				}
			}
		});
	},

	createConvertButton: function(o_record) {
		var i_self = this;
		var i_record = o_record;
		var o_button = Ext.widget("button", {
			text: ip2.i18n({
				da: "Konverter til intern",
				en: "Convert to internal"
			}),
			itemId: "btn_convert",
			hidden: o_record.get("FILEXTERNAL") ? false : true,
			handler: function(item) {
				var msg = ip2.i18n({
					da: "Ønsker du virkelig konverter til intern dette er en permenent handling...?",
					en: "Do you really wish to convert to an internal file, this is a permanet action..?"
				});

				var title = ip2.i18n({
					da: "Konverter",
					en: "Convert"
				});

				ip2.messageBox({
					icon: Ext.MessageBox.WARNING,
					title: title,
					closable: false,
					message: msg,
					yesText: ip2.i18n({
						da: "OK",
						en: "OK"
					}),
					yesFn: function () {

						var el = i_self.getEl();
						var i_form = i_self.form.getForm();
						var i_field = i_form.findField("FILNAME");
						var s_path = i_record.get("FILPATH");
						var s_url = i_record.get("FILORIPATH");
						var s_name = i_field.getValue();

						var msg = ip2.i18n({
							da: "Konverter...",
							en: "Converting..."
						});

						el.mask(msg);

						Ext.ux.file.util.Handler.curlFileFromURLWithName(s_path, s_url, s_name, function() {
							i_record.set("FILEXTERNAL", false);
							Ext.ux.file.util.Handler.upsertRecords([i_record], function(a_records) {
								var s_abs = i_record.get("FILPATH") + i_record.get("FILNAME");
								i_self.getImageInfo(s_abs);
								i_self.form.getForm().setValues({
									"FILEXTERNAL": 0
								});
								i_self.convertLbl.show();
								i_self.convertBtn.hide();
								el.unmask();
							});
						});
					},
					noText: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					})
				});
			}
		});
		i_self.convertBtn = o_button;
		return o_button;
	},

	createConvertLabel: function(o_record) {
		var i_self = this;
		var o_label = Ext.widget("displayfield", {
			itemId: "lbl_convert",
			hidden: o_record.get("FILEXTERNAL") ? true : false,
			value: ip2.i18n({
				da: "Filen er uploaded",
				en: "File is uploaded"
			}),
			fieldStyle: {
				"color": "green;",
				"cursor": "default"
			}
		});
		i_self.convertLbl = o_label;
		return o_label;
	},

	createLayout: function() {
		var i_cmp = this;
		var i_form = Ext.widget("form", {
			layout: "border",
			trackResetOnLoad: true,
			items: [
				i_cmp.createPanelWest(),
				i_cmp.createPnlInfo()
			],
			buttons: i_cmp.createButtons()
		});

		return i_form;
	},

	createPnlInfo: function() {
		var i_cmp = this;
		i_cmp.pnlInfo = Ext.widget("panel", {
			region: "center",
			layout: "border",
			flex: 1,
			items: [
				i_cmp.createFieldSetInfo(),
				i_cmp.createFieldSetImage()
			]
		});
		return i_cmp.pnlInfo;
	},

	createFieldSetImage: function() {
		var fieldset = Ext.widget("panel", {
			flex: 1,
			bodyPadding: 5,
			autoScroll: true,
			region: "south",
			title: ip2.i18n({
				da: "Flere oplysninger",
				en: "More information"
			}),
			layout: "anchor",
			items: [
				{
					xtype: "textfield",
					name: "FILWIDTH",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Brede",
						en: "Width"
					}),
					readOnly: true
				},
				{
					xtype: "textfield",
					name: "FILHEIGHT",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Højde",
						en: "Height"
					}),
					readOnly: true
				},
				{
					xtype: "textfield",
					name: "FILSIZE",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Størrelse",
						en: "Size"
					}),
					readOnly: true,
					getValue: function() {
						return this.trueValue;
					},
					setValue: function(_value) {
						var value = _value || 0;
						var rawValue = ip2.humanFileSize(value);
						this.trueValue = value;
						this.mixins.field.setValue.call(this, value);
						this.setRawValue(rawValue);
						return this;
					}
				},
				{
					xtype: "textfield",
					name: "FILEXT",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Fil type",
						en: "File type"
					}),
					readOnly: true
				}
			]
		});
		return fieldset;
	},

	createFieldSetInfo: function() {
		var i_cmp = this;
		var fieldset = Ext.widget("panel", {
			flex: 2,
			region: "center",
			bodyPadding: 5,
			autoScroll: true,
			title: ip2.i18n({
				da: "Generelt",
				en: "General"
			}),
			layout: "anchor",
			items: [
				{
					xtype: "textfield",
					name: "FILFILTKN",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "ID",
						en: "ID"
					}),
					readOnly: true,
					hidden: false
				},
				{
					xtype: "textfield",
					name: "FILMEDIA",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Media",
						en: "Media"
					}),
					readOnly: true,
					hidden: true
				},
				{
					xtype: "textfield",
					name: "FILNAME",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Navn",
						en: "Name"
					}),
					readOnly: false,
					hidden: false,
					msgTarget: "side",
					listeners: {
						change: function(item) {

							var value = this.getValue();
							i_cmp.form.getForm().setValues({
								"FILMEDIA": value
							});
							if (i_cmp.type == "new") {
								if (!i_cmp.originalTiltle) {
									i_cmp.originalTiltle = i_cmp.title;
								}
								var rawValue = this.getRawValue();
								if (rawValue === "") {
									i_cmp.setTitle(i_cmp.originalTiltle);
								}
								else {
									i_cmp.setTitle(i_cmp.originalTiltle + " - " + rawValue);
								}
							}
						}
					},
					getValue: function() {
						var value = this.getRawValue();
						return (value + "." + this.extension).trim();
					},
					setValue: function(_value) {
						var value = _value || "";
						var extension = value.split(".").pop();
						this.extension = extension;
						i_cmp.extension = extension;
						var name = value.replace("." + extension, "");
						this.mixins.field.setValue.call(this, name);
						this.setRawValue(name);
						if (i_cmp.type == "new") {
							if (!i_cmp.originalTiltle) {
								i_cmp.originalTiltle = i_cmp.title;
							}
							var rawValue = this.getRawValue();
							if (rawValue === "") {
								i_cmp.setTitle(i_cmp.originalTiltle);
							}
							else {
								i_cmp.setTitle(i_cmp.originalTiltle + " - " + rawValue + "." + extension);
							}
						}
						return this;
					}
				},
				{
					xtype: "textfield",
					name: "FILHEAD",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Overskrift",
						en: "Header"
					}),
					readOnly: false,
					emptyText: ip2.i18n({
						da: "ALT tekst",
						en: "ALT text"
					})
				},
				{
					xtype: "textarea",
					name: "FILSUB",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Underoverskrift",
						en: "Sub header"
					}),
					readOnly: false,
					emptyText: ip2.i18n({
						da: "Brug hvor template-design benytter ALT tekst delt i overskrift og underoverskrift ALT tekst",
						en: "Brug hvor template-design benytter ALT tekst delt i overskrift og underoverskrift ALT tekst"
					})
				},
				{
					xtype: "textfield",
					name: "FILTAG",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Tags",
						en: "Tags"
					}),
					readOnly: false
				},
				{
					xtype: "isotimestampfield",
					name: "FILCREATE",
					fieldLabel: ip2.i18n({
						da: "Oprettet",
						en: "Created"
					}),
					readOnly: true
				},
				{
					xtype: "isotimestampfield",
					name: "FILMODIFY",
					fieldLabel: ip2.i18n({
						da: "Ændret",
						en: "Changed"
					}),
					readOnly: true
				},
				{
					xtype: "textfield",
					name: "FILCRTBY",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Oprettet af",
						en: "Created by"
					}),
					readOnly: true
				},
				{
					xtype: "textfield",
					name: "FILPATH",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Sti",
						en: "Path"
					}),
					readOnly: true,
					hidden: false
				},
				{
					xtype: "textfield",
					name: "FILORIPATH",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Original sti",
						en: "Original path"
					}),
					readOnly: true,
					hidden: false
				},
				{
					xtype: "fieldcontainer",
					name: "FILEXTERNAL",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Ekstern",
						en: "External"
					}),
					layout: {
						type: "hbox",
						align: "center"
					},
					defaults: {
						"margin": "0 5 0 0"
					},
					items: [
						{
							xtype: "checkbox",
							name: "FILEXTERNAL",
							readOnly: true,
							hidden: false
						},
						i_cmp.createConvertButton(i_cmp.record),
						i_cmp.createConvertLabel(i_cmp.record)
					]
				}

			]
		});
		return fieldset;
	},

	createPanelWest: function() {
		var i_cmp = this;
		var i_panel_west = Ext.widget("panel", {
			layout: "border",
			region: "west",
			flex: 1,
			items: [
				i_cmp.createAreaDropzone(),
				i_cmp.createPnlRelations()
			]
		});
		return i_panel_west;
	},

	createAreaDropzone: function() {
		var i_cmp = this;
		var i_record = i_cmp.record;
		var url = "";
		if (i_cmp.type == "edit") {
			var b_isExternal = i_record.get("FILEXTERNAL");

			if (b_isExternal) {
				url = i_record.get("FILORIPATH");
			}
			else {
				url = i_record.get("FILPATH") + i_record.get("FILNAME");
			}
		}
		else {
			if (i_cmp.uploadname.indexOf(".") == -1) {
				url = "";
			}
			else {
				url = i_cmp.uploadname;
			}
		}

		var pnl = Ext.widget("form", {
			title: ip2.i18n({
				da: "Fil",
				en: "File"
			}),
			itemId: "frmUpload",
			layout: "fit",
			region: "center",
			flex: 2,
			bodyPadding: 20,
			dockedItems: [{
					xtype: "toolbar",
					dock: "top",
					items: [
						"->",
						{
							xtype: "fileuploadfield",
							itemId: "fileup",
							width: 60,
							buttonOnly: true,
							buttonConfig: {
								text: "",
								width: 60,
								cls: "x-ux-filemanager-images-upload"
							},
							listeners: {
								change: {
									fn: function(item, value) {
										var form = item.up("form");
										var a_files = item.fileInputEl.dom.files;
										if (a_files.length == 0) {
											return;
										}
										var s_name = a_files[0].name;
										var s_newExtension = value.split(".").pop().toLowerCase();

										if (Ext.ux.file.util.Handler.extensions.indexOf(s_newExtension) != -1) {
											if (i_cmp.uploadname.indexOf(".") == -1) {
												i_cmp.uploadname = i_cmp.uploadname + "." + s_newExtension;
											}
											else {
												i_cmp.uploadname = i_cmp.uploadname.replace("." + i_cmp.extension, "." + s_newExtension);
											}
											if (value) {
												var msg = ip2.i18n({
													da: "Uploader fil..",
													en: "Uploading file..."
												});
												form.setLoading(msg, true);
												i_cmp.setSavable(false);
												Ext.ux.file.util.Handler.uploadToTemp(a_files[0], function(i_record) {
													if (i_cmp.type == "new") {
														i_cmp.form.getForm().setValues({
															"FILNAME": s_name,
															"FILMEDIA": s_name,
															"FILEXT": s_newExtension
														});
													}
													else {
														i_cmp.form.getForm().setValues({
															"FILEXT": s_newExtension,
															"FILEXTERNAL": 0
														});
													}
													i_cmp.hasUploaded = true;
													i_cmp.uploadname = i_record.uploadname;
													i_cmp.onImageUpdate();
													form.setLoading(false);
												});
											}
										}
										else {
											var s_title = ip2.i18n({
												da: "Fejl",
												en: "Error"
											});
											var s_msg = ip2.i18n({
												da: "Denne fil type er ikke tilladt",
												en: "This fil type is not allowed"
											});
											Ext.Msg.show({
												title: s_title,
												msg: s_msg,
												buttons: Ext.Msg.OK,
												icon: Ext.Msg.ERROR
											});
										}
										item.reset();
									}
								}
							}
						}
					]
				}

			],
			items: [
				{
					xtype: "container",
					layout: "fit",
					setImage: function(url) {
						var size = this.getSize();
						var el = this.getEl();
						var o_record = i_cmp.record;
						var s_extension = o_record.get("FILEXT");
						var a_extension_image = ["jpg","jpeg","png","gif", "bmp"];
						if (o_record.get("FILEXTERNAL")) {
							if (a_extension_image.indexOf(s_extension) == -1) {
								url = Ext.ux.file.util.Handler.getUrlByExtension(url);
							}
							el.setStyle({
								"background-size": "contain"
							});
						}
						else {
							if (a_extension_image.indexOf(s_extension) != -1) {
								url = "/ip2-services/scaleImage.aspx?".concat(
									Ext.Object.toQueryString(ip2.extend({
										path: url,
										padCanvas: false,
										_dc: ip2.getDcTimestamp()
									}, size))
								);
							}
							else {
								url = Ext.ux.file.util.Handler.getUrlByExtension(url);
								el.setStyle({
									"background-size": "contain"
								});
							}
						}
						el.setStyle({
							"background-image": "url(\"" + url + "\")",
							"background-repeat": "no-repeat",
							"background-position": "50% 50%"
						});
					},
					listeners: {
						afterrender: {
							single: true,
							fn: function(item) {
								var dropzone = i_cmp.createDropzone();
								var el = item.getEl();
								dropzone.getEl().insertBefore(el);
								i_cmp.image = item;
							}
						},
						resize: function(item) {
							var url = "";
							var i_record = i_cmp.record;
							if (i_cmp.hasUploaded) {
								url = i_cmp.uploadname;
							}
							else {
								var b_isExternal = i_record.get("FILEXTERNAL");
								if (b_isExternal) {
									url = i_record.get("FILORIPATH");
								}
								else {
									url = i_record.get("FILPATH") + i_record.get("FILNAME");
								}
							}

							setTimeout(function() {
								item.setImage(url);
							}, 5);
						}
					}
				}
			]
		});
		return pnl;
	},

	createPnlRelations: function() {
		var i_cmp = this;
		var i_grid = i_cmp.createGridRelation(i_cmp.record);
		i_cmp.pnlRelations = Ext.widget("panel", {
			title: ip2.i18n({
				da: "Relationer",
				en: "Relations"
			}),
			layout: "fit",
			region: "south",
			flex: 1,
			items: [
				i_grid
			]
		});
		i_cmp.grid = i_grid;
		return i_cmp.pnlRelations;
	},

	createDropzone: function() {
		var i_cmp = this;
		var dropbox = Ext.widget("gallerydropbox", {
			flex: 1,
			dropText: ip2.i18n({
				en: "Drag-and-drop your image here<br /><small><small>*Allowed file types.. jpg, jpeg, gif or png</small></small>",
				da: "Træk-og-slip dit billede her<br /><small><small>*Tillade fil typer.. jpg, jpeg, gif, eller png</small></small>"
			}),
			extensions: Ext.ux.file.util.Handler.extensions,
			maxItems: 1,
			style: {
				"position": "absolute",
				"padding": "10px",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"font-size": "25px"
			},
			listeners: {
				drop: {
					fn: function(i_dropbox, a_files, o_event) {
						var plugin = i_dropbox.getDDPlugin();
						var form = i_cmp.down("#frmUpload");
						i_cmp.setSavable(false);
						if (plugin.enableDrop) {

							var msg = ip2.i18n({
								da: "Uploader fil..",
								en: "Uploading file..."
							});
							form.setLoading(msg, true);
							Ext.ux.file.util.Handler.uploadToTemp(a_files[0], function(i_record) {
								if (i_cmp.type == "new") {
									i_cmp.form.getForm().setValues({
										"FILNAME": i_record.name,
										"FILMEDIA": i_record.name,
										"FILEXT": i_record.extension
									});
								}
								else {
									i_cmp.form.getForm().setValues({
										"FILEXT": i_record.extension,
										"FILEXTERNAL": 0
									});
								}
								i_cmp.hasUploaded = true;
								i_cmp.uploadname = i_record.uploadname;
								i_cmp.onImageUpdate();
								form.setLoading(false);
							});
						}
					}
				},
				bodydragenter: function(i_dropbox, o_event) {
					var i_el = i_cmp.i_dropzone.getEl();
					if (i_el.dom) {
						var size = i_cmp.i_dropzone.getSize();
						i_dropbox.setSize(size);
						i_el.setStyle("opacity", "0.8");
					}
				},
				bodydragleave: function(i_dropbox, o_event) {
					var i_el = i_cmp.i_dropzone.getEl();
					if (i_el.dom) {
						i_el.setStyle("opacity", "0");
					}
				},
				dragenter: {
					fn: function(i_dropbox, o_event) {
						var items = o_event.dataTransfer.items || o_event.dataTransfer.files;
						var plugin = i_dropbox.getDDPlugin();
						if (items.length > i_dropbox.maxItems) {
							i_dropbox.addCls(plugin.failureCls);
							plugin.enableDrop = false;
						}
					}
				},
				dragleave: {
					fn: function(i_dropbox, o_event) {
						var plugin = i_dropbox.getDDPlugin();
						plugin.enableDrop = true;
					}
				}
			}
		});

		i_cmp.i_dropzone = Ext.widget("container", {
			layout: "fit",
			renderTo: Ext.getBody(),
			style: {
				"background-color": "white",
				"position": "absolute",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"display": "inline",
				"opacity": "0"
			},
			items: [dropbox]
		});

		return i_cmp.i_dropzone;
	},

	createButtons: function() {
		var i_cmp = this;

		var buttons = [
				{
					xtype: "button",
					width: 50,
					text: ip2.i18n({
						da: "Gem",
						en: "Save"
					}),
					listeners: {
						added: function(button) {
							i_cmp.buttonSave = button;
							i_cmp.setSavable(false);
						}
					},
					handler: function(item) {
						item.setDisabled(true);
						var i_form = i_cmp.form.getForm();
						var o_fieldValues = i_form.getFieldValues();
						var i_record = i_cmp.record;
						var i_store = i_cmp.store;
						var i_field = i_form.findField("FILNAME");
						if (i_field.getRawValue() === "") {

							i_field.markInvalid(ip2.i18n({
								da: "Dette må ikke være tom",
								en: "This must not be empty"
							}));
							return false;
						}
						var a_files = [{
							name: o_fieldValues.FILNAME
						}];
						var msg = ip2.i18n({
							da: "Valider fil navn...",
							en: "Validating filename.."
						});
						i_cmp.setLoading(msg, true);
						Ext.ux.file.util.Handler.checkFiles(o_fieldValues.FILPATH, a_files, function(o_result) {
							i_cmp.setLoading(false);
							var a_update = o_result.update;
							var field = i_form.findField("FILNAME");
							if (i_cmp.type == "new") {
								if (a_update.length > 0) {
									var msg = ip2.i18n({
										da: "Navnet findes allerede",
										en: "Name allready exists"
									});
									field.markInvalid(msg);
									item.setDisabled(false);
									return false;
								}
								else {
									i_record.set(o_fieldValues);
									var extension = i_record.get("FILNAME").split(".").pop();
									i_record.set("FILNAME", i_record.get("FILNAME").replace("." + extension, "." + extension.toLowerCase()));
									i_record.set("FILMEDIA", i_record.get("FILNAME"));
									i_cmp.form.setLoading(ip2.i18n({
										da: "Gemmer...",
										en: "Saving..."
									}), true);
									i_record.set("FILCREATE", ip2.createIsoTimeStamp());
									i_record.set("FILFILTKN", 0);
									Ext.ux.file.util.Handler.upsertRecords([i_record], function(a_records) {
										var s_fromPath = i_cmp.uploadname;
										Ext.ux.file.util.Handler.moveFromRecords(s_fromPath, a_records, function(a_records) {
											i_cmp.form.setLoading(false);
											i_store.load();
											i_cmp.close();
										});
									});
								}
							}
							else {
								if (a_update.length > 0 && i_cmp.oldName != o_fieldValues.FILNAME) {
									field.markInvalid(ip2.i18n({
										da: "Navnet findes allerede",
										en: "Name allready exists"
									}));
									item.setDisabled(false);
									return false;
								}
								else {
									i_record.set(o_fieldValues);
									if (i_cmp.hasUploaded) {
										var extension = i_record.get("FILNAME").split(".").pop();
										var newExtension = i_record.get("FILEXT");
										var s_newName = i_record.get("FILNAME").replace("." + extension, "." + newExtension);
										var s_path = i_record.get("FILPATH");
										i_record.set("FILNAME", s_newName);
										i_record.set("FILORIPATH", s_path);
									}
									i_record.set("FILMEDIA", i_record.get("FILNAME"));
									i_cmp.form.setLoading(ip2.i18n({
										da: "Gemmer...",
										en: "Saving..."
									}), true);
									Ext.ux.file.util.Handler.upsertRecords([i_record], function(a_records) {
										if (i_cmp.hasUploaded) {
											var s_fromPath = i_cmp.uploadname;
											Ext.ux.file.util.Handler.moveFromRecords(s_fromPath, a_records, function(a_records) {
												i_cmp.form.setLoading(false);
												i_store.load();
												i_cmp.close();
											});
										}
										else {
											if (i_cmp.oldName != i_record.get("FILNAME")) {
												var s_fromPath = i_record.get("FILPATH") + i_cmp.oldName;
												Ext.ux.file.util.Handler.moveFromRecords(s_fromPath, [i_record], function(a_records) {
													i_cmp.form.setLoading(false);
													i_store.load();
													i_cmp.close();
												});
											}
											else {
												i_cmp.form.setLoading(false);
												i_cmp.close();
												i_store.load();
											}
										}
									});
								}
							}
						});
					}
				},
				{
					xtype: "button",
					width: 50,
					text: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					}),
					handler: function(item) {
						i_cmp.close();
					}

				}
			];

		return buttons;
	},

	createGridRelation: function(i_record) {
		var i_self = this;
		var o_config = {
			filterable: false,
			b_load: false,
			allowNew: false,
			dmd: {
				path: "dmd/webshop.dmd",
				entityName: "WSHRELET00"
			}
		};

		var i_grid = Ext.widget("ip2pagingGridOld", o_config);
		var i_store = i_grid.getStore();

		i_store.on({
			beforeload: {
				fn: function(store) {
					store.proxy.extraParams.where = "RELCHDTKN = " + i_record.get("FILFILTKN");
					store.currentPage = 1;
				}
			}
		});

		i_grid.on({
			afterrender: {
				fn: function(i_item) {
					i_grid.events.itemdblclick.clearListeners();
					i_grid.events.itemcontextmenu.clearListeners();
					var i_toolbar = i_grid.getToolbar();
					var index = i_toolbar.removeExport();
					i_toolbar.items.removeAt(index);
				}
			}
		});

		return i_grid;
	},

	setSavable: function(saveable) {
		var i_cmp = this;
		i_cmp.buttonSave.setDisabled(!saveable);
	},

	onImageUpdate: function() {
		var i_cmp = this;
		var url = ip2.cleanPath(i_cmp.uploadname);
		i_cmp.image.setImage(url);
		var absPath = ip2.cleanPath(i_cmp.uploadname);
		i_cmp.getImageInfo(absPath);
	},

	getImageInfo: function(filepath) {
		var i_cmp = this;
		Ext.Ajax.request({
			url: "/ip2-services/imageIdentify.aspx",
			params: {
				file: filepath
			},
			success: function(o_response) {
				var o_info = JSON.parse(o_response.responseText);
				var width = o_info.width;
				var height = o_info.height;
				var size = o_info.filesize;

				i_cmp.form.getForm().setValues({
					FILWIDTH: width,
					FILHEIGHT: height,
					FILSIZE: size
				});
				i_cmp.setSavable(true);
			}
		});
	}
});
Ext.define("Ext.ux.file.view.Search", {

	extend: "Ext.window.Window",

	alias: "widget.filesearch",

	modal: true,

	constain: true,

	width: 800,

	height: 600,

	closable: true,

	layout: "fit",

	config: {
		path: "/",
		okFn: Ext.emptyFn,
		isOk: false,
		cancelFn: Ext.emptyFn,
		tree: null,
		grid: null,
		doSelection: true
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var s_title = ip2.i18n({
			da: "Søg efter et medie",
			en: "Search for a media"
		});

		i_self.setTitle(s_title);
		i_self.add(i_self.createLayout());

		return i_self;
	},

	createLayout: function() {

		var i_self = this;

		var i_form = Ext.widget("form", {
			layout: "border",
			items: [
				i_self.createTree(),
				i_self.createGrid()
			],
			buttons: i_self.createButtons()
		});

		return i_form;
	},

	createTree: function() {

		var i_self = this;

		var i_tree = Ext.ux.file.util.Handler.getUITree({
			useSystem: false,
			region: "west",
			flex: 1,
			path: "$root$",
			split: true,
			rootVisible: false,
			viewConfig: {
				loadMask: false
			},
			listeners: {
				select: {
					fn: function(model, i_node) {

						var i_grid = i_self.getGrid();
						var i_store = i_grid.getStore();

						i_store.loadPage(1);
					}
				}
			}
		});

		var i_store = i_tree.getStore();

		i_store.on({
			load: {
				fn: function(i_store, a_records) {

					var a_selected = i_tree.getSelection();

					if (a_selected.length === 0) {

						var s_path = i_self.getPath();

						Ext.Array.each(a_records, function(i_record) {

							if (i_record.get("path") == s_path && i_self.getDoSelection()) {
								i_self.setDoSelection(false);

								i_tree.getSelectionModel().select(i_first);
								return false;
							}
						});
					}

					Ext.Array.each(a_records, function(i_record) {
						i_record.set("allowDrag", false);

						if (!i_record.get("hasChild")) {
							i_record.set("loaded", true);
						}
						else {
							i_record.expand();
						}
					});
				}
			}
		});

		i_self.setTree(i_tree);

		return i_tree;
	},

	createGrid: function() {

		var i_self = this;

		var i_selectionModel = Ext.create("Ext.selection.RowModel", {
			mode: "SINGLE",
			enableKeyNav: true
		});

		var i_grid = Ext.ux.file.util.Handler.getUIGrid({
			autoLoad: false,
			flex: 3,
			region: "center",
			selMol: i_selectionModel,
			listeners: {
				afterrender: {
					fn: function(i_grid) {

						var i_toolbar = i_grid.getActionBar();

						var n_index = i_toolbar.removeExport();
						var o_component = i_toolbar.items.getAt(n_index);
						i_toolbar.remove(o_component, true);

						n_index = i_toolbar.removeAdd();
						if (n_index) {
							i_toolbar.items.removeAt(n_index);
						}

						i_grid.events.itemdblclick.clearListeners();
						i_grid.events.itemcontextmenu.clearListeners();

						i_grid.on({
							itemdblclick: {
								fn: function(i_view, i_record, i_element, n_index) {

									i_self.isOk = true;
									i_self.okFn(record);
									i_self.close();
								}
							},
							select: {
								fn: function(i_store, i_record) {

									var i_button = i_self.down("#btnOk");

									if (i_button) {
										i_button.setDisabled(false);
									}
								}
							}
						});
					}
				}
			}
		});

		var i_store = i_grid.getStore();

		i_store.on({
			beforeload: {
				fn: function(i_store, i_operation) {

					var i_tree = i_self.getTree();

					var a_selected = i_tree.getSelection();

					var i_selected = a_selected[0];

					var b_load = false;

					if (i_selected) {
						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();

						var s_path = "/";

						if (!i_selected.isRoot()) {
							s_path = i_selected.get("path");
						}

						Ext.apply(o_extraParams,  {
							where: "FILPATH like '" + s_path + "%'"
						});

						b_load = true;
					}

					return b_load;
				}
			}
		});

		i_self.setGrid(i_grid);

		return i_grid;
	},

	createButtons: function() {

		var i_self = this;

		var a_buttons = [
			{
				xtype: "button",
				itemId: "btnOk",
				iconCls: "pf-floppy_disk",
				disabled: true,
				text: ip2.i18n({
					da: "Ok",
					en: "Ok"
				}),
				handler: function(i_button) {

					i_self.isOk = true;

					var i_grid = i_self.getGrid();

					var a_selected = i_grid.getSelection();
					i_self.okFn(a_selected[0]);
					i_self.close();
				}
			},
			{
				xtype: "button",
				iconCls: "pf-navigate_cross",
				text: ip2.i18n({
					da: "Annuller",
					en: "Cancel"
				}),
				handler: function(i_button) {
					i_self.close();
				}
			}
		];

		return a_buttons;
	}
});
Ext.define("Ext.ux.file.view.Preview", {
	extend: "Ext.window.Window",
	alias: "widget.filepreview",
	layout: "fit",
	modal: true,
	record: undefined,
	width: 800,
	height: 600,
	constrain: true,

	initComponent: function () {
		var i_self = this;
		i_self.callParent(arguments);
		i_self.add(i_self.createForm());
		var i_record = i_self.record;
		var s_title = ip2.i18n({
			da: "Preview",
			en: "Preview"
		});
		s_title = s_title + ": " + i_record.get("FILNAME");
		i_self.setTitle(s_title);
		return i_self;
	},

	createForm: function() {
		var i_self = this;
		var i_form = Ext.widget("form", {
			layout: "border",
			items: [
				i_self.createPreivew(),
				i_self.createPanelInfo()
			],
			buttons: i_self.createButtons()
		});
		i_form.loadRecord(i_self.record);
		return i_form;
	},

	createPreivew: function() {
		var i_self = this;
		var i_preview = {
			xtype: "panel",
			region: "center",
			layout: "fit",
			title: ip2.i18n({
				da: "Fil",
				en: "File"
			}),
			flex: 3,
			bodyPadding: 20,
			items: [
				{
					xtype: "container",
					setImage: function() {
						var url = i_self.record.get("FILPATH") + i_self.record.get("FILNAME");
						var size = this.getSize();
						var el = this.getEl();
						el.setStyle({
							"background": 'url("' + url + '") no-repeat 50% 50%',
							"background-size": "contain"
						});
					},
					listeners: {
						afterrender: {
							single: true,
							fn: function(item) {

								var f_layout = item.doLayout || item.updateLayout;

								f_layout.call(item);

								setTimeout(function() {
									item.setImage();
								}, 5);
							}
						}
					}
				}
			]
		};
		return i_preview;
	},

	createPanelInfo: function() {
		var i_self = this;
		var i_panel = {
			xtype: "panel",
			region: "south",
			flex: 2,
			layout: "border",
			items: [
				i_self.createFieldSetInfo(),
				i_self.createFieldSetMeta()
			]
		};
		return i_panel;
	},

	createFieldSetInfo: function() {
		var i_self = this;
		var fieldset = {
			xtype: "panel",
			flex: 2,
			region: "west",
			autoScroll: true,
			bodyPadding: 5,
			title: ip2.i18n({
				da: "Generel information",
				en: "General information"
			}),
			layout: "anchor",
			items: [
				{
					xtype: "textfield",
					name: "FILMEDIA",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Media",
						en: "Media"
					}),
					readOnly: true,
					hidden: true
				},
				{
					xtype: "textfield",
					name: "FILNAME",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Navn",
						en: "Name"
					}),
					readOnly: true,
					hidden: false,
					getValue: function() {
						var value = this.getRawValue();
						return value + "." + this.extension;
					},
					setValue: function(value) {
						value = value || "";
						var extension = value.split(".").pop();
						this.extension = extension;
						i_self.extension = extension;
						var name = value.replace("." + extension, "");
						this.mixins.field.setValue.call(this, name);
						this.setRawValue(name);
						return this;
					}
				},
				{
					xtype: "isotimestampfield",
					name: "FILCREATE",
					fieldLabel: ip2.i18n({
						da: "Oprettet",
						en: "Created"
					}),
					readOnly: true
				},
				{
					xtype: "isotimestampfield",
					name: "FILMODIFY",
					fieldLabel: ip2.i18n({
						da: "Modificeret",
						en: "Modification"
					}),
					readOnly: true
				},
				{
					xtype: "textfield",
					name: "FILPATH",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Sti",
						en: "Path"
					}),
					readOnly: true,
					hidden: false
				},
				{
					xtype: "textfield",
					name: "FILORIPATH",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Original sti",
						en: "Original path"
					}),
					readOnly: true,
					hidden: false
				}
			]
		};
		return fieldset;
	},

	createFieldSetMeta: function() {
		var i_self = this;
		var fieldset = {
			xtype: "panel",
			flex: 1,
			region: "center",
			bodyPadding: 5,
			autoScroll: true,
			title: ip2.i18n({
				da: "Meta information",
				en: "Meta Information"
			}),
			layout: "anchor",
			items: [
				{
					xtype: "textfield",
					name: "FILWIDTH",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Brede",
						en: "Width"
					}),
					readOnly: true
				},
				{
					xtype: "textfield",
					name: "FILHEIGHT",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Højde",
						en: "Heigth"
					}),
					readOnly: true
				},
				{
					xtype: "textfield",
					name: "FILSIZE",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Størrelse",
						en: "Size"
					}),
					readOnly: true,
					getValue: function() {
						return this.trueValue;
					},
					setValue: function(value) {
						value = value || 0;
						var rawValue = ip2.humanFileSize(value);
						this.trueValue = value;
						this.mixins.field.setValue.call(this, value);
						this.setRawValue(rawValue);
						return this;
					}
				},
				{
					xtype: "textfield",
					name: "FILEXT",
					anchor: "99%",
					fieldLabel: ip2.i18n({
						da: "Fil type",
						en: "File type"
					}),
					readOnly: true
				}
			]
		};
		return fieldset;
	},

	createButtons: function() {
		var i_self = this;
		var a_buttons = [{
			xtype: "button",
			text: ip2.i18n({
				da: "Luk",
				en: "Close"
			}),
			handler: function(i_button) {
				i_self.close();
			}
		}];
		return a_buttons;
	}
});
Ext.define("Ext.ux.file.util.Handler", {

	singleton: true,

	model: null,

	extensions: [
		"jpg",
		"jpeg",
		"png",
		"gif",
		"bmp",
		"pdf",
		"docx",
		"doc",
		"xls",
		"xlsx",
		"xlm",
		"xlt",
		"xlw",
		"ppt",
		"txt",
		"dwg"
	],

	imageExtension: [
		"jpg",
		"jpeg",
		"png",
		"gif",
		"bmp"
	],

	getRecordById: function(id, f_callback) {
		var i_self = this;
		var a_batch = [];

		a_batch.push({
			type: "get",
			dmd: "dmd/webshop.dmd",
			entity: "WSHFILET00",
			context: "grid",
			uiName: "portfolio",
			where: "FILFILTKN = " + id,
			page: 1,
			start: 0,
			limit: -1
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {

				var o_result = Ext.decode(o_response.responseText);
				var o_batch = o_result.batch[0];
				var i_record;

				Ext.Array.each(o_batch.rows, function(o_record) {
					var Model = i_self.getModel();
					i_record = Model.create(o_record);
				});

				f_callback(i_record);
			}
		});
	},

	getRecordsById: function(a_ids, f_callback) {
		var i_self = this;
		var a_batch = [];

		Ext.Array.each(a_ids, function (id) {
			a_batch.push({
				type: "get",
				dmd: "dmd/webshop.dmd",
				entity: "WSHFILET00",
				context: "grid",
				uiName: "portfolio",
				where: "FILFILTKN = " + id,
				page: 1,
				start: 0,
				limit: -1
			});
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var a_records = [];
				var a_batch = o_result.batch;
				Ext.Array.each(a_batch, function(o_batch) {
					Ext.Array.each(o_batch.rows, function(o_record) {

						var Model = i_self.getModel();

						var i_record = Model.create(o_record);
						a_records.push(i_record);
					});
				});
				f_callback(a_records);
			}
		});
	},

	getRecordByName: function(path, name, f_callback) {
		var i_self = this;
		var a_batch = [];

		a_batch.push({
			type: "get",
			dmd: "dmd/webshop.dmd",
			entity: "WSHFILET00",
			context: "grid",
			uiName: "portfolio",
			where: "FILPATH = \"" + path + "\" AND FILNAME = \"" + name + "\"",
			page: 1,
			start: 0,
			limit: -1
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var a_records = [];
				var batch = o_result.batch[0];
				Ext.Array.each(batch.rows, function(o_record) {

					var Model = i_self.getModel();
					var record = Model.create(o_record);

					a_records.push(record);
				});
				f_callback(a_records);
			}
		});
	},

	getRecordsByName: function(path, a_names, f_callback) {
		var i_self = this;
		var a_batch = [];
		var s_where = "";

		for (var i = 0; i < a_names.length; i++) {
			var value = a_names[i];
			var a_ext = value.split(".");
			var s_ext = a_ext.pop();
			value = a_ext.join("") + "." + s_ext;
			if (i === 0) {
				s_where = s_where + "'" + value + "'";
			}
			else {
				s_where = s_where + ",'" + value + "'";
			}
		}

		a_batch.push({
			type: "get",
			dmd: "dmd/webshop.dmd",
			entity: "WSHFILET00",
			context: "grid",
			uiName: "portfolio",
			where: "FILPATH = '" + path + "' AND FILNAME IN (" + s_where + ")",
			page: 1,
			start: 0,
			limit: -1
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var a_records = [];
				var batch = o_result.batch[0];
				Ext.Array.each(batch.rows, function(o_record) {

					var Model = i_self.getModel();
					var record = Model.create(o_record);

					a_records.push(record);
				});
				f_callback(a_records);
			}
		});
	},

	getRecordsByPath: function(path, f_callback) {

		var i_self = this;
		var a_batch = [];

		a_batch.push({
			type: "get",
			dmd: "dmd/webshop.dmd",
			entity: "WSHFILET00",
			context: "grid",
			uiName: "portfolio",
			where: "FILPATH = '" + path +"'",
			page: 1,
			start: 0,
			limit: -1
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var a_records = [];
				var batch = o_result.batch[0];
				Ext.Array.each(batch.rows, function(o_record) {

					var Model = i_self.getModel();
					var i_record = Model.create(o_record);

					a_records.push(i_record);
				});
				f_callback(a_records);
			}
		});
	},

	getFilesByPath: function(path, f_callback) {
		var i_self = this;
		Ext.Ajax.request({
			url: "/ip2-Services/webbios.aspx",
			method: "GET",
			params: {
				func: "listdir",
				path: path
			},
			success: function(o_response) {
				var a_files = Ext.decode(o_response.responseText);
				var a_result = Ext.Array.filter(a_files, function(o_file) {
					return Ext.Array.indexOf(i_self.extensions, o_file.ext.toLowerCase()) > -1;
				});
				f_callback(a_result);
			}
		});
	},

	getRecordListByPath: function(path, f_callback) {
		var i_self = this;
		i_self.getFilesByPath(path, function(a_files) {
			var a_records = [];
			Ext.Array.each(a_files, function(o_file) {
				o_record = {
					name: o_file.text,
					size: o_file.size
				};
				a_records.push(o_record);
			});
			i_self.createRecordsNoUploadNoImageInfo(path, a_records, function(a_records) {
				f_callback(a_records);
			});
		});
	},

	getPathById: function(id, f_callback) {
		var i_self = this;
		var a_batch = [];

		a_batch.push({
			type: "get",
			dmd: "dmd/webshop.dmd",
			entity: "WSHFILET00",
			context: "grid",
			uiName: "portfolio",
			where: "FILFILTKN = " + id,
			page: 1,
			start: 0,
			limit: -1
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var o_batch = o_result.batch[0];
				var i_record;
				Ext.Array.each(o_batch.rows, function(o_record) {

					var Model = i_self.getModel();
					i_record = Model.create(o_record);
				});
				f_callback(i_record.get("FILPATH") + i_record.get("FILNAME"));
			}
		});
	},

	getModel: function () {

		var i_self = this;
		var i_model = i_self.model;

		if (!i_model) {
			try {
				i_self.model = ip2.model({
					dmd: "dmd/webshop.dmd",
					entityName: "WSHFILET00",
					context: "grid",
					uiName: "portfolio"
				});
			}
			catch (err) {}
		}

		return i_self.model;
	},

	getPathsById: function(a_ids, f_callback) {

		var i_self = this;
		var a_batch = [];

		Ext.Array.each(a_ids, function (id) {
			a_batch.push({
				type: "get",
				dmd: "dmd/webshop.dmd",
				entity: "WSHFILET00",
				context: "grid",
				uiName: "portfolio",
				where: "FILFILTKN = " + id,
				page: 1,
				start: 0,
				limit: -1
			});
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var a_paths = [];
				var a_batch = o_result.batch;
				Ext.Array.each(a_batch, function(o_batch) {
					Ext.Array.each(o_batch.rows, function(o_record) {

						var Model = i_self.getModel();
						var i_record = Model.create(o_record);
						var s_path = i_record.get("FILPATH");
						var s_name = i_record.get("FILNAME");
						var s_filename = [s_path, s_name].join();

						a_paths.push(s_filename);
					});
				});
				f_callback(a_paths);
			}
		});
	},

	getUrlByExtension: function(s_path, b_noStringify) {

		var s_url = "";
		var s_extension = s_path.split(".").pop().toLowerCase();
		var a_extension_image = ["jpg","jpeg","png","gif", "bmp"];
		var a_docs = ["doc", "docx"];
		var a_xls = ["xls", "xlsx", "xlm","xlt", "xlw"];
		var s_pdf = "pdf";
		var s_ppt = "ppt";
		var s_dwg = "dwg";
		var s_youtube = "youtube.com";
		var a_videos = ["mp4", "mov", "mpeg4", "wmv", "flv", "avi"];

		if (a_extension_image.indexOf(s_extension) != -1) {
			if (!b_noStringify) {
				s_url = "\"" + s_path + "\"";
			}
			else {
				s_url = s_path;
			}
		}
		else {
			if (s_pdf == s_extension) {
				s_url = "/portfolio/styles/icon/flatui/media/pdf.png";
			}
			else if (s_ppt == s_extension) {
				s_url = "/portfolio/styles/icon/flatui/media/ppt.png";
			}
			else if (s_dwg == s_extension) {
				s_url = "/portfolio/styles/icon/flatui/media/dwg.png";
			}
			else if (a_docs.indexOf(s_extension) != -1) {
				s_url = "/portfolio/styles/icon/flatui/media/doc.png";
			}
			else if (a_xls.indexOf(s_extension) != -1) {
				s_url = "/portfolio/styles/icon/flatui/media/xls.png";
			}
			else if (s_path.indexOf(s_youtube) != -1 || a_videos.indexOf(s_extension) != -1) {
				s_url = "/portfolio/styles/icon/flatui/media/mg-type-video.png";
			}
			else {
				s_url = "/portfolio/styles/icon/flatui/media/generic-doc.png";
			}
		}
		return s_url;
	},

	getHives: (function() {

		var a_hives;

		var resolve = function(path, b_system, fn) {
			var hives = Ext.Array.filter(a_hives, function(o) {
				return o.parent == path
					|| "/" + o.parent == path
					|| "/" + path == o.parent
					|| o.parent + "/" == path
					|| path + "/" == o.parent
					|| "/" + o.parent + "/" == path
					|| "/" + path + "/" == o.parent;
			});
			hives = Ext.Array.map(hives, function(o_hive) {
				if (o_hive.type == "system") {
					if (b_system) {
						return {
							path: "/" + o_hive.alias + "/",
							text: ip2.i18n(Ext.decode(o_hive.title)),
							isHive: true,
							hasChild: false,
							allowDrop: o_hive.allowDrop !== undefined ? Ext.decode(o_hive.allowDrop) : false,
							allowImport: o_hive.allowImport !== undefined ? Ext.decode(o_hive.allowImport) : false,
							allowAdd: o_hive.allowAdd !== undefined ? Ext.decode(o_hive.allowAdd) : false,
							iconCls: o_hive.iconCls || "",
							type: o_hive.type || "",
							saveUrl: o_hive.saveUrl !== undefined ? Ext.decode(o_hive.saveUrl) : false || true

						};
					}
				}
				else {
					return {
						path: "/" + o_hive.alias + "/",
						text: ip2.i18n(Ext.decode(o_hive.title)),
						isHive: true,
						hasChild: true,
						allowDrop: o_hive.allowDrop !== undefined ? Ext.decode(o_hive.allowDrop) : false,
						allowImport: o_hive.allowImport !== undefined ? Ext.decode(o_hive.allowImport) : false,
						allowAdd: o_hive.allowAdd !== undefined ? Ext.decode(o_hive.allowAdd) : false,
						iconCls: o_hive.iconCls || "",
						type: o_hive.type || "",
						saveUrl: o_hive.saveUrl !== undefined ? Ext.decode(o_hive.saveUrl) : false || true
					};
				}
			});
			hives = Ext.Array.filter(hives, function(o) {
				return o !== undefined;
			});

			return hives;
		};

		return function(path, b_system, b_all) {

			path = path || "";

			if (!a_hives) {
				var responseText = ip2.sajax.request({
					url: "/ip2-services/webBios.aspx?func=getHives"
				});

				a_hives = Ext.decode(responseText);
				a_hives = a_hives.filter(function(o) {
					return o.filemanager;
				}).sort(function(a, b) {
					return a.alias.length - b.alias.length;
				});

				var _paths = {};

				a_hives.forEach(function(o) {

					o.parent = "$root$";

					for (var prop in _paths) {
						// prop = parent;
						// /abc is not parent of /abcdef
						// /abc is parent of /abc/def
						// /abc/ is parent of /abc/def
						if (o.alias.indexOf(prop) === 0 && (

							// If parent ends with / (eg. parent=/abc/, we=/abc/def)
							prop.slice(-1) == "/"

							// If we start with slash where parent ends (eg. parent=/abc, we=/abc/def)
							|| o.alias.slice(prop.length).charAt(0) == "/"
						)) {
							o.parent = prop;
						}
					}

					_paths[o.alias] = true;
				});
			}

			return b_all ? a_hives.slice() : resolve(path, b_system);
		};
	})(),

	getHiveByPath: function(s_path) {
		var i_self = this;
		var a_split = s_path.split("/");
		a_split = Ext.Array.filter(a_split, function(s_value) {
			return s_value !== "";
		});
		a_split.pop();
		var s_parent = a_split.join("/");
		var a_hives = i_self.getHives(s_parent, false, true).filter(function(o_hive) {
			return o_hive.alias == s_path
			|| "/" + o_hive.alias + "/" == s_path
			|| o_hive.alias + "/" == s_path
			|| "/" + o_hive.alias == s_path;
		});
		a_hives = Ext.Array.map(a_hives, function(o_hive) {
				if (o_hive.type == "system") {
					if (b_system) {
						return {
							path: "/" + o_hive.alias + "/",
							text: ip2.i18n(Ext.decode(o_hive.title)),
							isHive: true,
							hasChild: false,
							allowDrop: o_hive.allowDrop !== undefined ? Ext.decode(o_hive.allowDrop) : false,
							allowImport: o_hive.allowImport !== undefined ? Ext.decode(o_hive.allowImport) : false,
							allowAdd: o_hive.allowAdd !== undefined ? Ext.decode(o_hive.allowAdd) : false,
							iconCls: o_hive.iconCls || "",
							type: o_hive.type || "",
							saveUrl: o_hive.saveUrl !== undefined ? Ext.decode(o_hive.saveUrl) : false || true

						};
					}
				}
				else {
					return {
						path: "/" + o_hive.alias + "/",
						text: ip2.i18n(Ext.decode(o_hive.title)),
						isHive: true,
						hasChild: true,
						allowDrop: o_hive.allowDrop !== undefined ? Ext.decode(o_hive.allowDrop) : false,
						allowImport: o_hive.allowImport !== undefined ? Ext.decode(o_hive.allowImport) : false,
						allowAdd: o_hive.allowAdd !== undefined ? Ext.decode(o_hive.allowAdd) : false,
						iconCls: o_hive.iconCls || "",
						type: o_hive.type || "",
						saveUrl: o_hive.saveUrl !== undefined ? Ext.decode(o_hive.saveUrl) : false || true
					};
				}
			});
		a_hives = Ext.Array.filter(a_hives, function(o) {
			return o !== undefined;
		});
		return a_hives.length > 0 ? a_hives[0] : { saveUrl: true };
	},

	getImageInfo: function(a_records, f_callback) {
		var i_self = this;

		var a_batch = [];

		Ext.Array.each(a_records, function(o_record) {
			var filepath = o_record.get("FILPATH") + o_record.get("FILNAME");
			a_batch.push({
				type: "call",
				pgm: "imageIdentify",
				parms: {
					file: filepath
				}
			});
		});

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			timeout: "100000",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var a_batch = Ext.decode(o_response.responseText).batch;
				Ext.Array.each(a_batch, function(o_batch, n_index) {
					var width = o_batch.width || 0;
					var height = o_batch.height || 0;
					var size = o_batch.filesize || 0;
					a_records[n_index].set("FILWIDTH", width);
					a_records[n_index].set("FILHEIGHT", height);
					a_records[n_index].set("FILSIZE", size);
					a_records[n_index].set("FILMODIFY", ip2.date2dbDate(new Date()));
				});
				f_callback(a_records);
			}
		});
	},

	getUIConflickWindow: function(i_animateTarget, i_component, s_path, a_files, f_callback, use_handler) {

		var i_self = this;
		var i_el = i_component.bodyEl !== undefined ? i_component.bodyEl : i_component.getEl();
		var a_result = [];
		var b_usehandler = use_handler !== null ? use_handler : true;


		var i_window = Ext.widget("fileconflict", {
			files: a_files,
			animateTarget: i_animateTarget !== null ? i_animateTarget : "",
			path: s_path,
			width: 900,
			height: 600,
			okFn: function(a_override, a_rename) {

				var msg = "";
				var b_rename = false;
				var b_override = false;

				if (b_usehandler) {
					if (a_rename.length > 0) {

						b_rename = true;

						msg = a_rename.length > 1 ? ip2.i18n({
							da: "Opretter filer....",
							en: "Creating files..."
						}) : ip2.i18n({
							da: "Opretter file....",
							en: "Creating file..."
						});

						i_el.mask(msg);

						Ext.ux.file.util.Handler.createRecords(s_path, a_rename, true, function(a_records) {

							b_rename = false;

							Ext.Array.each(a_records, function(o_record) {
								a_result.push(o_record);
							});

							if (!b_override) {
								i_el.unmask();
								f_callback(false, a_result);
							}
						});
					}
					if (a_override.length > 0) {

						b_override = true;

						if (!b_rename) {

							msg = a_override.length > 1 ? ip2.i18n({
								da: "Overskriver filer....",
								en: "Overwriting files..."
							}) : ip2.i18n({
								da: "Overskriver file....",
								en: "Overwriting file..."
							});

							i_el.mask(msg);
						}

						var a_files = [];

						Ext.Array.each(a_override, function(o_overwrite) {
							a_files.push(o_overwrite.file);
						});

						Ext.ux.file.util.Handler.updateRecordsFileInfo(s_path, a_files, function(a_records) {
							b_override = false;
							Ext.Array.each(a_records, function(o_record) {
								a_result.push(o_record);
							});
							if (!b_rename) {
								i_el.unmask();
								f_callback(false, a_result);
							}
						});
					}
					if (a_override.length === 0 && a_rename.length === 0) {

						i_el.unmask();
						f_callback(false, a_result, false);
					}
				}
				else {
					i_el.unmask();
					f_callback(false, a_override, a_rename);
				}
			},
			cancelFn: function() {
				f_callback(true, a_result, []);
			}
		});
		i_window.show();
	},

	getUIGrid: function(o_config) {

		var i_selectionModel = Ext.create("Ext.selection.CheckboxModel", {
			mode: "MULTI",
			enableKeyNav: true
		});

		var o_gridConfig = {
			selModel: o_config.selMol !== undefined ? o_config.selMol : i_selectionModel,
			dmd: {
				path: "dmd/webshop.dmd",
				entityName: "WSHFILET00"
			},
			setPath: function(s_path) {

				var i_panel = this;
				var i_grid = i_panel.getGrid();
				var i_store = i_grid.getStore();
				var i_proxy = i_store.getProxy();
				var o_extraParams = i_proxy.getExtraParams();
				o_extraParams.where = "FILPATH like '" + path + "%'";
				i_store.currentPage = 1;
				i_store.load();
			}
		};

		Ext.apply(o_gridConfig, o_config);

		var i_panel = Ext.widget("ip2pagingGridOld", o_gridConfig);

		return i_panel;
	},

	getUITree: function(o_config) {

		var i_self = this;
		var path = o_config.path || "$root$";
		var b_system = o_config.useSystem !== undefined ? o_config.useSystem : true;
		var store = "";
		if (o_config.store) {
			store = o_config.store;
		}
		else {
			store = Ext.create("Ext.ux.file.store.TreeHive", {
				useSystem: b_system,
				root: {
					text: ip2.i18n({
						da: "...",
						en: "..."
					}),
					id: "/",
					path: path,
					expanded: false,
					selected: true,
					allowDrop: false
				}
			});
		}

		var i_tree = {
			layout: "fit",
			rootVisible: false,
			animate: false,
			useArrows: true,
			border: false,
			store: store,
			viewConfig: {
				loadMask: false
			},
			reload: function(node, reloadParent, select) {
				var i_tree = this;
				var i_store = i_tree.getStore();
				if (reloadParent) {
					if (node && node.parentNode) {
						var parent = node.parentNode;
						parent.removeAll(false);
						i_store.load({
							node: parent
						});
						if (select) {
							i_tree.getSelectionModel().select(parent);
						}
					}
				}
				else {
					if (node) {
						node.removeAll(false);
						i_store.load({
							node: node
						});
					}
				}
			}
		};

		Ext.Object.merge(i_tree, o_config);

		return Ext.widget("treepanel", i_tree);
	},

	getWindowSize: function () {

		var d = document;
		var root = d.documentElement;
		var body = d.body;
		var wid = window.innerWidth || root.clientWidth || body.clientWidth;
		var hi = window.innerHeight || root.clientHeight || body.clientHeight;

		var size = {
			width: wid,
			height: hi
		};

		return size;
	},

	/******
	    	@ path The path where to check if the files exist ex.  "/pp-static/images/..."
	   		@ a_files : Array of file object
	    	@ f_callback the function that will be called with the result of the check, returns {create : array, update : array}
	    *****/
	checkFiles: function(path, a_files, f_callback) {
		var a_batch = [];

		Ext.Array.each(a_files, function (o_file) {
			var s_path = ip2.cleanPath(path + "/" + o_file.name);
			if (!Ext.isNumber(o_file)) {
				a_batch.push({
					type: "call",
					pgm: "webbios",
					parms: {
						func: "checkstmf",
						file: s_path
					}
				});
			}
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {

				var o_json = Ext.decode(o_response.responseText, true);
				var a_create = [];
				var a_update = [];

				Ext.Array.each(o_json.batch, function (o_request, n_index) {
					var a_recepient = o_request.exists ? a_update : a_create;
					a_recepient.push(a_files[n_index]);
				});

				f_callback({
					update: a_update,
					create: a_create
				});
			}
		});
	},

	/******
    	@ path The path where to check if the files exist ex.  "/pp-static/images/"
   		@ a_records : Array of records of type file record
    	@ f_callback the function that will be called with the result of the check, returns {create : array, update : array}
    *****/

	checkRecords: function(path, a_records, f_callback) {
		var a_batch = [];

		Ext.Array.each(a_records, function (o_record) {
			if (!Ext.isNumber(o_record)) {
				a_batch.push({
					type: "call",
					pgm: "webbios",
					parms: {
						func: "checkstmf",
						file: ip2.cleanPath(path + "/" + o_record.get("FILNAME"))
					}
				});
			}
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {

				var o_json = Ext.decode(o_response.responseText, true);
				var a_create = [];
				var a_update = [];

				Ext.Array.each(o_json.batch, function (o_request, n_index) {
					var a_recepient = o_request.exists ? a_update : a_create;
					a_recepient.push(a_records[n_index]);
				});

				f_callback(a_create, a_update);
			}
		});
	},

	validateSuggestions: function(a_records, s_path, callback) {
		var i_self = this;
		var a_batch = [];

		Ext.Array.each(a_records, function(o_file) {
			a_batch.push({
				type: "call",
				pgm: "webbios",
				parms: {
					func: "checkstmf",
					file: s_path + "/" + o_file.suggestedName
				}
			});
		});

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var a_batch = Ext.decode(o_response.responseText).batch;
				var a_invalid = [];
				Ext.Array.each(a_batch, function(o_batch, n_index) {
					if (o_batch.exists) {
						a_invalid.push(a_records[n_index]);
					}
				});
				callback(a_invalid);
			}
		});
	},

	getSuggestions: function(a_files, s_path, f_callback) {
		var i_self = this;
		var a_batch = [];

		Ext.Array.each(a_files, function(o_file) {
			var b_external = o_file.external ? o_file.external : false;
			a_batch.push({
				type: "call",
				pgm: b_external ? "wshFilNamSuggest" : "wshgetsuggestedname",
				parms: {
					file: o_file.name,
					dir: s_path
				}
			});
		});

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var a_batch = Ext.decode(o_response.responseText).batch;
				var a_records = [];
				Ext.Array.each(a_batch, function(o_batch, n_index) {
					var o_record = {
						suggestion: o_batch.suggestedName
					};
					a_records.push(o_record);
				});

				f_callback(a_records);
			}
		});
	},

	deleteDirectory: function(path, f_callback) {
		var i_self = this;
		Ext.Ajax.request({
			url: "/ip2-Services/webbios.aspx",
			params: {
				func: "rmdir",
				name: ip2.cleanPath(path)
			},
			success: function(o_response) {
				var o_result = Ext.decode(o_response.responseText);
				f_callback(o_result.success);
			}
		});
	},

	deleteFiles: function(a_files, f_callback) {
		var a_batch = [];
		Ext.Array.each(a_files, function(o_file) {
			a_batch.push({
				type: "call",
				pgm: "webbios",
				parms: {
					func: "unlink",
					name: o_file.path
				}
			});
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				f_callback();
			}
		});
	},

	unlinkRecords: function(a_records, f_callback) {
		var i_self = this;
		var a_batch = [];
		Ext.Array.each(a_records, function(o_record) {
			if (!Ext.isNumber(o_record)) {
				a_batch.push({
					type: "call",
					pgm: "webbios",
					parms: {
						func: "unlink",
						name: o_record.get("FILPATH") + o_record.get("FILNAME")
					}
				});
			}
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				f_callback();
			}
		});
	},

	deleteRecords: function(a_records, f_callback) {
		var i_self = this;
		var a_batch = [];
		var Model = i_self.getModel();

		Ext.Array.each(a_records, function (o_record) {

			if (!Ext.isNumber(o_record)) {

				var o_key = {};

				o_key[Model.idProperty] = o_record.get("FILFILTKN");

				a_batch.push({
					type: "delete",
					dmd: "dmd/webshop.dmd",
					entity: "WSHFILET00",
					key: o_key
				});
			}
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				i_self.unlinkRecords(a_records, function() {
					f_callback(true);
				});
			}
		});
	},

	createDirectory: function(path, f_callback) {
		var i_self = this;
		Ext.Ajax.request({
			url: "/ip2-Services/webbios.aspx",
			params: {
				func: "mkdir",
				name: path
			},
			success: function(o_response) {
				var o_result = Ext.decode(o_response.responseText);
				f_callback(o_result.success);
			}
		});
	},

	createModel: function() {

		var i_self = this;
		var Model = i_self.getModel();

		var i_record = Model.create({
			FILPATH: "",
			FILORIPATH: "",
			FILCRTBY: ip2.navigator.user.id,
			FILNAME: "",
			FILMEDIA: "",
			FILCREATE: ip2.date2dbDate(new Date()),
			FILMODIFY: ip2.date2dbDate(new Date()),
			FILEXT: "",
			FILEXTERNAL: false
		});

		return i_record;
	},

	/**
	 * Used for testing purposes only
	 */
	createFakeRecords: function(seed) {

		var i_self = this;
		var Model = i_self.getModel();
		var a_records = [];

		for (var i = 1; i <= seed; i++) {

			var i_record = Model.create({
				FILFILTKN: i,
				FILPATH: "",
				FILORIPATH: "",
				FILCRTBY: ip2.navigator.user.id,
				FILNAME: "",
				FILMEDIA: "",
				FILCREATE: ip2.date2dbDate(new Date()),
				FILMODIFY: ip2.date2dbDate(new Date()),
				FILEXT: "",
				FILEXTERNAL: false
			});

			a_records.push(i_record);
		}

		return a_records;
	},

	createRecords: function(path, a_files, b_rename, f_callback) {

		var i_self = this;
		var Model = i_self.getModel();

		i_self.uploadFiles(path, a_files, b_rename, function(a_files) {
			path = ip2.cleanPath(path) + "/";
			var a_records = [];

			Ext.Array.each(a_files, function(o_file) {

				var s_extension = o_file.name.split(".").pop();
				s_extension = s_extension.toLowerCase();

				var i_record = Model.create({
					FILPATH: path,
					FILORIPATH: path + o_file.name,
					FILCRTBY: ip2.navigator.user.id,
					FILNAME: o_file.name,
					FILMEDIA: o_file.name,
					FILCREATE: ip2.date2dbDate(new Date()),
					FILMODIFY: ip2.date2dbDate(new Date()),
					FILEXT: s_extension,
					FILEXTERNAL: false
				});

				a_records.push(i_record);
			});

			i_self.getImageInfo(a_records, function(a_records) {
				i_self.upsertRecords(a_records, function(a_records) {
					f_callback(a_records);
				});
			});
		});
	},

	createRecordByUrlWithName: function(s_path, s_url, s_name, f_callback) {
		var i_self = this;
		var a_batch = [];
		a_batch.push({
			type: "call",
			pgm: "webbios",
			parms: {
				func: "httpRequest",
				parms: {
					request: {
						url: s_url,
						metode: "GET"
					},
					response: {
						outputFile: s_path + s_name
					}
				}
			}
		});
		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdproxy.aspx?",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var o_batch = o_result.batch[0];
				if (o_batch.success) {

					var a_files = [{
						name: s_name
					}];

					i_self.createRecordsNoUpload(s_path, a_files, function(a_records) {
						Ext.Array.each(a_records, function(o_record) {
							o_record.set("FILORIPATH", s_url);
						});
						i_self.upsertRecords(a_records, function(a_records) {
							f_callback(a_records);
						});
					});
				}
			}
		});
	},

	createRecordByUrl: function(s_path, s_url, f_callback) {
		var i_self = this;
		var s_name = s_url.split("/").pop();
		var a_batch = [];
		a_batch.push({
			type: "call",
			pgm: "webbios",
			parms: {
				func: "httpRequest",
				parms: {
					request: {
						url: s_url,
						metode: "GET"
					},
					response: {
						outputFile: s_path + s_name
					}
				}
			}
		});
		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdproxy.aspx?",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var o_batch = o_result.batch[0];
				if (o_batch.success) {

					var a_files = [{
						name: s_name
					}];

					i_self.createRecordsNoUpload(s_path, a_files, function(a_records) {
						Ext.Array.each(a_records, function(o_record) {
							o_record.set("FILORIPATH", s_url);
						});
						i_self.upsertRecords(a_records, function(a_records) {
							f_callback(a_records);
						});
					});
				}
			}
		});
	},

	createRecordsNoUpload: function(path, a_files, f_callback) {

		var i_self = this;
		var Model = i_self.getModel();
		var a_records = [];

		Ext.Array.each(a_files, function(o_file) {

			var s_extension = o_file.name.split(".").pop();
			s_extension = s_extension.toLowerCase();

			var i_record = Model.create({
				FILPATH: path,
				FILORIPATH: path + o_file.name,
				FILCRTBY: ip2.navigator.user.id,
				FILNAME: o_file.name,
				FILMEDIA: o_file.name,
				FILCREATE: ip2.date2dbDate(new Date()),
				FILMODIFY: ip2.date2dbDate(new Date()),
				FILEXT: s_extension,
				FILEXTERNAL: o_file.external || false
			});
			a_records.push(i_record);
		});

		i_self.getImageInfo(a_records, function(a_records) {
			f_callback(a_records);
		});
	},

	createRecordsNoUploadNoImageInfo: function(path, a_files, f_callback) {

		var i_self = this;
		var Model = i_self.getModel();
		var a_records = [];
		var index = 1;

		Ext.Array.each(a_files, function(o_file) {

			var s_extension = o_file.name.split(".").pop();
			s_extension = s_extension.toLowerCase();

			var i_record = Model.create({
				FILFILTKN: index,
				FILPATH: path,
				FILORIPATH: path + o_file.name,
				FILNAME: o_file.name,
				FILMEDIA: o_file.name,
				FILCREATE: ip2.date2dbDate(new Date()),
				FILMODIFY: ip2.date2dbDate(new Date()),
				FILEXT: s_extension,
				FILSIZE: o_file.size,
				FILEXTERNAL: o_file.external || false
			});

			a_records.push(i_record);

			index++;
		});

		f_callback(a_records);
	},

	createRecordsNoUploadNoImageInfoNoIndex: function(path, a_files, f_callback) {

		var i_self = this;
		var Model = i_self.getModel();
		var a_records = [];

		Ext.Array.each(a_files, function(o_file) {

			var s_extension = o_file.name.split(".").pop();
			s_extension = s_extension.toLowerCase();

			var i_record = Model.create({
				FILPATH: path,
				FILORIPATH: path + o_file.name,
				FILNAME: o_file.name,
				FILMEDIA: o_file.name,
				FILCREATE: ip2.date2dbDate(new Date()),
				FILMODIFY: ip2.date2dbDate(new Date()),
				FILEXT: s_extension,
				FILSIZE: o_file.size,
				FILEXTERNAL: o_file.external || false
			});

			a_records.push(i_record);
		});

		f_callback(a_records);
	},

	createRecordTemporary: function(path, o_file, f_callback) {
		var i_self = this;
		var Model = i_self.getModel();
		var a_records = [];
		i_self.uploadToTemp(o_file, function(o_result) {
			var name = o_result.name;
			var o_record = Model.create({
				FILPATH: o_result.tmpPath,
				FILORIPATH: path + o_file.name,
				FILCRTBY: ip2.navigator.user.id,
				FILNAME: o_result.tmpName,
				FILMEDIA: o_result.name,
				FILCREATE: ip2.date2dbDate(new Date()),
				FILMODIFY: ip2.date2dbDate(new Date()),
				FILEXT: o_result.extension,
				FILEXTERNAL: false
			});
			o_record.uploadname = o_result.uploadname;
			a_records.push(o_record);
			i_self.getImageInfo(a_records, function(a_records) {
				var o_record = a_records[0];
				delete o_record.extension;
				delete o_record.tmpPath;
				delete o_record.tmpName;
				o_record.set("FILNAME", name);
				o_record.set("FILPATH", path);
				f_callback(o_record);
			});
		});
	},

	createTags: function(a_records, s_tags, f_callback) {
		var i_self = this;
		Ext.Array.each(a_records, function(o_record) {
			o_record.set("FILTAG", s_tags);
		});

		i_self.upsertRecords(a_records, function(a_records) {
			f_callback(a_records);
		});
	},

	curlFileFromURL: function(s_path, s_url, f_callback) {
		var i_self = this;
		var s_name = s_url.split("/").pop();
		var a_batch = [];
		a_batch.push({
			type: "call",
			pgm: "webbios",
			parms: {
				func: "httpRequest",
				parms: {
					request: {
						url: s_url,
						metode: "GET"
					},
					response: {
						outputFile: s_path + s_name
					}
				}
			}
		});
		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdproxy.aspx?",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var o_batch = o_result.batch[0];
				if (o_batch.success) {
					f_callback();
				}
			}
		});
	},

	curlFileFromURLWithName: function(s_path, s_url, s_name, f_callback) {
		var i_self = this;
		var a_batch = [];
		a_batch.push({
			type: "call",
			pgm: "webbios",
			parms: {
				func: "httpRequest",
				parms: {
					request: {
						url: s_url,
						metode: "GET"
					},
					response: {
						outputFile: s_path + s_name
					}
				}
			}
		});
		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdproxy.aspx?",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				var o_batch = o_result.batch[0];
				if (o_batch.success) {
					f_callback();
				}
			}
		});
	},

	consulidateDirectory: function(path, f_callback) {
		var i_self = this;
		var a_new_records = [];
		var a_delete = [];
		i_self.getRecordsByPath(path, function(a_records) {
			i_self.getFilesByPath(path, function(a_files) {
				Ext.Array.each(a_records, function(i_record) {
					var b_found = false;
					Ext.Array.each(a_files, function(o_file) {
						var s_key = i_record.get("FILPATH") + i_record.get("FILNAME");
						if (s_key == (path + o_file.text)) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_delete.push(i_record);
					}
				});
				Ext.Array.each(a_files, function(o_file) {
					var b_found = false;
					Ext.Array.each(a_records, function(i_record) {
						var s_key = i_record.get("FILPATH") + i_record.get("FILNAME");
						if (s_key == (path + o_file.text)) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						var o_record = {
							name: o_file.text
						};
						a_new_records.push(o_record);
					}
				});
				if (a_new_records.length > 0) {
					i_self.createRecordsNoUploadNoImageInfoNoIndex(path, a_new_records, function(a_records) {
						if (a_delete.length > 0) {
							i_self.deleteRecords(a_delete, function(a_result) {
								f_callback(a_records, a_delete);
							});
						}
						else {
							f_callback(a_records, a_delete);
						}
					});
				}
				else {
					if (a_delete.length > 0) {
						i_self.deleteRecords(a_delete, function(a_result) {
							f_callback(a_new_records, a_delete);
						});
					}
					else {
						f_callback(a_new_records, a_delete);
					}
				}
			});
		});
	},

	hasFileManager: function() {

		var i_self = this;

		var o_dmd = ip2.resource.get("dmd/webshop.dmd");
		var o_model = o_dmd.model;
		var a_entities = o_model.entities;
		var b_result = false;

		var o_search = Ext.Array.findBy(a_entities, function(o_value) {
			return o_value.name == "WSHFILET00";
		});

		if (o_search) {
			b_result = true;
		}

		return b_result;
	},

	upsertRecords: function(a_records, f_callback) {
		var i_self = this;
		var a_batch = [];

		Ext.Array.each(a_records, function (o_record) {
			if (!Ext.isNumber(o_record)) {
				var key = {};
				key[o_record.idProperty] = o_record.get(o_record.idProperty);
				a_batch.push({
					type: "upsert",
					dmd: "dmd/webshop.dmd",
					entity: "WSHFILET00",
					key: key,
					row: o_record.data
				});
			}
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				var o_result = Ext.decode(o_response.responseText);
				Ext.Array.each(o_result.batch, function(o_batch, n_index) {
					Ext.Array.each(o_batch.row, function(value) {
						a_records[n_index].set("FILFILTKN", value);
					});
				});
				f_callback(a_records);
			}
		});
	},

	updateRecordsFileInfo: function(path, a_files, f_callback) {
		var i_self = this;
		i_self.uploadFiles(path, a_files, false, function(a_files) {
			var a_names = [];
			Ext.Array.each(a_files, function(o_file) {
				a_names.push(o_file.name);
			});
			i_self.getRecordsByName(path, a_names, function(a_records) {
				i_self.getImageInfo(a_records, function(a_records) {
					i_self.upsertRecords(a_records, function(a_records) {
						f_callback(a_records);
					});
				});
			});
		});
	},

	uploadFiles: function(s_path, a_files, b_rename, f_callback) {

		var i_self = this;

		var i_formData = new FormData();
		var i_xhr = new XMLHttpRequest();
		var a_records = [];

		i_self.processFiles(a_files, function(a_processed) {

			Ext.Array.each(a_processed, function(o_record) {

				var s_url;

				if (!b_rename) {
					s_url = ip2.cleanPath([s_path, o_record.name].join("/"));
					if (o_record.file) {
						i_formData.append(s_url, o_record.file, o_record.name);
					}
					else {
						i_formData.append(s_url, o_record);
					}
					a_records.push(o_record);
				}
				else {
					s_url = ip2.cleanPath([s_path, o_record.suggestedName].join("/"));
					i_formData.append(s_url, o_record.file, o_record.name);
					a_records.push({ name: o_record.suggestedName });
				}
			});

			i_xhr.onreadystatechange = function () {

				var a_data = [];
				var a_fail = [];

				if (i_xhr.readyState == 4 && i_xhr.status == 200) {
					var a_result;

					try {
						a_result = Ext.decode(i_xhr.responseText, true);
						f_callback(a_records);
					}
					catch (err) {
						f_callback([]);
					}
				}
			};

			i_xhr.open("POST", "ip2-services/webbios.aspx?action=movestmf", true);
			i_xhr.send(i_formData);
		});
	},

	uploadToTemp: function(o_file, f_callback) {
		var i_self = this;
		var i_formData = new FormData();
		var i_xhr = new XMLHttpRequest();

		var extension = o_file.name.split(".").pop().toLowerCase();
		var s_uploadname = "_upload" + ip2.getDcTimestamp() + "." + extension;
		var s_preset = ip2.preset.staticPath || "pp-static";

		var filepath = ip2.cleanPath(s_preset + "/" + s_uploadname);
		i_formData.append(filepath, o_file);

		i_xhr.onreadystatechange = function () {

			if (i_xhr.readyState == 4 && i_xhr.status == 200) {
				var o_result;

				try {
					o_result = Ext.decode(i_xhr.responseText, true);
				}
				catch (err) {}

				if (o_result) {
					o_result.name = o_file.name;
					o_result.extension = extension;
					o_result.uploadname = filepath;
					o_result.tmpName = s_uploadname;
					o_result.tmpPath = ip2.cleanPath(s_preset) + "/";
					f_callback(o_result);
				}
			}
		};

		i_xhr.open("POST", "ip2-services/webbios.aspx?action=movestmf", true);
		i_xhr.send(i_formData);
	},

	moveAndDeleteOldRecords: function(toPath, a_move, f_callback) {
		var i_self = this;
		var a_names = [];
		Ext.Array.each(a_move, function(o_record) {
			a_names.push(o_record.get("FILNAME"));
		});
		i_self.getRecordsByName(toPath, a_names, function(a_records) {
			i_self.deleteRecords(a_records, function(success) {
				i_self.moveRecords(toPath, a_move, function(a_result) {
					f_callback(a_result);
				});
			});
		});
	},

	moveFromRecords: function(fromPath, a_records, f_callback) {
		var i_self = this;
		var a_batch = [];

		Ext.Array.each(a_records, function (o_record) {
			if (!Ext.isNumber(o_record)) {
				a_batch.push({
					type: "call",
					pgm: "webbios",
					parms: {
						func: "rename",
						from: fromPath,
						to: o_record.get("FILPATH") + o_record.get("FILMEDIA"),
						replace: true
					}
				});
			}
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				Ext.Array.each(a_records, function(o_record) {
					o_record.set("FILFILIA", o_record.get("FILNAME"));
				});
				f_callback(a_records);
			}
		});
	},

	moveRecords: function(toPath, a_records, f_callback) {
		var i_self = this;
		var a_batch = [];

		Ext.Array.each(a_records, function (o_record) {
			if (!Ext.isNumber(o_record)) {
				a_batch.push({
					type: "call",
					pgm: "webbios",
					parms: {
						func: "rename",
						from: o_record.get("FILPATH") + o_record.get("FILMEDIA"),
						to: toPath + o_record.get("FILNAME"),
						replace: true
					}
				});
			}
		});

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				Ext.Array.each(a_records, function(o_record) {
					o_record.set("FILPATH", toPath);
					o_record.set("FILMEDIA", o_record.get("FILNAME"));
				});
				i_self.upsertRecords(a_records, function(a_records) {
					f_callback(a_records);
				});
			}
		});
	},

	processFiles: function(a_files, f_callback) {

		var i_self = this;

		f_callback = f_callback || Ext.emptyFn;

		var a_result = [];

		var n_count = a_files.length;

		var n_width = 600;

		Ext.Array.each(a_files, function(o_record) {

			var i_file = o_record.file || o_record;
			var s_extension = i_file.name.split(".").pop();

			if (Ext.Array.contains(i_self.imageExtension, s_extension)) {

				var i_fileReader = new FileReader();

				i_fileReader.onload = function () {

					var i_image = new Image();
					i_image.src = i_fileReader.result;

					i_image.onload = function () {

						var i_canvas = document.createElement("canvas");
						var i_context = i_canvas.getContext("2d");
						var i_outCanvas = document.createElement("canvas");
						var i_outContext = i_outCanvas.getContext("2d");

						if (i_image.width > n_width) {
							i_canvas.width = n_width; // destination canvas size
							i_canvas.height = i_canvas.width * i_image.height / i_image.width;

							var cur = {
								width: Math.floor(i_image.width * 0.5),
								height: Math.floor(i_image.height * 0.5)
							};

							i_outCanvas.width = cur.width;
							i_outCanvas.height = cur.height;

							i_outContext.drawImage(i_image, 0, 0, cur.width, cur.height);

							while (cur.width * 0.5 > n_width) {
								cur = {
									width: Math.floor(cur.width * 0.5),
									height: Math.floor(cur.height * 0.5)
								};
								i_outContext.drawImage(i_outCanvas, 0, 0, cur.width * 2, cur.height * 2, 0, 0, cur.width, cur.height);
							}

							i_context.drawImage(i_outCanvas, 0, 0, cur.width, cur.height, 0, 0, i_canvas.width, i_canvas.height);

							var s_name = i_file.name || "";

							if (Ext.browser.is.IE) {

								n_count--;

								var i_blob = i_canvas.msToBlob();
								i_blob.name = i_file.name;

								var i_newFile = {
									file: i_blob,
									name: s_name,
									type: i_file.type
								};

								a_result.push(i_newFile);

								if (n_count === 0) {

									f_callback(a_result);
								}
							}
							else {
								i_canvas.toBlob(function (i_blob) {

									n_count--;
									i_blob.name = i_file.name;

									var i_newFile = {
										file: i_blob,
										name: s_name,
										type: i_file.type
									};

									a_result.push(i_newFile);

									if (n_count === 0) {
										f_callback(a_result);
									}
								});
							}
						}
						else {
							a_result.push(i_file);
						}
					};
				};

				i_fileReader.readAsDataURL(i_file);
			}
			else {

				n_count--;

				a_result.push(i_file);

				if (n_count === 0) {
					f_callback(a_result);
				}
			}
		});
	}

});
Ext.define("Ext.ux.file.view.Conflict", {

	extend: "Ext.window.Window",
	alias: ["widget.fileconflict"],

	//properties
	modal: true,
	width: 800,
	height: 600,
	layout: "fit",
	files: [],
	path: "",
	isOk: false,
	isCancel: false,
	closable: false,
	a_rename: [],
	a_override: [],
	okFn: Ext.emptyFn,
	cancelFn: Ext.emptyFn,

	initComponent: function(config) {
		var i_cmp = this;
		i_cmp.addListeners();
		i_cmp.callParent(config);
		i_cmp.add(i_cmp.createMain());
		var title = ip2.i18n({
			da: "Fil konflikt",
			en: "File conflict"
		});
		i_cmp.setTitle(title);
		i_cmp.getSuggestions();
	},

	addListeners: function() {
		var i_cmp = this;
		Ext.Object.merge(i_cmp, {
			listeners: {
				close: function() {
					if (i_cmp.isOk) {
						var a_override = i_cmp.a_override;
						var a_rename = i_cmp.a_rename;
						i_cmp.okFn(a_override, a_rename);
					}
					else if (i_cmp.isCancel) {
						i_cmp.cancelFn();
					}
					else {
						i_cmp.cancelFn();
					}
				}
			}
		});
	},

	createMain: function() {
		var i_cmp = this;
		var container = {
			xtype: "form",
			layout: "border",
			items: [
				i_cmp.createNorth(),
				i_cmp.createCenter()
			],
			buttons: i_cmp.createButtons()
		};
		return container;
	},

	createButtons: function() {
		var i_cmp = this;
		var a_buttons = [
			{
				text: ip2.i18n({
					da: "Ok",
					en: "Ok"
				}),
				handler: function () {
					i_cmp.isOk = true;
					i_cmp.isCancel = false;
					var i_form = i_cmp.down("#formRecords");

					var a_files = i_cmp.files;
					i_cmp.a_override = [];
					i_cmp.a_rename = [];

					ip2.each(a_files, function (o_file, n_index) {

						var extension = o_file.name.split(".").pop();
						var s_fileName = o_file.name.replace("." + extension, "");
						var i_record = i_form.down("#record_" + n_index);
						var b_overwrite = i_record.down("#i_" + n_index + "_replace").getValue();
						var b_rename = i_record.down("#i_" + n_index + "_rename").getValue();
						if (b_overwrite) {
							var o_record = {
								file: o_file,
								index: n_index
							};
							i_cmp.a_override.push(o_record);
						}
						if (b_rename) {
							var s_suggested = i_record.down("#i_" + n_index + "_suggested").getValue();
							var o_record = {
								file: o_file,
								index: n_index,
								suggestedName: s_suggested
							};
							i_cmp.a_rename.push(o_record);
						}
					});

					if (i_cmp.a_rename.length > 0) {
						var msg = ip2.i18n({
							da: "Validerer navne",
							en: "Validating names"
						});
						i_cmp.setLoading(msg, true);
						Ext.ux.file.util.Handler.validateSuggestions(i_cmp.a_rename, i_cmp.path, function(a_invalid) {
							i_cmp.setLoading(false);
							if (a_invalid.length > 0) {
								ip2.each(a_invalid, function(o_record) {
									var i_field = i_form.down("#i_" + o_record.index + "_suggested");
									var msg = ip2.i18n({
										da: "Navnet findes allerede",
										en: "Name allready exists"
									});
									i_field.markInvalid(msg);
								});
							}
							else {
								i_cmp.close();
							}
						});
					}
					else {
						i_cmp.close();
					}
				}
			},
			{
				text: ip2.i18n({
					da: "Annuller",
					en: "Cancel"
				}),
				handler: function () {
					i_cmp.isCancel = true;
					i_cmp.isOk = false;
					i_cmp.close();
				}
			}

		];
		return a_buttons;
	},

	createNorth: function() {
		var i_cmp = this;
		var a_files = i_cmp.files;
		var layout = {
			xtype: "container",
			layout: "hbox",
			region: "north",
			height: 91,
			style: {
				padding: a_files.length >= 4 ? "15px 30px 20px 15px" : "15px 15px 20px 15px",
				borderBottom: "1px solid #8C8C8C"
			},
			items: [
				{
					xtype: "container",
					flex: 5,
					items: [
						{
							xtype: "container",
							autoEl: "h1",
							style: {
								fontSize: "14px",
								marginBottom: "10px"
							},
							html: ip2.i18n({
								da: "Vælg en handling for filerne før du trykker ok",
								en: "Select a action for the files before you press ok"
							})
						},
						{
							xtype: "container",
							autoEl: "p",
							html: ip2.i18n({
								da: "En eller flere filer findes i destinations folderen, vælg en handling",
								en: "One or more files exist in the destination folder, select a action"
							})
						}
					]
				},
				{
					xtype: "form",
					flex: 3,
					layout: "hbox",
					bodyStyle: "background-color:transparent;",
					style: {
						"text-align": "center"
					},
					border: 0,
					items: [
						{
							xtype: "radiofield",
							checked: true,
							labelAlign: "top",
							fieldLabel: ip2.i18n({
								da: "Skip",
								en: "Skip"
							}),
							width: 40,
							itemId: "skip_all",
							b_allowed: true,
							listeners: {
								change: {
									fn: function(i_self, newVal, oldVal) {

										if (i_self.b_allowed) {

											var i_replace_all = i_cmp.down("#replace_all");
											i_replace_all.b_allowed = false;
											i_replace_all.setValue(false);
											i_replace_all.b_allowed = true;

											var i_rename_all = i_cmp.down("#rename_all");
											i_rename_all.b_allowed = false;
											i_rename_all.setValue(false);
											i_rename_all.b_allowed = true;

											var i_form_records = i_cmp.down("#formRecords").getForm();

											i_form_records.getFields().each(function(i_record_field) {
												if (i_record_field.isSkip) {
													i_record_field.setValue(newVal);
												}
											});
										}
									}
								}
							}
						},
						{
							xtype: "radiofield",
							checked: false,
							labelAlign: "top",
							fieldLabel: ip2.i18n({
								da: "Overskriv",
								en: "Overwrite"
							}),
							width: 70,
							itemId: "replace_all",
							b_allowed: true,
							listeners: {
								change: {
									fn: function(i_self, newVal, oldVal) {

										if (i_self.b_allowed) {
											var i_skip_all = i_cmp.down("#skip_all");
											i_skip_all.b_allowed = false;
											i_skip_all.setValue(false);
											i_skip_all.b_allowed = true;

											var i_rename_all = i_cmp.down("#rename_all");
											i_rename_all.b_allowed = false;
											i_rename_all.setValue(false);
											i_rename_all.b_allowed = true;

											var i_form_records = i_cmp.down("#formRecords").getForm();

											i_form_records.getFields().each(function(i_record_field) {
												if (i_record_field.isReplace) {
													i_record_field.setValue(newVal);
												}
											});
										}
									}
								}
							}
						},
						{
							xtype: "fieldcontainer",
							layout: "hbox",
							flex: 2,
							style: {
								marginRight: "3px"
							},
							items: [
								{
									xtype: "radiofield",
									checked: false,
									readOnly: false,
									labelAlign: "top",
									fieldLabel: ip2.i18n({
										da: "Omdøb",
										en: "Rename"
									}),
									width: 50,
									itemId: "rename_all",
									b_allowed: true,
									listeners: {
										change: {
											fn: function(i_self, newVal, oldVal) {
												if (i_self.b_allowed) {

													var i_skip_all = i_cmp.down("#skip_all");
													i_skip_all.b_allowed = false;
													i_skip_all.setValue(false);
													i_skip_all.b_allowed = true;

													var i_replace_all = i_cmp.down("#replace_all");
													i_replace_all.b_allowed = false;
													i_replace_all.setValue(false);
													i_replace_all.b_allowed = true;

													var i_form_records = i_cmp.down("#formRecords").getForm();

													i_form_records.getFields().each(function(i_record_field) {
														if (i_record_field.isRename) {
															i_record_field.setValue(newVal);
														}
													});
												}
											}
										}
									}
								},
								{
									xtype: "container",
									flex: 1
								}
							]
						}

					]
				}
			]
		};
		return layout;
	},

	createCenter: function() {
		var i_cmp = this;
		var a_files = i_cmp.files;

		var a_extension_image = ["jpg","jpeg","png","gif", "bmp"];
		var a_docs = ["doc", "docx"];
		var a_xls = ["xls", "xlsx", "xlm","xlt", "xlw"];
		var s_pdf = "pdf";

		var s_path = i_cmp.path;
		var index = -1;

		var form = {
			xtype: "form",
			layout: "anchor",
			region: "center",
			itemId: "formRecords",
			border: false,
			autoScroll: true,
			items: (function () {
				var a_items = [];
				var s_dc = ip2.getDcTimestamp();

				ip2.each(a_files, function (o_file, n_index) {
					index++;
					var extension = o_file.name.split(".").pop();
					var s_fileName = o_file.name.replace("." + extension, "");
					var url = "";
					var b_extension = false;

					if (s_pdf == extension) {
						url = "/portfolio/styles/icon/flatui/media/pdf.png?_dc=" + s_dc;
						b_extension = true;
					}
					else if (a_docs.indexOf(extension) != -1) {
						url = "/portfolio/styles/icon/flatui/media/doc.png?_dc=" + s_dc;
						b_extension = true;
					}
					else if (a_xls.indexOf(extension) != -1) {
						url = "/portfolio/styles/icon/flatui/media/xls.png?_dc=" + s_dc;
						b_extension = true;
					}
					else {
						if (o_file.http) {
							url = o_file.http + "?_dc=" + s_dc;
						}
						else {
							url = [s_path, o_file.name].join("/") + "?_dc=" + s_dc;
						}
					}

					if (b_extension) {
						o_file.src = url;
					}

					a_items.push({
						xtype: "container",
						style: {
							padding: "15px",
							borderBottom: "1px solid #CCC"
						},
						layout: "hbox",
						flex: 1,
						items: [
							{
								xtype: "container",
								flex: 5,
								layout: "hbox",
								style: {
									fontSize: "11px"
								},
								items: [
									{
										xtype: "container",
										autoEl: "div",
										width: 100,
										height: 76,
										file: o_file,
										style: {
											marginRight: "10px",
											"background-image": "url(\"" + url + "\")",
											"background-size": "contain",
											"background-repeat": "no-repeat",
											"background-position": "50% 50%",
											"border": "1px solid black"
										},
										listeners: {
											afterrender: {
												fn: function(item) {
													var i_image = item;
													if (item.file.src) {
														i_image.getEl().dom.style.backgroundImage = "url(\"" + item.file.src + "?dc=" + ip2.getDcTimestamp() + "\")";
													}
													else {
														var reader = new FileReader();
														reader.onload = (function(i_file) {
															return function(e) {
																i_image.getEl().dom.style.backgroundImage = "url(\"" + e.target.result + "\")";
															};
														})(item.file);

														reader.readAsDataURL(item.file);
													}
												}
											}
										}
									},
									{
										xtype: "container",
										autoEl: "span",
										html: "<big><big><big><big><big><big>&#10137;</big></big></big></big></big></big>",
										style: {
											marginRight: "10px",
											marginLeft: "0px",
											paddingTop: "15px"
										}
									},
									{
										xtype: "container",
										autoEl: "div",
										width: 100,
										height: 76,
										file: o_file,
										style: {
											marginRight: "10px",
											"background-image": "url(\"" + url + "\")",
											"background-size": "contain",
											"background-repeat": "no-repeat",
											"background-position": "50% 50%",
											"border": "1px solid black"
										}
									},
									{
										xtype: "container",
										flex: 1,
										style: {
											paddingTop: "5px"
										},
										items: [
											{
												xtype: "container",
												html: o_file.name,
												style: {
													fontWeight: 700,
													fontSize: "12px"
												}
											},
											{
												xtype: "container",
												style: {
													color: "#8C8C8C",
													lineHeight: "19px"
												},
												html: s_path
											}
										]
									}
								]
							},
							{
								xtype: "container",
								flex: 3,
								itemId: "record_" + index,
								layout: "hbox",
								style: {
									paddingTop: "12px",
									"text-align": "center"
								},
								items: [
									{
										xtype: "radiofield",
										width: 40,
										checked: true,
										itemId: "i_" + index + "_skip",
										index: index,
										b_allowed: true,
										isSkip: true,
										listeners: {
											change: {
												fn: function(i_self, newVal, oldVal) {
													if (i_self.b_allowed) {
														var i_rename = i_cmp.down("#i_" + i_self.index + "_rename");
														var i_replace = i_cmp.down("#i_" + i_self.index + "_replace");
														var i_suggested = i_cmp.down("#i_" + i_self.index + "_suggested");

														i_rename.b_allowed = false;
														i_rename.setValue(false);
														i_rename.b_allowed = true;

														i_replace.b_allowed = false;
														i_replace.setValue(false);
														i_replace.b_allowed = true;

														var i_replace_all = i_cmp.down("#replace_all");
														var i_rename_all = i_cmp.down("#rename_all");
														var i_skip_all = i_cmp.down("#skip_all");

														var isAllRenameChecked = i_cmp.isAllRenameChecked();
														var isAllReplaceChecked = i_cmp.isAllReplaceChecked();
														var isAllSkipChecked = i_cmp.isAllSkipChecked();

														i_replace_all.b_allowed = false;
														i_replace_all.setValue(isAllReplaceChecked);
														i_replace_all.b_allowed = true;

														i_rename_all.b_allowed = false;
														i_rename_all.setValue(isAllRenameChecked);
														i_rename_all.b_allowed = true;

														i_skip_all.b_allowed = false;
														i_skip_all.setValue(isAllSkipChecked);
														i_skip_all.b_allowed = true;

														i_suggested.setReadOnly(true);
													}
												}
											}
										}
									},
									{
										xtype: "radiofield",
										width: 70,
										checked: false,
										itemId: "i_" + index + "_replace",
										index: index,
										b_allowed: true,
										isReplace: true,
										listeners: {
											change: {
												fn: function(i_self, newVal, oldVal) {
													if (i_self.b_allowed) {
														var i_rename = i_cmp.down("#i_" + i_self.index + "_rename");
														var i_skip = i_cmp.down("#i_" + i_self.index + "_skip");
														var i_suggested = i_cmp.down("#i_" + i_self.index + "_suggested");

														i_rename.b_allowed = false;
														i_rename.setValue(false);
														i_rename.b_allowed = true;

														i_skip.b_allowed = false;
														i_skip.setValue(false);
														i_skip.b_allowed = true;

														var i_replace_all = i_cmp.down("#replace_all");
														var i_rename_all = i_cmp.down("#rename_all");
														var i_skip_all = i_cmp.down("#skip_all");

														var isAllRenameChecked = i_cmp.isAllRenameChecked();
														var isAllReplaceChecked = i_cmp.isAllReplaceChecked();
														var isAllSkipChecked = i_cmp.isAllSkipChecked();

														i_replace_all.b_allowed = false;
														i_replace_all.setValue(isAllReplaceChecked);
														i_replace_all.b_allowed = true;

														i_rename_all.b_allowed = false;
														i_rename_all.setValue(isAllRenameChecked);
														i_rename_all.b_allowed = true;

														i_skip_all.b_allowed = false;
														i_skip_all.setValue(isAllSkipChecked);
														i_skip_all.b_allowed = true;

														i_suggested.setReadOnly(true);
													}
												}
											}
										}
									},
									{
										xtype: "fieldcontainer",
										layout: "hbox",
										flex: 2,
										items: [
											{
												xtype: "radiofield",
												width: 50,
												checked: false,
												itemId: "i_" + index + "_rename",
												index: index,
												isRename: true,
												b_allowed: true,
												listeners: {
													change: {
														fn: function(i_self, newVal, oldVal) {
															if (i_self.b_allowed) {
																var i_replace = i_cmp.down("#i_" + i_self.index + "_replace");
																var i_skip = i_cmp.down("#i_" + i_self.index + "_skip");
																var i_suggested = i_cmp.down("#i_" + i_self.index + "_suggested");

																i_replace.b_allowed = false;
																i_replace.setValue(false);
																i_replace.b_allowed = true;

																i_skip.b_allowed = false;
																i_skip.setValue(false);
																i_skip.b_allowed = true;

																var i_replace_all = i_cmp.down("#replace_all");
																var i_rename_all = i_cmp.down("#rename_all");
																var i_skip_all = i_cmp.down("#skip_all");

																var isAllRenameChecked = i_cmp.isAllRenameChecked();
																var isAllReplaceChecked = i_cmp.isAllReplaceChecked();
																var isAllSkipChecked = i_cmp.isAllSkipChecked();

																i_replace_all.b_allowed = false;
																i_replace_all.setValue(isAllReplaceChecked);
																i_replace_all.b_allowed = true;

																i_rename_all.b_allowed = false;
																i_rename_all.setValue(isAllRenameChecked);
																i_rename_all.b_allowed = true;

																i_skip_all.b_allowed = false;
																i_skip_all.setValue(isAllSkipChecked);
																i_skip_all.b_allowed = true;

																i_suggested.setReadOnly(false);
															}
														}
													}
												}
											},
											{
												xtype: "textfield",
												flex: 1,
												itemId: "i_" + index + "_suggested",
												readOnly: true,
												index: index,
												getValue: function() {
													var value = this.getRawValue();
													return value + "." + this.extension;
												},
												setValue: function(_value) {
													var value = _value || "";
													var extension = value.split(".").pop();
													this.extension = extension;
													i_cmp.extension = extension;
													var name = value.replace("." + extension, "");
													this.mixins.field.setValue.call(this, name);
													this.setRawValue(name);
													return this;
												}
											}
										]
									}
								]
							}
						]
					});
				});

				return a_items;
			})()
		};
		return form;
	},

	isAllReplaceChecked: function() {
		var i_cmp = this;
		var i_form_records = i_cmp.down("#formRecords").getForm();
		var checked = true;
		var fields = i_form_records.getFields();

		for (var i = 0; i < fields.items.length; i++) {
			var i_field = fields.items[i];
			if (!i_field.checked && i_field.isReplace) {
				checked = false;
				break;
			}
		}
		return checked;
	},

	isAllRenameChecked: function() {
		var i_cmp = this;
		var i_form_records = i_cmp.down("#formRecords").getForm();
		var checked = true;
		var fields = i_form_records.getFields();

		for (var i = 0; i < fields.items.length; i++) {
			var i_field = fields.items[i];
			if (!i_field.checked && i_field.isRename) {
				checked = false;
				break;
			}
		}
		return checked;
	},

	isAllSkipChecked: function() {
		var i_cmp = this;
		var i_form_records = i_cmp.down("#formRecords").getForm();
		var checked = true;
		var fields = i_form_records.getFields();

		for (var i = 0; i < fields.items.length; i++) {
			var i_field = fields.items[i];
			if (!i_field.checked && i_field.isSkip) {
				checked = false;
				break;
			}
		}
		return checked;
	},

	getSuggestions: function() {
		var i_cmp = this;
		var a_files = i_cmp.files;
		var s_path = i_cmp.path;
		Ext.ux.file.util.Handler.getSuggestions(a_files, s_path, function(a_records) {
			var i_form_records = i_cmp.down("#formRecords");
			ip2.each(a_records, function(o_record, n_index) {
				var field = i_form_records.down("#i_" + n_index + "_suggested");
				var field = field.setValue(o_record.suggestion);
			});
		});
	}
});
Ext.define("Ext.ux.file.field.Filemanager", {
	extend: "Ext.form.FieldContainer",

	mixins: {
		field: "Ext.form.field.Field"
	},

	alias: [
		"widget.fieldfilemanager"
	],

	layout: "fit",
	minHeight: 300,
	height: 300,

	config: {
		grid: null,
		tree: null,
		pnlBorder: null
	},

	initComponent: function(config) {
		var i_self = this;
		i_self.callParent(arguments);

		var o_config = config || {};
		var i_border = i_self.createLayout();
		i_self.add(i_border);
	},

	createLayout: function() {

		var i_self = this;

		var i_pnlBorder = Ext.widget("panel", {
			layout: "border",
			items: [
				i_self.createTree(),
				i_self.createGrid()
			]
		});

		i_self.setPnlBorder(i_pnlBorder);
		return i_pnlBorder;
	},

	createGrid: function() {

		var i_self = this;

		var i_selectionModel = Ext.create("Ext.selection.RowModel", {
			mode: "SINGLE",
			enableKeyNav: true,
			allowDeselect: false
		});

		var i_grid = Ext.ux.file.util.Handler.getUIGrid({
			autoLoad: false,
			flex: 3,
			region: "center",
			selMol: i_selectionModel,
			split: true,
			listeners: {
				afterrender: {
					fn: function(i_grid) {

						i_grid.events.itemdblclick.clearListeners();
						i_grid.events.itemcontextmenu.clearListeners();

						i_grid.on({
							select: {
								fn: function(store, record) {
									i_self.setValue(record.get("FILFILTKN"));
								}
							}
						});
					}
				}
			}
		});

		var i_store = i_grid.getStore();

		i_store.on({
			beforeload: {
				fn: function(i_store, i_operation) {

					var i_tree = i_self.getTree();

					var a_selected = i_tree.getSelection();

					var i_selected = a_selected[0];

					var b_load = false;

					if (i_selected) {
						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();

						var s_path = "/";

						if (!i_selected.isRoot()) {
							s_path = i_selected.get("path");
						}

						Ext.apply(o_extraParams,  {
							where: "FILPATH like '" + s_path + "%'"
						});

						b_load = true;
					}

					return b_load;
				}
			}
		});

		i_self.setGrid(i_grid);

		return i_grid;
	},

	createTree: function() {

		var i_self = this;

		var i_tree = Ext.ux.file.util.Handler.getUITree({
			useSystem: false,
			region: "west",
			flex: 1,
			path: "$root$",
			split: true,
			rootVisible: false,
			viewConfig: {
				loadMask: false
			},
			listeners: {
				select: {
					fn: function(i_model, i_node) {

						var i_grid = i_self.getGrid();
						var i_store = i_grid.getStore();

						i_store.loadPage(1);
					}
				}
			}
		});

		var i_store = i_tree.getStore();

		i_store.on({
			load: {
				fn: function(i_store, a_records) {

					var a_selected = i_tree.getSelection();

					if (a_selected.length === 0) {

						var i_first = a_records[0];
						
						i_tree.getSelectionModel().select(i_first);
					}

					Ext.Array.each(a_records, function(i_record) {
						i_record.set("allowDrag", false);

						if (!i_record.get("hasChild")) {
							i_record.set("loaded", true);
						}
						else {
							i_record.expand();
						}
					});
				}
			}
		});

		i_self.setTree(i_tree);

		return i_tree;
	},

	setValue: function(value) {

		var i_self = this;
		if (!Ext.isNumber(value)) {
			value = parseInt(value);
			if (isNaN(value)) {
				value = 0;
			}
		}

		if (!Ext.isDefined(i_self.orginalValue)) {
			i_self.orginalValue = value;
		}
		i_self.value = value;
		i_self.mixins.field.setValue.call(i_self, value);
	},

	getValue: function() {
		var i_self = this;
		return i_self.value;
	},

	isDirty: function() {
		var i_self = this;
		return i_self.orginalValue != i_self.value;
	}
});
Ext.define("Portfolio.ux.file.view.Explorer", {

	alternateClassName: [
		"Ext.ux.file.view.Explorer"
	],

	title: ip2.i18n({
		da: "Fil explorer",
		en: "File explorer"
	}),

	extend: "Ext.window.Window",

	alias: [
		"widget.ux.file.view.explorer",
		"widget.file.explorer"
	],

	closable: false,

	width: 800,
	height: 600,

	layout: "fit",

	bodyPadding: 5,

	modal: true,

	config: {
		path: "",
		saveAction: false,
		navigator: null,
		objectGrid: null,
		fileExtension: [
			{
				ext: "*",
				desc: "All Files (*.*)"
			}
		],
		extensionField: null,
		pathField: null,
		fileName: null,
		formPanel: null
	},

	listeners: {
		folderselect: {
			fn: function(i_self, i_record) {

				var i_panel = i_self.getFormPanel();
				var i_form = i_panel.getForm();

				var o_values = i_panel.getValues();

				Ext.apply(o_values, {
					path: ip2.cleanPath(i_record.get("id")),
					filename: ""
				});

				i_form.setValues(o_values);
			}
		},
		fileselect: {
			fn: function(i_self, i_record) {

				var i_panel = i_self.getFormPanel();
				var i_form = i_panel.getForm();

				var s_path = ip2.cleanPath(i_record.get("id"));

				if (s_path.split(".").length > 1) {

					var a_split = s_path.split(".");
					a_split.pop();

					var s_join = a_split.join("");

					a_split = s_join.split("/");
					a_split.pop();

					s_path = a_split.join("/");
				}

				var o_values = {
					filename: i_record.get("text"),
					path: s_path
				};

				i_form.setValues(o_values);
			}
		}
	},

	initComponent: function() {

		var i_self = this;

		i_self.callParent(arguments);

		i_self.createModels();

		var i_formpanel = i_self.createLayout();

		i_self.add(i_formpanel);

		i_formpanel.isValid();
	},

	createModels: function() {

		if (!Ext.ClassManager.isCreated("objectList")) {
			Ext.define("objectList", {
				extend: "Ext.data.Model",
				proxy: {
					type: "ajax",
					url: "/ip2-services/webBios.aspx",
					extraParams: {
						func: "listdir",
						metaData: true,
						sort: true
					},
					reader: {
						type: "json",
						rootProperty: "rows",
						totalProperty: "totalRows"
					}
				}
			});
		}

		if (!Ext.ClassManager.isCreated("fileExtension")) {
			Ext.define("fileExtension", {
				extend: "Ext.data.Model",fields: [
					{
						type: "string",
						name: "ext"
					},
					{
						type: "string",
						name: "desc"
					}
				]
			});
		}
	},

	createLayout: function() {

		var i_self = this;

		var i_north = i_self.createNorth();
		var i_navigator = i_self.createNavigator();
		var i_center = i_self.createCenter();
		var i_south = i_self.createSouth();

		var i_form = Ext.widget("form", {
			layout: "border",
			border: false
		});

		i_form.on({
			validityChange: {
				fn: function(i_form, b_valid) {

					var i_button = i_self.down("#explorer-button-ok");

					i_button[b_valid ? "enable" : "disable"]();
				}
			}
		});

		i_form.add([
			i_north,
			i_center,
			i_navigator,
			i_south
		]);

		i_form.addDocked(i_self.createFooter());
		i_self.setFormPanel(i_form);

		return i_form;
	},

	createNorth: function() {

		var i_self = this;

		var i_path = Ext.widget("textfield", {
			name: "path",
			fieldLabel: ip2.i18n({
				da: "Sti",
				en: "Path"
			}),
			labelWidth: 40,
			allowBlank: true,
			value: i_self.getPath(),
			enableKeyEvents: true,
			listeners: {
				specialKey: {
					fn: function(i_field, i_event) {

						if (i_event.getKey() == i_event.ENTER) {

							var i_navigator = i_self.getNavigator();
							var i_store = i_navigator.getStore();

							var s_value = i_field.getValue();
							var i_root = i_navigator.getRootNode();
							i_root.removeAll(false);

							i_self.setPath(s_value);

							i_store.load({
								node: i_root
							});
						}
					}
				}
			}
		});

		var i_panel = Ext.widget("panel", {
			region: "north",
			bodyPadding: 3,
			defaults: {
				anchor: "100%"
			},
			layout: "anchor",
			items: [
				i_path
			]
		});

		i_self.setPathField(i_path);

		return i_panel;
	},

	createCenter: function() {

		var i_self = this;

		var i_panel = Ext.widget("panel", {
			border: false,
			layout: "fit",
			region: "center",
			flex: 1,
			items: [
				i_self.createObjectGrid()
			]
		});

		return i_panel;
	},

	createSouth: function() {

		var i_self = this;

		var b_save = i_self.getSaveAction();

		var a_extensions = i_self.getFileExtension();

		var a_fields = [];

		var i_fileName = Ext.widget("textfield", {
			name: "filename",
			fieldLabel: ip2.i18n("filename"),
			allowBlank: !b_save ? true : false,
			flex: 1,
			readOnly: !b_save,
			validator: function(value) {

				var i_fileExtensions = i_self.getExtensionField();

				var b_valid = true;
				var s_pop = value.split(".").pop();
				var s_extension = i_fileExtensions.getValue();

				if (s_extension != "*") {
					b_valid = s_pop == s_extension;
				}

				if (!b_valid) {
					return ip2.i18n({
						da: "Filen skal have samme type ( " + s_extension + " )",
						en: "File must have the same extension ( " + s_extension + " )"
					});
				}

				return b_valid;
			}
		});

		a_fields.push(i_fileName);

		var i_extensionStore = Ext.create("Ext.data.Store", {
			model: "fileExtension",
			data: a_extensions
		});

		var i_fileExtensions = Ext.widget("combobox", {
			name: "extension",
			displayField: "desc",
			valueField: "ext",
			store: i_extensionStore,
			queryMode: "local",
			typeAhead: true,
			anchor: b_save ? "100%" : null,
			hideLabel: b_save ? false : true,
			fieldLabel: ip2.i18n({
				da: "Type",
				en: "Type"
			}),
			margin: "0 0 0 0",
			listeners: {
				afterrender: {
					fn: function(i_field) {

						var a_extensions = i_self.getFileExtension();

						i_field.setValue(a_extensions[0].ext);
					}
				},
				select: {
					fn: function(i_field, i_record) {

						var i_objectGrid = i_self.getObjectGrid();
						var i_store = i_objectGrid.getStore();
						var i_formpanel = i_self.getFormPanel();

						i_store.load();

						i_formpanel.isValid();
					}
				}
			}
		});

		a_fields.push(i_fileExtensions);

		var i_south = Ext.widget("panel", {
			region: "south",
			collapsible: false,
			bodyPadding: 10,
			defaults: {
				margin: "0 5 0 0"
			},
			layout: {
				type: "hbox",
				align: "stretch"
			},
			items: a_fields
		});

		i_self.setExtensionField(i_fileExtensions);

		return i_south;
	},

	createFooter: function() {

		var i_self = this;

		var b_save = i_self.getSaveAction();

		var a_items = [
			"->",
			{
				xtype: "button",
				text: ip2.i18n({
					da: "Anuller",
					en: "Cancel"
				}),
				handler: function() {
					i_self.close();
				}
			},
			{
				xtype: "button",
				text: b_save ? ip2.i18n({
					da: "Gem",
					en: "Save"
				}) : ip2.i18n({
					da: "Åben",
					en: "Open"
				}),
				itemId: "explorer-button-ok",
				disabled: b_save ? false : true,
				ui: "primary-button",
				handler: function() {

					var i_formpanel = i_self.getFormPanel();
					var o_values = i_formpanel.getValues();

					var i_objectGrid = i_self.getObjectGrid();

					var a_path = [];

					a_path.push(o_values.path);
					a_path.push(o_values.filename);

					var s_file = ip2.cleanPath(a_path.join("/"));

					if (b_save) {

						var a_batch = [
							{
								type: "call",
								pgm: "webbios",
								parms: {
									func: "checkstmf",
									file: s_file
								}
							}
						];

						Ext.Ajax.request({
							url: "/ip2-Services/ip2dmdproxy.aspx",
							jsonData: {
								batch: a_batch
							},
							success: function (o_response) {

								var o_result = Ext.decode(o_response.responseText, true);

								var b_exists = false;

								Ext.Array.each(o_result.batch, function(o_values) {

									if (o_values.exists) {
										b_exists = true;
										return false;
									}
								});

								if (b_exists) {

									ip2.messageBox({
										icon: Ext.MessageBox.WARNING,
										title: ip2.i18n("replaceExisting"),
										closable: false,
										message: Ext.String.format(ip2.i18n("fileAlreadyExists"), o_values.filename),
										yesFn: function () {
											i_self.fireEvent("filesave", i_self, s_file);
											i_self.close();
										},
										yesText: ip2.i18n({
											da: "Ja",
											en: "Yes"
										}),
										noText: ip2.i18n({
											da: "Nej",
											en: "No"
										})
									});
								}
								else {
									i_self.fireEvent("filesave", i_self, s_file);
									i_self.close();
								}
							}
						});
					}
					else {

						i_self.fireEvent("fileopen", i_self, s_file);
						i_self.close();
					}
				}
			}
		];

		var i_toolbar = Ext.widget("toolbar", {
			ui: "footer",
			dock: "bottom",
			items: a_items
		});

		return i_toolbar;
	},

	createNavigator: function() {

		var i_self = this;

		var i_navigator = Ext.widget("treepanel", {
			region: "west",
			width: 200,
			split: true,
			collapsible: false,
			lines: false,
			useArrows: true,
			autoScroll: true,
			rootVisible: false,
			frame: false,
			store: Ext.create("Ext.data.TreeStore", {
				folderSort: true,
				proxy: {
					type: "ajax",
					url: "/ip2-services/webBios.aspx"
				},
				root: {
					id: "",
					expanded: false
				}
			}),
			listeners: {
				select: {
					fn: function(i_view, i_record) {

						var i_panel = i_self.getFormPanel();
						var i_form = i_panel.getForm();

						var s_recordExtension = i_record.get("ext");
						var s_path = "";

						if (s_recordExtension == "folder") {

							var i_objectGrid = i_self.getObjectGrid();
							var i_store = i_objectGrid.getStore();

							s_path = i_self.getPath();

							if (!i_record.isRoot()) {

								var i_current = i_record;

								var a_path = [];

								while (!i_current.isRoot()) {

									a_path.unshift(i_current.get("text"));
									i_current = i_current.parentNode;
								};

								a_path.unshift(s_path);

								s_path = a_path.join("/");
							}

							s_path = ip2.cleanPath(s_path);

							i_form.setValues({
								path: s_path,
								filename: ""
							});

							i_store.load();
						}
						else{
							i_self.fireEvent("fileselect", i_self, i_record);
						}
					}
				},
				itemdblclick: {
					fn: function (i_view, i_record, i_element, n_index, i_event) {

						i_event.preventDefault();

						var s_extension = i_record.get("ext");

						var i_formpanel = i_self.getFormPanel();
						var o_values = i_formpanel.getValues();

						if (s_extension != "folder") {

							var a_path = [];

							a_path.push(o_values.path);
							a_path.push(o_values.filename);

							var s_file = ip2.cleanPath(a_path.join("/"));

							i_self.fireEvent("fileopen", i_self, s_file);

							i_self.close();
						}
					}
				},
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_formpanel = i_self.getFormPanel();

						var o_values = {
							extension: "folder"
						};

						if (i_formpanel) {
							o_values = i_formpanel.getValues();
						}

						var i_node = i_operation.node;

						var s_path = i_self.getPath();

						var i_navigator = i_self.getNavigator();

						var i_selected = i_node;

						if (!i_selected.isRoot()) {

							var i_current = i_selected;

							var a_path = [];

							while (!i_current.isRoot()) {

								a_path.unshift(i_current.get("text"));
								i_current = i_current.parentNode;
							};

							a_path.unshift(s_path);

							s_path = a_path.join("/");
						}

						s_path = ip2.cleanPath(s_path);

						var i_proxy = i_store.getProxy();
						var o_params = i_proxy.getExtraParams();

						var s_extensions = o_values.extension;

						Ext.apply(o_params, {
							func: "listdir",
							extension: s_extensions,
							path: s_path,
							sort: true,
							node: null
						});

						delete i_operation.node;
					}
				}
			}
		});

		i_self.setNavigator(i_navigator);

		return i_navigator;
	},

	createObjectGrid: function() {

		var i_self = this;

		var i_grid = Ext.widget("gridpanel", {
			region: "center",
			store: Ext.create("Ext.data.Store", {
				model: "objectList",
				listeners: {
					beforeload: {
						fn: function(i_store, i_operation) {

							var i_formpanel = i_self.getFormPanel();
							var o_values = i_formpanel.getValues();

							var i_proxy = i_store.getProxy();
							var o_extraParams = i_proxy.getExtraParams();

							var s_path = o_values.path;

							if (s_path.split(".").length > 1) {

								var a_split = s_path.split(".");
								a_split.pop();

								var s_join = a_split.join("");

								a_split = s_join.split("/");
								a_split.pop();

								s_path = a_split.join("/");
							}

							Ext.apply(o_extraParams, {
								path: s_path,
								extension: o_values.extension
							});
						}
					}
				}
			}),
			columns: [
				{
					header: "",
					dataIndex: "ext",
					renderer: function(value) {

						var s_icon = "";

						var s_url = "";

						switch (value) {
							case "bmp":
								s_url = "/system/shared/collection/icons/16x16/plain/bmp.png";
								break;
							case "dbm":
								s_url = "/system/shared/collection/icons/16x16/plain/branch.png";
								break;
							case "doc":
								s_url = "/system/shared/collection/icons/16x16/plain/doc.png";
								break;
							case "docx":
								s_url = "/system/shared/collection/icons/16x16/plain/doc.png";
								break;
							case "eml":
								s_url = "/system/shared/collection/icons/16x16/plain/eml.png";
								break;
							case "folder":
								s_url = "/system/shared/collection/icons/16x16/plain/folder.png";
								break;
							case "gif":
								s_url = "/system/shared/collection/icons/16x16/plain/gif.png";
								break;
							case "htm":
								s_url = "/system/shared/collection/icons/16x16/plain/html.png";
								break;
							case "html":
								s_url = "/system/shared/collection/icons/16x16/plain/html.png";
								break;
							case "jpg":
								s_url = "/system/shared/collection/icons/16x16/plain/jpg.png";
								break;
							case "jpeg":
								s_url = "/system/shared/collection/icons/16x16/plain/jpg.png";
								break;
							case "pdf":
								s_url = "/system/shared/collection/icons/16x16/plain/pdf.png";
								break;
							case "png":
								s_url = "/system/shared/collection/icons/16x16/plain/png.png";
								break;
							case "ppt":
								s_url = "/system/shared/collection/icons/16x16/plain/ppt.png";
								break;
							case "tif":
								s_url = "/system/shared/collection/icons/16x16/plain/tif.png";
								break;
							case "xls":
								s_url = "/system/shared/collection/icons/16x16/plain/xls.png";
								break;
							case "xlsx":
								s_url = "/system/shared/collection/icons/16x16/plain/xls.png";
								break;
							case "xml":
								s_url = "/system/shared/collection/icons/16x16/plain/xml.png";
								break;
							default:
								s_url = "/system/shared/collection/icons/16x16/plain/document_empty.png";
								break;
						}

						s_icon = "<img src=\"" + s_url + "\"/>";

						return s_icon;
					},
					width: 40
				},
				{
					header: "Name",
					dataIndex: "text",
					flex: 2,
					menuDisabled: true,
					sortable: false
				},
				{
					header: "Changed",
					dataIndex: "mtime",
					width: 68
				},
				{
					header: "Size (kb)",
					dataIndex: "size",
					align: "right",
					width: 66
				}
			],
			listeners: {
				itemkeyup: {
					fn: function(i_view, i_selected, i_element, n_index, i_event) {

						var i_grid = i_view.grid;
						var i_store = i_grid.getStore();
						var a_records = i_store.getRange();
						var i_newSelect;
						var n_prev;

						var s_key = String.fromCharCode(i_event.keyCode).toLowerCase();

						if (i_event.getKey() != i_event.ENTER) {

							Ext.Array.each(a_records, function(i_record) {

								var s_text = i_record.get("text") || "";
								s_text = s_text.toLowerCase();

								if (Ext.String.startsWith(s_text, s_key)) {

									var n_current = i_store.find("text", i_record.get("text"));

									if (Ext.isEmpty(n_prev)) {
										if (n_current < n_index) {
											n_prev = n_current;
										}
									}

									if (n_current > n_index) {
										i_newSelect = i_record;
										return false;
									}
								}
							});

							if (!i_newSelect && !Ext.isEmpty(n_prev)) {
								i_newSelect = i_store.getAt(n_prev);
							}
							if (i_newSelect) {
								i_view.select(i_newSelect);
								i_view.focusNode(i_newSelect, 20);
							}
						}
						else {
							i_grid.fireEvent("itemdblclick", i_view, i_selected, i_element, n_index, i_event);
						}
					}
				},
				select: {
					fn: function(i_view, i_record) {

						var s_extension = i_record.get("ext");

						var i_panel = i_self.getFormPanel();
						var i_form = i_panel.getForm();

						if (s_extension != "folder") {
							i_self.fireEvent("fileselect", i_self, i_record);
						}
						else {
							i_form.setValues({
								filename: ""
							});
						}
					}
				},
				itemdblclick: {
					fn: function(i_view, i_record, i_element, n_index, i_event) {

						i_event.preventDefault();

						var s_extension = i_record.get("ext");

						var i_formpanel = i_self.getFormPanel();
						var o_values = i_formpanel.getValues();

						if (s_extension == "folder") {

							i_self.fireEvent("folderselect", i_self, i_record);

							var i_grid = i_view.grid;
							var i_store = i_grid.getStore();

							i_store.load();
						}
						else {
							var a_path = [];

							a_path.push(o_values.path);
							a_path.push(o_values.filename);

							var s_file = ip2.cleanPath(a_path.join("/"));

							i_self.fireEvent("fileopen", i_self, s_file);

							i_self.close();
						}
					}
				}
			}
		});

		i_self.setObjectGrid(i_grid);

		return i_grid;
	},

	getPathToSelected: function() {

		var i_self = this;

		var s_path = i_self.getPath();

		var i_navigator = i_self.getNavigator();
		var i_selected = i_navigator.getSelection()[0];

		var a_path = [];

		if (!i_selected.isRoot()) {

			var i_current = i_selected;

			while (!i_current.isRoot()) {

				a_path.unshift(i_current.get("text"));
				i_current = i_current.parentNode;
			};

			a_path.unshift(s_path);
		}

		s_path = a_path.join("/");

		s_path = ip2.cleanPath(s_path);

		return s_path;
	}
});
Ext.define("Ext.ux.file.view.Editor", {

	extend: "Ext.panel.Panel",

	requires: [
		"Ext.ux.form.field.AceTextArea",
		"Ext.ux.file.view.Explorer"
	],

	alias: [
		"widget.ux.file.view.editor",
		"widget.file.editor"
	],

	config: {
		mode: "text",
		editor: null,
		toolbar: null,
		file: "",
		useOwner: false,
		allowNew: true,
		allowOpen: true,
		fileMap: {},
		fileExtension: [
			{
				"ext": "*",
				"desc": "All Files (*.*)"
			}
		]
	},

	layout: "fit",

	initComponent: function() {

		var i_self = this;

		i_self.callParent(arguments);

		i_self.setFileMap({
			dmd: "json",
			xpd: "json",
			lib: "json",
			aspx: "javascript",
			widget: "javascript",
			txt: "text",
			sqltpl: "sql"
		});

		i_self.add(i_self.createEditor());
		i_self.addDocked(i_self.createToolbar());
	},

	createEditor: function() {

		var i_self = this;

		var i_editor = Ext.widget("acetextarea", {
			mode: i_self.getMode(),
			showPrintMargin: false,
			userWorker: true,
			listeners: {
				afterrender: {
					fn: function(i_field) {

						var s_file = i_self.getFile();

						if (s_file) {

							i_self.getFileFromPath(s_file, function(s_data) {

								var s_extension = s_file.split(".").pop().toLowerCase();

								var o_fileMape = i_self.getFileMap();

								var i_acefield = i_editor.getEditor();

								if (o_fileMape.hasOwnProperty(s_extension)) {
									s_extension = o_fileMape[s_extension];
								}

								i_acefield.setOptions({
									mode: "ace/mode/" + s_extension
								});

								i_editor.setValue(s_data);

								i_self.setFile(s_file);

								i_self.doTitleUpdate(s_file);
							});
						}
					},
					buffer: 10
				}
			}
		});

		i_self.setEditor(i_editor);

		return i_editor;
	},

	createToolbar: function() {

		var i_self = this;

		var i_toolbar = Ext.widget("toolbar", {
			dock: "top",
			items: [
				{
					xtype: "button",
					text: ip2.i18n({
						da: "Menu",
						en: "Menu"
					}),
					menu: {
						items: i_self.createMenuItems()
					}
				}
			]
		});

		i_self.setToolbar(i_toolbar);

		return i_toolbar;
	},

	createMenuItems: function() {

		var i_self = this;

		var a_items = [];

		if (i_self.getAllowNew()) {

			var i_newItem = Ext.widget("menuitem", {
				text: ip2.i18n({
					da: "Ny",
					en: "New"
				}),
				iconCls: "pf-add",
				menu: {
					items: [
						{
							xtype: "menuitem",
							text: "Json",
							handler: function(i_button) {

								var i_editor = i_self.getEditor();

								i_editor.setValue("");

								var i_acefield = i_editor.getEditor();

								i_acefield.setOptions({
									mode: "ace/mode/json"
								});

								i_self.setFile("");

								i_self.doTitleUpdate("Json");
							}
						},
						{
							xtype: "menuitem",
							text: "Javascript",
							handler: function(i_button) {

								var i_editor = i_self.getEditor();

								i_editor.setValue("");

								var i_acefield = i_editor.getEditor();

								i_acefield.setOptions({
									mode: "ace/mode/javascript"
								});

								i_self.setFile("");

								i_self.doTitleUpdate("Javascript");
							}
						},
						{
							xtype: "menuitem",
							text: "Html",
							handler: function(i_button) {

								var i_editor = i_self.getEditor();

								i_editor.setValue("");

								var i_acefield = i_editor.getEditor();

								i_acefield.setOptions({
									mode: "ace/mode/html"
								});

								i_self.setFile("");

								i_self.doTitleUpdate("Html");
							}
						},
						{
							xtype: "menuitem",
							text: "Xml",
							handler: function(i_button) {

								var i_editor = i_self.getEditor();

								i_editor.setValue("");

								var i_acefield = i_editor.getEditor();

								i_acefield.setOptions({
									mode: "ace/mode/xml"
								});

								i_self.setFile("");

								i_self.doTitleUpdate("Xml");
							}
						}
					]
				}
			});

			a_items.push(i_newItem);
		}

		if (i_self.getAllowOpen()) {

			var i_openItem = Ext.widget("menuitem", {
				text: ip2.i18n({
					da: "Åben",
					en: "Open"
				}),
				iconCls: "pf-gearwheel",
				handler: function(i_button) {

					var i_editor = i_self.getEditor();

					i_self.openFile(function(s_data, s_type) {

						var o_fileMape = i_self.getFileMap();

						var i_acefield = i_editor.getEditor();

						if (o_fileMape.hasOwnProperty(s_type)) {
							s_type = o_fileMape[s_type];
						}

						i_acefield.setOptions({
							mode: "ace/mode/" + s_type
						});

						i_editor.setValue(s_data);
					});
				}
			});

			a_items.push(i_openItem);
		}

		var i_saveFile = Ext.widget("menuitem", {
			text: ip2.i18n({
				da: "Gem",
				en: "Save"
			}),
			iconCls: "pf-floppy_disk",
			handler: function(i_button) {

				var i_editor = i_self.getEditor();

				var s_value = i_editor.getValue();

				var s_file = i_self.getFile();

				if (s_file) {
					i_self.saveFileToPath(s_file, s_value);
					i_self.fireEvent("filesave", i_self, s_file);
				}
				else {
					i_self.doSaveAs(s_value);
				}
			}
		});

		var i_saveAsFile = Ext.widget("menuitem", {
			text: ip2.i18n({
				da: "Gem som",
				en: "Save as"
			}),
			iconCls: "pf-floppy_disk",
			handler: function(i_button) {

				var i_editor = i_self.getEditor();

				i_self.doSaveAs(i_editor.getValue());
			}
		});

		a_items.push(i_saveFile);
		a_items.push(i_saveAsFile);

		return a_items;
	},

	getFileFromPath: function(s_path, f_callback) {

		Ext.Ajax.request({
			url: "/ip2-services/webBios.aspx",
			params: {
				func: "readstmf",
				file: s_path
			},
			success: function (o_response) {

				var s_result = o_response.responseText;

				f_callback(s_result);
			}
		});
	},

	saveFileToPath: function(s_file, s_data) {

		Ext.Ajax.request({
			url: "/ip2-services/webBios.aspx",
			params: {
				func: "writestmf",
				data: s_data,
				file: s_file,
				ignoreStaticDir: true
			}
		});
	},

	openFile: function(f_callback) {

		var i_self = this;

		f_callback = f_callback || Ext.emptyFn;

		var i_explorer = Ext.widget("file.explorer", {
			path: ip2.baseconfig.session.preset.root || "/",
			saveAction: false,
			listeners: {
				fileopen: {
					fn: function(i_explorer, s_file) {

						var s_extension = s_file.split(".").pop().toLowerCase();

						i_self.getFileFromPath(s_file, function(s_data) {

							f_callback(s_data, s_extension);
						});

						i_self.setFile(s_file);

						i_self.doTitleUpdate(s_file);
					}
				}
			}
		});

		i_explorer.show();
	},

	doSaveAs: function(s_value) {

		var i_self = this;

		var i_editor = i_self.getEditor();

		var s_data = s_value;

		var s_file = i_self.getFile();

		var s_part = ip2.baseconfig.session.preset.root || "/";

		if (s_file) {

			if (s_file.split(".").length > 1) {

				var a_split = s_file.split(".");
				a_split.pop();

				var s_temp = a_split.join("");

				a_split = s_temp.split("/");
				a_split.pop();

				s_path = a_split.join("/");
			}
		}

		var i_explorer = Ext.widget("file.explorer", {
			path: s_path,
			saveAction: true,
			fileExtension: i_self.getFileExtension(),
			listeners: {
				filesave: {
					fn: function(i_explorer, s_file) {

						i_self.saveFileToPath(s_file, s_data);

						var s_extension = s_file.split(".").pop().toLowerCase();

						var o_fileMape = i_self.getFileMap();

						var i_acefield = i_editor.getEditor();

						if (o_fileMape.hasOwnProperty(s_extension)) {
							s_extension = o_fileMape[s_extension];
						}

						i_acefield.setOptions({
							mode: "ace/mode/" + s_extension
						});

						i_self.setFile(s_file);

						i_self.doTitleUpdate(s_file);

						i_self.fireEvent("filesave", i_self, s_file);
					}
				}
			}
		});

		i_explorer.show();
	},

	doTitleUpdate: function(s_file) {

		var i_self = this;

		var a_title = [];

		var s_part = ip2.i18n({
			da: "Editing",
			da: "Edíting"
		});

		a_title.push(s_part);
		a_title.push(s_file);

		var b_setOwner = i_self.getUseOwner();

		var i_owner = b_setOwner ? i_self.ownerCt || i_self : i_self;

		i_owner.setTitle(a_title.join(" - "));
	}
});
Ext.define('Ext.ux.form.field.DecimalNumber', {
	
	extend: 'Ext.form.field.Number',
	
	alias: ['widget.decimalnumber'],
	
	forcePrecision: false,

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		return i_cmp;
	},

	valueToRaw: function(value) {
		
		var me = this;
		var decimalSeparator = me.decimalSeparator;
		
		value = me.parseValue(value);
		value = me.fixPrecision(value);
		value = Ext.isNumber(value) ? value : parseFloat(String(value).replace(decimalSeparator, '.'));
		
		if (isNaN(value)) {
			value = '';
		}
		else {
			value = me.forcePrecision ? value.toFixed(me.decimalPrecision) : parseFloat(value);
			value = String(value).replace(".", decimalSeparator);
		}
		
		return value;
	}
});
Ext.define("Ext.ux.serppreview.Container", {
	extend: "Ext.container.Container",

	alias: "widget.serppreviewcontainer",
	
	host: '',

	config: {
		titleField: null,
		urlField: null,
		descriptionField: null,
		keywordsField: null,
		htmlContainer: null,

		titleInput: null,
		urlInput: null,
		descInput: null,
		keyInput: null
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent();

		i_self.on({
			afterrender: {
				fn: function(item) {

					var i_form = i_self.up("entityform");

					if (i_form) {

						var i_titleField = i_form.form.findField(i_self.titleField);
						var i_urlField = i_form.form.findField(i_self.urlField);
						var i_descriptionField = i_form.form.findField(i_self.descriptionField);
						var i_keywordsField = i_form.form.findField(i_self.keywordsField);

						if(i_titleField) {
							i_self.mon(i_titleField, "change", function(item) {
								i_self.updateHTML();
							});
							i_self.setTitleInput(i_titleField);
						}
						if(i_urlField) {
							i_self.mon(i_urlField, "change", function(item) {
								i_self.updateHTML();
							});
							i_self.setUrlInput(i_urlField);
						}
						if(i_descriptionField) {
							i_self.mon(i_descriptionField, "change", function(item) {
								i_self.updateHTML();
							});
							i_self.setDescInput(i_descriptionField);
						}
						if(i_keywordsField) {
							i_self.mon(i_keywordsField, "change", function(item) {
								i_self.updateHTML();
							});
							i_self.setKeyInput(i_keywordsField);
						}

						i_self.updateHTML();
					}
					
				},
				buffer: 10
			}
		});

		ip2.getSiteConfig(function (serversetting) {
			i_self.host = serversetting.http_host;
		});
		
		return i_self;
	},

	updateHTML: function() {
		var i_self = this;
		var div = i_self.getHTML();
		i_self.update(div.innerHTML);
		delete div;
	},

	changeLanguage: function() {
		var i_self = this;
		i_self.updateHTML();
	},

	getHeightLightedHTML: function(value, search, bold, findwords, type) {

		var s_search = search.replace(/,/g, " ");
		var a_search = s_search.split(" ");
		a_search = Ext.Array.filter(a_search, Boolean);
		var s_html = Ext.isObject(value) ? ip2.i18n(value) : value;
		var regex;
		if (findwords) {
			regex = new RegExp('\\b(' + a_search.join('|') + ')\\b', "gi");
		}
		else {
			regex = new RegExp('(' + a_search.join("|") + ')', "gi");
		}

		if (bold) {
			if (type == "url") {
				s_html = s_html.replace(regex, '<span style="background-color:#FFFBD3;color:#006621;"><b>$1</b></span>');
			}
			if (type == "meta") {
				s_html = s_html.replace(regex, '<span style="background-color:#FFFBD3;color:#6a6a6a;"><b>$1</b></span>');
			}
		}
		else {
			if (type == "url") {
				s_html = s_html.replace(regex, '<span style="background-color:#FFFBD3;color:#006621;">$1</span>');
			}
			if (type == "meta") {
				s_html = s_html.replace(regex, '<span style="background-color:#FFFBD3;color:#6a6a6a;">$1</span>');
			}
			else {
				s_html = s_html.replace(regex, '<span style="background-color:#FFFBD3;">$1</span>');
			}
		}

		return s_html;
	},

	getHTML: function() {
		var i_self = this;
		var n_description = i_self.getDescInput() ? i_self.getDescInput().getValue().length : 0;
		var n_url = i_self.getUrlInput() ? i_self.getUrlInput().getValue().length : 0;
		var n_titletag = i_self.getTitleInput() ? i_self.getTitleInput().getValue().length : 0;
		var s_description = "";
		var s_url = "";
		var s_titletag = "";
		var s_da = "";
		var s_en = "";

		if (n_titletag == 0) {
			s_da = "Dette er et eksempel på hvordan din Title Tag vil se ud i Google søgeresultater";
			s_en = "This is an example of how your Title Tag will look in Google search results";

			s_titletag = ip2.i18n({
				da: s_da,
				en: s_en
			});
		}
		else {
			s_titletag = i_self.getTitleInput() ? i_self.getTitleInput().getValue() : "";
		}

		if (n_description == 0) {
			s_da = "Metabeskrivelsen skal helst holdes inden for 156 karakterer " +
				"hvorfor Google ellers klipper din tekst. Aflever dit budskab af " +
				"inden for 156 og opnå bedre CTR";

			s_en = "Meta description should preferably be kept within 156 characters " +
				"or Google might cut your text. Deliver your message of within 156 and " +
				"achieve better CTR";

			s_description = ip2.i18n({
				da: s_da,
				en: s_en
			});
		}
		else {
			if (n_description > 156) {
				s_description = (i_self.getDescInput() ? i_self.getDescInput().getValue() : "").slice(0, 156);
			}
			else {
				s_description = i_self.getDescInput() ? i_self.getDescInput().getValue() : "";
			}
		}
		if (n_url == 0) {
			s_da = "www.domain.dk/page/url";
			s_en = "www.domain.dk/page/url";

			s_url = ip2.i18n({
				da: s_da,
				en: s_en
			});
		}
		else {
			s_url = i_self.host + "/page/" + i_self.getUrlInput() ? i_self.getUrlInput().getValue() : "";
			if (s_url.length > 156) {
				s_url = s_url.slice(0, 156);
			}
		}
		var s_search = i_self.getKeyInput() ? i_self.getKeyInput().getValue() : "";
		if (Ext.isEmpty(s_search)) {
			var o_values = {
				titleTag: i_self.getHeightLightedHTML(s_titletag, s_search, false, true, "title"),
				url: i_self.getHeightLightedHTML(s_url, s_search, true, true, "url"),
				description: i_self.getHeightLightedHTML(s_description, s_search, true, true, "meta")
			};
		}
		else {
			var o_values = {
				titleTag: s_titletag,
				url: s_url,
				description: s_description
			};
		}

		if (n_description > 156) {
			o_values.description += '...';
		}
		var regex = new RegExp("\n", "g");
		o_values.description = o_values.description.replace(regex, "</br>");
		var i_template;
		if (!i_self.template) {
			var tpl = new Ext.XTemplate(
				'<tpl for=".">',
					'<h3 style="',
						'color: #1a0dab;',
						'text-overflow: ellipsis;',
						'font-family: arial, sans-serif;',
						'max-width: 512px;',
						'overflow: hidden;',
						'white-space: nowrap;',
						'font-size: 18px;',
						'font-weight: normal;',
						'line-height: 1.2;',
						'margin: 0;',
					'">{titleTag}</h3>',
					'<div style="',
						'color: #006621;',
						'font-style: normal;',
						'font-size: 14px;',
						'text-overflow: ellipsis;',
						'font-family: arial, sans-serif;',
						'max-width: 512px;',
						'line-height: 16px',
						'overflow: hidden;',
						'white-space: nowrap;',
					'">{url}</div>',
					'<div style="',
						'max-width: 512px;',
						'line-height: 1.4;',
						'font-family: arial, sans-serif;',
						'word-wrap: break-word;',
						'font-size: 13px;',
						'font-weight: normal;',
						'color: #545454;',
					'">{description}</div>',
				'</tpl>'
			);
			i_self.template = tpl.compile();
			i_template = i_self.template;
		}
		else {
			i_template = i_self.template;
		}

		var div = document.createElement("div");
		i_template.overwrite(div, o_values);
		return div;
	}
});
Ext.define("Ext.ux.serppreview.FieldContainer", {
	extend: "Ext.form.FieldContainer",
	alias: "widget.serppreviewfield",

	// THIS SHOULD NOT BE NEEDED
	mixins: {
		field: "Ext.form.field.Field"
	},

	isFormField: false,

	config: {
		htmlContainer: null
	},

	initComponent: function() {

		var i_self = this;

		i_self.isFormField = false;

		i_self.callParent();

		i_self.initField();

		var i_htmlcontainer = Ext.widget("serppreviewcontainer", {
			titleField: i_self._xpdConfig.titleField,
			urlField: i_self._xpdConfig.urlField,
			descriptionField: i_self._xpdConfig.descriptionField,
			keywordsField: i_self._xpdConfig.keywordsField
		});

		i_self.setHtmlContainer(i_htmlcontainer);
		i_self.add(i_htmlcontainer);

		return i_self;
	},

	changeLanguage: function() {

		var i_self = this;
		i_self.getHtmlContainer().changeLanguage();
	},

	getValue: function() {
		return "";
	},

	setValue: function() {
		var test = "";
	},

	isDirty: function() {
		return false
	},

	isValid: function() {
		return true;
	}
});
Ext.define("Ext.ux.plugin.Charcount", {
	alias: "plugin.charcount",

	config: {
		textfield: null,
		characterConfig: null,
		textPre: "",
		textPost: "",
		textSeperator: "",
		maxLength: 0,
		warningThreshold: 0,
		lowerThreshold: 0,
		countdown: false,
		hookField: false
	},

	overloader: function(config) {

		var o_clone = {
			textPre: "",
			textPost: "",
			textSeperator: "",
			maxLength: 0,
			countdown: false,
			lowerThreshold: 0,
			warningThreshold: 10,
			hookField: false
		};

		if (Ext.isObject(config)) {

			Ext.apply(o_clone, config);

			var a_text = ["textPre", "textPost", "textSeperator", "hookField"];

			Ext.Array.each(a_text, function(s_key) {
				if (o_clone[s_key]) {
					o_clone[s_key] = ip2.i18n(o_clone[s_key]);
				}
			});
		}
		return o_clone;
	},

	init: function(i_textfield) {

		var i_self = this;
		i_self.textfield = i_textfield;

		var o_clone = i_self.overloader(i_textfield.characterCount);
		Ext.applyIf(i_self, o_clone);

		i_self.maxLength = o_clone.length || Number.MAX_VALUE != i_textfield.maxLength ? i_textfield.maxLength : 0;

		var value = i_textfield.getValue();

		if (i_self.hookField) {

			var o_meta = value.meta;

			var s_current = i_textfield.getLanguage();

			var b_active = i_textfield.getLanguageActive();

			value = b_active ? value.text[s_current] : value["default"];
		}

		i_self.value = value.length;

		if (!i_textfield.rendered) {
			i_textfield.on({
				afterrender: {
					fn: i_self.handleAfterrender,
					scope: i_self
				}
			});
		}
		else {
			i_self.handleAfterrender();
		}
	},

	handleAfterrender: function() {

		var i_self = this;
		var i_textfield = i_self.textfield;

		i_textfield.on({
			change: {
				fn: i_self.updateValue,
				scope: i_self
			}
		});

		i_self.createInfoArea();

		i_self.updateValue();
	},

	updateValue: function() {

		var i_self = this;
		var i_textfield = i_self.textfield;

		var value = i_textfield.getValue();

		if (i_self.hookField) {

			var s_current = i_textfield.getLanguage();
			var b_active = i_textfield.getLanguageActive();

			value = b_active ? value.text[s_current] : value["default"];
		}

		value = value.length;

		var i_span_value = i_self.getInfoArea();

		if (value <= i_self.lowerThreshold) {
			i_span_value.setStyle("color", "#D74B3D");
		}
		else {
			var n_value = i_self.maxLength - value;

			if (n_value <= i_self.warningThreshold) {
				if (n_value <= 0) {
					i_span_value.setStyle("color", "#D74B3D");
				}
				else {
					i_span_value.setStyle("color", "#FC9B47");
				}
			}
			else {
				i_span_value.setStyle("color", "#35AC19");
			}
		}
		i_span_value.update(String(value));
	},

	getInfoArea: function() {

		var i_self = this;
		var i_textfield = i_self.textfield;
		var i_element = i_textfield.getEl();
		return i_element.select(".x-plugin-charcount span.plugin-value", true);
	},

	createInfoArea: function() {

		var i_self = this;

		var i_tpl = new Ext.XTemplate(
			"<tpl for=\".\">",
				"<div class=\"" + Ext.baseCSSPrefix + "plugin-charcount\"" + ">",
					"<tpl if=\"this.isBlank(" + i_self.maxLength + ") == false\">",
						"<tpl if=\"this.isBlank(values.textPre) == false\">",
							"<span class=\"plugin-textPre\">{textPre} </span>",
						"</tpl>",
						"<tpl if=\"values.countdown == false\">",
							"<tpl if=\"this.isLowerThreshold(values.lowerThreshold, values.value) == true\">",
								"<span class=\plugin-value\ style=\"font-weight: 900; color:#D74B3D;\">{value}</span>",
							"</tpl>",
							"<tpl if=\"this.isLowerThreshold(values.lowerThreshold, values.value) == false\">",
								"<span class=\"plugin-value\" style=\"font-weight: 900; color:#35AC19;\">{value}</span>",
							"</tpl>",
						"</tpl>",
						"<tpl if=\"values.countdown == true\">",
							"<tpl if=\"this.isLowerThreshold(values.lowerThreshold, values.value) == true\">",
								"<span class=\"plugin-value\" style=\"font-weight: 900; color:#D74B3D;\">{[this.getValue(values.value, values.maxLength)]}</span>",
							"</tpl>",
							"<tpl if=\"this.isLowerThreshold(values.lowerThreshold, values.value) == false\">",
								"<span class=\"plugin-value\" style=\"font-weight: 900; color:#35AC19;\">{[this.getValue(values.value, values.maxLength)]}</span>",
							"</tpl>",
						"</tpl>",
						"<tpl if=\"this.isBlank(values.textSeperator) == false\">",
							"<span class=\"plugin-textSeperator\"> {textSeperator}</span>",
							"<span class=\"plugin-maxLength\" style=\"font-weight: 900;\"> {maxLength}</span>",
						"</tpl>",
						"<tpl if=\"this.isBlank(values.textPost) == false\">",
							"<span class=\"plugin-textPost\"> {textPost}</span>",
						"</tpl>",
					"</tpl>",
				"</tpl>",
			"</div>",
			{
				getValue: function(value, maxvalue) {
					return maxvalue - value;
				},
				isBlank: function(value) {

					value = value || "";

					return value.length === 0;
				},
				isLowerThreshold: function(lowerThreshold, value) {
					return value <= lowerThreshold;
				}
			}
		);

		var i_textfield = i_self.textfield;
		var i_inputWrap = i_textfield.inputWrap;

		var i_created = Ext.DomHelper.createDom(i_tpl.apply(i_self));

		i_inputWrap.append(i_created);
	}
});
Ext.define("Ext.ux.grid.DropZone", {
	extend: "Ext.container.Container",
	alias: [
		"widget.ux.grid.dropzone"
	],
	layout: "fit",
	config: {
		grid: null,
		entity: {},
		overZone: false,
		dragging: 0,
		zone: null,
		zones: [],
		wrapperComponent: null
	},
	dropFn: Ext.emptyFn,
	style: {
		"position": "absolute",
		"padding": "5px",
		"top": "0px",
		"left": "0px",
		"right": "0px",
		"bottom": "0px",
		"font-size": "5px"
	},
	listeners: {
		afterrender: {
			fn: function() {
				var i_self = this;
				i_self.setDragging(0);

				var i_dropzone = i_self.getZone();
				var i_container = i_self.getWrapperComponent();

				i_self.mon(Ext.getBody(), "dragenter", function(i_event) {
					var n_dragging = i_self.getDragging();
					if (n_dragging === 0) {
						var i_el = i_dropzone.getEl();
						if (i_el.dom) {
							i_el.setStyle("display", "inline");
							i_el.setStyle("z-index", "1");
						}

						if (i_container) {

							var o_size = i_container.getSize();

							i_self.setSize(o_size.width, o_size.height);
							i_dropzone.setSize(o_size.width, o_size.height);
							o_size = i_self.getSize();
							i_el.setSize(o_size);
						}
					}

					n_dragging++;
					i_self.setDragging(n_dragging);
				});

				i_self.mon(Ext.getBody(), "dragleave", function(i_event) {

					var n_dragging = i_self.getDragging();
					n_dragging--;

					var i_el = i_dropzone.getEl();
					if (i_el.dom && n_dragging === 0) {
						i_el.setStyle("display", "none");
						i_el.setStyle("z-index", "0");
					}

					i_self.setDragging(n_dragging);
				});

				document.body.addEventListener("drop", function(o_event) {
					var i_el = i_dropzone.getEl();
					if (i_el.dom) {
						i_el.setStyle("display", "none");
					}
					i_self.setDragging(0);
				});
			}
		},
		dragenter: {
			element: "el",
			fn: function (i_event) {

				var i_self = this.component;

				var n_dragging = i_self.getDragging();
				n_dragging++;
				i_self.setDragging(n_dragging);
			}
		},
		dragleave: {
			element: "el",
			fn: function (i_event) {

				var i_self = this.component;

				var n_dragging = i_self.getDragging();
				n_dragging--;
				i_self.setDragging(n_dragging);
			}
		},
		drop: {
			fn: function(i_container, a_result, o_config) {

				var i_self = this;
				var i_dropzone = i_self.getZone();
				i_self.setDragging(0);
				var i_el = i_dropzone.getEl();
				if (i_el.dom) {
					i_el.setStyle("display", "none");
					i_el.setStyle("z-index", "0");
				}

				var s_value = "";
				var a_join = [];

				Ext.Array.each(a_result, function(o_value) {

					var s_path = o_value.FILPATH || o_value.PATH;
					var s_name = o_value.FILNAME || o_value.NAME;

					a_join.push(s_path);
					a_join.push(s_name);
				});

				s_value = ip2.cleanPath(a_join.join("/"));

				i_self.dropFn(s_value, o_config);
			}
		}
	},
	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var a_zones = i_self.getZones();
		var i_grid = i_self.getGrid();

		if (i_grid) {

			var s_dmd = i_grid.dmdName;
			var o_entity = i_self.getEntity();
			var s_view = i_grid.uiName;
			var o_drop = o_entity.ui.grids[s_view].drop || {
				entities: []
			};

			Ext.Array.each(o_drop.entities, function(o_config) {

				var o_dmd = ip2.resource.get(o_config.dmd);

				var a_entities = o_dmd.model.entities;

				var o_entity = Ext.Array.findBy(a_entities, function(o_value) {
					return o_value.name == o_config.name;
				});

				Ext.apply(o_config, {
					title: o_entity.title,
					dmdName: s_dmd
				});
			});

			i_self.add(i_self.createPortlet(o_drop.entities));
		}
		else {
			i_self.add(i_self.createPortlet(a_zones));
		}

		return i_self;
	},

	createPortlet: function(a_entires) {

		var i_self = this;

		var i_portlet = Ext.widget("container", {
			border: 0,
			layout: {
				type: "vbox",
				padding: 0,
				align: 'stretch'

			},
			style: {
				"background-color": a_entires.length ? "white" : "transparent",
				"position": "absolute",
				"padding": "5px",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"font-size": "5px",
				"display": "none",
				"opacity": "0.9"
			},
			items: i_self.createColumns(a_entires)
		});

		i_self.setZone(i_portlet);

		return i_portlet;
	},

	createColumns: function(a_entires) {

		var i_self = this;

		var a_columns = [];

		a_entires = Ext.Array.filter(a_entires, function(o_value) {
			return o_value.path;
		});

		var n_count = a_entires.length;

		if (n_count % 2 == 0) {
			n_count = Math.ceil(n_count / 6);
		}
		else {
			n_count = Math.ceil(n_count / 5);
		}

		var a_items = [];

		Ext.Array.each(a_entires, function(o_config) {

			var i_result = i_self.createPortletItem(o_config);
			if (i_result) {
				a_items.push(i_result);
			}
		});

		if (a_items.length > 0) {
			var i_row = Ext.widget("container", {
				flex: 1,
				border: 0,
				layout: {
					type: "hbox",
					padding: 5,
					align: "stretch"
				},
				items: a_items
			});

			a_columns.push(i_row);
		}

		return a_columns;
	},

	createPortletItem: function(o_config) {

		var i_self = this;
		var i_portletItem = Ext.widget("container", {
			border: 0,
			draggable: false,
			closable: false,
			collapsible: false,
			layout: "fit",
			flex: 1,
			items: [
				{
					xtype: "gallerydropbox",
					flex: 1,
					path: o_config.path,
					dropConfig: o_config,
					dropText: ip2.i18n(o_config.title) + "</br><small><small>" +
					ip2.i18n(
						{
							da: "Drop for at oprette record ",
							en: "Drop to create record"
						}
					) + "</small></small>",
					extensions: ["*"],
					maxItems: o_config.maxItems || 1,
					style: {
						"position": "absolute",
						"padding": "5px",
						"top": "0px",
						"left": "0px",
						"right": "0px",
						"bottom": "0px",
						"font-size": "25px"
					},
					listeners: {
						drop: {
							fn: function(i_dropbox, a_files, i_event) {

								var i_plugin = i_dropbox.getDDPlugin();

								if (i_plugin.enableDrop) {

									var s_message = ip2.i18n({
										da: "Kontrolerer filer....",
										en: "Checking files..."
									});

									i_self.setLoading(s_message, true);

									var s_uploadpath = i_dropbox.path;

									Ext.ux.file.util.Handler.checkFiles(s_uploadpath, a_files, function(o_result) {
										i_self.setLoading(false);
										var a_update = o_result.update;
										var a_create = o_result.create;
										var b_update = false;
										var b_cancel = false;
										var b_create = false;
										var a_result = [];
										if (a_update.length > 0) {
											b_update = true;
											Ext.ux.file.util.Handler.getUIConflickWindow(i_dropbox.getEl(),
												i_self,
												i_dropbox.path,
												a_update,
												function(b_cancel, a_override, a_rename) {

													b_cancel = b_cancel;

													if (!b_cancel) {
														b_cancel = (a_override.length === 0 && a_rename.length === 0);
													}

													if (b_cancel) {
														if (!b_create) {
															i_self.setLoading(false);
															i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
														}
														return;
													}
													var a_complete = a_override.concat(a_rename);

													var a_temp = [];

													Ext.Array.each(a_complete, function(o_record) {
														a_temp.push(o_record.file);
													});

													s_message = ip2.i18n({
														da: "Overskriver fil....",
														en: "Overwriting file..."
													});

													i_self.setLoading(s_message);

													if (Ext.ux.file.util.Handler.hasFileManager()) {
														Ext.ux.file.util.Handler.updateRecordsFileInfo(s_uploadpath, a_temp, function(a_records) {
															Ext.Array.each(a_records, function(i_record) {
																a_result.push(i_record.data);
															});
															if (!b_create) {
																i_self.setLoading(false);
																i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
															}
															else {
																s_message = ip2.i18n({
																	da: "Opretter filer....",
																	en: "Creating files..."
																});
																i_self.setLoading(s_message);
															}
														});
													}
													else {
														Ext.ux.file.util.Handler.uploadFiles(s_uploadpath, a_temp, false, function(a_values) {
															Ext.Array.each(a_values, function(o_value) {
																a_result.push({
																	PATH: s_uploadpath,
																	NAME: o_value.file.name
																});
															});
															if (!b_create) {
																i_self.setLoading(false);
																i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
															}
															else {
																s_message = ip2.i18n({
																	da: "Opretter filer....",
																	en: "Creating files..."
																});
																i_self.setLoading(s_message);
															}
														});
													}
												},
												false
											);
										}
										if (a_create.length > 0) {
											b_create = true;
											if (!b_update) {
												i_self.setLoading(false);
												s_message = ip2.i18n({
													da: "Opretter filer....",
													en: "Creating files..."
												});
												i_self.setLoading(s_message);
											}

											if (Ext.ux.file.util.Handler.hasFileManager()) {
												Ext.ux.file.util.Handler.createRecords(s_uploadpath, a_create, false, function(a_records) {
													b_create = false;
													Ext.Array.each(a_records, function(i_record) {
														a_result.push(i_record.data);
													});
													if (!b_update) {
														i_self.setLoading(false);
														i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
													}
													if (b_cancel) {
														i_self.setLoading(false);
														i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
													}
												});
											}
											else {
												Ext.ux.file.util.Handler.uploadFiles(s_uploadpath, a_create, false, function(a_values) {
													b_create = false;
													Ext.Array.each(a_values, function(o_value) {
														a_result.push({
															PATH: s_uploadpath,
															NAME: o_value.file.name
														});
													});
													if (!b_update) {
														i_self.setLoading(false);
														i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
													}
													if (b_cancel) {
														i_self.setLoading(false);
														i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
													}
												});
											}
										}
									});
								}
								i_self.setDragging(0);
								var i_dropzone = i_self.getZone();
								var i_el = i_dropzone.getEl();
								if (i_el.dom) {
									i_el.setStyle("display", "none");
									i_el.setStyle("z-index", "0");
								}
							}
						},
						dragenter: {
							fn: function(i_dropbox, o_event) {

								var i_plugin = i_dropbox.getDDPlugin();
								var a_items = o_event.dataTransfer.items || o_event.dataTransfer.files;
								var s_dmd = o_config.dmdName || "";
								i_self.setOverZone(true);

								if (s_dmd) {
									if (!(ip2.isAccessible("app." + s_dmd + ".data.create") ||
										ip2.isAccessible("app." + s_dmd + ".data." + i_self.entity.name + ".create")) ||
										i_dropbox.maxItems < a_items.length) {
										i_dropbox.addCls(i_plugin.failureCls);
										i_plugin.enableDrop = false;
									}
								}
								else {
									if (!i_dropbox.maxItems < a_items.length) {
										i_dropbox.addCls(i_plugin.failureCls);
										i_plugin.enableDrop = false;
									}
								}
							}
						},
						dragleave: {
							fn: function(i_dropbox, o_event) {
								var i_plugin = i_dropbox.getDDPlugin();
								i_plugin.enableDrop = true;
								i_self.setOverZone(false);
							}
						}
					}
				}
			]
		});

		return i_portletItem;
	}
});
Ext.define("Ext.ux.form.field.ISOTimestampPreSaveField", {
	extend: "Ext.ux.form.field.ISOTimestampField",

	alias: "widget.isotimestamppresavefield",

	initComponent: function () {
		var i_self = this;
		i_self.callParent();
	},

	presave: function() {
		var i_self = this;
		var value = ip2.createIsoTimeStamp();
		i_self.setValue(value);
	}
});
Ext.define("Ext.ux.form.field.Html", {

	extend: "Ext.form.FieldContainer",

	mixins: {
		field: 'Ext.form.field.Field'
	},

	isFormField: false,
	alias: "widget.htmlfield",

	initComponent: function () {

		var i_self = this;
		i_self.callParent();

		i_self.initField();
	},

	setValue: function(value) {

		var i_self = this;
		i_self.update(value);
	}
});
Ext.define("Ext.ux.form.field.Combi", {

	extend: "Ext.form.FieldContainer",

	isFormField: false,
	alias: "widget.fieldcombi",
	fields: [],
	layout: {
		type: "hbox",
		align: "stretch"

	},
	defaults: {
		margin: "0 5 0 0"
	},

	initComponent: function () {

		var i_self = this;
		i_self.callParent();
	}
});
Ext.define("Ext.ux.help.view.Manager", {

	extend: "Ext.panel.Panel",
	alias: "widget.helpmanager",
	layout: "border",

	statics: {
		HELP_TEXT_CMP_ID: Ext.id(null, 'hlptxt-')
	},

	initComponent: function() {
		var i_self = this;
		i_self.callParent();
		i_self.add(i_self.createLayout());
		i_self.enableBubble("dirtychange");
		return i_self;
	},

	createLayout: function() {

		i_self = this;

		var a_items = [
			i_self.createWest(),
			i_self.createCenter()
		];

		return a_items;
	},

	createWest: function() {

		var i_self = this;
		var i_panel = Ext.widget("panel", {
			itemId: "helper-west",
			region: "west",
			width: 200,
			title: ip2.i18n({
				da: "Applikationer",
				en: "Applications"
			}),
			layout: "fit",
			items: [
				i_self.createTree()
			]
		});
		return i_panel;
	},

	createTree: function() {

		var i_self = this;
		var o_ns = ip2.resource.get("adm.ns", true);

		var i_tree = Ext.widget("treepanel", {
			useArrows: true,
			rootVisible: false,
			animate: false,
			listeners: {
				select: {
					fn: function(i_node, i_record) {
						if (i_record.get("leaf")) {
							var i_center = i_self.getCenter();
							i_center.setLoading(true);

							i_self.doSave(function(a_records) {
								var i_selected = i_record;
								var s_app = i_record.get("label").split(".").shift();

								i_self.getApplicationSteps(s_app, function(a_items) {
									Ext.Array.each(a_items, function(o_item) {
										if (o_item.label == i_selected.get("label")) {
											i_selected.set("helps", o_item.helps);
										}
									});

									var o_item = i_selected.data;
									var i_form = i_self.createUI(o_item);

									i_center.removeAll(true);
									i_center.add(i_form);
									i_center.setLoading(false);
									i_self.fireEvent("dirtychange", i_self, false);
								});
							});
						}
					}
				}
			}
		});

		var i_root = i_tree.getRootNode();

		i_self.getApplications(function(a_items) {

			i_root.appendChild(a_items);

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

				var i_item = o_item;

				i_self.getApplicationSteps(i_item.name, function(a_items) {
					var a_result = a_items;
					i_root.cascadeBy(function(i_node) {

						if (i_node.get("name") == i_item.name) {

							Ext.Array.each(a_result, function(o_result) {
								o_result.leaf = true;
								if (o_result.label) {
									var s_title = ip2.i18n(o_ns.getTextValue(o_result.label));
									if (!Ext.isString(s_title)) {
										s_title = "";
									}
									o_result.text = s_title;
								}
							});

							i_node.appendChild(a_result);
						}
					});
				});
			});
		});
		i_self.tree = i_tree;
		return i_tree;
	},

	createUI: function(o_item) {

		var i_self = this;
		var a_groups = [];
		var o_ns = ip2.resource.get("adm.ns", true);

		var a_fields = i_self.createFields(o_item.helps);
		var i_form = Ext.widget("form", {
			layout: "anchor",
			items: a_fields,
			bodyPadding: 5,
			autoScroll: true,
			buttons: [
				{
					text: "Gem",
					handler: function() {
						i_self.setLoading(true);
						i_self.doSave(function(a_records) {
							i_self.setLoading(false);
						});
					}
				}
			]
		});
		return i_form;
	},

	createFields: function(o_helps) {

		var i_self = this;

		var a_fields = [];
		var a_keys = Ext.Object.getKeys(o_helps);
		var o_xpd = ip2.resource.get("help.xpd", true);
		var o_ns = ip2.resource.get("adm.ns", true);

		Ext.Array.each(a_keys, function(s_key) {

			var o_help = o_helps[s_key];
			var o_props = o_help.hlpprop || {};

			var a_xpdFields = Ext.ux.xpd.Handler.getFieldsWithValues(o_xpd, 1, o_props);
			Ext.Array.each(a_xpdFields, function(i_field) {
				i_field.propname = i_field.name;
				i_field.name = s_key + "." + i_field.name;
			});

			var s_title = ip2.i18n(o_ns.getTextValue(o_help.label));

			if (o_help.context) {
				var s_enumKey = 'helpContext';
				var i_resource = ip2.resource.get('adm.ns', true);
				var s_context = String(i_resource.getEnumValue(s_enumKey + '~' + o_help.context));

				// Enum value not defined / translated.
				if (!s_context) {
					s_context = o_help.context.replace(/^./, function(_) {
						return _;
					});
				}

				s_title += ' (' + s_context + ')';
			}

			var i_field = Ext.widget("fieldset", {
				name: s_key,
				title: s_title,
				collapsible: true,
				token: o_help.hlphlptkn != undefined ? o_help.hlphlptkn : 0,
				cmpid: Ext.getClass(i_self).HELP_TEXT_CMP_ID,
				prop: "HLPPROP",
				defaults: {
					margins: "0 5 0 0 "
				},
				layout: {
					type: "anchor"
				},
				items: a_xpdFields,
				getValue: function() {
					var i_fieldset = this;
					var a_fields = i_fieldset.items.items;
					var o_return = {};
					Ext.Array.each(a_fields, function(i_field) {
						var s_name = i_field.name.split(".").pop();
						var s_value = i_field.getValue();
						o_return[s_name] = s_value;
					});
					return o_return;
				}
			});

			a_fields.push(i_field);
		});

		return a_fields;
	},

	createCenter: function() {

		var i_self = this;

		var i_panel = Ext.widget("panel", {
			itemId: "helper-center",
			region: "center",
			title: ip2.i18n({
				da: "Hjælpetekster",
				en: "Help texts"
			}),
			layout: "fit"
		});

		return i_panel;
	},

	getApplications: function(f_callback) {

		var i_self = this;
		var o_ns = ip2.resource.get("adm.ns", true);

		Ext.Ajax.request({
			url: '/wsh-services/wshhelp.aspx',
			params: {
				action: "listapps"
			},
			success: function (response) {
				var result = {};
				result = JSON.parse(response.responseText);
				var a_items = result.items || [];
				Ext.Array.each(a_items, function(o_item) {
					var s_title = ip2.i18n(o_ns.getTextValue(o_item.label));
					if (!Ext.isString(s_title)) {
						s_title = "";
					}
					o_item.leaf = false;
					o_item.text = s_title;
				});
				f_callback(a_items);
			}
		});
	},

	getApplicationSteps: function(s_application, f_callback) {

		var i_self = this;

		Ext.Ajax.request({
			url: '/wsh-services/wshhelp.aspx',
			params: {
				action: "liststeps",
				app: s_application
			},
			success: function (response) {
				var result = {};
				result = JSON.parse(response.responseText);
				var a_items = result.items || [];
				f_callback(a_items);
			}
		});
	},

	getCenter: function() {
		var i_self = this;
		var i_center;
		if (i_self._centerpanel) {
			i_center = i_self._centerpanel;
		}
		else {
			var center = i_self.down("#helper-center");
			if (center) {
				i_self._centerpanel = center;
				i_center = center;
			}
		}
		return i_center;
	},

	doSave: function(f_callback) {

		var i_self = this;
		var a_fieldsets = i_self.query("[cmpid=" +
			Ext.getClass(i_self).HELP_TEXT_CMP_ID + "]");
		var a_records = [];
		Ext.Array.each(a_fieldsets, function(i_fieldset) {
			var n_token = i_fieldset.token;
			var s_prop = i_fieldset.prop;
			var o_value = i_fieldset.getValue();
			var i_record = i_self.getModel().create();
			i_record.set(i_record.idProperty, n_token);
			i_record.set("HLPID", i_fieldset.name);
			i_record.set(s_prop, JSON.stringify(o_value));
			a_records.push(i_record);
		});
		i_self.upsertRecords(a_records, f_callback);
	},

	getModel: function() {

		if (!i_self.model) {
			var f_model = ip2.model({
				dmd: "dmd/webshop.dmd",
				entityName: "WSHHLPET00",
				context: 'form',
				uiName: "portfolio"
			});
			i_self.model = f_model;
		}
		return i_self.model;
	},

	upsertRecords: function(a_records, f_callback) {
		var i_self = this;
		var a_batch = [];

		Ext.Array.each(a_records, function (i_record) {
			var key = {};
			key[i_record.idProperty] = i_record.get(i_record.idProperty);
			a_batch.push({
				type: 'upsert',
				dmd: 'dmd/webshop.dmd',
				entity: "WSHHLPET00",
				key: key,
				row: i_record.data
			});
		});

		Ext.Ajax.request({
			url: '/ip2-Services/ip2dmdproxy.aspx',
			jsonData: {
				transaction: {
					batch: a_batch
				}
			},
			success: function (o_response) {
				var o_result = JSON.parse(o_response.responseText);
				Ext.Array.each(o_result.batch, function(o_batch, n_index) {
					Ext.Array.each(o_batch.row, function(value) {
						a_records[n_index].set("HLPHLPTKN", value);
					});
				});
				f_callback(a_records);
			}
		});
	}
});
Ext.define('Ext.ux.form.field.PrePostTextField', {
	extend: 'Ext.form.field.Text',
	alias: 'widget.preposttextfield',

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
	},

	onPreLoad: function(n_value) {
		var i_self = this;
		var o_preConfig = i_self.preConfig || {};

		var o_params = {};

		o_params[o_preConfig.token] = n_value;
		o_params.action = o_preConfig.action;

		Ext.Ajax.request({
			url: o_preConfig.url,
			params: o_params,
			success: function (o_response) {

				var o_result = JSON.parse(o_response.responseText);
				if (o_result.success && o_result[o_preConfig.property] != i_self.getValue()) {
					i_self.suspendCheckChange++;
					i_self.setValue(o_result[o_preConfig.property]);
					i_self.resetOriginalValue();
					i_self.suspendCheckChange--;
				}
			}
		});
	},

	onPostSave: function(n_value, f_callback) {
		var i_self = this;
		var s_value = i_self.getValue();
		var o_postConfig = i_self.postConfig || {};

		var o_params = {};

		o_params[o_postConfig.token] = n_value;
		o_params[o_postConfig.property] = s_value;
		o_params.action = o_postConfig.action;

		Ext.Ajax.request({
			url: o_postConfig.url,
			params: o_params,
			success: function (o_response) {

				f_callback();
			}
		});
	}
});
Ext.define("Ext.ux.form.field.ComboInline", {
	extend: "Ext.form.field.ComboBox",
	alias: "widget.comboinline",

	config: {
		valueField: "value",
		displayField: "key"
	},

	initComponent: function() {

		var i_self = this;

		Ext.apply(i_self, {
			queryMode: "local",
			displayField: i_self.getDisplayField(),
			valueField: i_self.getValueField(),
			triggerAction: 'all',
			displayTpl: i_self.getDisplayTemplate(),
			tpl: i_self.getItemTemplate(),
			maxLength: 1000,
			store: Ext.create("Ext.data.Store", {
				fields: [
					{ name: "key", type: "auto" },
					{ name: "value", type: "auto" }
				],
				data: i_self.values,
				idProperty: i_self.getValueField()
			})
		});

		i_self.callParent();

		return i_self;
	},

	getDisplayTemplate: function() {

		var i_self = this;

		var i_template = Ext.create('Ext.XTemplate',
			'<tpl for=".">',
				'{[this.renderer(values.key)]}',
			'</tpl>',
			{
				renderer: function(s_key) {
					if (s_key) {
						return ip2.i18n(s_key);
					}
					else {
						return "";
					}
				}
			}
		);
		return i_template;
	},

	getItemTemplate: function() {

		var i_self = this;

		var i_template = Ext.create('Ext.XTemplate',
			'<tpl for=".">',
				'<li role="option" class="x-boundlist-item">',
					'{[this.renderer(values.key)]}',
				'</li>',
			'</tpl>',
			{
				renderer: function(s_key) {
					if (s_key) {
						return ip2.i18n(s_key);
					}
					else {
						return "";
					}
				}
			}
		);
		return i_template;
	},

	renderer: function(value) {

		var i_field = this;
		var s_return = value;
		Ext.Array.each(i_field.values, function(o_record) {
			if (o_record.value == value) {
				s_return = ip2.i18n(o_record.key);
			}
		});
		return s_return;
	}
});
Ext.define("Ext.ux.form.field.ComboSql", {
	extend: "Ext.form.field.ComboBox",
	alias: "widget.combosql",

	config: {
		action: "searchRow",
		columns: "",
		schema: "",
		table: "",
		valueColumn: "",
		keyColumn: "",
		options: null,
		cte: false,
		where: "",
		displayField: "key",
		valueField: "value",
		triggered: false,
		params: null,
		url: "",
		rootProperty: "rows",
		totalProperty: "totalProperty",
		actionMethods: {}
	},

	queryParam: "search",

	queryCaching: false,

	triggers: {
		clear: {
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			weight: 1,
			handler: "onClearClick",
			hidden: true,
			scope: "this"
		},
		picker: {
			weight: 2,
			handler: "onTriggerClick",
			scope: "this"
		}
	},

	listeners: {
		afterrender: {
				fn: function (i_self) {
					var value = i_self.getValue();
					if (i_self.inputEl) {

						i_self.setIconCls("x-ux-search-icon");

						if (!value) {
							i_self.getTrigger("clear").hide();
						}
						else {
							i_self.getTrigger("clear").show();
						}

						if (i_self.readOnly) {
							i_self.setIconCls("");
							i_self.getTrigger("clear").hide();
						}
					}
				},
				single: true
			},
		change: {
			fn: function(i_self, value) {
				if (i_self.inputEl) {
					if (!value || (value && value.length === 0)) {
						i_self.allQuery = "";
						i_self.clearValue();
						i_self.getTrigger("clear").hide();
					}
					else {
						i_self.allQuery = i_self.lastQuery;
						if (!i_self.readOnly) {
							i_self.getTrigger("clear").show();
						}
					}
				}
			}
		}
	},

	initComponent: function() {

		var i_self = this;

		var o_actionMethods = i_self.getActionMethods() || {};

		Ext.applyIf(o_actionMethods, {
			create: "POST",
			read: "POST",
			update: "PATCH",
			destroy: "DELETE"
		});

		Ext.apply(i_self, {
			queryMode: "remote",
			displayField: i_self.getDisplayField(),
			valueField: i_self.getValueField(),
			triggerAction: "all",
			minChars: 1,
			typeAhead: false,
			maxLength: 1000,
			displayTpl: i_self.getDisplayTemplate(),
			tpl: i_self.getItemTemplate()
		});

		var o_options = i_self.getOptions() || {};

		Ext.applyIf(o_options, {
			library: i_self.getSchema(),
			file: i_self.getTable()
		});

		var i_model;

		if (o_options.schema && o_options.table) {
			if (Ext.ClassManager.isCreated(Ext.dynapp.util.Service.getModelName(o_options))) {
				i_model = Ext.ClassManager.get(Ext.dynapp.util.Service.getModelName(o_options));
			}
			else {
				i_model = Ext.define(Ext.dynapp.util.Service.getModelName(o_options), {
					extend: "Ext.data.Model",
					fields: [
						{ name: i_self.getDisplayField(), type: "auto" },
						{ name: i_self.getValueField(), type: "auto" }
					],
					idProperty: i_self.getValueField(),
					proxy: {
						url: Ext.dynapp.util.Service.getPath(o_options),
						type: "ajax",
						paramsAsJson: true,
						actionMethods: {
							read: "POST"
						},
						reader: {
							type: "json",
							rootProperty: "rows",
							totalProperty: "totalProperty"
						}
					}
				});
			}
		}
		else {
			i_model = Ext.define(ip2.unique("sqlcombo-"), {
				extend: "Ext.data.Model",
				fields: [
					{ name: i_self.getDisplayField(), type: "auto" },
					{ name: i_self.getValueField(), type: "auto" }
				],
				idProperty: i_self.getValueField(),
				proxy: {
					url: i_self.getUrl(),
					type: "ajax",
					paramsAsJson: o_actionMethods.read == "POST",
					actionMethods: o_actionMethods,
					reader: {
						type: "json",
						rootProperty: i_self.getRootProperty(),
						totalProperty: i_self.getTotalProperty()
					}
				}
			});
		}

		var i_store = Ext.create("Ext.data.Store", {
			model: i_model,
			remoteSort: true,
			autoLoad: false,
			autoSync: false,
			pageSize: 100
		});

		i_store.on({
			beforeload: {
				fn: function(i_store, i_operations) {

					var s_value = i_self.getValue() || "";
					var i_proxy = i_store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();

					Ext.apply(o_extraParams, {
						action: i_self.getAction(),
						search: "",
						columns: i_self.getColumns(),
						start: 0,
						limit: 100,
						cte: i_self.getCte()
					});

					Ext.Object.merge(o_extraParams, i_self.getParams(), i_self.getExtraParams());

					if (o_extraParams.where) {
						delete o_extraParams.where;
					}

					var o_params = i_operations.getParams() || {};

					if (i_self.getCte() && s_value) {
						o_extraParams.where = i_self.getDisplayField() + " like '%" + s_value + "%'";
						delete o_extraParams.search;
						delete o_params.search;
					}
					else if (i_self.getValueColumn() && !o_params.search) {
						o_extraParams.where = i_self.getValueColumn() + " = '" + s_value + "'";
						delete o_extraParams.search;
						delete o_params.search;
					}
				}
			}
		});

		i_self.store = i_store;
		i_self.callParent();

		return i_self;
	},

	getExtraParams: function() {

		var i_self = this;
		return i_self.params || {};
	},

	initValue: function() {

		var i_self = this;

		var value = i_self.value;

		var a_loaded = [];

		if (Ext.isEmpty(value)) {
			value = null;
		}

		var a_values = Ext.Array.from(value);

		var n_load = a_values.length;

		var i_store = i_self.getStore();

		if (n_load) {

			var i_proxy = i_store.getProxy();
			var o_extraParams = i_proxy.getExtraParams();

			o_extraParams[i_self.getValueField()] = value;

			i_store.load({
				callback: function(a_records, i_store) {

					i_self.suspendCheckChange++;
					i_self.setValue(value);
					i_self.suspendCheckChange--;
					i_self.originalValue = i_self.lastValue = i_self.getValue();
					i_self.resetOriginalValue();

					delete o_extraParams[i_self.getValueField()];

					i_proxy.setExtraParams(o_extraParams);
				}
			});
		}
		else {
			i_self.originalValue = i_self.lastValue = i_self.getValue();
			i_self.resetOriginalValue();
		}
	},

	onTriggerClick: function() {

		var i_self = this;
		i_self.setTriggered(true);
		i_self.queryCaching = false;
		i_self.callParent(arguments);
	},

	getWhereTemplate: function(o_options) {

		var i_self = this;
		var o_values = {
			library: o_options.library,
			file: o_options.file
		};
		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl>",
				i_self.getWhere(),
			"</tpl>"
		);

		var i_compiled = i_tpl.compile();
		return i_compiled.apply(o_values);
	},

	getDisplayTemplate: function() {

		var i_self = this;

		var s_displayField = i_self.getDisplayField();

		var i_template = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"{[this.renderer(values ? values[\"" + s_displayField + "\"] : \"\")]}",
			"</tpl>",
			{
				renderer: function(value) {
					return ip2.i18n(value);
				}
			}
		);
		return i_template;
	},

	getItemTemplate: function() {

		var i_self = this;

		var s_displayField = i_self.getDisplayField();

		var i_template = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"<li role=\"option\" class=\"x-boundlist-item\">",
					"{[this.renderer(values ? values[\"" + s_displayField + "\"] : \"\")]}",
				"</li>",
			"</tpl>",
			{
				renderer: function(value) {
					return ip2.i18n(value);
				}
			}
		);
		return i_template;
	},

	onClearClick: function () {

		var i_self = this;

		i_self.setSelection(null);
		i_self.clearValue();

		return i_self;
	}
});
Ext.define("Ext.ux.form.field.ComboTable", {
	extend: "Ext.form.field.ComboBox",
	alias: "widget.combotable",

	schema: "",
	table: "",
	isLoaded: false,
	queryParam: "query",

	initComponent: function() {

		var i_self = this;
		Ext.apply(i_self, {
			queryMode: 'remote',
			displayField: "key",
			valueField: "value",
			triggerAction: 'all',
			minChars: 1,
			typeAhead: false,
			maxLength: 1000,
			displayTpl: i_self.getDisplayTemplate(),
			tpl: i_self.getItemTemplate()
		});
		var i_model;
		if (Ext.ClassManager.isCreated("model.Table")) {
			i_model = Ext.ClassManager.get("model.Table");
		}
		else {
			var i_model = Ext.define("model.Table", {
				extend: "Ext.data.Model",
				fields: [
					{ name: "key", type: "auto" },
					{ name: "value", type: "auto" }
				],
				idProperty: "key",
				proxy: {
					url: "ip2-services/ip2Services.aspx",
					type: "ajax",
					reader: {
						type: 'json',
						rootProperty: "rows",
						totalProperty: "totalRows"
					}
				}
			});
		}
		var i_store = Ext.create('Ext.data.Store', {
			model: i_model,
			remoteSort: true,
			autoLoad: false,
			autoSync: false,
			pageSize: 100
		});
		i_store.on({
			load: {
				fn: function(store, records) {
					if (!i_self.isLoaded) {
						i_self.isLoaded = true;
						if (i_self.value) {
							i_self.setValue(i_self.value);
						}
					}
				}
			},
			beforeload: {
				fn: function(store) {
					var i_proxy = store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();

					Ext.apply(o_extraParams, {
						plugin: 'DB2',
						func: 'getDataModels',
						lib: i_self.schema,
						limit: -1
					});
				}
			}
		});
		i_self.store = i_store;
		i_self.callParent();
		i_self.on({
			afterrender: {
				fn: function(item) {
					var store = item.getStore();
					store.load();
				}
			}
		});

		return i_self;
	},

	getWhereTemplate: function(o_options) {

		var i_self = this;
		var o_values = {
			library: o_options.library,
			file: o_options.file
		};
		var i_tpl = Ext.create('Ext.XTemplate',
			'<tpl for=".">',
				i_self.where,
			'</tpl>'
		);
		var div = document.createElement("div");
		var i_compiled = i_tpl.compile();
		div = i_compiled.overwrite(div, o_values);
		var s_value = div.data;
		delete div;
		return s_value;
	},

	getDisplayTemplate: function() {

		var i_self = this;

		var i_template = Ext.create('Ext.XTemplate',
			'<tpl for=".">',
				'{[this.renderer(values.key)]}',
			'</tpl>',
			{
				renderer: function(s_key) {
					return ip2.i18n(s_key);
				}
			}
		);
		return i_template;
	},

	getItemTemplate: function() {

		var i_self = this;

		var i_template = Ext.create('Ext.XTemplate',
			'<tpl for=".">',
				'<li role="option" class="x-boundlist-item">',
					'{[this.renderer(values.key)]}',
				'</li>',
			'</tpl>',
			{
				renderer: function(s_key) {
					return ip2.i18n(s_key);
				}
			}
		);
		return i_template;
	}
});
Ext.define("Ext.ux.form.field.CollectionPicker", {
	extend: "Ext.form.field.ComboBox",
	alias: "widget.collectionpickerfield",

	config: {
		xpd: "",
		displayField: "value",
		valueField: "key",
		values: null
	},

	initComponent: function() {

		var i_self = this;
		i_self.init();
		Ext.apply(i_self, {
			queryMode: "local",
			triggerAction: 'all',
			displayTpl: i_self.getDisplayTemplate(),
			tpl: i_self.getItemTemplate(),
			maxLength: 1000,
			store: Ext.create("Ext.data.Store", {
				fields: [
					{ name: i_self.getValueField(), type: "int" },
					{ name: i_self.getDisplayField(), type: "auto" }
				],
				idProperty: i_self.getValueField(),
				data: i_self.getValues()
			})
		});
		i_self.callParent();
		return i_self;
	},

	init: function() {

		var i_self = this;
		var s_xpd = i_self.getXpd();
		var o_xpd = ip2.resource.get(s_xpd);

		i_self.setXpd(o_xpd);

		var a_data = i_self.getValues();

		if (!a_data) {
			i_self.setValues(i_self.getRecords());
		}
	},

	getDisplayTemplate: function() {

		var i_self = this;
		var o_xpd = i_self.getXpd();
		var o_collections = o_xpd.collections;

		var i_template = Ext.create('Ext.XTemplate',
			'<tpl for=".">',
				'{[this.renderer(values.key)]}',
			'</tpl>',
			{
				renderer: function(s_key) {

					var s_value = s_key;

					if (s_key) {

						Ext.Object.each(o_collections, function(s_collection) {
							var o_collection = o_collections[s_collection];
							if (o_collection.id == s_key) {
								s_value = ip2.xpd.translate(o_xpd, o_collection.title);
								return false;
							}
						});
					}
					return s_value;
				}
			}
		);
		return i_template;
	},

	getItemTemplate: function() {

		var i_self = this;
		var o_xpd = i_self.getXpd();
		var o_collections = o_xpd.collections;

		var i_template = Ext.create('Ext.XTemplate',
			'<tpl for=".">',
				'<li role="option" class="x-boundlist-item">',
					'{[this.renderer(values.key)]}',
				'</li>',
			'</tpl>',
			{
				renderer: function(s_key) {

					s_value = s_key;

					if (s_key) {

						var s_value = s_key;

						Ext.Object.each(o_collections, function(s_collection) {
							var o_collection = o_collections[s_collection];
							if (o_collection.id == s_key) {
								s_value = ip2.xpd.translate(o_xpd, o_collection.title);
								return false;
							}
						});
					}
					return s_value;
				}
			}
		);
		return i_template;
	},

	getRecords: function() {

		var i_self = this;
		var a_data = [];
		var o_xpd = i_self.getXpd();
		var o_collections = o_xpd.collections;

		Ext.Object.each(o_collections, function(s_collection) {
			if (s_collection !== "all") {
				var o_collection = o_collections[s_collection];
				var o_value = {
					key: o_collection.id,
					value: o_collection.title
				};
				a_data.push(o_value);
			}
		});

		o_xpd = i_self.getXpd();

		Ext.Array.each(a_data, function(o_data) {
			o_data.value = ip2.xpd.translate(o_xpd, o_data.value);
		});

		return a_data;
	}
});
Ext.define("Ext.ux.form.field.EnumComboBox", {

	extend: "Ext.form.field.ComboBox",

	alias: [
		"widget.enumcombobox",
		"widget.enumpicker"
	],

	config: {
		file: "adm.ns",
		"enum": "",
		regexp: "webr~{0}~",
		search: null
	},

	queryMode: "local",

	forceSelection: true,

	valueField: "key",

	displayField: "text",

	initComponent: function() {

		var i_self = this;
		var i_store = i_self.createStore();

		i_self.store = i_store;
		i_self.callParent(arguments);
	},

	createStore: function() {

		var i_self = this;
		var s_regexp = i_self.getRegexp();
		var s_search = i_self.getSearch();

		s_regexp = s_regexp.replace("{0}", i_self.getEnum());

		var s_valueKey = i_self.valueField || 'key';
		var s_displayKey = i_self.displayField || 'text';

		var a_data = [];

		var o_enum = ip2.resource.get(i_self.getFile());
		if (o_enum) {
			var i_dynamicNs = new ip2.DynamicNS(o_enum);

			var a_data = [];
			var a_keys = i_dynamicNs.getEnumLayoutKeys(i_self.getEnum());

			Ext.Array.each(a_keys, function(s_key) {

				var o_value = i_dynamicNs.getEnumValue(s_key);

				if (s_regexp) {
					s_key = s_key.replace(new RegExp(s_regexp, 'g'), "" || "");
				}
				else if (s_search) {
					s_key = s_key.replace("", "" || "");
				}

				var o_dataValue = {};
				o_dataValue[s_valueKey] = s_key;
				o_dataValue[s_displayKey] = ip2.i18n(o_value);
				a_data.push(o_dataValue);
			});

			a_data.sort(function (a, b) {

				var s_keyA = a[s_valueKey] || 0;
				var s_keyB = b[s_valueKey] || 0;

				if (Ext.isNumber(parseFloat(s_keyA)) && Ext.isNumber(parseFloat(s_keyA))) {
					return parseFloat(s_keyA) > parseFloat(s_keyB);
				}
				else {

					s_keyA = a[s_displayKey];
					s_keyB = b[s_displayKey];

					return s_keyA.toLowerCase() > s_keyB.toLowerCase();
				}
			});
		}

		var i_store = Ext.create("Ext.data.Store", {
			fields: [
				{ name: s_valueKey, type: 'auto' },
				{ name: s_displayKey, type: 'auto' }
			],
			proxy: {
				type: 'memory'
			}
		});

		i_store.loadData(a_data);

		return i_store;
	}
});
Ext.define("Ext.ux.form.field.FileEditor", {

	extend: "Ext.form.field.Text",

	alias: [
		"widget.ux.form.field.fileeditor",
		"widget.field.fileeditor"
	],

	requires: [
		"Ext.ux.file.view.Editor"
	],

	triggers: {
		edit: {
			cls: "pf-edit",
			handler: "onEditClick",
			weight: 1,
			scope: "this"
		}
	},

	config: {
		fileExtension: [
			{
				"ext": "*",
				"desc": "All Files (*.*)"
			}
		]
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
	},

	onEditClick: function() {

		var i_self = this;

		var value = i_self.getValue();

		if (value) {

			var i_window = Ext.widget("window", {
				width: 800,
				height: 600,
				modal: true,
				layout: "fit"
			});

			var i_editor = Ext.widget("file.editor", {
				file: value,
				useOwner: true,
				allowNew: false,
				allowOpen: false,
				fileExtension: i_self.getFileExtension(),
				listeners: {
					filesave: {
						fn: function(i_editor, s_file) {

							i_self.setValue(s_file);

							i_window.close();
						}
					}
				}
			});

			i_window.add(i_editor);

			i_window.show();
		}
	}
});
Ext.define("Ext.ux.form.field.Registration", {

	alias: [
		"widget.ux.form.field.registration"
	],

	extend: "Ext.form.FieldContainer",

	mixins: {
		field: "Ext.form.field.Field"
	},

	config: {
		actionBar: null,
		grid: null
	},

	minWidth: 300,
	minHeigt: 200,

	layout: "fit",

	listeners: {
		afterrender: {
			fn: function(i_field) {
				i_field.fireEvent("change", i_field, i_field.getValue());
			}
		},
		change: {
			fn: function(i_field, value) {

				var i_user = Portfolio.util.Handler.getUser();

				var i_grid = i_field.getGrid();
				var i_store = i_grid.getStore();

				var n_index = i_store.find("USREML", i_user.get("USREML"));

				var i_actionBar = i_field.getActionBar();
				var i_buttion = i_actionBar.items.get("button-register");

				i_buttion[n_index > -1 ? "disable" : "enable"]();
			}
		}
	},

	initComponent: function() {

		var i_self = this;

		i_self.callParent(arguments);
		i_self.add(i_self.createGrid());
		i_self.initField();

		return i_self;
	},

	createActionBar: function() {

		var i_self = this;

		var i_actionBar = Ext.widget("toolbar", {
			dock: "top",
			items: [
				{
					xtype: "button",
					iconCls: "pf-add",
					itemId: "button-register",
					text: ip2.i18n({
						da: "Tilmeld",
						en: "Register"
					}),
					handler: function(i_button) {

						var i_user = Portfolio.util.Handler.getUser();

						var i_grid = i_self.getGrid();
						var i_store = i_grid.getStore();

						i_store.loadData([{
							USRUSRTKN: i_user.get("USRUSRTKN"),
							NOTIFY: true,
							USREML: i_user.get("USREML")
						}], true);
					}
				}
			]
		});

		i_self.setActionBar(i_actionBar);

		return i_actionBar;
	},

	createGrid: function() {

		var i_self = this;

		var i_grid = Ext.widget("gridpanel", {
			columns: i_self.createColumns(),
			store: i_self.createStore(),
			listeners: {
				itemcontextmenu: {
					fn: function(i_view, i_record, i_html, n_index, i_event) {

						i_event.stopEvent();

						var i_user = Portfolio.util.Handler.getUser();

						var a_coords = i_event.getXY();

						if (i_record.get("USREML") == i_user.get("USREML")) {

							var a_items = [];

							var i_delete = Ext.widget("menuitem", {
								text: ip2.i18n({
									da: "Slet",
									en: "Delete"
								}),
								itemId: "itmDelete",
								iconCls: "pf-delete",
								handler: function () {

									var i_grid = i_self.getGrid();
									var i_store = i_grid.getStore();

									i_store.remove(i_record);
								}
							});

							a_items.push(i_delete);

							var i_menu = Ext.create("Ext.menu.Menu", {
								allowOtherMenus: false,
								items: a_items
							});

							i_menu.showAt([a_coords[0], a_coords[1]]);
						}
					}
				}
			}
		});

		i_grid.addDocked(i_self.createActionBar());

		i_self.setGrid(i_grid);

		return i_grid;
	},

	createStore: function() {

		var i_self = this;

		var i_store = Ext.create("Ext.data.Store", {
			autoLoad: false,
			fields: [
				{
					name: "NOTIFY",
					type: "boolean"
				},
				{
					name: "USREML",
					type: "string"
				}
			],
			listeners: {
				datachanged: {
					fn: function(i_store) {
						i_self.checkChange();
					}
				},
				update: {
					fn: function() {
						i_self.checkChange();
					}
				}
			}
		});

		return i_store;
	},

	createColumns: function() {

		var a_columns = [
			{
				xtype: "checkcolumn",
				dataIndex: "NOTIFY",
				text: ip2.i18n({
					da: "Aktiv",
					en: "Active"
				}),
				width: 80,
				sortable: false,
				menuDisabled: true,
				draggable: false,
				listeners: {
					beforecheckchange: {
						fn: function(i_column, n_index, b_checked) {

							var i_owner = i_column.ownerCt;
							var i_grid = i_owner.grid;
							var i_store = i_grid.getStore();
							var i_record = i_store.getAt(n_index);

							var i_user = Portfolio.util.Handler.getUser();

							return i_user.get("USREML") == i_record.get("USREML");
						}
					}
				}
			},
			{
				dataIndex: "USREML",
				sortable: false,
				menuDisabled: true,
				draggable: false,
				text: ip2.i18n({
					da: "E-mail",
					en: "E-mail"
				}),
				flex: 1
			}
		];

		return a_columns;
	},

	getValue: function() {

		var i_self = this;

		var i_grid = i_self.getGrid();
		var i_store = i_grid.getStore();

		var a_records = i_store.getRange();

		var a_data = [];

		Ext.Array.each(a_records, function(i_record) {

			a_data.push(i_record.getData());
		});

		return Ext.encode(a_data);
	},

	setValue: function(value) {

		var i_self = this;
		var i_grid = i_self.getGrid();
		var i_store = i_grid.getStore();

		if (Ext.isEmpty(value, false)) {
			value = null;
		}

		if (Ext.isBoolean(value)) {

			var i_user = Portfolio.util.Handler.getUser();

			value = {
				USRUSRTKN: i_user.get("USRUSRTKN"),
				NOTIFY: true,
				USREML: i_user.get("USREML")
			};
		}

		var a_values = Ext.Array.from(value);

		if (Ext.isString(value)) {
			value = Ext.decode(value, true) || "";

			a_values = Ext.Array.from(value);
		}

		i_store.loadData(a_values);

		return i_self.mixins.field.setValue.call(i_self, i_self.getValue());
	},

	isDirty: function() {

		var i_self = this;

		var s_originalValue = i_self.originalValue;
		var s_value = i_self.getValue();

		return s_originalValue != s_value;
	}
});
if (!Ext.ClassManager.isCreated("Ext.ux.icon.view.model.DataView")) {
	Ext.define("Ext.ux.icon.view.model.DataView", {
		extend: "Ext.data.Model",
		fields: [
			{ name: "keyword", type: "auto" },
			{ name: "icon", type: "auto" }
		],
		idProperty: "icon",
		proxy: {
			url: "/ip2-services/ip2transaction.aspx",
			type: "ajax",
			paramsAsJson: true,
			$configStrict: false,
			reader: {
				type: "json",
				rootProperty: "rows",
				totalProperty: "totalRows"
			},
			getMethod: function(request) {
				return "POST";
			}
		}
	});
}
Ext.define("Ext.ux.icon.view.DataView", {
	extend: "Ext.view.View",
	alias: "widget.ux.icon.view.dataview",

	config: {
		search: null,
		searchBar: null,
		choiseBar: null,
		actionFn: Ext.emptyFn,
		choise: null
	},

	itemSelector: 'div.record-wrap',
	selectedItemCls: "x-ux-icon-selected-item",
	layout: "anchor",
	autoScroll: true,

	initComponent: function () {

		var i_self = this;
		i_self.store = i_self.createStore();
		i_self.tpl = i_self.createTemplate();
		i_self.callParent();
		i_self.createListeners();
		return i_self;
	},

	createListeners: function() {

		var i_self = this;
		i_self.on({
			afterrender: {
				fn: function(i_view) {

					var i_navigationModel = i_view.getNavigationModel();
					i_navigationModel.focusCls = "x-ux-icon-selected";
				}
			},
			itemdblclick: {
				fn: function(i_view, i_record) {
					var f_action = i_view.getActionFn();
					f_action(i_self.getPath(i_record));
				}
			},
			itemkeyup: {
				fn: function(i_view, i_record, i_item, n_index, i_event) {
					if (i_event.getKey() == Ext.event.Event.ENTER) {
						var f_action = i_view.getActionFn();
						f_action(i_self.getPath(i_record));
					}
				}
			}
		});
	},

	createTopBars: function() {

		var i_self = this;

		var i_searchBar = Ext.widget("toolbar", {
			itemId: "searchBar",
			items: [
				i_self.createSearch()
			],
			docked: "top"
		});

		var i_choiseBar = Ext.widget("toolbar", {
			itemId: "choiseBar",
			items: [
				i_self.createChoises()
			],
			docked: "top"
		});

		i_self.setSearchBar(i_searchBar);
		i_self.setChoiseBar(i_choiseBar);

		return [i_searchBar, i_choiseBar];
	},

	getPath: function(i_record) {

		var i_self = this;
		var i_radiogrp = i_self.getChoise();
		var o_value = i_radiogrp.getValue();

		return "/system/images/icons/extjs5/" + o_value.folder + "/16x16/" + i_record.get("icon") + ".png";
	},

	createChoises: function() {

		var i_self = this;

		var i_radiogrp = Ext.widget("radiogroup", {
			fieldLabel: ip2.i18n({
				da: "Udgave",
				en: "Choise"
			}),
			margin: "0 5 0 5",
			labelWidth: 50,
			columns: 4,
			vertical: false,
			flex: 1,
			itemId: "radiogrpchoises",
			items: [
				{
					boxLabel: ip2.i18n({
						da: "Sort",
						en: "Black"
					}),
					name: 'folder',
					inputValue: 'dark_gray',
					checked: true
				},
				{
					boxLabel: ip2.i18n({
						da: "Sort/blå",
						da: "Black/blue"
					}),
					name: 'folder',
					inputValue: 'blue_dark_gray'
				}

			],
			listeners: {
				afterrender: {
					fn: function(i_field) {
						i_field.labelEl.setStyle("vertical-align", "middle");
					}
				},
				change: {
					fn: function(i_field, s_newValue) {

						var i_searchField = i_self.getSearch();
						i_searchField.onSearch(i_searchField);
					}
				}
			}
		});

		i_self.setChoise(i_radiogrp);

		return i_radiogrp;
	},

	createTemplate: function() {

		var i_self = this;

		var i_template = new Ext.XTemplate(
			'<tpl for=".">',
				'<div style="',
					'width: 80px;',
					'float:left;',
					'padding: 5px 5px 5px 5px;',
					'margin: 5px 5px 5px 5px;',
					'" class="record-wrap">',
					'<div style="margin:auto;',
						'width: 32px;',
						'height: 32px;',
						'background-image: url(\'{[this.getUrl(values)]}\');',
						'background-position: center center;',
						'background-size: cover;">',
					'</div>',
					'<h3 style="',
						'font-size:12px;',
						'font-weight:normal;',
						'text-align:center;',
						'white-space: nowrap;',
						'width: 70px;',
						'text-overflow: ellipsis;',
						'overflow: hidden;',
						'margin:0;',
						'">{icon}',
					'</h3>',
				'</div>',
			'</tpl>',
			'<div class="x-clear"></div>',
			{
				getUrl: function(values) {

					var i_template = this;
					var i_radiogrp = i_template.dataview.getChoise();
					var o_value = i_radiogrp.getValue();
					return "/system/images/icons/extjs5/" + o_value.folder + "/32x32/" + values.icon + ".png";
				},
				dataview: i_self
			}
		);
		return i_template;
	},

	createSearch: function() {

		var i_self = this;

		var i_field = Ext.widget("textfield", {
			fieldLabel: ip2.i18n({
				da: "Søg",
				en: "Search"
			}),
			width: 300,
			labelWidth: 50,
			isFormField: false,
			enableKeyEvents: true,
			margin: "0 5 0 5",
			triggers: {
				clear: {
					cls: "x-form-clear-trigger",
					scope: "this",
					hidden: true,
					handler: "onClear"
				},
				search: {
					cls: "x-form-search-trigger",
					scope: "this",
					handler: "onSearch"
				}
			},
			onClear: function(i_field) {
				i_field.setValue("");
				i_field.onSearch(i_field);
			},
			onSearch: function(i_field) {

				var s_value = i_field.getValue();
				var i_trigger = i_field.getTrigger("clear");
				var i_store = i_self.getStore();

				i_trigger[s_value ? "show" : "hide"]();

				if (s_value) {
					i_store.loadPage(1);
				}
				else {
					i_store.loadRawData([]);
				}
			},
			listeners: {
				keydown: {
					fn: function(i_field, i_event) {
						if (i_event.keyCode == i_event.ENTER) {
							i_field.onSearch(i_field);
						}
					}
				}
			}
		});

		i_self.setSearch(i_field);
		return i_field;
	},

	createStore: function() {

		var i_self = this;

		var i_store = Ext.create("Ext.data.Store", {
			model: "Ext.ux.icon.view.model.DataView",
			autoLoad: false,
			pageSize: 100,
			listeners: {
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_search = i_self.getSearch();
						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();

						Ext.apply(o_extraParams, {
							action: "ip2navProxy.listIcons",
							search: i_search.getValue()
						});
					}
				}
			}
		});

		return i_store;
	}
});
Ext.define("Ext.ux.icon.view.Panel", {
	extend: "Ext.form.Panel",
	alias: "widget.ux.icon.view.panel",

	config: {
		dataView: null,
		actionFn: Ext.emptyFn
	},

	layout: "fit",

	initComponent: function () {

		var i_self = this;
		var i_dataview = i_self.createDataView();

		i_self.callParent();
		i_self.add(i_dataview);
		i_self.addDocked(i_dataview.createTopBars());
		return i_self;
	},

	createDataView: function() {

		var i_self = this;
		var i_dataview = Ext.widget("ux.icon.view.dataview", {
			actionFn: i_self.getActionFn()
		});
		i_self.setDataView(i_dataview);
		return i_dataview;
	}
});
Ext.define("Ext.ux.form.field.IconPicker", {
	extend: "Ext.form.field.Text",
	alias: "widget.ux.form.field.iconpicker",

	editable: false,
	emptyText: ip2.i18n({
		da: "Url til ikon",
		en: "URL to icon"
	}),

	triggers: {
		search: {
			cls: Ext.baseCSSPrefix + "form-search-trigger",
			handler: "onSearchClick",
			weight: 1,
			scope: "this"
		}
	},

	requires: [
		"Ext.ux.file.util.Handler"
	],

	initComponent: function() {

		var i_self = this;

		// WE DO NOT WANT TO BE ABLE TO WRITE ANYTHING INTO THE FIELD
		//BUT ONLY USE THE PICKER...
		if (i_self.editable) {
			i_self.editable = false;
		}

		i_self.callParent();

		if (i_self.getValue()) {
			i_self.setIconCls(i_self.getCSS(i_self.getValue()));
		}

		return i_self;
	},

	onSearchClick: function() {

		var i_self = this;

		var i_window = Ext.widget("window", {
			title: ip2.i18n({
				da: "Server ikoner",
				en: "Server icons"
			}),
			layout: "fit",
			items: [],
			width: 865,
			height: 655,
			bodyPadding: 5
		});

		var i_dataview = Ext.widget("ux.icon.view.panel", {
			layout: "fit",
			actionFn: function (s_path) {
				i_self.setValue(s_path);
				i_self.setIconCls(i_self.getCSS(s_path));
				i_window.close();
			}
		});

		i_window.add(i_dataview);

		i_window.show();
	},

	getCSS: function(value) {
		var i_cmp = this;
		var s_name = i_cmp.getId() + "-css";
		var o_css = Ext.util.CSS.getRule("." + s_name);
		var a_value = value.split(".");
		var i_date = new Date();
		var n_time = i_date.getTime();
		var s_extensions = a_value.pop().toLowerCase();
		if (!o_css) {
			var s_url = value;
			if (Ext.ux.file.util.Handler.imageExtension.indexOf(s_extensions) == -1) {
				s_url = Ext.ux.file.util.Handler.getUrlByExtension(value);
			}
			var s_css = "." + s_name + "{" +
				"background-image: url(\"" + s_url + "\") !important;" +
				"background-size: 16px;" +
				"padding-left : 25px !important;" +
				"}";
			o_css = Ext.util.CSS.createStyleSheet(s_css, s_name);
		}
		else {
			if (Ext.ux.file.util.Handler.imageExtension.indexOf(s_extensions) == -1) {
				o_css.style.setProperty("background-image", "url(\"" + Ext.ux.file.util.Handler.getUrlByExtension(value) + "\")");
			}
			else {
				o_css.style.setProperty("background-image", "url(\"" + value + "?_dc=" + n_time + "\")");
			}
		}
		return s_name;
	}
});
Ext.define("Ext.ux.hsvwheel.Picker", {

	statics: {
		wheelCssClass: "hsvcolorwheel",
		createWheel: function (i_cmp) {

			// Create the colowheel
			var Class = Ext.ux.hsvwheel.Picker;
			var s_wheelCssClass = "." + Class.wheelCssClass;
			var i_el = i_cmp.getEl();
			var i_dom = i_el.query(s_wheelCssClass)[0];

			var i_wheel = HsvWheelColorPicker(i_dom, function (s_hex) {
				i_cmp.fireEvent("update", i_cmp, s_hex);
			});

			return i_wheel;
		}
	},

	extend: "Ext.Component",

	alias: [
		"widget.hsvwheel",
		"widget.hsvwheelpicker"
	],

	mixins: {
		mashup: "Ext.mixin.Mashup"
	},

	requiredScripts: [
		"/portfolio/app/ux/hsvwheel/_css/wheel.css",
		"/portfolio/app/ux/hsvwheel/_js/wheel.js"
	],

	minWidth: 150,
	minHeight: 200,

	_wheel: null,

	initComponent: function () {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;

		var s_wheelCssClass = i_cmp.getRewriter().wheelCssClass;

		Ext.apply(i_cmp, {
			cls: "x-ux-hsvwheel-picker",
			layout: "fit",
			style: "background-color: #E6E6E6",
			html: "<div class=\"" + s_wheelCssClass + "-wrapper\"><div class=\"" + s_wheelCssClass + " normal\"></div></div>"
		});

		i_cmp.callParent(arguments);

		i_cmp.on({
			afterrender: {
				fn: i_cmp.onAfterRender
			}
		});

		return i_cmp;
	},

	onAfterRender: function () {

		var i_cmp = this;
		var i_el = i_cmp.getEl();

		i_cmp._wheel = i_cmp.getRewriter().createWheel(i_cmp);

		i_cmp.fireEvent("wheelready", i_cmp, i_cmp._wheel);

		return i_cmp;
	},

	select: function (s_hex) {

		var i_cmp = this;

		s_hex = s_hex.replace("#", "");
		s_hex = "#" + s_hex;


		var i_wheel = i_cmp.getWheel();

		// Wheel not yet instanciated!!
		if (!i_wheel) {

			i_cmp.on("wheelready", function () {
				i_cmp.select(s_hex);
			});
			return false;
		}

		i_wheel.setHex(s_hex);

		return i_cmp;
	},

	getWheel: function () {

		return this._wheel;
	},
	getRewriter: function () {

		return Ext.ux.hsvwheel.Picker;
	}
});
Ext.define("Ext.ux.hsvwheel.Field", {

	extend: "Ext.form.field.Picker",

	alias: ["widget.hsvwheelfield"],

	/**
	 * @cfg {String} [triggerCls="x-form-date-trigger"]
	 * An additional CSS class used to style the trigger button. The trigger will always get the class "x-form-trigger"
	 * and triggerCls will be **appended** if specified (default class displays a calendar icon).
	 */
	triggers: {
		cls: "x-ux-hsvwheel-trigger",
		handler: "onTriggerClick",
		scope: "this"
	},

	enableKeyEvents: true,
	enforceMaxLength: true,
	maxLength: 6,
	cls: "x-ux-hsvwheel-field",
	maskRe: /[a-f0-9]/i,
	regex: /^([0-9a-f]{3}){1,2}$/i,
	regexText: "Not a valid hex color must be a character (A-F) or a number (0-9) - as well have a length of 3 or 6",
	validateOnChange: true,

	onFocusLeave: Ext.emptyFn,

	squared: true,

	__silencePicker: false,

	_preview: null,

	initComponent: function () {

		var i_cmp = this;

		i_cmp.callParent(arguments);

		i_cmp.on({
			"afterrender": {
				fn: i_cmp.onAfterRender
			}
		});

		return i_cmp;
	},

	initValue: function () {

		var i_cmp = this;
		i_cmp.value = i_cmp.value || "";
		var value = i_cmp.value;

		i_cmp.originalValue = value;

		i_cmp.setValue(value);

		return i_cmp;
	},

	addControls: function () {

		var i_cmp = this;

		i_cmp.on({
			"keyup": {
				fn: function () {
					var s_hex = i_cmp.inputEl.getValue();
					i_cmp.setValue(s_hex);
				}
			}
		});
	},

	onAfterRender: function () {

		var i_cmp = this;

		i_cmp.createPreview();

		i_cmp.addControls();

		return i_cmp;
	},
	onChange: function (s_hex) {

		var i_cmp = this;

		if (i_cmp.rendered) {
			var i_picker = i_cmp.getPicker();
			var b_silencePicker = i_cmp.__silencePicker;

			if (!b_silencePicker && i_picker) {
				i_cmp.getPicker().select(s_hex);
			}

			i_cmp.updatePreview(s_hex);
			i_cmp.validate();
		}

		return i_cmp;
	},
	onExpand: function () {

		var i_cmp = this;
		var i_picker = i_cmp.getPicker();
		var s_value = this.getValue();

		i_picker.select(s_value);
	},
	onCollapse: function () {

		var i_cmp = this;

		i_cmp.focus(false, 60);
	},

	createPicker: function () {

		var i_cmp = this;
		var i_picker;

		i_picker = Ext.widget("hsvwheelpicker", {
			pickerField: i_cmp,
			ownerCt: i_cmp.ownerCt,
			renderTo: document.body,
			floating: true,
			hidden: true,
			focusOnShow: true,
			listeners: {
				update: function (i_picker, s_hex) {
					i_cmp.__silencePicker = true;

					// TODO - get a sweet regex here - should be easy
					s_hex = s_hex.replace("#", "");
					i_cmp.setValue(s_hex);
					i_cmp.__silencePicker = false;
				}
			},
			keyNavConfig: {
				esc: function() {
					i_cmp.collapse();
				}
			}
		});

		return i_picker;
	},

	createPreview: function () {

		var i_cmp = this;
		var s_hex = i_cmp.getValue();
		var i_inputEl = i_cmp.inputEl;
		var i_preview;

		Ext.DomHelper.insertBefore(i_inputEl,
			"<div style=\"" +
				"position: absolute;" +
				"top: 40%;" +
				"left: 5px;" +
				"width: 11px;" +
				"height: 11px;" +
				"border: 1px solid #000000;" +
				"background-color: transparent;\"" +
			"></div>"
		);
		i_cmp._preview = i_inputEl.prev();

		i_cmp.updatePreview(s_hex);

		return i_cmp;
	},
	getPreview: function () {

		return this._preview;
	},
	updatePreview: function (s_hex) {

		var i_cmp = this;
		var i_preview = i_cmp.getPreview();
		var s_value = s_hex.replace("#", "");
		var b_valid = i_cmp.validateValue(s_value);

		if (!i_preview) {
			return i_cmp;
		}

		if (b_valid) {

			i_preview.removeCls("error");
			i_preview.setStyle("background-color", s_hex);
		}
		else {
			i_preview.addCls("error");
		}

		return i_cmp;
	},

	update: function (s_hex) {

		var i_cmp = this;

		i_cmp.setValue(s_hex);

		return i_cmp;
	},

	getValue: function () {

		var i_cmp = this;
		var s_value = i_cmp.value;
		if (s_value) {
			s_value = "#" + s_value;
		}
		return s_value;
	},

	setValue: function (s_hex) {

		var i_cmp = this;
		if (s_hex && s_hex.indexOf("#") == 0) {
			s_hex = s_hex.slice(1);
		}

		if (!s_hex) {
			s_hex = "";
		}

		i_cmp.callParent([s_hex]);
		if (i_cmp.originalValue.indexOf("#") == -1) {
			i_cmp.resetOriginalValue();
		}

		return i_cmp;
	},

	/**
	 * @param {Object} [value] The value to get errors for (defaults to the current field value)
	 * @return {String[]} All validation errors for this field
	 */
	getErrors: function (value) {

		var i_cmp = this;
		var a_errors = i_cmp.callParent(arguments);

		var s_value = i_cmp.value;

		return a_errors;
	}
});
Ext.define('Ext.ux.folderExplorer.Grid', {
	extend: 'Ext.grid.Panel',
	alias: 'widget.folderExplorerGrid',
	initComponent: function() {
		var me = this;

		me.setupI18N();

		var modelName = 'folderExplorerRows';

		var url = '/ip2-services/ip2services.aspx?func=getFolderExplorerRows';

		if (me.path) {
			url += '&path=' + me.path;
		}
		if (me.extentions) {
			url += '&extnList=' + me.extentions;
		}

		if (!Ext.ClassManager.isCreated(modelName)) {
			Ext.define(modelName, {
				extend: 'Ext.data.Model',
				proxy: {
					type: 'ajax',
					url: url,
					reader: {
						type: 'json',
						rootProperty: 'rows'
					}
				}
			});
		}

		me.columns = me.columns || [];
		me.columns.push(
			{ header: me.getI18N('name'), dataIndex: 'name', flex: 1 }
		);
		me.columns.push(
			{ header: me.getI18N('importDate'), dataIndex: 'ts', width: 100, renderer: me.ts2dateRenderer }
		);
		me.columns.push(
			{ header: me.getI18N('importTime'), dataIndex: 'ts', width: 100, renderer: me.ts2timeRenderer }
		);
		me.columns.push(
			{
				xtype: 'actioncolumn',
				width: 25,
				items: [{
					iconCls: 'pf-eye',
					text: me.getI18N('showLog'),
					tooltip: me.getI18N('showLogTips').toString(),
					handler: function(view, rowIndex, colIndex) {
						var grid = view.up('grid');
						var record = grid.getStore().getAt(rowIndex);

						var win = Ext.create('Ext.ux.folderExplorer.LogWindow', {
							record: record
						});
						win.show();
					},
					getClass: function(value, meta, record) {
						if (record.get('logs') == 0) {
							return '';
						}
						else {
							return 'pf-eye';
						}
					}
				}]
			}
		);
		me.columns.push(
			{ header: me.getI18N('noOfLogs'), dataIndex: 'logs', width: 100, renderer: me.noOfLogsRenderer }
		);

		me.store = Ext.create('Ext.data.Store', {
			model: modelName,
			autoLoad: true
		});

		me.dockedItems = [{
			xtype: 'toolbar',
			dock: 'top',
			items: [{
				xtype: 'button',
				text: me.getI18N('refresh'),
				iconCls: 'pf-refresh',
				handler: function() {
					me.store.load();
				}
			},{
				xtype: 'button',
				text: me.getI18N('upload'),
				iconCls: 'pf-arrow-up',
				handler: function() {
					me.upload();
				}
			}]
		}];

		me.callParent();
	},

	/* ---------------------------------------------------------------------------------------------------
	Renderer timestamp to date
   ---------------------------------------------------------------------------------------------------- */
	ts2dateRenderer: function(value) {
		if (value == 0) {
			return '';
		}

		var year = Ext.Date.format(value, 'Y');

		if (year == 1970) {
			return '';
		}

		return Ext.Date.format(value, 'd.m.Y');
	},

	/* ---------------------------------------------------------------------------------------------------
	Renderer timestamp to time
   ---------------------------------------------------------------------------------------------------- */
	ts2timeRenderer: function(value) {
		if (value == 0) {
			return '';
		}

		var year = Ext.Date.format(value, 'Y');

		if (year == 1970) {
			return '';
		}

		return Ext.Date.format(value, 'H.i.s');
	},

	/* ---------------------------------------------------------------------------------------------------
	Renderer number of logs
   ---------------------------------------------------------------------------------------------------- */
	noOfLogsRenderer: function(value) {
		if (value == 0) {
			return '';
		}

		return value;
	},

	/* ---------------------------------------------------------------------------------------------------
	Upload
   ---------------------------------------------------------------------------------------------------- */
	upload: function(value) {
		var me = this;

		Ext.create('Ext.window.Window', {
			title: me.getI18N('upload'),
			bodyStyle: {
				padding: '10px',
				'background-color': 'white'
			},
			items: [{
				xtype: 'form',
				border: false,
				items: [{
					xtype: 'fileuploadfield',
					name: '*ILOB:uploadIlob',
					emptyText: me.getI18N('browse_placeholder'),
					buttonText: me.getI18N('browse'),
					width: 500
				}]
			}],
			buttons: [{
				xtype: 'button',
				text: me.getI18N('upload'),
				iconCls: 'pf-arrow-up',
				handler: function() {
					var win = this.up('window');
					var form = win.down('form');
					var field = form.down('fileuploadfield');
					var file = field.getValue();
					if (Ext.isEmpty(file)) {
						Ext.Msg.show({
							title: me.getI18N('message'),
							msg: me.getI18N('select_a_spreadsheet'),
							buttons: Ext.Msg.OK,
							icon: Ext.Msg.ERROR
						});
						return;
					}
					if (file.indexOf('.xls') == -1) {
						Ext.Msg.show({
							title: me.getI18N('message'),
							msg: me.getI18N('must_be_a_spreadsheet'),
							buttons: Ext.Msg.OK,
							icon: Ext.Msg.ERROR
						});
						return;
					}

					me.setLoading(
						ip2.i18n({
							da: 'Vent venligst...',
							en: 'Please wait...'
						})
					);

					var files = field.fileInputEl.dom.files;
					var fileName = files[0].name;

					var formData = new FormData();
					var xhr = new XMLHttpRequest();

					var filepath = me.path + '/' + fileName;
					formData.append(filepath, files[0]);

					xhr.onreadystatechange = function () {

						if (xhr.readyState == 4 && xhr.status == 200) {
							var result;

							me.setLoading(false);

							try {
								result = Ext.decode(xhr.responseText);
							}
							catch (err) {}

							if (result[0].success) {
								win.close();
							}
						}
					};

					xhr.open('POST', 'ip2-services/webbios.aspx?action=movestmf&ignoreStaticDir=true&path=' + me.path, true);
					xhr.send(formData);
				}
			},{
				xtype: 'button',
				text: me.getI18N('cancel'),
				iconCls: 'pf-navigate_cross',
				handler: function() {
					var win = this.up('window');
					win.close();
				}
			}]
		}).show();
	},

	/* ----------------------------------------------------------------------------------------------------
		Setup I18N
	---------------------------------------------------------------------------------------------------- */
	setupI18N: function() {
		var texts = {
			ns: 'IP2',
			lang: ['da', 'en'],
			enums: {},
			text: {
				refresh: {
					value: { da: 'Opfrisk', en: 'Refresh' }
				},
				upload: {
					value: { da: 'Upload', en: 'Upload' }
				},
				browse: {
					value: { da: 'Gennemse...', en: 'Browse...' }
				},
				browse_placeholder: {
					value: { da: 'Gennemse for at vælge regneark', en: 'Browse for select a spreadsheet' }
				},
				select_a_spreadsheet: {
					value: { da: 'Vælg venligst et regneark', en: 'Please select a spreadsheet' }
				},
				must_be_a_spreadsheet: {
					value: { da: 'Den valgte skal være et regneark', en: 'The selected must be a spreadsheet' }
				},
				cancel: {
					value: { da: 'Luk', en: 'Cancel' }
				},
				name: {
					value: { da: 'Navn', en: 'Name' }
				},
				importDate: {
					value: { da: 'Importet d.', en: 'Date of import' }
				},
				importTime: {
					value: { da: 'Importet kl.', en: 'Time of import' }
				},
				noOfLogs: {
					value: { da: 'Antal logs', en: 'Number of logs' }
				},
				showLog: {
					value: { da: 'Vis logs', en: 'Show logs' }
				},
				showLogTips: {
					value: { da: 'Vis logs', en: 'Show logs' }
				},
				confirmImportTitle: {
					value: { da: 'Bekræft import', en: 'Confirm import' }
				},
				confirmImport: {
					value: { da: 'Bekræft venligst import af: ', en: 'Please confirm import of: ' }
				},
				receipt: {
					value: { da: 'Kvittering', en: 'Receipt' }
				},
				message: {
					value: { da: 'Meddelelse', en: 'Message' }
				},
				logWindowTitle: {
					value: { da: 'Log:', en: 'Log:' }
				},
				please_wait: {
					value: { da: 'Vent venligst...', en: 'Please wait...' }
				}
			}
		};

		ip2.folderExplorer = new ip2.DynamicNS(texts);
		ip2.folderExplorer.setLanguage(ip2.session.getLanguage());
	},

	/* ----------------------------------------------------------------------------------------------------
		get I18N by key
	---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return ip2.i18n(ip2.folderExplorer.getTextValue(key));
	}
});
Ext.define('Ext.ux.folderExplorer.LogGrid', {
	extend: 'Ext.grid.Panel',
	alias: 'widget.folderExplorerLogGrid',
	initComponent: function() {
		var me = this;

		var modelName = 'folderExplorerLogRows';

		if (!Ext.ClassManager.isCreated(modelName)) {
			Ext.define(modelName, {
				extend: 'Ext.data.Model',
				proxy: {
					type: 'ajax',
					url: '/ip2-services/ip2Services.aspx?func=getFolderExplorerLogRows',
					reader: {
						type: 'json',
						rootProperty: 'rows'
					}
				}
			});
		}

		me.columns = [
			{ header: me.getI18N('message'), dataIndex: 'LTMSG', flex: 1 }
		];

		me.store = Ext.create('Ext.data.Store', {
			model: modelName,
			autoLoad: true,
			listeners: {
				beforeload: function(store) {
					store.proxy.extraParams.spreadsheet = me.record.data.path;
				}
			}
		});

		me.dockedItems = [{
			xtype: 'toolbar',
			dock: 'top',
			items: [{
				xtype: 'button',
				text: me.getI18N('refresh'),
				iconCls: 'pf-refresh',
				handler: function() {
					me.store.load();
				}
			}]
		}];

		me.callParent();
	},

	/* ----------------------------------------------------------------------------------------------------
		get I18N by key
	---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return ip2.i18n(ip2.folderExplorer.getTextValue(key));
	}
});
Ext.define('Ext.ux.folderExplorer.LogWindow', {
	extend: 'Ext.window.Window',
	alias: ['widget.ip2FolderExplorerLogWindow'],
	height: 240,
	width: 440,
	autoScroll: true,
	collapsible: true,
	layout: {
		type: 'fit'
	},
	initComponent: function() {
		var me = this;

		me.title = me.getI18N('logWindowTitle') + ' ' + me.record.data.name;

		me.grid = Ext.create('Ext.ux.folderExplorer.LogGrid', {
			record: me.record,
			border: false
		});

		me.items = [
			me.grid
		];

		me.buttons = [{
			xtype: 'button',
			iconCls: 'pf-close',
			text: 'OK',
			handler: function() {
				me.close();
			}
		}];

		me.callParent();
	},

	/* ----------------------------------------------------------------------------------------------------
		get I18N by key
	---------------------------------------------------------------------------------------------------- */
	getI18N: function(key) {
		return ip2.i18n(ip2.folderExplorer.getTextValue(key));
	}
});
Ext.define("Ext.ux.svg.DrawRoom", {
	extend: "Ext.container.Container",
	alias: ["widget.drawroom"],

	config: {
		polygonEl: null,
		points: null,
		movePoints: null,
		mode: null,
		svg: null,
		mouseDown: false,
		mouseDownX: 0,
		mouseDownY: 0,
		focuced: null,
		mapPath: null,
		zoomFactor: 1,
		mapSize: null,
		allowDraw: true
	},

	modes: {
		NORMAL: 0,
		DRAW: 1,
		RESIZE: 2,
		SELECT: 3
	},

	layout: "auto",
	style: {
		"overflow-y": "auto"
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		i_self.updatePoints = Ext.Function.createBuffered(i_self.updatePoints, 500);

		i_self.enableBubble("pointchange");
		i_self.enableBubble("drawcomplete");
		i_self.enableBubble("polygonmove");

		i_self.on({
			afterrender: {
				fn: function(i_container) {
					i_container.add(i_self.createSvg());
				}
			}
		});
	},

	updateMap: function(s_path, points) {

		var i_self = this;
		var mapLoader = new Image();

		var i_svg = i_self.getSvg();
		var s_background = i_svg.getEl().dom.style.backgroundImage;

		s_background = s_background.slice(4, -1).replace(/["|']/g, "");

		if (s_path) {
			if (s_background !== s_path) {
				i_self.setLoading(true);
			}

			mapLoader.onload = function() {
				i_self.setLoading(false);
				var zoomFactor = (i_self.getWidth() - Ext._scrollbarSize.width) / mapLoader.width;
				var i_svg = i_self.getSvg();
				i_svg.getEl().dom.style.backgroundImage = 'url(' + s_path + ')';
				i_svg.getEl().dom.style.backgroundSize = 'contain';
				i_svg.getEl().dom.style.backgroundRepeat = 'no-repeat';

				i_self.setZoomFactor(zoomFactor);

				i_self.setMapSize({
					width: mapLoader.width,
					height: mapLoader.height
				});

				i_svg.setHeight(zoomFactor * mapLoader.height);

				i_self.deletePolygon();

				if (points && points.length) {
					i_self.setValue(points);
					i_self.createPolygon();
					i_self.draw();
				}
			};

			mapLoader.src = s_path;
		}
		else {
			i_self.setLoading(false);

			var i_svg = i_self.getSvg();
			i_svg.getEl().dom.style.backgroundImage = 'none';

			i_self.setMapSize({
				width: i_self.getWidth(),
				height: 0
			});

			i_svg.setHeight(0);

			i_self.deletePolygon();
		}
	},

	updatePoints: function(newValue) {

		var i_self = this;
		i_self.fireEvent("pointchange", i_self, i_self.getValue());
	},

	setPoints: function(newValue) {
		this.points = newValue;
		this.updatePoints(newValue);
	},

	getPointIndex: function(x, y, points) {
		if (arguments.length == 2) {
			points = this.getPoints();
		}
		if (!points) {
			return;
		}
		for (var i = 0; i < points.length; i += 2) {
			var x2 = points[i];
			var y2 = points[i + 1];

			if (Math.abs(x - x2) < 5 && Math.abs(y - y2) < 5) {
				return i;
			}
		}

		return -1;
	},

	createSvg: function() {

		var i_self = this;

		var i_component = Ext.widget("component", {
			height: 100,
			autoEl: {
				tag: 'svg',
				style: 'width: 100%; border: none;'
			},
			listeners: {
				afterrender: {
					fn: function(i_svg) {

						i_self.setSvg(i_svg);
						i_self.setMode(i_self.modes.NORMAL);

						var s_path = i_self.getMapPath();

						if (s_path) {
							var a_points = i_self.getPoints();
							i_self.updateMap(s_path, a_points);
						}

						if (i_self.getAllowDraw()) {
							i_self.attachListeners(i_svg.getEl().dom);
						}
					}
				},
				resize: {
					fn: function(i_svg) {

						// getValue (Points) BEFORE updating zoomFactor:
						var a_points = i_self.getValue();
						var size = i_self.getMapSize();
						if (size) {
							var zoomFactor = (i_self.getWidth() - Ext._scrollbarSize.width) / size.width;
							i_self.setZoomFactor(zoomFactor);
							i_svg.setHeight(zoomFactor * size.height);
						}
						if (a_points) {
							i_self.setValue(a_points);
							i_self.draw();
						}
					}
				}
			}
		});

		return i_component;
	},

	setValue: function(points) {
		var i_self = this;
		var zoomFactor = i_self.getZoomFactor();
		i_self.setPoints(points.map(function(point) {
			return point * zoomFactor;
		}));
	},

	getValue: function() {
		var points = this.getPoints();
		var zoomFactor = this.getZoomFactor();
		return points ? points.map(function(point) {
			return point / zoomFactor;
		}) : null;
	},

	initDraw: function(x, y) {
		var i_self = this;
		var modes = i_self.modes;
		i_self.setMode(modes.DRAW);
		i_self.createPolygon();
		i_self.setPoints([]);
		i_self.addCoord(x, y);
		i_self.draw();
	},
	addCoord: function(x, y) {
		var i_self = this;
		var points = i_self.getPoints();
		points.push(x, y);
		i_self.setPoints(points);
	},
	draw: function(x, y) {
		var i_self = this;
		var points = i_self.getPoints();
		if (arguments.length == 2) {
			points = points.concat(x, y);
		}
		var polyEl = i_self.getPolygonEl();
		if (polyEl) {
			polyEl.setAttribute('points', points.join(' '));
		}
	},
	createPolygon: function() {
		var svg = this.getSvg().getEl().dom;
		var poly = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
		poly.style.fill = 'rgba(112,181,93,0.2)';
		poly.style.stroke = '#70b55d';
		poly.style.strokeDasharray = '3, 5';
		poly.style.strokeLinejoin = 'round';
		poly.style.strokeWidth = '3px';
		svg.appendChild(poly);
		this.setPolygonEl(poly);
	},
	deletePolygon: function() {
		var polyEl = this.getPolygonEl();
		if (polyEl && polyEl.parentNode) {
			polyEl.parentNode.removeChild(polyEl);
		}
		this.setPolygonEl(null);
		this.setPoints(null);
		this.setMovePoints(null);
	},
	selectPolygon: function() {
		var i_self = this;
		var modes = i_self.modes;
		i_self.setMode(modes.SELECT);
		var poly = this.getPolygonEl();
		poly.style.fill = 'rgba(181,112,93,0.2)';
		poly.style.stroke = '#b5705d';
		poly.style.strokeDasharray = '3, 5';
		poly.style.strokeLinejoin = 'round';
		poly.style.strokeWidth = '3px';
	},
	deselectPolygon: function() {
		var i_self = this;
		var modes = i_self.modes;
		i_self.setMode(modes.SELECT);
		var poly = this.getPolygonEl();
		poly.style.fill = 'rgba(112,181,93,0.2)';
		poly.style.stroke = '#70b55d';
		poly.style.strokeDasharray = '3, 5';
		poly.style.strokeLinejoin = 'round';
		poly.style.strokeWidth = '3px';
	},
	movePolygon: function(x, y) {
		var polyEl = this.getPolygonEl();
		var points = this.getPoints().map(function(val, key) {
			if (key & 1) {
				// y
				return val + y;
			}
			else {
				// x
				return val + x;
			}
		});
		this.setMovePoints(points);
		polyEl.setAttribute('points', points.join(' '));
	},

	addHandle: function(idx) {

		var i_self = this;
		var points = i_self.getPoints();
		var polyEl = i_self.getPolygonEl();
		var xy = points.slice(idx);
		var svg = this.getSvg().getEl().dom;

		var x = xy[0] - 15;
		var y = xy[1] - 15;

		var handle = document.createElement('div');
		handle.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
		handle.style.border = '1px solid rgba(255, 255, 255, 0.8)';
		handle.style.borderRadius = '100px';
		handle.style.position = 'absolute';
		handle.style.left = x + 'px';
		handle.style.top = y + 'px';
		handle.style.width = 30 + 'px';
		handle.style.height = 30 + 'px';

		var down = false;
		var startX;
		var startY;

		handle.addEventListener('mousedown', function(evt) {
			startX = evt.pageX - svg.getBoundingClientRect().left;
			startY = evt.pageY - svg.getBoundingClientRect().top;
			down = true;
		});
		handle.addEventListener('mousemove', function(evt) {
			if (down) {
				var offsetX = evt.pageX - svg.getBoundingClientRect().left - startX;
				var offsetY = evt.pageY - svg.getBoundingClientRect().top - startY;
				points.splice(idx, 2, offsetX + xy[0], offsetY + xy[1]);
				i_self.setPoints(points);
				i_self.draw();
				handle.style.left = (offsetX + x) + 'px';
				handle.style.top = (offsetY + y) + 'px';
			}
		});
		handle.addEventListener('mouseup', function(evt) {
			down = false;
			i_self.fireEvent("polygonmove", i_self, i_self.getValue());
		});

		handle.addEventListener('mouseout', function() {
			if (!down && handle.parentNode) {
				handle.parentNode.removeChild(handle);
			}
		});
		svg.parentNode.appendChild(handle);
	},

	attachListeners: function(el) {

		var i_self = this;

		var svg = i_self.getSvg().getEl().dom;
		var modes = i_self.modes;

		el.addEventListener('mouseover', function() {
			i_self.setFocuced(true);
		});
		el.addEventListener('mousemove', function() {
			i_self.setFocuced(true);
		});
		el.addEventListener('mouseout', function() {
			i_self.setFocuced(false);
		});

		el.addEventListener('mousedown', function(evt) {
			var x = evt.pageX - svg.getBoundingClientRect().left;
			var y = evt.pageY - svg.getBoundingClientRect().top;

			i_self.setMouseDown(true);
			i_self.setMouseDownX(x);
			i_self.setMouseDownY(y);

			switch (i_self.getMode()) {
				case modes.NORMAL:
					if (event.which != 1) {
						// Left click only!
						return;
					}
					if (!i_self.getPolygonEl()) {
						i_self.initDraw(x, y);
					}
					else if (evt.target.nodeName == 'polygon') {
						i_self.selectPolygon();
					}
					break;
				case modes.DRAW:
					if (event.which != 1) {
						// Left click only!
						return;
					}
					if (i_self.getPointIndex(x, y, i_self.getPoints().slice(0, 2)) > -1) {
						if (i_self.getPoints().length >= 6) {
							i_self.draw();
							i_self.setMode(modes.NORMAL);
						}
					}
					else {
						i_self.addCoord(x, y);
						i_self.draw();
					}
					break;
				case modes.SELECT:
					if (evt.target.nodeName != 'polygon') {
						i_self.deselectPolygon();
						i_self.setMode(modes.NORMAL);
					}
					else if (event.which == 3) {
						// Right click and on polygon
						i_self.deletePolygon();
						i_self.setMode(modes.NORMAL);
					}
			}
		});
		el.addEventListener('mouseup', function() {
			i_self.setMouseDown(false);
			switch (i_self.getMode()) {
				case modes.SELECT:
					var mp = i_self.getMovePoints();
					if (mp) {
						i_self.setPoints(mp);
						i_self.fireEvent("polygonmove", i_self, i_self.getValue());
					}
					i_self.draw();
					break;
			}
		});
		el.addEventListener('mousemove', function(evt) {
			var x = evt.pageX - svg.getBoundingClientRect().left;
			var y = evt.pageY - svg.getBoundingClientRect().top;

			switch (i_self.getMode()) {
				case modes.DRAW:
					i_self.draw(x, y);
					break;
				case modes.SELECT:
					if (i_self.getMouseDown()) {
						var startX = i_self.getMouseDownX();
						var startY = i_self.getMouseDownY();
						var offsetX = x - startX;
						var offsetY = y - startY;
						i_self.movePolygon(offsetX, offsetY);
					}
					else {
						var idx = i_self.getPointIndex(x, y);
						if (idx > -1) {
							i_self.addHandle(idx);
						}
					}
					break;
				case modes.NORMAL:
					var idx = i_self.getPointIndex(x, y);
					if (idx > -1) {
						i_self.addHandle(idx);
					}
					break;

			}
		});
		el.addEventListener('contextmenu', function(evt) {
			var x = evt.pageX - svg.getBoundingClientRect().left;
			var y = evt.pageY - svg.getBoundingClientRect().top;

			switch (i_self.getMode()) {
				case modes.DRAW:
					if (i_self.getPoints().length >= 6) {
						i_self.draw();
						i_self.setMode(modes.NORMAL);
						i_self.fireEvent("drawcomplete", i_self, i_self.getValue());
					}
					break;
			}
		});
		document.addEventListener('keydown', function(evt) {
			if (!i_self.getFocuced()) {
				return;
			}

			switch (i_self.getMode()) {
				case modes.SELECT:
					if (evt.key == 'Delete') {
						i_self.deletePolygon();
						i_self.setMode(modes.NORMAL);
						i_self.fireEvent("drawcomplete", i_self, i_self.getValue());
					}
					break;
				case modes.DRAW:
					if (evt.key == 'Delete') {
						i_self.deletePolygon();
						i_self.setMode(modes.NORMAL);
						i_self.fireEvent("drawcomplete", i_self, i_self.getValue());
					}
					if (evt.key == 'Enter') {
						if (i_self.getPoints().length >= 6) {
							i_self.draw();
							i_self.setMode(modes.NORMAL);
							i_self.fireEvent("drawcomplete", i_self, i_self.getValue());
						}
					}
					break;
			}
		});
	}
});
Ext.define("Ext.ux.link.Window", {

	extend: "Ext.window.Window",

	title: ip2.i18n({
		da: "Direkte Link",
		en: "Direct Link"
	}),

	layout: "fit",
	alias: [
		"widget.link.window"
	],

	config: {
		urlField: null,
		hideField: null,
		model: null,
		activeTabIndex: 0,
		app: null
	},

	width: 650,
	modal: true,
	ui: "message",

	"static": {
		tpl: "{protocol}//{host}{pathname}{search}{hash}",
		appTpl: "{app}-{paths}-{config}"
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
		i_self.add(i_self.createLayout());
		return i_self;
	},

	createLayout: function() {

		var i_self = this;

		var i_panel = Ext.widget("panel", {
			layout: {
				type: "vbox",
				align: "stretch"
			},
			defaults: {
				anchor: "100%"
			},
			bodyPadding: 20,
			items: i_self.createItems()
		});

		return i_panel;
	},

	createItems: function() {

		var i_self = this;

		var a_fields = [];

		var i_hide = Ext.widget("checkboxgroup", {
			name: "hide",
			columns: 6,
			vertical: false,
			items: [
				{
					boxLabel: ip2.i18n({
						da: "Topbar",
						en: "Header"
					}),
					name: "check",
					inputValue: 1,
					checked: true
				},
				{
					boxLabel: ip2.i18n({
						da: "Navigation",
						en: "Navigation"
					}),
					name: "check",
					inputValue: 2,
					checked: true
				},
				{
					boxLabel: ip2.i18n({
						da: "Hjælp",
						en: "Help"
					}),
					name: "check",
					inputValue: 4,
					checked: true
				},
				{
					boxLabel: ip2.i18n({
						da: "Faneblade",
						en: "Tabs"
					}),
					name: "check",
					inputValue: 8,
					checked: true
				},
				{
					boxLabel: ip2.i18n({
						da: "Meddelelser",
						en: "Messages"
					}),
					name: "check",
					inputValue: 16,
					checked: true
				},
				{
					boxLabel: ip2.i18n({
						da: "Vindue",
						en: "Window"
					}),
					name: "window",
					inputValue: 1,
					checked: false
				}

			],
			listeners: {
				change: {
					fn: function(i_field) {

						var o_value = i_field.getValue();
						var n_hide = 31;
						var n_window = 0;
						var i_url = i_self.getUrlField();

						if (o_value.check) {

							var a_values = o_value.check;
							if (!Ext.isArray(o_value.check)) {
								a_values = Ext.Array.from(o_value.check);
							}

							Ext.Array.each(a_values, function(n_value) {
								n_hide -= n_value;
							});
						}
						if (o_value.window) {
							n_window = o_value.window;
						}
						i_url.setValue(i_self.getUrl(n_hide, n_window));
					}
				}
			}
		});

		var i_url = Ext.widget("textfield", {
			name: "url",
			readOnly: true,
			listeners: {
				afterrender: {
					fn: function(i_field) {

						i_field.setValue(i_self.getUrl(0));

						var i_copy = i_field.getTrigger("copy");

						if (i_copy) {
							i_copy.show();
							i_copy.field.readOnly = false;
						}
					},
					buffer: 10
				}
			},
			triggers: {
				copy: {
					cls: "x-ux-form-trigger-copy",
					tooltip: ip2.i18n({
						da: "Kopier til udklipsholderen",
						en: "Copy to clipboard"
					}),
					handler: function() {
						var i_field = i_self.getUrlField();
						var i_inputDom = i_field.inputEl.dom;
						i_inputDom.select();
						document.execCommand("copy");
					},
					isFieldEnabled: function() {
						return true;
					}
				}
			}
		});

		var i_email = Ext.widget("textfield", {
			name: "email",
			vtype: "email",
			allowBlank: true,
			emptyText: ip2.i18n({
				da: "Indtast modtagers e-mail og send",
				en: "Type in recievers e-mail and send"
			}),
			listeners: {
				change: {
					fn: function(i_field, s_value) {

						var i_trigger = i_field.getTrigger("send");
						var b_valid = i_field.isValid();

						if (i_trigger) {
							i_trigger[b_valid && s_value ? "show" : "hide"]();
						}
					}
				},
				validitychange: {
					fn: function(i_field, b_valid) {

						var i_trigger = i_field.getTrigger("send");
						
						var s_value = i_field.getValue();

						if (i_trigger) {
							i_trigger[b_valid && s_value ? "show" : "hide"]();
						}
					} 
				}
			},
			triggers: {
				send: {
					hidden: true,
					cls: "x-ux-form-trigger-send",
					handler: function() {
						if (i_email.isValid()) {

							var i_template = Ext.create("Ext.XTemplate",
								"mailto:{email}?body={[this.encodeBody(values.body)]}",
								{
									encodeBody: function(value) {
										return encodeURIComponent(value);
									}
								}
							);

							var s_mail = i_email.getValue();

							var s_value = i_template.apply({
								email: s_mail,
								body: i_url.getValue()
							});

							window.open(s_value, "_blank");
						}
						
					}
				}
			}
		});

		

		a_fields.push(i_hide);
		a_fields.push(i_url);
		a_fields.push(i_email);

		i_self.setUrlField(i_url);
		i_self.setHideField(i_hide);

		return a_fields;
	},

	getUrl: function(n_hide, n_window) {

		var i_self = this;

		var s_template = i_self["static"].tpl;

		var s_value = "";

		var o_config = {
			protocol: window.location.protocol,
			host: window.location.host,
			pathname: window.location.pathname,
			search: ""
		};

		var i_model = i_self.getModel();
		var o_app = i_self.getApp();

		s_value = s_value.replace("{protocol}", window.location.protocol);
		s_value = s_value.replace("{host}", window.location.host);
		s_value = s_value.replace("{pathname}", window.location.pathname);

		if (n_hide) {
			Ext.apply(o_config, {
				search: "?layout=" + n_hide
			});
		}

		if (i_model) {

			var s_hash;

			if (i_model.entity) {

				if (n_window) {
					s_hash = "#" + n_window + "-entity-" + i_model.entity.name;
				}
				else {
					s_hash = "#entity-" + i_model.entity.name;
				}

				if (i_model.get(i_model.idProperty)) {
					s_hash = s_hash + "-" + i_model.get(i_model.idProperty);
					if (i_self.getActiveTabIndex()) {
						s_hash = s_hash + "-" + i_self.getActiveTabIndex();
					}
				}
				else {
					s_hash = s_hash + "-" + i_model.view;
				}

				if (i_model.dmdFile) {
					s_hash = s_hash + "-" + i_model.dmdFile;
				}

				Ext.apply(o_config, {
					hash: s_hash
				});
			}
			else if (i_model.widget) {

				if (i_model.widget.name) {

					if (n_window) {
						s_hash = "#" + n_window + "-widget-" + i_model.widget.name;
					}
					else {
						s_hash = "#widget-" + i_model.widget.name;
					}
				}
				else {

					if (i_model.entity) {

						if (n_window) {
							s_hash = "#" + n_window + "-widget-" + i_model.entity.name;
						}
						else {
							s_hash = "#widget-" + i_model.entity.name;
						}

						if (i_model.get(i_model.idProperty)) {
							s_hash = s_hash + "-" + i_model.get(i_model.idProperty);
						}
						if (i_model.xpd) {
							s_hash = s_hash + "-" + i_model.xpd;
						}
						if (i_model.dmdFile) {
							s_hash = s_hash + "-" + i_model.dmdFile;
						}
					}
				}
			}
			else if (i_model.dynapp) {

				s_hash = "#dynapp-" + i_model.dynapp.library + "-" + i_model.dynapp.file;
			}

			Ext.apply(o_config, {
				hash: s_hash
			});
		}
		else if (o_app) {

			s_template = i_self["static"].appTpl;

			var s_apptpl = n_window ? "1-" + s_apptpl : s_apptpl;

			o_config = {
				app: o_app.main,
				paths: Ext.urlEncode(o_app.paths),
				config: Ext.urlEncode(o_app.config),
				hash: "#" + s_apptpl
			};
		}
		else {

			Ext.apply(o_config, {
				hash: window.location.hash
			});
		}

		var i_template = Ext.create("Ext.XTemplate", s_template);

		i_template.compile();

		s_value = i_template.apply(o_config);

		return s_value;
	}
});
Ext.define("Ext.ux.buffer.Proxy", {
	extend: "Ext.data.proxy.Ajax",
	alias: "proxy.ux.buffer",
	paramsAsJson: true,
	type: "ajax",
	reader: {
		type: "json",
		headers: {
			"Accept": "application/json"
		},
		rootProperty: "rows",
		totalProperty: "totalRows"
	},
	actionMethods: {
		read: "POST"
	}
});
Ext.define("Ext.ux.buffer.Store", {
	
	extend: "Ext.data.Store",

	config: {
		idProperty: null
	},
	
	constructor: function() {
		
		var i_self = this;
		i_self.callParent(arguments);
		var s_idProperty = i_self.getIdProperty();

		if (s_idProperty) {

			var i_model = i_self.getModel();
			var i_proto = i_model.prototype;

			var a_fields = i_proto.getFields();

			var s_oldId = i_proto.getIdProperty();

			if (s_oldId !== s_idProperty) {

				var a_result = Ext.Array.filter(a_fields, function(i_field) {
					return i_field.name !== s_oldId;
				});

				i_model.idProperty = i_proto.idProperty = s_idProperty;

				i_model.replaceFields(a_result, true);
				
			}
		}
	},
});
Ext.define("Ext.ux.buffer.Grid", {
	extend: "Ext.grid.Panel",
	alias: [
		"widget.ux.buffer.grid",
		"widget.legacy.subfile"
	],
	requires: [
		"Ext.ux.buffer.Proxy"
	],

	config: {
		toolbar: null,
		pageSize: 100
	},

	initComponent: function() {

		var i_self = this;
		var o_config = i_self.initialConfig;

		var i_store = i_self.createStore(o_config);

		var a_columns = i_self.columns || [];

		var a_newColumns = Ext.Array.filter(a_columns, function(o_config) {
			return !o_config.hidden;
		});

		i_self.store = i_store;
		i_self.columns = a_newColumns;

		i_self.callParent(arguments);
	},

	createStore: function(o_config) {

		var i_self = this;

		var a_fields = [];
		var a_columns = o_config.columns || [];

		Ext.Array.each(a_columns, function(o_column) {
			var o_field = Ext.apply({
				name: o_column.dataIndex
			});

			o_field.type = o_column.dataType || "auto";
			a_fields.push(o_field);
		});

		var o_storeConfig = Ext.applyIf({}, {
			remoteSort: true,
			pageSize: i_self.getPageSize(),
			autoLoad: false,
			proxy: {
				url: o_config.url || "",
				type: "ux.buffer"
			},
			fields: a_fields
		}, o_config.store);

		var i_store = Ext.create("Ext.data.BufferedStore", o_storeConfig);

		return i_store;
	},

	load: function(o_options, f_callback) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_proxy = i_store.getProxy();

		f_callback = f_callback || Ext.emptyFn;

		if (o_options) {
			i_proxy.setExtraParams(o_options);
		}
		
		i_store.load({
			callback: f_callback
		});
	}
});
Ext.define("Ext.ux.buffer.controller.Form", {
	extend: "Ext.app.ViewController",

	alias: "controller.ux.buffer.controller.form",

	onSpecialKey: function(i_field, i_event) {

		var i_controller = this;

		if (i_event.getKey() === i_event.ENTER) {
			i_controller.onSave();
		}
	},

	onSave: function(f_callback) {

		f_callback = f_callback ||  Ext.emptyFn;

		var i_controller = this;
		var i_view = i_controller.getView();

		var i_record = i_view.getRecord();
		var o_values = i_view.getValues();

		i_record.set(o_values);

		var url = i_view.getUrl();
		var s_url = "";

		if (Ext.isObject(url)) {
			s_url = url.save || url.set;
		}

		i_view.setLoading("Saving");

		Ext.Ajax.request({
			url: s_url,
			jsonData: {
				row: i_record.getData()
			},
			method: "POST",
			success: function (o_response) {

				i_view.setLoading(false);

				var o_result = Ext.decode(o_response.responseText, true) || {};

				if (!o_result.success) {

					var a_errors = o_result.errors;

					Ext.Array.each(a_errors, function(o_config) {

						var i_field = i_view.getForm().findField(o_config.name || o_config.id);
						if (i_field) {
							i_field.markInvalid(o_config.message || o_config.msg);
						}
					});
				}

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

				i_view.setLoading(false);
				f_callback(false);
			}
		});
	}

});
Ext.define("Ext.ux.buffer.view.Form", {
	extend: "Ext.form.Panel",

	requires: [
		"Ext.ux.buffer.Proxy",
		"Ext.ux.buffer.Store",
		"Ext.ux.buffer.controller.Form"
	],

	alias: [
		"widget.ux.buffer.view.form",
		"widget.legacy.storeform"
	],

	config: {
		store: null,
		url: null,
		idProperty: null
	},

	trackResetOnLoad: true,

	controller: "ux.buffer.controller.form",

	initComponent: function() {

		var i_self = this;

		i_self.callParent(arguments);

		i_self.createStore();
		i_self.addHandler();
	},

	createStore: function() {

		var i_self = this;
		var i_form = i_self.getForm();
		var a_result = i_form.getFields();

		var a_fields = [];

		Ext.Array.each(a_result.items, function(i_field) {
			var o_config = Ext.apply({
				name: i_field.name
			});

			o_config.type = "auto";
			a_fields.push(o_config);
		});

		var s_url = i_self.getUrl() || "";

		if (Ext.isObject(s_url)) {
			s_url = s_url.load || s_url.get;
		}

		var o_storeConfig = Ext.applyIf({}, {
			remoteSort: true,
			pageSize: 100,
			autoLoad: false,
			idProperty: i_self.getIdProperty(),
			proxy: {
				url: s_url || "",
				type: "ux.buffer"
			},
			fields: a_fields,
			listeners: {
				load: {
					fn: function(i_store, a_records) {

						a_records = Ext.Array.from(a_records);

						if (a_records.length > 0) {

							var i_record = a_records[0];
							i_self.loadRecord(i_record);
						}
					}
				}
			}
		});

		var i_store = Ext.create("Ext.ux.buffer.Store", o_storeConfig);
		var i_model = i_store.getModel();
		var i_record = i_model.create({});

		i_self.setStore(i_store);
		i_self.loadRecord(i_record);
	},

	addHandler: function() {

		var i_self = this;
		var i_form = i_self.getForm();
		var i_monitor = i_form.getFields();

		Ext.Array.each(i_monitor.items, function(i_field) {

			i_field.on({
				specialkey: "onSpecialKey"
			});
		});
	},

	load: function(o_options) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_proxy = i_store.getProxy();
		if (o_options) {
			i_proxy.setExtraParams(o_options);
		}
		i_store.load();
	},

	save: function(f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var i_controller = i_self.getController();
		i_controller.onSave(function(b_success) {
			f_callback(b_success);
		});
	}
});
Ext.define("Ext.ux.form.field.EntityComboBox", {

	extend: "Ext.form.field.ComboBox",

	alias: [
		"widget.entitycombo",
		"widget.entitycombobox",
		"widget.entitypicker",
		"widget.ux.form.field.entitycombobox"
	],

	iconCls: "x-ux-search-icon",
	pageSize: 20,
	queryParam: "search",
	queryMode: "remote",
	typeAhead: true,
	minChars: 1,
	triggerAction: "all",
	forceSelection: false,
	cancelSearch: false,
	queryCaching: false,

	cls: "x-ux-field-entitycombobox",

	triggers: {
		clear: {
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			weight: 1,
			handler: "onClearClick",
			hidden: true,
			scope: "this"
		},
		"new": {
			cls: "x-ux-form-trigger-add",
			weight: 3,
			handler: "onAddClick",
			scope: "this"
		},
		picker: {
			weight: 2,
			handler: "onTriggerClick",
			scope: "this"
		}
	},

	lastQuery: "",

	config: {
		customFilter: null,
		dmd: "",
		entity: "",
		view: "portfolio",
		context: "grid",
		extraParams: null,
		columns: [],
		model: null,
		union: null,
		unions: [],
		stored: null,
		allowAdd: false,
		changeOnLoad: false
	},

	listeners: {
		afterrender: {
			fn: function (i_field) {
				var value = i_field.getValue();
				if (i_field.inputEl) {

					i_field.setIconCls("x-ux-search-icon");

					if (Ext.isEmpty(value)) {
						i_field.getTrigger("clear").hide();
					}
					else {
						i_field.getTrigger("clear").show();
					}

					if (i_field.readOnly) {
						i_field.setIconCls("");
						i_field.getTrigger("clear").hide();
						i_field.getTrigger("new").hide();
					}
					else {
						i_field.getTrigger("new")[i_field.getAllowAdd() ? "show" : "hide"]();
					}
				}
			},
			single: true
		},
		change: {
			fn: function (i_field, value) {
				if (i_field.inputEl) {

					var a_values = Ext.Array.from(value);

					if (a_values.length === 0) {
						i_field.allQuery = "";
						i_field.clearValue();
						i_field.getTrigger("clear").hide();
					}
					else {
						i_field.allQuery = i_field.lastQuery;
						if (!i_field.readOnly) {
							i_field.getTrigger("clear").show();
						}
					}
				}
			}
		},
		enable: {
			fn: function (i_field) {

				var s_value = i_field.getValue();

				i_field.getTrigger("clear")[s_value ? "show" : "hide"]();

				i_field.getTrigger("new")[i_field.getAllowAdd() ? "show" : "hide"]();

				i_field.setIconCls("x-ux-search-icon");
			},
			buffer: 10
		},
		disable: {
			fn: function (i_field) {
				i_field.setIconCls("");
				i_field.getTrigger("clear").hide();
				i_field.getTrigger("new").hide();
			},
			buffer: 10
		},
		writeablechange: {
			fn: function (i_field, b_readOnly) {

				var s_value = i_field.getValue();
				var b_allowAdd = i_field.getAllowAdd();

				i_field.setIconCls(!b_readOnly ? "x-ux-search-icon" : "");

				i_field.getTrigger("clear")[b_readOnly || !s_value ? "hide" : "show"]();

				i_field.getTrigger("new")[b_readOnly ? "hide" : "show"]();

				if (!b_readOnly) {
					i_field.getTrigger("new")[b_allowAdd ? "show" : "hide"]();
				}


			},
			buffer: 10
		},
		autosize: {
			fn: function (i_field) {
				var i_picker = i_field.getPicker();
				i_picker.setWidth(i_field.bodyEl.getWidth());
			},
			buffer: 1
		}
	},

	overloadConfig: function (o_config) {

		if (Ext.isObject(o_config.dmd)) {

			var o_dmd = o_config.dmd;

			if (o_dmd.extraParams) {
				o_config.extraParams = o_dmd.extraParams;
			}
			if (o_dmd.pageSize) {
				o_config.pageSize = o_dmd.pageSize;
			}
			if (o_dmd.uiName) {
				o_config.view = o_dmd.uiName;
			}
			if (o_dmd.view) {
				o_config.view = o_dmd.view;
			}

			o_config.entity = o_dmd.entity;
			o_config.dmd = o_dmd.file;
		}
	},

	initComponent: function () {

		var i_self = this;
		var o_config = Ext.apply({}, i_self.initialConfig);

		i_self.overloadConfig(o_config);

		Ext.apply(i_self, ip2.pick(o_config, [
			"dmd",
			"entity",
			"view",
			"extraParams",
			"pageSize"
		]));

		i_self.store = i_self.createStore(o_config);

		i_self.initDefinitions();

		i_self.callParent(arguments);

		return i_self;
	},

	initDefinitions: function () {

		var i_self = this;

		Ext.apply(i_self, {
			tpl: i_self.getDisplayTemplate(),
			displayTpl: i_self.getTemplate()
		});
	},

	initValue: function () {

		var i_self = this;

		var value = i_self.value || null;
		var a_temp = [];

		if(Ext.isArray(value)) {
			value = Ext.Array.from(value).filter(function(value){
				return !Ext.isEmpty(value);
			});
		}

		if (Ext.isEmpty(value)) {
			value = null;
		}

		i_self.setUnion(null);

		if (value) {

			if (Ext.isString(value)) {
				a_temp = value.split(",");
			}
			else {
				a_temp = Ext.Array.from(value);
			}
		}

		var a_values = Ext.Array.from(a_temp);

		var n_load = a_values.length;

		var i_store = i_self.getStore();

		if (n_load) {

			var a_result = [];

			Ext.Array.each(a_values, function (value) {
				if (Ext.isString(value)) {
					value = "'" + value + "'";
				}
				a_result.push(value);
			});

			var s_where = i_self.valueField + " in (" + a_result.join(",") + ")";

			var o_extraParams = i_store.extraParams = i_store.extraParams || {};

			var s_tempWhere = o_extraParams.where || "";

			Ext.apply(o_extraParams, {
				where: s_where
			});

			i_store.load({
				callback: function (a_records, i_store) {

					i_self.suspendCheckChange++;
					i_self.setValue(value);
					i_self.suspendCheckChange--;

					i_self.originalValue = i_self.lastValue = i_self.value = value;
					i_self.checkDirty();

					o_extraParams.where = s_tempWhere;
				}
			});
		}
		else {
			i_self.suspendCheckChange++;
			i_self.setValue(null);
			i_self.suspendCheckChange--;
			i_self.originalValue = i_self.lastValue = i_self.value = null;
			i_self.checkDirty();
		}
	},

	validateValue: function (value) {

		var i_self = this;
		var errors = i_self.getErrors(value);
		var isValid = Ext.isEmpty(errors);

		i_self[isValid ? "clearInvalid" : "markInvalid"](errors);

		return isValid;
	},

	createStore: function (o_config) {

		var i_self = this;
		var o_store;
		var i_store;
		var b_autoLoad = true;

		var s_dmd = i_self.getDmd();
		var s_entity = i_self.getEntity();

		var o_info = ip2.dmd.getInfo({
			dmd: s_dmd,
			entity: s_entity
		});

		var o_entity = o_info.entity;

		var s_idColumn = i_self.valueField || o_entity.idColumn;

		if (!s_idColumn) {
			var a_primary = o_entity.primaryKey || [];

			s_idColumn = a_primary.join("_");
		}

		i_self.valueField = s_idColumn || "id";

		if (o_config.hasOwnProperty("autoLoad")) {
			b_autoLoad = o_config.autoLoad;
		}

		var o_settings = ip2.pick(o_config, [
			"dmd",
			"entity",
			"view",
			"extraParams",
			"pageSize",
			"context"
		]);

		o_settings.context = o_settings.context || "grid";

		o_store = Ext.apply({
			remoteSort: true,
			autoLoad: false,
			autoAbort: true
		}, o_settings);

		if (o_store.extraParams) {

			var o_extraParams = o_store.extraParams;

			if (o_extraParams.filter) {
				if (i_self.getCustomFilter()) {
					o_extraParams.filter.push(i_self.getCustomFilter());
				}
			}

			Ext.Object.each(o_extraParams, function (s_key, value) {
				o_store.extraParams[s_key] = typeof value == "object" && value !== null ? Ext.encode(value) : value;
			});
		}

		i_store = Ext.create("Ext.ux.data.dmd.Store", o_store);

		i_store.on({
			load: {
				fn: function (store, a_records) {

					if (i_self.getChangeOnLoad()) {
						i_self.fireEvent("change", i_self, value);
					}
				}
			},
			beforeload: {
				fn: function (i_store, i_operation) {

					var i_proxy = i_store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();
					var a_union = i_self.getUnion();
					var o_model = i_store.dmdObject.model;
					var a_entities = o_model.entities;
					var o_entity = Ext.Array.findBy(a_entities, function (o_value) {
						return o_value.name == i_self.getEntity();
					});
					var o_view = o_entity.ui.grids[i_self.getView()];
					var o_extra = i_store.extraParams = i_store.extraParams || {};

					var o_params = i_operation.getParams() || {};

					delete o_extraParams.where;

					i_store.setUnion(a_union);
					Ext.apply(o_extraParams, o_extra);

					if (o_view.wheres && o_params.search) {
						o_extraParams.where = i_self.getWhere();
						delete o_params.search;
					}

					if (o_entity.language) {
						o_extraParams.languageColumn = o_entity.language.column;
						o_extraParams.language = o_extraParams.language = ip2.navigator.user.settings.language || "en";
					}

					if (o_extraParams.hasOwnProperty("language")) {
						o_extraParams.language = ip2.navigator.user.settings.language || "en";
					}
				}
			}
		});

		var i_model = i_store.getModel();

		i_self.setModel(i_model);

		return i_store;
	},

	getWhere: function () {

		var i_self = this;
		var i_store = i_self.getStore();
		var o_model = i_store.dmdObject.model;
		var a_entities = o_model.entities;
		var s_view = i_self.getView();

		var o_entity = Ext.Array.findBy(a_entities, function (o_value) {
			return o_value.name == i_self.getEntity();
		});

		var value = i_self.getRawValue();
		var s_where = "";
		var o_view = o_entity.ui.grids[s_view];

		if (o_view.wheres && value) {

			var a_search = value.split(" ");
			var a_where = [];

			Ext.Array.each(a_search, function (s_key) {
				a_where.push("" + o_view.wheres + "" + " like '%" + s_key + "%'");
			});
			s_where = a_where.join(" AND ");
		}
		return s_where;
	},

	onBindStore: function (i_store, o_initial) {
		var i_self = this;
		i_self.callParent(arguments);

		var i_pickerSelectionModel = i_self.pickerSelectionModel;

		i_pickerSelectionModel.deselectOnContainerClick = false;
	},

	createPicker: function () {

		var i_self = this;
		var i_picker;

		var o_options = Ext.apply({
			xtype: "boundlist",
			pickerField: i_self,
			selectionModel: i_self.pickerSelectionModel,
			floating: true,
			hidden: true,
			store: i_self.getStore(),
			preserveScrollOnRefresh: true,
			pageSize: i_self.pageSize,
			tpl: i_self.tpl,
			listeners: {
				resize: {
					fn: function () {

						var i_self = this;
						var i_toolbar = i_self.pagingToolbar;

						if (i_self.rendered && i_toolbar && i_toolbar.rendered) {

							if (i_self.getStore().getTotalCount() <= i_self.pageSize) {
								i_self.el.last().setSize(null, 0);
								i_self.pagingToolbar.el.setVisible(false, false);
							}
							else {
								i_toolbar.setSize(null, null);
								i_self.el.last().setSize(null, null);
							}
						}
					}
				}
			},
			createPagingToolbar: function () {
				var i_toolbar = Ext.widget("pagingtoolbar", {
					itemId: "pagingToolbar",
					pageSearch: false,
					pageSizeEdit: false,
					store: i_self.getStore(),
					border: false,
					displayInfo: true
				});

				i_self._toolbar = i_toolbar;

				return i_toolbar;
			}
		}, i_self.listConfig, i_self.defaultListConfig);

		i_picker = i_self.picker = Ext.widget(o_options);
		i_picker.navigationModel.navigateOnSpace = false; // THIS DISABLES SELECT ON SPACE...

		if (i_self.pageSize) {
			i_picker.pagingToolbar.on("beforechange", i_self.onPageChange, i_self);
		}

		if (!i_picker.initialConfig.maxHeight) {
			i_picker.on({
				beforeshow: i_self.onBeforePickerShow,
				scope: i_self
			});
		}

		i_picker.getSelectionModel().on({
			"beforeselect": i_self.onBeforeSelect,
			"beforedeselect": i_self.onBeforeDeselect,
			scope: i_self
		});

		return i_picker;
	},

	onAddClick: function () {

		var i_self = this;

		var o_size = ip2.getWindowSize();

		var i_window = Ext.widget("window", {
			width: o_size.width * 0.6,
			height: o_size.height * 0.6,
			layout: "fit",
			border: false
		});

		var i_entityForm = Ext.widget("entityform", {
			dmd: i_self.getDmd(),
			entity: i_self.getEntity(),
			view: i_self.getView(),
			keys: {},
			action: "new",
			dataParent: i_window,
			transactiontype: i_self.getEntity(),
			activeTabIndex: 0,
			closable: false,
			buttons: [
				{
					xtype: "button",
					text: "Save",
					iconCls: "pf-floppy_disk",
					handler: function (i_button) {

						i_window.setLoading(true);

						var i_entityForm = i_button.up("entityform");

						if (i_entityForm) {
							i_entityForm.save(function (i_record) {

								i_self.loadNewRecord(i_record, function (o_data) {

									var i_store = i_self.getStore();
									i_store.loadData([o_data], true);
									i_self.setValue(i_record.get(i_record.idProperty));
									i_window.setLoading(true);
									i_window.close();
								});
							});
						}
					}
				},
				{
					xtype: "button",
					text: "Close",
					iconCls: "pf-navigate_cross",
					handler: function () {

						i_window.close();
					}
				}
			]
		});

		var i_actionBar = i_entityForm.getActionbar();
		i_actionBar.hide();

		i_window.add(i_entityForm);
		i_window.show();
	},

	onClearClick: function () {

		var i_self = this;

		i_self.setSelection(null);
		i_self.clearValue();

		return i_self;
	},

	getDisplayFields: function () {

		var i_self = this;
		var a_fields = [];
		var i_model = i_self.getModel();
		var a_columns = i_model.getFields();

		Ext.Array.each(a_columns, function (o_column) {
			if (o_column.isTitle) {
				a_fields.push(o_column.as || o_column.name);
			}
		});

		if (a_fields.length === 0) {
			a_fields.push(i_model.idProperty);
		}

		return a_fields;
	},

	getRenderFn: function () {

		var i_self = this;
		var a_fields = i_self.getDisplayFields();

		var f_renderer = function (v) {

			var s_value = v[i_self.valueField];
			var a_values = [];

			Ext.Array.each(a_fields, function (s_field) {
				if (v[s_field]) {
					a_values.push(ip2.i18n(v[s_field]));
				}
			});

			if (a_values.length > 0) {
				if (a_values.length == 1) {
					s_value = a_values[0];
				}
				else {
					s_value = a_values.join(" - ");
				}
			}

			return s_value;
		};

		return f_renderer;
	},

	getDisplayTemplate: function () {

		var i_self = this;
		return i_self.getRenderTemplate(i_self.getRenderFn());
	},

	getRenderTemplate: function (f_renderer) {

		var i_self = this;

		f_renderer = Ext.isFunction(f_renderer) ? f_renderer : i_self.getRenderFn();

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
			"<li role=\"option\" class=\"x-boundlist-item\" style=\"text-overflow: ellipsis; white-space: nowrap; overflow:hidden;\">",
			"{[this.renderer(values)]}",
			"</li>",
			"</tpl>",
			{
				renderer: f_renderer
			}
		);

		return i_tpl;
	},

	getTemplate: function () {

		var i_cmp = this;

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
			"{[typeof values === \"string\" ? values : this.renderer(values)]}",
			"<tpl if=\"xindex < xcount\">" + i_cmp.delimiter + "</tpl>",
			"</tpl>",
			{
				renderer: i_cmp.getRenderFn()
			}
		);
		return i_tpl;
	},

	onTriggerClick: function () {

		var i_self = this;
		if (!i_self.readOnly && !i_self.disabled) {
			if (i_self.isExpanded) {
				i_self.collapse();
			}
			else {
				i_self.allQuery = "";
				delete i_self.lastQuery;
				if (i_self.triggerAction === "all") {
					i_self.doQuery(i_self.allQuery, true);
				}
				else if (i_self.triggerAction === "last") {
					i_self.doQuery(i_self.lastQuery, true);
				}
				else {
					i_self.doQuery(i_self.getRawValue(), false, true);
				}
			}
		}
	},

	onPageChange: function (toolbar, newPage) {

		this.loadPage(newPage, {
			rawQuery: true
		});
		return false;
	},

	setValue: function (value) {

		var i_self = this;
		var a_union = [];

		if (value && Ext.isString(value)) {
			value = value.split(",");
		}

		value = Ext.Array.from(value).filter(function(value) {
			return !Ext.isEmpty(value);
		});

		var a_args = [value];

		i_self.callParent(a_args);

		if (value) {

			a_union = ip2.dmd.unionize(i_self.valueField, value);

			if (i_self.getUnions()) {

				var a_unions = i_self.getUnions() || [];

				Ext.Array.each(a_unions, function (o_template) {
					a_union.push(o_template);
				});
			}

			var o_extraParams = i_self.getExtraParams() || {};

			if (o_extraParams.filter) {

				var a_temp = [];

				if (Ext.isArray(o_extraParams.filter)) {
					a_temp = o_extraParams.filter;
				}
				else if (Ext.isString(o_extraParams.filter)) {

					var a_decoded = Ext.decode(o_extraParams.filter, true);

					a_temp = Ext.Array.from(a_decoded);
				}

				Ext.Array.each(a_temp, function (o_template) {
					a_union.push(o_template);
				});
			}

			var o_customFilter = i_self.getCustomFilter();

			if (o_customFilter) {
				a_union.push(o_customFilter);
			}

			i_self.setUnion(a_union);
		}
		else {
			i_self.setUnion(null);
		}

		return i_self;
	},

	loadNewRecord: function (i_record, f_callback) {

		var i_self = this;

		f_callback = f_callback || Ext.emptyFn;

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			params: {
				action: "getRows",
				context: i_self.getContext() || "grid",
				dmdFile: i_self.getDmd(),
				uiName: i_self.getView(),
				model: i_self.getEntity(),
				where: i_record.idProperty + " = " + i_record.get(i_record.idProperty)
			},
			success: function (o_response) {

				var o_result = Ext.decode(o_response.responseText, true) || {
					success: false,
					rows: [{}]
				};

				if (!o_result.rows) {
					o_result.rows = [{}];
				}

				var o_data = o_result.rows[0];

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

	getGrowWidth: function () {

		var i_self = this;

		var value = i_self.inputEl.dom.value;
		var a_fields;
		var i_store;
		var dataLn;
		var currentLongestLength;
		var i;
		var item;
		var itemLn;

		if (i_self.growToLongestValue) {

			a_fields = i_self.getDisplayFields();
			i_store = i_self.store;
			dataLn = i_store.data.length;
			currentLongestLength = 0;

			for (i = 0; i < dataLn; i++) {

				var a_values = [];

				Ext.Array.each(a_fields, function(s_field){
					var s_value = i_store.getAt(i).data[s_field];
					a_values.push(s_value);
				});

				item = a_values.join(" - ");

				itemLn = item.length;

				if (itemLn > currentLongestLength) {
					currentLongestLength = itemLn;
					value = item;
				}
			}
		}
		return value;
	}
});
Ext.define("Ext.ux.form.field.RestEntityPicker", {

	extend: "Ext.form.field.ComboBox",

	alias: [
		"widget.restentitypicker",
		"widget.ux.form.field.restentitycombobox"
	],

	iconCls: "x-ux-search-icon",
	pageSize: 20,
	queryParam: "search",
	queryMode: "remote",
	queryDelay: 250,
	typeAhead: true,
	minChars: 1,
	triggerAction: "all",
	forceSelection: false,
	cancelSearch: false,
	queryCaching: false,

	cls: "x-ux-field-restentitycombobox",

	triggers: {
		clear: {
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			weight: 1,
			handler: "onClearClick",
			hidden: true,
			scope: "this"
		},
		"new": {
			cls: "x-ux-form-trigger-add",
			weight: 2,
			handler: "onAddClick",
			scope: "this"
		},
		picker: {
			weight: 3,
			handler: "onTriggerClick",
			scope: "this"
		}
	},

	emptyText: ip2.i18n({
		da: "Søg...",
		en: "Search..."
	}),

	lastQuery: "",

	config: {
		dmd: "",
		entity: "",
		model: null,
		allowAdd: false,
		url: "",
		searchUrl: "",
		rootProperty: "rows",
		totalProperty: "totalElements",
		limitParam: "limit",
		proxy: null,
		asObject: false
	},

	initComponent: function () {

		var i_self = this;

		i_self.store = i_self.createStore();

		i_self.callParent(arguments);

		i_self.initDefinitions();

		i_self.on({
			afterrender: {
				fn: function (i_self) {
					var value = i_self.getValue();
					if (i_self.inputEl) {

						i_self.setIconCls("x-ux-search-icon");

						if (Ext.isEmpty(value)) {
							i_self.getTrigger("clear").hide();
						}
						else {
							i_self.getTrigger("clear").show();
						}

						if (i_self.readOnly) {
							i_self.setIconCls("");
							i_self.getTrigger("clear").hide();
							i_self.getTrigger("new").hide();
						}
						else {
							i_self.getTrigger("new")[i_self.getAllowAdd() ? "show" : "hide"]();
						}
					}
				},
				single: true
			},
			change: {
				fn: function(i_self, value) {
					if (i_self.inputEl) {
						if (!value || (value && value.length === 0)) {
							i_self.allQuery = "";
							i_self.clearValue();
							i_self.getTrigger("clear").hide();
						}
						else {
							i_self.allQuery = i_self.lastQuery;
							if (!i_self.readOnly) {
								i_self.getTrigger("clear").show();
							}
						}
					}
				}
			},
			enable: {
				fn: function(i_field) {

					var s_value = i_field.getValue();

					i_field.getTrigger("clear")[s_value ? "show" : "hide"]();

					i_field.getTrigger("new")[i_field.getAllowAdd() ? "show" : "hide"]();

					i_field.setIconCls("x-ux-search-icon");
				},
				buffer: 10
			},
			disable: {
				fn: function(i_field) {
					i_field.setIconCls("");
					i_field.getTrigger("clear").hide();
					i_field.getTrigger("new").hide();
				},
				buffer: 10
			},
			writeablechange: {
				fn: function(i_field, b_readOnly) {

					var s_value = i_field.getValue();
					var b_allowAdd = i_field.getAllowAdd();

					i_field.setIconCls(!b_readOnly ? "x-ux-search-icon" : "");

					if (s_value) {
						i_field.getTrigger("clear")[b_readOnly ? "hide" : "show"]();
					}
					else {
						i_field.getTrigger("clear").hide();
					}

					i_field.getTrigger("new")[b_readOnly ? "show" : "hide"]();

					if (b_readOnly) {
						i_field.getTrigger("new")[b_allowAdd ? "show" : "hide"]();
					}
				},
				buffer: 10
			}
		});

		return i_self;
	},

	initDefinitions: function () {

		var i_self = this;

		var s_dmd = i_self.getDmd();
		var s_entity = i_self.getEntity();

		var i_model = ip2.model({
			dmd: s_dmd,
			entity: s_entity
		});

		i_self.setModel(i_model);

		Ext.apply(i_self, {
			tpl: i_self.getDisplayTemplate(),
			displayTpl: i_self.getTemplate()
		});
	},

	initValue: function() {

		var i_self = this;
		var value = i_self.value;

		var s_dmd = i_self.getDmd();
		var s_entity = i_self.getEntity();

		var i_model = i_self.getModel();

		var a_loaded = [];

		if (Ext.isEmpty(value)) {
			value = null;
		}

		var a_values = Ext.Array.from(value);
		var i_created;

		if (Ext.isObject(value)) {

			var i_store = i_self.getStore();

			i_self.on({
				afterrender: {
					fn: function(i_field) {

						i_created = i_model.create(value);

						i_self.suspendCheckChange++;
						i_self.setValue(i_created);
						i_self.suspendCheckChange--;
					},
					single: true
				}
			});

			i_self.originalValue = i_self.lastValue = value;
			i_self.resetOriginalValue();
		}
		else {

			var n_load = a_values.length;

			if (n_load) {

				var i_proxy = i_self.getProxy();

				var s_root = i_proxy.getReader().getRootProperty();

				var i_reader = i_proxy.getReader();

				i_reader.setRootProperty("");

				i_model.setProxy(i_proxy);

				Ext.Array.each(a_values, function(n_value) {

					i_created = i_model.create({});
					i_created.set(i_created.idProperty, n_value);

					i_created.load({
						callback: function(i_record, i_operation, b_success) {

							n_load--;

							if (i_record.get(i_record.idProperty)) {
								a_loaded.push(i_record);
							}

							if (n_load === 0) {

								i_reader.setRootProperty(s_root);

								var i_store = i_self.getStore();

								i_store.loadData(a_loaded, true);

								i_self.suspendCheckChange++;
								i_self.setValue(a_values);
								i_self.suspendCheckChange--;
								i_self.originalValue = i_self.lastValue = i_self.getValue();
							}
						}
					});
				});
			}
			else {
				i_self.suspendCheckChange++;
				i_self.setValue(a_values);
				i_self.suspendCheckChange--;
				i_self.originalValue = i_self.lastValue = i_self.getValue();
			}
		}
	},

	getValue: function() {

		var i_self = this;
		var result = i_self.value;

		var i_selection = i_self.getSelectedRecord();

		if (i_selection) {
			if (i_self.getAsObject()) {
				result = i_selection.getData();
			}
		}

		return result;
	},

	createStore: function() {

		var i_self = this;

		var s_dmd = i_self.getDmd();
		var s_entity = i_self.getEntity();

		var i_model = ip2.model({
			dmd: s_dmd,
			entity: s_entity
		});

		var o_info = ip2.dmd.getInfo({
			dmd: s_dmd,
			entity: s_entity
		});

		var o_entity = o_info.entity;

		var s_idColumn = i_self.valueField || o_entity.idColumn;

		if (!s_idColumn) {
			var a_primary = o_entity.primaryKey || [];

			s_idColumn = a_primary.join("_");
		}

		i_self.valueField = s_idColumn || "id";

		var i_store = Ext.create("Ext.data.Store", {
			model: i_model,
			proxy: i_self.createProxy(),
			pageSize: i_self.pageSize,
			autoLoad: false,
			listeners: {
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();
						var s_page = i_proxy.getPageParam();

						var n_page = i_operation.getPage() || 1;

						if (!i_operation.getUrl()) {
							i_operation.setUrl(i_proxy.getUrl());
						}

						n_page--;

						if (n_page <= 0) {
							n_page = 1;
						}

						var o_apply = {};
						o_apply[s_page] = n_page;

						Ext.apply(o_extraParams, o_apply);
					}
				}
			}
		});

		i_self.setModel(i_model);

		return i_store;
	},

	onBindStore: function(i_store, o_initial) {

		var i_self = this;
		i_self.callParent(arguments);

		var i_pickerSelectionModel = i_self.pickerSelectionModel;

		i_pickerSelectionModel.deselectOnContainerClick = false;
	},

	isEqual: function(newVal, oldVal) {

		var i_self = this;
		var b_equal = true;

		var a_new = Ext.Array.from(newVal);
		var a_old = Ext.Array.from(oldVal);

		var n_length = a_new.length;

		if (a_new.length !== a_old.length) {
			b_equal = false;
		}

		if (b_equal) {
			if (i_self.getAsObject()) {

				var s_new = Ext.encode(newVal);
				var s_old = Ext.encode(oldVal);

				b_equal = s_new == s_old;
			}
			else {
				for (var i = 0; i > n_length; i++) {

					if (a_old[i] !== a_new[i]) {
						b_equal = false;
					}
				}
			}
		}

		return b_equal;
	},

	createPicker: function() {

		var i_self = this;
		var i_picker;

		var o_options = Ext.apply({
			xtype: "boundlist",
			pickerField: i_self,
			selectionModel: i_self.pickerSelectionModel,
			floating: true,
			hidden: true,
			store: i_self.getStore(),
			preserveScrollOnRefresh: true,
			pageSize: i_self.pageSize,
			tpl: i_self.tpl,
			createPagingToolbar: function() {
				var i_toolbar = Ext.widget("pagingtoolbar", {
					itemId: "pagingToolbar",
					pageSearch: false,
					pageSizeEdit: false,
					store: i_self.getStore(),
					border: false,
					displayInfo: true
				});

				i_self._toolbar = i_toolbar;

				return i_toolbar;
			}
		}, i_self.listConfig, i_self.defaultListConfig);

		i_picker = i_self.picker = Ext.widget(o_options);
		i_picker.navigationModel.navigateOnSpace = false; // THIS DISABLES SELECT ON SPACE...

		if (i_self.pageSize) {
			i_picker.pagingToolbar.on("beforechange", i_self.onPageChange, i_self);
		}

		if (!i_picker.initialConfig.maxHeight) {
			i_picker.on({
				beforeshow: i_self.onBeforePickerShow,
				scope: i_self
			});
		}

		i_picker.getSelectionModel().on({
			"beforeselect": i_self.onBeforeSelect,
			"beforedeselect": i_self.onBeforeDeselect,
			scope: i_self
		});

		return i_picker;
	},

	onAddClick: function() {

		var i_self = this;

		var o_size = ip2.getWindowSize();

		var s_entity = i_self.getEntity();
		var s_dmd = i_self.getDmd();

		var i_window = Ext.widget("window", {
			width: o_size.width * 0.6,
			height: o_size.height * 0.6,
			layout: "fit",
			border: false
		});

		var i_entityForm = Ext.widget("entityform", {
			dmd: s_dmd,
			entity: s_entity,
			view: "portfolio",
			keys: {},
			action: "new",
			dataParent: i_window,
			transactiontype: s_entity,
			activeTabIndex: 0,
			closable: false,
			buttons: [
				{
					xtype: "button",
					text: "Save",
					iconCls: "pf-floppy_disk",
					handler: function(i_button) {

						i_window.setLoading(true);

						var i_entityForm = i_button.up("entityform");

						if (i_entityForm) {
							i_entityForm.save(function(i_record) {

								i_self.loadNewRecord(i_record, function(i_loaded) {

									var i_store = i_self.getStore();
									i_store.loadData([i_loaded], true);
									i_self.setValue(i_loaded.get(i_loaded.idProperty));
									i_window.setLoading(true);
									i_window.close();
								});
							});
						}
					}
				},
				{
					xtype: "button",
					text: "Close",
					iconCls: "pf-navigate_cross",
					handler: function() {

						i_window.close();
					}
				}
			]
		});

		var i_actionBar = i_entityForm.getActionbar();
		i_actionBar.hide();

		i_window.add(i_entityForm);
		i_window.show();
	},

	onClearClick: function() {

		var i_self = this;

		i_self.clearValue();

		return i_self;
	},

	getDisplayFields: function () {

		var i_self = this;
		var a_fields = [];
		var i_model = i_self.getModel();
		var a_columns = i_model.getFields();

		Ext.Array.each(a_columns, function(o_column) {
			if (o_column.isTitle) {
				a_fields.push(o_column.as || o_column.name);
			}
		});

		if (a_fields.length === 0) {
			a_fields.push(i_model.idProperty);
		}

		return a_fields;
	},

	getRenderFn: function() {

		var i_self = this;
		var a_fields = i_self.getDisplayFields();

		var f_renderer = function (o_values) {

			var s_value = null;
			var a_values = [];

			Ext.Array.each(a_fields, function(s_field) {
				if (o_values[s_field]) {
					a_values.push(ip2.i18n(o_values[s_field]));
				}
			});

			if (a_values.length > 0) {
				if (a_values.length == 1) {
					s_value = a_values[0];
				}
				else {
					s_value = a_values.join(" - ");
				}
			}

			return s_value;
		};

		return f_renderer;
	},

	getDisplayTemplate: function () {

		var i_self = this;
		return i_self.getRenderTemplate(i_self.getRenderFn());
	},

	getRenderTemplate: function(f_renderer) {

		var i_self = this;

		f_renderer = Ext.isFunction(f_renderer) ? f_renderer : i_self.getRenderFn();

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"<li role=\"option\" class=\"x-boundlist-item\" style=\"text-overflow: ellipsis; white-space: nowrap; overflow:hidden;\">",
					"{[this.renderer(values)]}",
				"</li>",
			"</tpl>",
			{
				renderer: f_renderer
			}
		);

		return i_tpl;
	},

	getTemplate: function() {

		var i_self = this;

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"{[typeof values === \"string\" ? values : this.renderer(values)]}",
				"<tpl if=\"xindex < xcount\">" + i_self.delimiter + "</tpl>",
			"</tpl>",
			{
				renderer: i_self.getRenderFn()
			}
		);
		return i_tpl;
	},

	onTriggerClick: function() {

		var i_self = this;
		if (!i_self.readOnly && !i_self.disabled) {
			if (i_self.isExpanded) {
				i_self.collapse();
			}
			else {
				i_self.allQuery = "";
				delete i_self.lastQuery;
				if (i_self.triggerAction === "all") {
					i_self.doQuery(i_self.allQuery, true);
				}
				else if (i_self.triggerAction === "last") {
					i_self.doQuery(i_self.lastQuery, true);
				}
				else {
					i_self.doQuery(i_self.getRawValue(), false, true);
				}
			}
		}
	},

	onPageChange: function(toolbar, newPage) {

		this.loadPage(newPage, {
			rawQuery: true
		});
		return false;
	},

	loadNewRecord: function(i_record, f_callback) {

		var i_self = this;

		var i_model = i_self.getModel();

		var i_load = i_model.create({});

		i_load.set(i_model.idProperty, i_record.get(i_record.idProperty));

		f_callback = f_callback || Ext.emptyFn;

		i_load.load({
			success: function(i_record, i_operation) {
				f_callback(i_record);
			},
			failure: function() {
				f_callback({});
			}
		});
	},

	createProxy: function() {

		var i_self = this;

		var s_limit = i_self.getLimitParam();

		var i_proxy = Portfolio.util.Handler.getProxyByEntity({
			dmd: i_self.getDmd(),
			entity: i_self.getEntity()
		});

		i_proxy.setLimitParam(s_limit || "limit");

		var i_reader = i_proxy.getReader();

		i_reader.setRootProperty(i_self.getRootProperty() || "rows");
		i_reader.setTotalProperty(i_self.getTotalProperty() || "totalElements")

		i_proxy.on({
			exception: {
				fn: function (i_proxy, i_response, i_operation) {

					var s_type = i_response.responseType;

					Ext.USE_NATIVE_JSON = false;

					var o_result = Ext.decode(i_response.responseText, true);

					//Ext.USE_NATIVE_JSON = true;

					if (s_type == "json") {
						o_result = i_response.responseJson;
					}

					o_result = o_result || {
						stmt: i_response.aborted ? "request aborted" : "",
						message: i_response.aborted ? "request aborted" : ""
					};

					var i_requst = i_operation.getRequest();

					var o_params = i_requst.getParams();
					var s_url = i_requst.getUrl();

					var o_config = {
						statement: o_result.stmt,
						params: o_params,
						url: s_url
					};

					if (Portfolio.util.Message) {
						Portfolio.util.Message.Add("Proxy exception", {
							message: o_result.message,
							params: o_config
						}, "sql");
					}
				}
			}
		});

		if (i_self.getUrl()) {
			i_proxy.setUrl(i_self.getUrl());
		}

		i_self.setProxy(i_proxy);

		return i_proxy;
	},

	setValue: function(value) {

		var i_self = this;

		var a_result = [];

		var i_model = i_self.getModel();

		var a_values = Ext.Array.from(value);

		Ext.Array.each(a_values, function(value) {

			var i_result = value;

			if (Ext.isObject(value)) {

				if (!value.isModel) {
					i_result = i_model.create(value);
				}
			}

			a_result.push(i_result);
		});

		i_self.callOverridden(a_result);

		if (Ext.isObject(value)) {

			var i_result = value;

			if (i_result.isModel) {
				i_self.value = i_result.getData();
			}
			else {

				i_result = i_model.create(value);

				i_self.value = i_result.getData();
			}
		}
	},

	getWhere: function () {

		var i_self = this;
		var o_model = i_self.getModel().prototype.dmdModel;
		var a_entities = o_model.entities;
		var s_view = "portfolio";

		var o_entity = Ext.Array.findBy(a_entities, function (o_value) {
			return o_value.name == i_self.getEntity();
		});

		var value = i_self.getRawValue();
		var s_where = "";
		var o_view = o_entity.ui.grids[s_view];

		if (o_view.wheres && value) {

			var a_search = value.split(" ");
			var a_where = [];

			Ext.Array.each(a_search, function (s_key) {
				a_where.push("" + o_view.wheres + "" + " like '%" + s_key + "%'");
			});
			s_where = a_where.join(" AND ");
		}
		return s_where;
	}
});
Ext.define("Ext.ux.form.field.LanguageComboBox", {

	extend: "Ext.ux.form.field.EntityComboBox",

	alias: [
		"widget.languagecombo",
		"widget.languagecombobox"
	],

	config: {
		dmd: "dmd/portfolio.dmd",
		entity: "NAVLNG",
		view: "portfolio",
		extraParams: null,
		localeStore: null
	},

	initComponent: function () {

		var i_self = this;

		var o_initalConfig = i_self.initialConfig || {};

		Ext.applyIf(o_initalConfig, {
			dmd: i_self.getDmd(),
			entity: i_self.getEntity(),
			view: i_self.getView(),
			extraParams: i_self.getExtraParams()
		});

		i_self.createLocaleStore();

		i_self.callParent(arguments);

		return i_self;
	},

	createLocaleStore: function() {

		var i_self = this;

		var i_store = Ext.create("Ext.ux.data.store.Locale", {});

		i_self.setLocaleStore(i_store);
	},

	getRenderFn: function() {

		var i_self = this;
		var a_fields = i_self.getDisplayFields();

		var i_localStore = i_self.getLocaleStore();

		var f_renderer = function (v) {

			v = v || {};
			var s_value = null;
			var a_values = [];

			Ext.Array.each(a_fields, function(s_field) {
				if (v[s_field]) {
					a_values.push(ip2.i18n(v[s_field]));
				}
			});

			if (a_values.length > 0) {

				a_values = Ext.Array.map(a_values, function(value) {

					var i_record = i_localStore.findRecord("code", value);

					var s_return = value;

					if (i_record) {
						s_return = ip2.i18n(i_record.get("language"));
					}

					return s_return;
				});

				if (a_values.length == 1) {
					s_value = a_values[0];
				}
				else {
					s_value = a_values.join(" - ");
				}
			}

			return s_value;
		};

		return f_renderer;
	},

	getRenderTemplate: function(f_renderer) {

		var i_self = this;

		var i_localStore = i_self.getLocaleStore();

		f_renderer = Ext.isFunction(f_renderer) ? f_renderer : i_self.getRenderFn();

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"<li role=\"option\" class=\"x-boundlist-item\" style=\"text-overflow: ellipsis; white-space: nowrap; overflow:hidden;\">",
					"<img src=\"{[this.getFlag(values.LNGID)]}\" style=\"padding-right:10px; vertical-align:middle; width:32px; height: 16px;\" />",
					"{[this.renderer(values)]}",
				"</li>",
			"</tpl>",
			{
				getFlag: function(s_id) {

					var i_record = i_localStore.findRecord("code", s_id);

					var s_result = "";

					if (i_record) {
						s_result = "/portfolio/styles/icon/flags/" + i_record.get("flag") + ".png";
					}

					return s_result;
				},
				renderer: f_renderer
			}
		);

		return i_tpl;
	},

	getTemplate: function() {

		var i_self = this;

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"{[typeof values === \"string\" ? values : this.renderer(values)]}",
			"</tpl>",
			{
				renderer: i_self.getRenderFn()
			}
		);
		return i_tpl;
	}
});
Ext.define("Ext.ux.form.field.ComboObjectType", {

	extend: "Ext.form.field.ComboBox",

	alias: "widget.comboobjecttype",

	isLoaded: false,

	queryParam: "search",

	config: {
		keyField: "key",
		valueField: "value",
		url: "",
		options: null
	},

	triggers: {
		clear: {
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			weight: 1,
			handler: "onClearClick",
			hidden: true,
			scope: "this"
		},
		picker: {
			weight: 3,
			handler: "onTriggerClick",
			scope: "this"
		}
	},

	requires: [
		"Ext.ux.buffer.Proxy"
	],

	listeners: {
		afterrender: {
			fn: function(i_field) {

				var value = i_field.getValue();
				i_field.fireEvent("change", i_field, value);
			}
		},
		change: {
			fn: function(i_field, value) {

				var i_self = this;

				if (value) {
					i_self.getTrigger("clear").show();
				}
				else {
					i_self.getTrigger("clear").hide();
				}
			}
		}
	},

	initComponent: function() {

		var i_self = this;

		Ext.apply(i_self, {
			queryMode: "remote",
			displayField: i_self.getKeyField(),
			valueField: i_self.getValueField(),
			triggerAction: "all",
			minChars: 1,
			typeAhead: false,
			maxLength: 1000,
			pageSize: 0,
			displayTpl: i_self.getDisplayTemplate(),
			tpl: i_self.getItemTemplate()
		});

		var i_store = Ext.create("Ext.data.Store", {
			fields: [
				{ name: i_self.getKeyField(), type: "auto" },
				{ name: i_self.getValueField(), type: "auto" }
			],
			proxy: {
				url: i_self.getUrl(),
				type: "ux.buffer"
			},
			remoteSort: true,
			autoLoad: false,
			autoSync: false,
			pageSize: 0
		});

		i_store.on({
			load: {
				fn: function(i_store, a_records) {

					if (!i_self.isLoaded) {

						i_self.isLoaded = true;

						if (i_self.value && a_records.length > 0) {
							i_self.setValue(i_self.value);
						}
						else {
							i_self.setValue("");
						}
						i_self.resetOriginalValue();
					}
				}
			},
			beforeload: {
				fn: function(i_store) {

					var i_proxy = i_store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();

					Ext.apply(o_extraParams, i_self.getOptions());

					Ext.apply(o_extraParams, {
						start: 0,
						limit: 100
					});
				}
			}
		});

		i_self.store = i_store;
		i_self.callParent();

		i_self.on({
			afterrender: {
				fn: function(i_field) {

					var i_store = i_field.getStore();
					i_store.load();
				}
			}
		});

		return i_self;
	},

	getDisplayTemplate: function() {

		var i_self = this;

		var i_template = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"{[this.renderer(values." + i_self.getKeyField() + ")]}",
			"</tpl>",
			{
				renderer: function(s_key) {
					return ip2.i18n(s_key);
				}
			}
		);
		return i_template;
	},

	getItemTemplate: function() {

		var i_self = this;

		var i_template = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"<li role=\"option\" class=\"x-boundlist-item\">",
					"{[this.renderer(values." + i_self.getKeyField() + ")]}",
				"</li>",
			"</tpl>",
			{
				renderer: function(s_key) {
					return ip2.i18n(s_key);
				}
			}
		);
		return i_template;
	},

	onClearClick: function() {

		var i_self = this;

		i_self.clearValue();

		return i_self;
	}
});
Ext.define("Ext.ux.data.dmd.Reader", {

	extend: "Ext.data.reader.Json",

	alternateClassName: [
		"Ext.data.DmdReader"
	],

	alias: "reader.dmd",

	root: "rows",

	totalProperty: "totalRows",

	nameProperty: "name",

	fields: null,

	extractData: function(a_root) {

		var i_reader = this;

		Ext.Array.each(a_root, function (o_item, n_index, a_context) {
			Ext.Object.each(o_item, function (s_key, value, o_context) {
				var s_hackedUpperCasedKeyHaveToFixService = s_key;
				o_context[s_hackedUpperCasedKeyHaveToFixService] = value;
			});

			a_context[n_index] = o_item;
		});

		var a_data = i_reader.callParent(arguments);

		return a_data;
	}
});
Ext.define('Ext.ux.data.dmd.Writer', {
	
	extend: 'Ext.data.writer.Json',
	
	alternateClassName: 'Ext.data.DmdWriter',
	
	alias: 'writer.dmd',

	root: 'rows',

	fields: null,

	nameProperty: 'name'
});
Ext.define('Ext.ux.data.dmd.Types', {

	singleton: true
},
function () {

	var o_type = Ext.data.Types;
	var o_sort = Ext.data.SortTypes;

	Ext.apply(o_type, {
		CHAR: {
			convert: o_type.STRING.convert,
			sortType: o_type.STRING.sortType,
			type: 'char'
		},
		INTEGER: {
			convert: o_type.INTEGER.convert,
			sortType: o_type.INTEGER.sortType,
			type: 'integer'
		},
		NUM6DATE: {
			convert: function (value) {
				return value;
			},
			sortType: o_sort.asDate,
			type: 'num6date'
		},
		NUM8DATE: {
			convert: function (value) {
				return value;
			},
			sortType: o_sort.asDate,
			type: 'num8date'
		},
		VARCHAR: {
			convert: o_type.STRING.convert,
			sortType: o_type.STRING.sortType,
			type: 'varchar'
		}
	});
});
Ext.define("Ext.ux.data.dmd.Proxy", {

	statics: {
		url: "/ip2-services/ip2dmdproxy.aspx",
		requests: new Ext.util.MixedCollection(),
		delay: 5,
		counter: 0,
		counterIncrement: 5,
		interval: null,
		processRecordToBatch: function (o_row, i_record, o_params) {

			var i_self = this;
			var o_batch = {};

			if (i_record) {
				// Set the key property for batch transaction
				var idProperty = i_record.idProperty;
				var idValue = i_record.get(idProperty);
				var o_key = {};
				o_key[idProperty] = idValue;

				Ext.apply(o_batch, {
					key: o_key,
					row: o_row
				});
			}

			Ext.apply(o_batch, o_params);

			return o_batch;
		},
		/**
		 * @method getActionParams
		 *
		 */
		getActionParams: function (i_request) {

			var i_self = this;
			var o_params = Ext.apply({}, i_request.getParams());
			var result = [];

			// Batch objects use type as their key
			o_params.type = i_self.type;

			// Attach an _action property to be used on return of response to concat possible array of batches
			o_params._action = i_request.getAction();
			o_params._id = i_request._id;

			// Overload sort property
			// Can come as array of stringed objects or string - we export as string
			// "LCDLCDTKN ASC, LCDCOD DESC" from
			// [{property: "LCDLCDTKN", "direction": "ASC"}]
			if (o_params.sort) {

				var value = o_params.sort;
				var a_sorters = Ext.decode(o_params.sort, true) || [];

				if (Ext.isString(value)) {
					a_sorters = Ext.Array.map(value.split(","), function (s_value) {
						var a_values = Ext.Array.filter(s_value.split(" "), Boolean);
						return Ext.apply({}, {
							property: a_values[0],
							direction: a_values[1] ? a_values[1] : "ASC"
						});
					});
				}
				else {
					a_sorters.push(value);
				}

				var a_result = [];

				Ext.Array.each(a_sorters, function(o_sorter) {
					a_result.push(o_sorter.property + " " + o_sorter.direction);
				})

				o_params.sort = a_result.join(", ");
			}

			var a_records = i_request.records;

			if (a_records && a_records.length > 1) {
				Ext.Array.each(i_request.jsonData.rows, function (o_data, n_index) {
					var i_record = a_records[n_index];
					var o_batch = Ext.ux.data.dmd.Proxy.processRecordToBatch(o_data, i_record, o_params);
					result.push(o_batch);
				});
			}
			else if (a_records && a_records.length == 1) {
				var o_data = i_request.jsonData.rows;
				var i_record = a_records[0];
				var o_batch = Ext.ux.data.dmd.Proxy.processRecordToBatch(o_data, i_record, o_params);
				result.push(o_batch);
			}
			else if (!a_records) {
				result.push(o_params);
			}

			switch (o_params.type) {

			case "get":
				Ext.Array.each(result, function (o_batch, n_index, a_contex) {

					delete o_batch.page;
					delete o_batch.fullresponse;

					a_contex[n_index] = o_batch;
				});
			break;

			case "upsert":

				var a_blacklist = [
					"context",
					"uiName"
				];

				Ext.Array.each(result, function (o_batch, n_index, a_contex) {

					Ext.Array.each(a_blacklist, function (s_key) {
						if (o_batch[s_key] != null) {
							delete o_batch[s_key];
						}
					});

					o_batch.fullresponse = true;

					a_contex[n_index] = o_batch;
				});

			break;

			case "delete":

				var a_blacklist = [
					"context",
					"uiName"
				];

				Ext.Array.each(result, function (o_batch, n_index, a_contex) {

					Ext.Array.each(a_blacklist, function (s_key) {
						if (o_batch[s_key] != null) {
							delete o_batch[s_key];
						}
					});

					a_contex[n_index] = o_batch;
				});

			break;

			default:
			break;
			}

			return result;
		},
		actionMap: {
			create: {
				type: "upsert",
				fn: function (i_request) {
					return Ext.ux.data.dmd.Proxy.getActionParams.call(this, i_request);
				}
			},
			read: {
				type: "get",
				fn: function (i_request) {
					return Ext.ux.data.dmd.Proxy.getActionParams.call(this, i_request);
				}
			},
			update: {
				type: "upsert",
				fn: function (i_request) {
					return Ext.ux.data.dmd.Proxy.getActionParams.call(this, i_request);
				}
			},
			destroy: {
				type: "delete",
				fn: function (i_request) {
					return Ext.ux.data.dmd.Proxy.getActionParams.call(this, i_request);
				}
			}
		},
		doBatchRequest: function (i_request) {

			var i_controller = this;

			i_controller.counter = 0;

			i_controller.requests.add(i_request);

			if (!i_controller.interval) {

				i_controller.interval = setInterval(function () {

					if (i_controller.counter >= i_controller.delay) {

						var i_requests = i_controller.requests;
						var i_batch = i_requests.clone();

						i_requests.clear();

						clearInterval(i_controller.interval);
						i_controller.counter = 0;
						i_controller.interval = null;

						i_controller.executeBatch(i_batch);
					}
					else {
						i_controller.counter += i_controller.counterIncrement;
					}
				}, i_controller.counterIncrement);
			}
		},
		buildBatch: function (i_requests) {

			var i_controller = this;
			var o_map = i_controller.actionMap;
			var a_batch = [];

			i_requests.each(function (i_request) {

				var s_action = i_request.getAction();
				var i_map = o_map[s_action];

				i_request._id = ip2.unique("request-");

				var a_requestBatch = i_map.fn(i_request);
				a_batch.push(a_requestBatch);

				//var o_params = i_map.fn(i_request);
				//a_batch.push(o_params);
			});

			return a_batch;
		},
		executeBatch: function (i_requests) {

			var i_controller = this;
			var a_batch = i_controller.buildBatch(i_requests);

			// WONT WORK - NEED SOMETHING TO DISTINGUISH THE DIFFERENT REQUESTS APART
			// LIKE 2 DIFFERENT GET REQUESTS NEEDS TO CALL BACK ONLY THOSE BELONGING
			// MAY NEED HELP FROM SERVICE??

			var getBaseInfo = function (o_map, s_key) {

				var n_total = o_map[s_key].total;
				var n_start = 0;

				if (s_key == "read") {
					n_start += o_map.create.total;
				}
				if (s_key == "update") {
					n_start += o_map.create.total + o_map.read.total;
				}
				if (s_key == "destroy") {
					n_start += o_map.create.total + o_map.read.total + o_map.update.total;
				}

				return {
					start: n_start,
					total: n_total
				};
			};

			// Build a control map in case we have multiple batches for same operation!
			var o_controlMap = {
				create: {
					request: [],
					total: 0,
					weight: 1
				},
				read: {
					request: [],
					total: 0,
					weight: 2
				},
				update: {
					request: [],
					total: 0,
					weight: 3
				},
				destroy: {
					request: [],
					total: 0,
					weight: 4
				}
			};

			// SORT BATCH ARRAYS BASED ON CRUD WEIGHTS IN CONTROL MAP
			a_batch.sort(function (a, b) {

				var a_return = 0;
				var b_return = 0;
				var o_first;

				o_first = a[0];
				a_return = o_controlMap[o_first._action].weight;

				o_first = b[0];
				b_return = o_controlMap[o_first._action].weight;

				return a_return - b_return;
			});

			// SORT EACH CRUD ARRAY BASED ON REQUEST ID
			Ext.Array.each(a_batch, function (a_requestBatch, n_index, a_contex) {
				a_requestBatch.sort(function (a, b) {
					var a_return = Number(a._id.replace("request-", ""));
					var b_return = Number(b._id.replace("request-", ""));
					return a_return - b_return;
				});
				a_contex[n_index] = a_requestBatch;
			});

			// Create a flat payloadbatch of all batches and keep track of
			// request affiliation
			var a_payloadBatch = [];

			Ext.Array.each(a_batch, function (batch) {
				Ext.Array.each(batch, function (o_original, n_index) {

					var o_batch = Ext.apply({}, o_original);

					var s_id = o_batch._id;
					var o_control = o_controlMap[o_batch._action];

					o_control.total++;

					// Add a object to the request with total if it does not exist
					// { name: "request-2", total: 0 }
					var o_requestControl;

					Ext.Array.some(o_control.request, function (o_request) {
						if (o_request.name == s_id) {
							o_requestControl = o_request;
							return true;
						}
					});

					// No request control object in array - push it in
					if (!o_requestControl) {
						o_requestControl = {
							name: s_id,
							total: 0
						};
						o_control.request.push(o_requestControl);
					}

					o_requestControl.total++;

					delete o_batch._id;
					delete o_batch._action;

					a_payloadBatch.push(o_batch);
				});
			});

			Ext.Ajax.request({
				url: i_controller.url,
				jsonData: {
					batch: a_payloadBatch
				},
				success: function (i_response, o_options) {

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

					var o_result = Ext.decode(i_response.responseText, true) || {
						batch: []
					};

					//Ext.USE_NATIVE_JSON = true;

					var a_batchResponse = o_result.batch || [];

					i_requests.each(function (i_request, n_index) {

						// This request can have more batches - so we concat from
						// info in o_controlMap
						var s_action = i_request.getAction();
						var s_id = i_request._id;

						var o_base = getBaseInfo(o_controlMap, s_action);
						var n_start = o_base.start;

						// Now find the start for this request and total so we can
						// iterate the right range in a_batchResponse for this requests
						// batch replies - then overload the response
						var o_control = o_controlMap[s_action];
						var o_requestControl;

						Ext.Array.some(o_control.request, function (o_request) {
							if (o_request.name != s_id) {
								n_start += o_request.total;
							}
							else {
								o_requestControl = o_request;
								return true;
							}
						});

						var n_total = n_start + o_requestControl.total;

						// Response can be row or rows - must deliver as
						// { totalRows: x, rows: [{LCDLCDTKN: 1, xxxx:xxx....}]}
						// Use all properties apart from row or rows to merge on top of json

						var o_dummy;
						var a_rows = [];
						var o_json = {};

						for (n_start; n_start < n_total; n_start++) {

							var o_batch = a_batchResponse[n_start];
							o_dummy = o_dummy || o_batch;

							if (o_batch.row) {
								a_rows.push(o_batch.row);
							}
							else if (o_batch.rows) {
								a_rows = o_batch.rows;
							}
						}

						// Make sure all row keys are uppercased
						Ext.Array.each(a_rows, function (o_row) {
							Ext.Object.each(o_row, function (s_key, value, o_context) {
								var s_upperCaseKey = s_key;
								if (s_key != s_upperCaseKey) {
									o_context[s_upperCaseKey] = value;
									delete o_context[s_key];
								}
							});
						});

						Ext.apply(o_json, o_dummy);

						delete o_json.row;
						delete o_json.rows;

						Ext.apply(o_json, {
							rows: a_rows
						});

						i_response = {
							responseText: Ext.encode(o_json),
							success: true
						};

						i_request.callback.call(i_request.getProxy(), i_request.getParams(), true, i_response);
					});
				},
				failure: function(o_response, o_options) {
				}
			});
		}
	},

	requires: [
		"Ext.data.proxy.Ajax"
	],

	extend: "Ext.data.proxy.Ajax",

	alias: "proxy.dmd",

	fields: null,

	constructor: function (o_config) {

		var Proxy = Ext.ux.data.dmd.Proxy;
		var i_proxy = this;

		// Set reader defaults

		Ext.apply(o_config, {
			reader: Ext.apply({
				type: "dmd",
				rootProperty: "rows",
				totalProperty: "totalRows",
				nameProperty: "name"
			}, o_config.reader),
			writer: Ext.apply({
				type: "dmd",
				rootProperty: "rows",
				nameProperty: "name"
			}, o_config.writer)
		});

		Ext.apply(i_proxy, {
			url: Proxy.url
		});

		i_proxy.callParent([o_config]);
	},

	extractResponseData: function(o_response) {

		var i_proxy = this;
		var i_reader = i_proxy.getReader();

		var o_data = Ext.decode(o_response.responseText);

		var b_asRow = o_data.hasOwnProperty("row");
		var a_result = Ext.Array.from(o_data.rows || o_data.row);

		if (b_asRow) {
			delete o_data.row;
		}

		var a_selected = Ext.Array.from(o_data.selected);

		if (a_selected.length > 0) {
			o_data[i_reader.getTotalProperty()] += a_selected.length;
			a_result = a_selected.concat(a_result);
		}

		o_data[i_reader.getRootProperty()] = a_result;

		return o_data;
	},

	doRequest: function(i_operation, f_callback, i_scope) {

		if (isNaN(i_operation.start) || isNaN(i_operation.page)) {
			if (isNaN(i_operation.start)) {
				i_operation.start = 0;
			}
			if (isNaN(i_operation.page)) {
				i_operation.page = 1;
			}
		}
		var Proxy = Ext.ux.data.dmd.Proxy;
		var i_proxy = this;
		var i_writer = i_proxy.getWriter();
		var i_request = i_proxy.buildRequest(i_operation, f_callback, i_scope);

		if (i_operation.allowWrite()) {
			i_request = i_writer.write(i_request);
		}

		Ext.apply(i_request, {
			headers: i_proxy.headers,
			timeout: i_proxy.timeout,
			scope: i_proxy,
			callback: i_proxy.createRequestCallback(i_request, i_operation),
			method: i_proxy.getMethod(i_request),
			disableCaching: false,
			proxy: i_proxy
		});
		i_request.setUrl(Ext.urlAppend(Proxy.url, Ext.String.format("{0}={1}", this.getCacheString(), Ext.Date.now())));

		Proxy.doBatchRequest(i_request);
	}
});
Ext.define("Ext.ux.data.dmd.Store", {

	extend: "Ext.data.Store",

	/**
	 * @cfg {String} dmd
	 * Name of the DMD file
	 */
	dmd: "",

	/**
	 * @cfg {String} entity
	 * Name of the entity in the DMD
	 */
	entity: "",

	/**
	 * @cfg {String} [view="portfolio"]
	 * Name of the view to use
	 */
	view: "portfolio",

	/**
	 * @cfg {String} [context="grid"]
	 * View context (grid or form)
	 */
	context: "grid",

	/**
	 * @cfg {Object} [key=null]
	 */
	key: null,

	/**
	 * @cfg {Array} [union=null]
	 */
	union: null,

	/**
	 * @cfg {Boolean} [meta=false]
	 */
	meta: null,

	extraParams: null,

	/**
	 * @property {Object} dmdObject
	 * The DMD object from path
	 */
	dmdObject: null,

	/**
	 * @property {String} batchUpdateMode
	 * Sets the updating behavior based on batch synchronization. 'operation' (the default) will update the Store's
	 * internal representation of the data after each operation of the batch has completed, 'complete' will wait until
	 * the entire batch has been completed before updating the Store's data. 'complete' is a good choice for local
	 * storage proxies, 'operation' is better for remote proxies, where there is a comparatively high latency.
	 */
	batchUpdateMode: "complete",

	constructor: function(o_config) {

		var i_store = this;

		// Get the DMD object from the dmd property,
		// set it - and overload config name to path
		var o_dmd = ip2.resource.get(o_config.dmd);
		var o_model = o_dmd.model;

		i_store.dmdObject = Ext.clone(o_dmd);
		o_config.dmd = o_dmd._path;

		var o_entity = Ext.Array.findBy(o_model.entities, function(o_value) {
			return o_value.name == o_config.entity;
		});

		var o_ui = o_entity.ui || {
			grids: {}
		};

		var o_view = o_ui.grids[o_config.view] || o_ui.grids.portfolio;

		Ext.applyIf(o_config, {
			sort: o_view.sort
		});

		var i_model = ip2.model(o_config);

		var o_params = ip2.dmd.createExtraParams(o_config);

		var o_proxy = Ext.apply({
			type: "dmd",
			extraParams: o_params
		}, o_dmd.proxy);

		Ext.applyIf(o_config, {
			model: i_model,
			proxy: o_proxy
		});

		var o_settings = Ext.apply({}, o_config);
		i_store.callParent([o_settings]);

		return i_store;
	},

	getExtraParams: function () {

		var i_store = this;
		var i_proxy = i_store.getProxy();

		return i_proxy.getExtraParams();
	},
	setExtraParams: function (o_params) {

		var i_store = this;
		var i_proxy = i_store.getProxy();

		i_proxy.setExtraParams(o_params);
	},

	getKey: function () {

		var i_store = this;
		var o_params = i_store.getExtraParams();

		return o_params.key;
	},
	setKey: function (value) {

		var i_store = this;
		var o_params = i_store.getExtraParams();

		if (value && Ext.Object.getSize(value)) {
			i_store.key = value;
			o_params.key = value;
		}
		else {
			i_store.key = null;
			delete o_params.key;
		}

		return i_store;
	},
	getMeta: function () {

		var i_store = this;
		var o_params = i_store.getExtraParams();

		return o_params.meta;
	},
	setMeta: function (value) {

		var i_store = this;
		var o_params = i_store.getExtraParams();

		value = value ? true : false;
		i_store.meta = value;
		o_params.meta = value;

		return i_store;
	},
	getUnion: function () {

		var i_store = this;
		var o_params = i_store.getExtraParams();

		return o_params.union;
	},
	setUnion: function (a_union) {

		var i_store = this;
		var o_params = i_store.getExtraParams();

		if (!a_union || !a_union.length || a_union == null) {
			i_store.union = null;
			delete o_params.union;
		}
		else {
			i_store.union = a_union;
			o_params.union = a_union;
		}

		return i_store;
	}
});
Ext.define("Ext.ux.grid.filter.Base", {
	extend: "Ext.button.Split",

	alias: "widget.filterbase",

	iconCls: "pf-arrow_up",

	dataIndex: "",
	dataType: "string",
	overRuleable: true,
	toolbar: undefined,
	menu: undefined,
	fields: undefined,
	config: undefined,
	sortInfo: undefined,
	isFilter: true,
	sortDirection: "ASC",
	iconAlign: "right",
	useRaw: false,

	config: {
		allowMenu: true
	},

	listeners: {
		mouseover: {
			fn: function () {

				var i_self = this;
				var s_iconCls = i_self.sortInfo.direction == "ASC" ? "pf-arrow_up" : "pf-arrow_down";
				i_self.setIconCls(s_iconCls);
			}
		},
		mouseout: {
			fn: function () {

				var i_self = this;
				var s_iconCls = i_self.sortInfo.direction == "ASC" ? "pf-arrow_up" : "pf-arrow_down";
				i_self.setIconCls(s_iconCls);
			}
		},
		click: {
			fn: function() {

				var i_self = this;
				i_self.changeSort();
				var o_config = i_self.getConfig();
				o_config.applyFn();
			}
		}
	},

	initComponent: function() {

		var i_self = this;
		i_self.iconCls = i_self.sortDirection == "ASC" ? "pf-arrow_up" : "pf-arrow_down";
		i_self.callParent(arguments);

		if (i_self.getAllowMenu()) {
			i_self.createMenu();
		}
		else {
			i_self.setMenu(null);
		}

		i_self.createSortInfo();

		return i_self;
	},

	createMenu: function() {

		var i_self = this;

		var i_menu = Ext.widget("menu", {
			plain: true,
			enableKeyNav: false,
			listeners: {
				beforehide: {
					fn: function() {

						var i_menu = this;

						var a_fields = i_menu.query("combobox");

						var b_close = true;

						Ext.Array.each(a_fields, function(i_field) {
							if (i_field.isExpanded) {
								b_close = false;
								return false;
							}
						});

						return b_close;
					}
				}
			}
		});

		i_menu.button = i_self;

		i_self.setMenu(i_menu);
	},

	createSortInfo: function() {

		var i_self = this;

		var o_sortInfo = {
			property: i_self.sortProperty || i_self.dataIndex,
			direction: i_self.sortDirection || "ASC"
		};

		i_self.sortInfo = o_sortInfo;
	},

	changeSort: function() {

		var i_self = this;
		i_self.sortInfo.direction = i_self.sortInfo.direction == "ASC" ? "DESC" : "ASC";
		var s_iconCls = i_self.sortInfo.direction == "ASC" ? "pf-arrow_up" : "pf-arrow_down";
		i_self.setIconCls(s_iconCls);
	},

	getNot: function() {

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

		var b_not = false;
		if (o_config.checkBoxNot) {
			b_not = o_config.checkBoxNot.getValue();
		}

		return b_not;
	},

	setNot: function(value) {

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

		o_config.checkBoxNot.setValue(value);
	},

	getFilterValue: function() {
		// Implement in extended class
	},

	getSortInfo: function() {

		var i_self = this;
		return i_self.sortInfo;
	},

	getConfig: function() {

		var i_self = this;
		return i_self.config;
	},

	onFocusLeave: function(e) {

		var i_self = this;
		var i_menu = i_self.getMenu();
		var event = e.event;

		if (i_menu && !event.within(i_menu.getEl())) {
			i_menu.hide();
		}
	},

	getDataIndex: function() {

		var i_self = this;
		var o_config = i_self.getConfig();
		var s_dataIndex = o_config.dataIndex;

		if (s_dataIndex.indexOf(".") > -1) {
			var a_splitData = s_dataIndex.split(".");
			var s_root = a_splitData.shift();

			var i_templatet = Ext.create("Ext.XTemplate",
				"jsonGetStr({root},'{path}')"
			);

			i_templatet.compile();

			s_dataIndex = i_templatet.apply({
				root: s_root,
				path: a_splitData.join(".")
			});
		}

		return s_dataIndex;
	}
});
Ext.define("Ext.ux.grid.filter.Array", {
	extend: "Ext.ux.grid.filter.Base",
	alias: "widget.filterarray",

	config: {
		where: "usrusrtkn in ( select  NAVERLRL00.ERLENTTKN " +
				"from navrolet00 , naverlrl00 " +
				"WHERE NAVERLRL00.ERLROLTKN = navrolet00.ROLROLTKN and NAVERLRL00.ERLENT = " +
				"'NAVUSRET00' and navrolet00.ROLROLTKN in ({[values]}) " +
				")"
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
	},

	createMenu: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var config = {
			dataIndex: i_self.dataIndex,
			dataType: "array",
			overRuleable: i_self.overRuleable != null ? i_self.overRuleable : true,
			applyFn: i_self.applyFn || Ext.emptyFn,
			dmd: i_self.dmd,
			useRaw: i_self.useRaw != null ? i_self.useRaw : false,
			removeFn: i_self.removeFn || Ext.emptyFn
		};

		var i_panel = Ext.ux.grid.filter.util.create(config);

		i_self.config = config;
		i_self.menu.add(i_panel);
	},

	getFilterValue: function() {

		var i_self = this;
		var o_config = i_self.getConfig();
		var a_checkbox = o_config.checkboxes;
		var a_field = o_config.fields;
		var b_not = i_self.getNot();
		var a_value = "";
		var s_where = "";
		var s_criteria = "";
		var s_type = "";
		var n_index = 0;

		Ext.Array.each(a_checkbox, function(i_checkbox) {

			var i_field = a_field[n_index];

			if (i_checkbox.checked) {
				a_value = i_field.getValue();
				s_criteria = i_checkbox.criteria;
				s_type = i_checkbox.type;
			}
			n_index++;
		});

		if (a_value) {

			s_where = i_self.getWhereTemplete(a_value.join(","));
		}

		return s_where;
	},

	getWhereTemplete: function(value) {

		var i_self = this;

		var i_tpl = Ext.create('Ext.XTemplate',
			'<tpl>',
				i_self.getWhere(),
			'</tpl>'
		);
		i_tpl.compile();
		return i_tpl.apply(value);
	}
});
Ext.define("Ext.ux.grid.filter.String", {
	extend: "Ext.ux.grid.filter.Base",
	alias: "widget.filterstring",

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
	},

	createMenu: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var config = {
			dataIndex: i_self.dataIndex,
			dataType: "string",
			overRuleable: i_self.overRuleable != null ? i_self.overRuleable : true,
			applyFn: i_self.applyFn || Ext.emptyFn,
			removeFn: i_self.removeFn || Ext.emptyFn
		};

		var i_panel = Ext.ux.grid.filter.util.create(config);

		i_self.config = config;
		i_self.menu.add(i_panel);
	},

	getFilterValue: function() {

		var i_self = this;
		var o_config = i_self.getConfig();
		var a_checkbox = o_config.checkboxes;
		var a_field = o_config.fields;
		var b_not = i_self.getNot();
		var b_filled = i_self.getFilled();
		var s_value = "";
		var s_where = "";
		var s_criteria = "";
		var s_type = "";
		var n_index = 0;
		var s_dataIndex = i_self.getDataIndex();

		Ext.Array.each(a_checkbox, function(i_checkbox) {

			var i_field = a_field[n_index];

			if (i_checkbox.checked) {
				s_value = i_field.getValue();
				s_criteria = i_checkbox.criteria;
				s_type = i_checkbox.type;
			}
			n_index++;
		});

		s_value = s_value || "";

		var a_split = [];

		var a_valueSplit = s_value.split(",");

		if (a_valueSplit.length > 1) {
			a_split = s_criteria.split(" ");
			s_where = i_self.getInStatement(s_dataIndex, a_split[0], a_split[1], s_type, b_not, a_valueSplit);
		}
		else {
			if (s_value) {
				a_split = s_criteria.split(" ");
				a_split[1] = "" + a_split[1] + "";

				s_criteria = a_split.join(" ");
				if (s_type == "eq") {
					s_criteria = s_criteria.replace("{0}", "'" + s_value + "'");
				}
				else {
					s_criteria = s_criteria.replace("{0}", s_value);
				}

				if (o_config.dataIndex.indexOf(".") > -1) {

					var s_root = o_config.dataIndex.split(".").shift();

					s_dataIndex  = s_root + " like '%" + s_value +"%'" + " AND " + s_dataIndex;
				}

				s_where = "" + s_dataIndex + "" + (b_not ? " NOT " + s_criteria : " " + s_criteria);
			}
			else {
				if (b_filled) {
					var i_template = new Ext.XTemplate( 
						"{dataIndex}",
						"<tpl if=\"this.hasValue(not)\">",
							"<tpl if=\"this.hasValue(filled)\">",
								" IS NULL OR {dataIndex} = ''",
							"</tpl>",
							"<tpl if=\"this.notValue(filled)\" >",
								" IS NOT NULL AND {dataIndex} <> '' ",
							"</tpl>",
						"</tpl>",
						"<tpl if=\"this.notValue(not)\">",
							"<tpl if=\"this.hasValue(filled)\">",
								" IS NOT NULL AND {dataIndex} <> ''",
							"</tpl>",
						"</tpl>",
						{
							hasValue: function(value) {
								return value ? 1 : 0;
							},
							notValue: function(value) {
								return value ? 0 :1;
							}
						}
					);

					i_template.compile();

					s_where = i_template.apply({
						dataIndex: "" + s_dataIndex + "",
						not: b_not,
						filled: b_filled
					});
				}
			}
		}
		return s_where;
	},

	getFilled: function() {

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

		var b_blank = false;
		if (o_config.checkBoxBlank) {
			b_blank = o_config.checkBoxBlank.getValue();
		}

		return b_blank;
	},

	getInStatement: function(s_dataIndex, s_criteria, s_replace, s_type, b_not, a_split) {

		var s_where = "";
		var a_result = [];

		Ext.Array.each(a_split, function(s_value) {
			if (s_value) {
				if (s_type == "eq") {
					a_result.push("'" + s_value.trim() + "'");
				}
				else {
					a_result.push("'%" + s_value.trim() + "%'");
				}
			}
		});

		if (s_type == "eq" ) {
			s_where = "" + s_dataIndex + "" + (b_not ? " NOT " : " ") + "IN " + "(" + a_result.join(", ") + ")";
		}
		else {
			s_where = "" + s_dataIndex + " LIKE " +
				a_result.join(" OR " + s_dataIndex + "" + (b_not ? " NOT LIKE " : " LIKE "));
		}

		return s_where;
	}
});
Ext.define("Ext.ux.grid.filter.Number", {
	extend: "Ext.ux.grid.filter.Base",
	alias: "widget.filternumber",

	initComponent: function() {
		var i_self = this;
		i_self.callParent(arguments);
	},


	createMenu: function() {
		var i_self = this;
		i_self.callParent(arguments);

		var config = {
			dataIndex: i_self.dataIndex,
			dataType: "number",
			decimals: i_self.decimals || 0,
			overRuleable: i_self.overRuleable != null ? i_self.overRuleable : true,
			applyFn: i_self.applyFn || Ext.emptyFn,
			removeFn: i_self.removeFn || Ext.emptyFn
		};

		var i_panel = Ext.ux.grid.filter.util.create(config);

		i_self.config = config;
		i_self.menu.add(i_panel);
	},

	getFilterValue: function() {

		var i_self = this;
		var o_config = i_self.getConfig();
		var a_checkbox = o_config.checkboxes;
		var a_field = o_config.fields;
		var b_not = i_self.getNot();
		var s_value;
		var s_second = "";
		var s_where = "";
		var s_criteria = "";
		var s_type = "";
		var n_index = 0;

		var s_dataIndex = i_self.getDataIndex();

		Ext.Array.each(a_checkbox, function(i_checkbox) {

			var i_field = a_field[n_index];

			if (i_checkbox.checked) {

				s_criteria = i_checkbox.criteria;
				s_type = i_checkbox.type;

				if (s_type == "bt") {
					var a_items = i_field.query("numberfield");
					s_value = a_items[0].getValue();
					s_second = a_items[1].getValue();
				}
				else {
					s_value = i_field.getValue();
				}
			}
			n_index++;
		});
		if (s_type == "bt") {
			if (s_value != null && s_second != null) {
				s_criteria = s_criteria.replace("{0}", s_value).replace("{1}", s_second);
				s_where = s_dataIndex + (b_not ? " NOT " + s_criteria : " " + s_criteria);
			}
		}
		else {
			if (s_value != null) {
				s_criteria = s_criteria.replace("{0}", s_value);
				s_where = s_dataIndex + (b_not ? " !" + s_criteria : " " + s_criteria);
			}
		}
		return s_where;
	}
});
Ext.define("Ext.ux.grid.filter.Enum", {
	extend: "Ext.ux.grid.filter.Base",
	alias: "widget.filterenum",

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
	},

	createMenu: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var config = {
			dataIndex: i_self.dataIndex,
			dataType: "enum",
			overRuleable: i_self.overRuleable != null ? i_self.overRuleable : true,
			multiSelect: i_self.multiSelect || false,
			values: i_self.values,
			applyFn: i_self.applyFn || Ext.emptyFn,
			removeFn: i_self.removeFn || Ext.emptyFn,
			useLike: i_self.useLike || false
		};

		var i_panel = Ext.ux.grid.filter.util.create(config);
		i_self.config = config;
		i_self.menu.add(i_panel);
	},

	getFilterValue: function() {

		var i_self = this;
		var o_config = i_self.getConfig();
		var a_checkbox = o_config.checkboxes;
		var a_field = o_config.fields;
		var b_not = i_self.getNot();
		var s_value = "";
		var s_where = "";
		var s_criteria = "";
		var s_type = "";
		var n_index = 0;
		var s_dataIndex = i_self.getDataIndex();

		Ext.Array.each(a_checkbox, function(i_checkbox) {

			var i_field = a_field[n_index];

			if (i_checkbox.checked) {
				s_criteria = i_checkbox.criteria;
				s_type = i_checkbox.type;
				s_value = i_field.getValue();
			}
			n_index++;
		});

		if (s_value !== "") {
			if (i_self.isString) {
				if (Ext.isArray(s_value)) {
					if (s_type == "eq") {
						s_criteria = s_criteria.replace("{0}", "'" + JSON.stringify(s_value) + "'");
					}
					else {
						var a_criteries = [];
						ip2.each(s_value, function(s_key) {
							var s_tmp = s_criteria.replace("{0}", s_key);
							s_tmp = s_tmp = (b_not ? " NOT " + s_tmp : " " + s_tmp);
							a_criteries.push(s_tmp);
						});
						if (b_not) {
							s_criteria = a_criteries.join(" AND 'atz' ");
						}
						else {
							s_criteria = a_criteries.join(" OR 'atz' ");
						}

						var regex = new RegExp("'atz'","g");
						if (!b_not) {
							s_where = "(" + s_dataIndex + s_criteria.replace(regex, s_dataIndex) + ")";
						}
						else {
							s_where = s_dataIndex + s_criteria.replace(regex, s_dataIndex);
						}
					}
				}
				else {
					s_criteria = s_criteria.replace("{0}", "'" + s_value + "'");
				}
				if (s_where == "") {
					s_where = s_dataIndex + (b_not ? " !" + s_criteria : " " + s_criteria);
				}
			}
			else {
				if (Ext.isArray(s_value)) {
					s_criteria = "IN ({0})";
					s_criteria = s_criteria.replace("{0}", s_value);
					s_where = s_dataIndex + (b_not ? " NOT " + s_criteria : " " + s_criteria);
				}
				else {
					s_criteria = s_criteria.replace("{0}", s_value);
					s_where = s_dataIndex + (b_not ? " !" + s_criteria : " " + s_criteria);
				}
			}
			return s_where;
		}
		else {
			return "";
		}
	}
});
Ext.define("Ext.ux.grid.filter.Entity", {
	extend: "Ext.ux.grid.filter.Base",
	alias: "widget.filterentity",

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
	},

	createMenu: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var config = {
			dataIndex: i_self.dataIndex,
			dataType: "entity",
			overRuleable: i_self.overRuleable != null ? i_self.overRuleable : true,
			dmd: i_self.dmd,
			applyFn: i_self.applyFn || Ext.emptyFn,
			removeFn: i_self.removeFn || Ext.emptyFn
		};

		var i_panel = Ext.ux.grid.filter.util.create(config);
		i_self.config = config;
		i_self.menu.add(i_panel);
	},

	getFilterValue: function() {

		var i_self = this;
		var o_config = i_self.getConfig();
		var a_checkbox = o_config.checkboxes;
		var a_field = o_config.fields;
		var b_not = i_self.getNot();
		var s_value = "";
		var s_where = "";
		var s_criteria = "";
		var s_type = "";
		var n_index = 0;
		var s_dataIndex = i_self.getDataIndex();

		Ext.Array.each(a_checkbox, function(i_checkbox) {

			var i_field = a_field[n_index];

			if (i_checkbox.checked) {
				s_criteria = i_checkbox.criteria;
				s_type = i_checkbox.type;
				s_value = i_field.getValue();
			}

			n_index++;
		});

		if (s_value) {
			s_criteria = s_criteria.replace("{0}", s_value);
			s_where = s_dataIndex + (b_not ? " !" + s_criteria : " " + s_criteria);
			return s_where;
		}
		else {
			return "";
		}
	}
});
Ext.define("Ext.ux.grid.filter.Boolean", {
	extend: "Ext.ux.grid.filter.Base",
	alias: "widget.filterboolean",

	initComponent: function() {
		var i_self = this;
		i_self.callParent(arguments);
	},

	createMenu: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var config = {
			dataIndex: i_self.dataIndex,
			dataType: "boolean",
			overRuleable: i_self.overRuleable != null ? i_self.overRuleable : true,
			applyFn: i_self.applyFn || Ext.emptyFn,
			removeFn: i_self.removeFn || Ext.emptyFn
		};

		var i_panel = Ext.ux.grid.filter.util.create(config);

		i_self.config = config;
		i_self.menu.add(i_panel);
	},

	getFilterValue: function() {

		var i_self = this;
		var o_config = i_self.getConfig();
		var a_checkbox = o_config.checkboxes;
		var a_field = o_config.fields;
		var b_not = i_self.getNot();
		var s_value = "";
		var s_where = "";
		var s_criteria = "";
		var s_type = "";
		var n_index = 0;

		var s_dataIndex = i_self.getDataIndex();

		Ext.Array.each(a_checkbox, function(i_checkbox) {

			var i_field = a_field[n_index];

			if (i_checkbox.checked) {
				s_criteria = i_checkbox.criteria;
				s_type = i_checkbox.type;
				s_value = i_field.getValue();
			}
			n_index++;
		});

		if (s_value !== "") {
			s_criteria = s_criteria.replace("{0}", s_value);
			s_where = s_dataIndex + (b_not ? " !" + s_criteria : " " + s_criteria);
			return s_where;
		}
		else {
			return "";
		}
	}
});
Ext.define("Ext.ux.grid.filter.Date", {
	extend: "Ext.ux.grid.filter.Base",
	alias: "widget.filterdate",

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
	},

	createMenu: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var config = {
			dataIndex: i_self.dataIndex,
			dataType: "date",
			dataDateType: i_self.dataDateType || "datetime",
			overRuleable: i_self.overRuleable != null ? i_self.overRuleable : true,
			applyFn: i_self.applyFn || Ext.emptyFn,
			removeFn: i_self.removeFn || Ext.emptyFn,
			asHigh: true
		};

		var i_panel = Ext.ux.grid.filter.util.create(config);
		i_self.config = config;
		i_self.menu.add(i_panel);
	},

	getFilterValue: function() {

		var i_self = this;
		var o_config = i_self.getConfig();
		var a_checkbox = o_config.checkboxes;
		var a_field = o_config.fields;
		var b_not = i_self.getNot();
		var s_eqDateValue = "";
		var s_eqTimeValue = "";
		var s_value = "";
		var s_second = "";
		var s_where = "";
		var s_criteria = "";
		var s_type = "";
		var n_index = 0;
		var s_dataIndex = i_self.getDataIndex();

		Ext.Array.each(a_checkbox, function(i_checkbox) {

			var i_field = a_field[n_index];

			if (i_checkbox.checked) {

				s_criteria = i_checkbox.criteria;
				s_type = i_checkbox.type;

				if (s_type == "bt") {

					var a_items = i_field.items.items;
					var i_first = a_items[0];
					var i_second = a_items[1];
					s_value = i_first.getValue();
					s_second = i_second.getValue();
				}
				else {
					if (s_type == "eq") {

						var i_datefield = i_field.getDateField();
						var i_timefield = i_field.getTimeField();
						s_eqDateValue = i_datefield.getSubmitValue();
						s_eqTimeValue = i_timefield.getSubmitValue();
						s_eqTimeValue = s_eqTimeValue.replace(new RegExp(":","g"), ".");
					}

					s_value = i_field.getValue();
				}
			}
			n_index++;
		});

		if (s_value !== "") {
			if (s_type == "bt") {
				if (o_config.dataDateType == "datetime" || o_config.dataDateType == "datetimesec") {
					s_criteria = s_criteria
					.replace("{0}", "TIMESTAMP('" + s_value + "')")
					.replace("{1}", "TIMESTAMP('" + s_second + "')");
					s_where = o_config.dataIndex + (b_not ? " NOT " + s_criteria : " " + s_criteria);
				}
				else {
					s_criteria = s_criteria
					.replace("{0}", "DATE('" + s_value + "')")
					.replace("{1}", "DATE('" + s_second + "')");
					s_where = "DATE(" + s_dataIndex + ") " + (b_not ? " NOT " + s_criteria : " " + s_criteria);
				}
			}
			else {
				if (s_type == "eq") {
					s_criteria = "char({0}){2}like '{1}%'"
					.replace("{0}", s_dataIndex)
					.replace("{1}", (s_eqDateValue + "-" + s_eqTimeValue))
					.replace("{2}", (b_not ? " NOT " : " "));
					s_where = s_criteria;
				}
				else {
					if (o_config.dataDateType == "datetime" || o_config.dataDateType == "datetimesec") {
						s_criteria = s_criteria.replace("{0}", "TIMESTAMP('" + s_value + "')");
						s_where = s_dataIndex + (b_not ? " NOT " + s_criteria : " " + s_criteria);
					}
					else {
						s_criteria = s_criteria.replace("{0}", "DATE('" + s_value + "')");
						s_where = "DATE(" + s_dataIndex + ") " + (b_not ? " NOT " + s_criteria : " " + s_criteria);
					}
				}
			}
			return s_where;
		}
		else {
			return "";
		}
	}
});
Ext.define("Ext.ux.grid.filter.util", {
	singleton: true,

	requires: [
		"Ext.ux.grid.filter.Base",
		"Ext.ux.grid.filter.Array",
		"Ext.ux.grid.filter.Boolean",
		"Ext.ux.grid.filter.Date",
		"Ext.ux.grid.filter.Entity",
		"Ext.ux.grid.filter.Enum",
		"Ext.ux.grid.filter.Number",
		"Ext.ux.grid.filter.String"
	],

	create: function(config) {

		var i_self = this;
		var i_panel = i_self.createPanel(config);

		return i_panel;
	},

	createFilter: function(o_config) {

		var i_self = this;
		var i_button;

		switch (o_config.dataType){
			case "string":
				i_button = Ext.widget("filterstring", o_config);
			break;
			case "int":
			case "float":
			case "decimal":
			case "number":
				i_button = Ext.widget("filternumber", o_config);
			break;
			case "enum":
				i_button = Ext.widget("filterenum", o_config);
			break;
			case "boolean":
				i_button = Ext.widget("filterboolean", o_config);
			break;
			case "entity":
				i_button = Ext.widget("filterentity", o_config);
			break;
			case "date":
				i_button = Ext.widget("filterdate", o_config);
			break;
			case "array":
				i_button = Ext.widget("filterarray", o_config);
			break;
		}
		return i_button;
	},

	createPanel: function (config) {

		var i_self = this;
		var size;

		switch (config.dataType) {
			case "string":
				size = {
					width: 380
				};
			break;
			case "int":
			case "float":
			case "decimal":
			case "number":
				size = {
					width: 380
				};
			break;
			case "date":
				if (config.dataDateType == "datetime" || config.dataDateType == "datetimesec") {
					size = {
						width: 600
					};
				}
				else {
					size = {
						width: 500
					};
				}
			break;
			case "boolean":
				size = {
					width: 380
				};
			break;
			case "enum":
				size = {
					width: 380
				};
			break;
			case "entity":
				size = {
					width: 380
				};
			break;
			case "array":
				size = {
					width: 380
				};
			break;
		}

		var a_checkbox = i_self.GenerateCheckBoxes(config);
		var a_fields = i_self.GenerateFields(config);

		var a_containers = [
			i_self.GenerateCheckBoxNot(config)
		];


		Ext.Array.each(a_checkbox, function(i_checkBox, n_index) {

			var i_field = a_fields[n_index];
			i_field.flex = 1;
			i_field.margin = "0 0 0 10";

			var i_fieldcontainer = Ext.widget("fieldcontainer", {
				layout: {
					type: "hbox",
					align: "stretch"
				},
				items: [
					i_checkBox,
					i_field
				]
			});

			a_containers.push(i_fieldcontainer);
		});

		if (config.dataType == "string") {
			a_containers.push(i_self.GenerateCheckBoxBlank(config));
		}

		var i_toolbar = Ext.widget("toolbar", {
			dock: "bottom",
			ui: "footer",
			items: [
				{
					xtype: "button",
					disabled: false,
					text: ip2.i18n({
						da: "Anvend",
						en: "Apply"
					}),
					dataIndex: config.dataIndex,
					dataType: config.dataType,
					handler: function (item) {
						var i_menu = item.up("menu");
						var i_form = i_menu.down("form");
						var a_fields = i_form.query("field");
						var b_valid = true;
						Ext.Array.each(a_fields, function (i_field) {
							if (!i_field.isValid()) {
								b_valid = false;
							}
						});
						if (b_valid) {
							i_menu.hide();
							config.applyFn();
						}
					}
				},
				"->",
				{
					xtype: "button",
					disabled: !config.overRuleable ? true : false,
					text: ip2.i18n({
						da: "Fjern",
						en: "Remove"
					}),
					handler: function (item) {
						var i_menu = item.up("menu");
						i_menu.hide();
						config.removeFn(i_menu.button);
					}
				},
			]
		});

		var i_panel = Ext.widget("form", {
			border: false,
			bodyBorder: false,
			width: size.width,
			layout: {
				type: "vbox",
				align: "stretch"
			},
			bodyPadding: 10,
			items: a_containers
		});

		i_panel.addDocked(i_toolbar);

		return i_panel;
	},

	GenerateCheckBoxes: function (config) {

		var i_self = this;
		var items = [];

		switch (config.dataType) {
			case "string":
				items.push(i_self.GenerateCheckBox(config, "like"));
				items.push(i_self.GenerateCheckBox(config, "eq"));
			break;
			case "number":
				items.push(i_self.GenerateCheckBox(config, "lt"));
				items.push(i_self.GenerateCheckBox(config, "gt"));
				items.push(i_self.GenerateCheckBox(config, "eq"));
				items.push(i_self.GenerateCheckBox(config, "bt"));
			break;
			case "date":
				items.push(i_self.GenerateCheckBox(config, "gt"));
				items.push(i_self.GenerateCheckBox(config, "eq"));
				items.push(i_self.GenerateCheckBox(config, "bt"));
			break;
			case "boolean":
				items.push(i_self.GenerateCheckBox(config, "eq"));
			break;
			case "enum":
				if (config.useLike) {
					items.push(i_self.GenerateCheckBox(config, "like"));
					items.push(i_self.GenerateCheckBox(config, "eq"));
				}
				else {
					items.push(i_self.GenerateCheckBox(config, "eq"));
				}

			break;
			case "array":
				items.push(i_self.GenerateCheckBox(config, "eq"));

			break;
			case "entity":
				items.push(i_self.GenerateCheckBox(config, "eq"));
			break;
		}
		config.checkboxes = items;
		return items;
	},

	GenerateCheckBox: function (config, criteria) {

		var i_self = this;
		var o_chkConfig;

		if (criteria == "like") {
			o_chkConfig = {
				fieldLabel: ip2.i18n({
					da: "Indholder",
					en: "Like"
				}),
				criteria: "like '%{0}%'",
				inputValue: ""
			};
		}
		if (criteria == "eq") {
			o_chkConfig = {
				fieldLabel: ip2.i18n({
					da: "Lige med",
					en: "Equal to"
				}),
				criteria: "= {0}",
				inputValue: ""
			};
		}
		if (criteria == "gt") {
			o_chkConfig = {
				fieldLabel: ip2.i18n({
					da: "Større end",
					en: "Greater than"
				}),
				criteria: "> {0}",
				inputValue: ""
			};
			if (config.dataType == "date") {
				o_chkConfig.fieldLabel = ip2.i18n({
					da: "Efter",
					en: "After"
				});
			}
		}
		if (criteria == "lt") {
			o_chkConfig = {
				fieldLabel: ip2.i18n({
					da: "Mindre end",
					en: "Less than"
				}),
				criteria: "< {0}",
				inputValue: ""
			};
			if (config.dataType == "date") {
				o_chkConfig.fieldLabel = ip2.i18n({
					da: "Før",
					en: "Before"
				});
			}
		}
		if (criteria == "bt") {
			o_chkConfig = {
				fieldLabel: ip2.i18n({
					da: "Mellem",
					en: "Between"
				}),
				criteria: "between {0} and {1}",
				inputValue: ""

			};
		}
		Ext.Object.merge(o_chkConfig, {
			dataType: config.dataType,
			dateType: config.dataDateType,
			type: criteria,
			allowChange: true
		});

		o_chkConfig.listeners = {
			change: {
				fn: function (item, newValue, oldValue) {
					var i_menu = item.up("menu");
					var button = i_menu.button;
					if (item.allowChange) {
						i_self.HandleCheckChange(button.config, item.type, newValue);
					}
				}
			}
		};

		o_chkConfig.isFormField = false;
		var i_checkBox = Ext.widget("checkboxfield", o_chkConfig);

		return i_checkBox;
	},

	GenerateFields: function(config) {

		var i_self = this;
		var a_items = [];

		switch (config.dataType) {
			case "string":
				a_items.push(i_self.GenerateField(config, "like"));
				a_items.push(i_self.GenerateField(config, "eq"));
			break;
			case "number":
				a_items.push(i_self.GenerateField(config, "lt"));
				a_items.push(i_self.GenerateField(config, "gt"));
				a_items.push(i_self.GenerateField(config, "eq"));
				a_items.push(i_self.GenerateField(config, "bt"));
			break;
			case "enum":
			case "entity":
			case "boolean":
				if (config.useLike) {
					a_items.push(i_self.GenerateField(config, "like"));
					a_items.push(i_self.GenerateField(config, "eq"));
				}
				else {
					a_items.push(i_self.GenerateField(config, "eq"));
				}
			break;
			case "array":
				a_items.push(i_self.GenerateField(config, "eq"));
			break;
			case "date":
				a_items.push(i_self.GenerateDateTimeField(config, "gt"));
				a_items.push(i_self.GenerateDateTimeField(config, "eq"));
				a_items.push(i_self.GenerateDateTimeField(config, "bt"));
			break;
		}

		if (a_items.length == config.checkboxes.length) {
			for (var i = 0; i < a_items.length; i++) {
				var f = a_items[i];
				var c = config.checkboxes[i];
				if (config.dataDateType != "datetime" && config.dataDateType != "datetimesec") {
					if (config.dataType != "date") {
						if (f.fieldtype != "bt") {
							f.checkBox = c;
							i_self.AddListener(f, config);
						}
						else {
							var f1 = f.items.items[0];
							var f2 = f.items.items[1];

							f1.checkBox = c;
							f2.checkBox = c;

							i_self.AddListener(f1, config);
							i_self.AddListener(f2, config);
						}
					}
					else {
						if (f.fieldtype != "bt") {
							var i_datefield = f.getDateField();
							i_datefield.checkBox = c;
							i_self.AddListener(i_datefield, config);
						}
						else {
							var fc1 = f.items.items[0];
							var fc2 = f.items.items[1];

							var i_datefield1 = fc1.getDateField();
							var i_datefield2 = fc2.getDateField();

							i_datefield1.checkBox = c;
							i_datefield2.checkBox = c;

							i_self.AddListener(i_datefield1, config);
							i_self.AddListener(i_datefield2, config);
						}
					}
				}
				else {
					if (f.fieldtype != "bt") {
						var i_datefield = f.getDateField();
						var i_timefield = f.getTimeField();

						i_datefield.checkBox = c;
						i_timefield.checkBox = c;

						i_self.AddListener(i_datefield, config);
						i_self.AddListener(i_timefield), config;
					}
					else {
						var fc1 = f.items.items[0];
						var fc2 = f.items.items[1];

						var i_datefield1 = fc1.getDateField();
						var i_timefield1 = fc1.getTimeField();

						var i_datefield2 = fc2.getDateField();
						var i_timefield2 = fc2.getTimeField();

						i_datefield1.checkBox = c;
						i_timefield1.checkBox = c;

						i_datefield2.checkBox = c;
						i_timefield2.checkBox = c;

						i_self.AddListener(i_datefield1, config);
						i_self.AddListener(i_timefield1, config);

						i_self.AddListener(i_datefield2, config);
						i_self.AddListener(i_timefield2, config);
					}
				}
			}
		}
		config.fields = a_items;
		return a_items;
	},

	GenerateField: function(config, type) {

		var i_self = this;
		var o_field;
		var labelAlign = "left";
		var i_field;

		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"<li role=\"option\" class=\"x-boundlist-item\">",
					"{[this.renderer(values.value)]}",
				"</li>",
			"</tpl>",
			{
				renderer: function(s_key) {
					return ip2.i18n(s_key) + " ";
				}
			}
		);

		var i_displayTpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
				"{[this.renderer(values.value)]}",
			"</tpl>",
			{
				renderer: function(s_key) {
					return ip2.i18n(s_key) + " ";
				}
			}
		);

		switch (type) {
			case "like":
				if (config.dataType == "enum") {

					o_field = {
						xtype: "combobox",
						anchor: "100%",
						readOnly: true,
						labelAlign: labelAlign,
						name: "cmbEqual",
						forceSelection: true,
						editable: false,
						multiSelect: config.multiSelect || false,
						valueField: "key",
						tpl: i_tpl,
						displayTpl: i_displayTpl,
						queryMode: "local",
						triggerAction: "all",
						store: {
							model: Ext.define(Ext.id(), {
								extend: "Ext.data.Model",
								fields: [
									{ name: "key" },
									{ name: "value" }
								]
							}),
							autoDestroy: true,
							autoLoad: true,
							proxy: {
								data: config.values,
								type: "memory"
							}
						},
						listeners: {
							afterrender: {
								fn: function (item) {
									var value = item.getValue();
									if (value == null) {
										item.setValue(item.store.getAt(0).get("key"));
									}
								}
							}
						}
					};
				}
				else {
					o_field = {
						anchor: "100%",
						labelAlign: labelAlign,
						name: "fieldLike",
						readOnly: true
					};
				}
			break;
			case "lt":
				o_field = {
					anchor: "100%",
					labelAlign: labelAlign,
					selectOnFocus: true,
					name: "fieldLess",
					readOnly: true
				};
			break;
			case "gt":
				o_field = {
					anchor: "100%",
					labelAlign: labelAlign,
					selectOnFocus: true,
					name: "fieldGreater",
					readOnly: true
				};
			break;
			case "eq":
				if (config.dataType == "enum") {
					o_field = {
						xtype: "combobox",
						anchor: "100%",
						readOnly: true,
						labelAlign: labelAlign,
						name: "cmbEqual",
						forceSelection: true,
						editable: false,
						multiSelect: config.multiSelect || false,
						valueField: "key",
						tpl: i_tpl,
						displayTpl: i_displayTpl,
						queryMode: "local",
						triggerAction: "all",
						store: {
							model: Ext.define(Ext.id(), {
								extend: "Ext.data.Model",
								fields: [
									{ name: "key" },
									{ name: "value" }
								]
							}),
							autoDestroy: true,
							autoLoad: true,
							proxy: {
								data: config.values,
								type: "memory"
							}
						},
						listeners: {
							afterrender: {
								fn: function (item) {
									var value = item.getValue();
									if (value == null) {
										item.setValue(item.store.getAt(0).get("key"));
									}
								}
							}
						}
					};
				}
				else if (config.dataType == "entity") {
					o_field = {
						anchor: "100%",
						dmd: config.dmd,
						readOnly: true,
						labelAlign: labelAlign,
						forceSelection: true,
						queryMode: "remote",
						triggerAction: "all"
					};
				}
				else if (config.dataType == "array") {
					o_field = {
						anchor: "100%",
						dmd: config.dmd,
						readOnly: true,
						labelAlign: labelAlign,
						forceSelection: true,
						queryMode: "remote",
						triggerAction: "all",
						useRaw: config.useRaw || true,
						multiSelect: true,
						typeAhead: false,
						listeners: {
							afterrender: {
								fn: function (item) {
									var value = item.getValue();
									if (value == null) {
										item.setValue(item.store.getAt(0));
									}
								}
							}
						}
					};
				}
				else if (config.dataType == "boolean") {
					o_field = {
						xtype: "combobox",
						anchor: "100%",
						readOnly: true,
						labelAlign: labelAlign,
						name: "cmbEqual",
						forceSelection: true,
						displayField: "value",
						editable: false,
						valueField: "key",
						listConfig: {
							getInnerTpl: function () {
								return "<div><SPAN>{value}</SPAN></div>";
							}
						},
						queryMode: "local",
						triggerAction: "all",
						store: {
							model: Ext.define(Ext.id(), {
								extend: "Ext.data.Model",
								fields: [
									{ name: "key" },
									{ name: "value" }
								]
							}),
							autoDestroy: true,
							autoLoad: true,
							proxy: {
								data: [{
									key: 1,
									value: ip2.i18n({
										da: "Ja",
										en: "Yes"
									})
								},
								{
									key: 0,
									value: ip2.i18n({
										da: "Nej",
										en: "No"
									})
								}],
								type: "memory"
							}
						},
						listeners: {
							afterrender: {
								fn: function (item) {
									item.setValue(item.store.getAt(0).get("key"));
								}
							}
						}
					};
				}
				else {
					o_field = {
						anchor: "100%",
						labelAlign: labelAlign,
						name: "fieldEqual",
						readOnly: true
					};
				}
			break;
			case "bt":
				switch (config.dataType) {
					case "number":
						var fField = Ext.widget("numberfield", {
							anchor: "100%",
							flex: 1,
							name: "FirstBetween",
							emptyText: ip2.i18n({
								da: "Fra",
								en: "From"
							}),
							readOnly: true,
							selectOnFocus: true,
							decimals: config.decimals || 0,
							isFormField: false,
							validator: function() {
								var i_self = this;
								if (i_self.readOnly) {
									return true;
								}
								else {
									var i_parent = i_self.up("form");
									var a_from = i_parent.query("field[name=SecondBetween]");
									var i_from = a_from.length > 0 ? a_from[0] : null;
									if (i_from) {
										var n_fromValue = i_from.getValue();
										var n_value = i_self.getValue();
										if (n_fromValue && n_fromValue < n_value) {
											return ip2.i18n({
												da: "Dette felt skal have den mindste værdi",
												en: "This field has to have the smallest value"
											});
										}
									}
									return true;
								}
							}
						});
						var sField = Ext.widget("numberfield", {
							margin: "0 0 0 0",
							anchor: "100%",
							flex: 1,
							name: "SecondBetween",
							emptyText: ip2.i18n({
								da: "Til",
								en: "To"
							}),
							readOnly: true,
							decimals: config.decimals || 0,
							isFormField: false,
							validator: function() {
								var i_self = this;
								if (i_self.readOnly) {
									return true;
								}
								else {
									var i_parent = i_self.up("form");
									var a_from = i_parent.query("field[name=FirstBetween]");
									var i_from = a_from.length > 0 ? a_from[0] : null;
									if (i_from) {
										var n_fromValue = i_from.getValue();
										var n_value = i_self.getValue();
										if (n_value && n_fromValue > n_value) {
											return ip2.i18n({
												da: "Dette felt skal have den største værdi",
												en: "This field has to have the largest value"
											});
										}
									}
									return true;
								}
							}
						});
						if (config.decimals > 0) {
							fField.forcePrecision = true;
							fField.decimalSeparator = ".";

							sField.forcePrecision = true;
							sField.decimalSeparator = ".";
						}
						o_field = {
							border: false,
							defaults: { "margin": "0 5 0 0" },
							items: [fField, sField],
							layout: {
								type: "hbox",
								align: "strech"
							},
							bodyPadding: 0
						};
					break;
				}
			break;
		}

		o_field.fieldtype = type;

		if (type == "bt") {
			i_field = Ext.widget("fieldcontainer", o_field);
		}
		else {
			o_field.isFormField = false;
			switch (config.dataType) {
				case "string":
					i_field = Ext.widget("textfield", o_field);
				break;
				case "number":
					if (type != "bt") {
						if (o_field.decimals > 0) {
							o_field.decimalSeparator = ".";
							o_field.forcePrecision = true;
						}
						i_field = Ext.widget("numberfield", o_field);
					}
				break;
				case "enum":
				case "boolean":
					i_field = Ext.widget("combobox", o_field);
				break;
				case "entity":
				case "array":
					i_field = Ext.widget("entitycombobox", o_field);
				break;
			}
		}
		return i_field;
	},

	GenerateDateTimeField: function (config, type) {

		var i_self = this;
		var o_field = undefined;
		var labelAlign = "left";
		var i_field = undefined;

		switch (type) {
			case "gt":
			case "eq":
				o_field = {
					anchor: "100%",
					flex: 1,
					labelAlign: labelAlign,
					readOnly: true,
					selectOnFocus: true,
					time: (config.dataDateType == "datetime" || config.dataDateType == "datetimesec") ? true : false,
					isFormField: false
				};
			break;
			case "bt":
				var fField = Ext.widget("isotimestampfield", {
					anchor: "100%",
					flex: 1,
					emptyText: ip2.i18n({
						da: "Fra",
						en: "From"
					}),
					time: (config.dataDateType == "datetime" || config.dataDateType == "datetimesec") ? true : false,
					readOnly: true,
					selectOnFocus: true,
					isFormField: false
				});
				var sField = Ext.widget("isotimestampfield", {
					anchor: "100%",
					flex: 1,
					emptyText: ip2.i18n({
						da: "Til",
						en: "To"
					}),
					asHigh: config.asHigh ? config.asHigh : false,
					time: (config.dataDateType == "datetime" || config.dataDateType == "datetimesec") ? true : false,
					readOnly: true,
					selectOnFocus: true,
					timevalue: 23.59,
					isFormField: false
				});
				o_field = {
					border: false,
					items: [fField, sField],
					layout: {
						type: "hbox",
						align: "strech"
					},
					bodyPadding: 0,
					isFormField: false
				};
			break;
		}

		o_field.dateType = config.dataDateType;
		o_field.fieldtype = type;

		if (type != "bt") {
			i_field = Ext.widget("isotimestampfield", o_field);
			var i_datefield = i_field.getDateField();
			i_datefield.on({
				expand: {
					fn: function() {
						var i_menu = i_datefield.up("menu");
						if (i_menu) {
							i_menu.doHiding = false;
						}
					}
				},
				collapse: {
					fn: function() {
						var i_menu = i_datefield.up("menu");
						if (i_menu) {
							i_menu.doHiding = true;
						}
					}
				}
			});
		}
		else {
			i_field = Ext.widget("fieldcontainer", o_field);

			var i_isodatetimefield1 = i_field.items.items[0];
			var i_isodatetimefield2 = i_field.items.items[1];

			var i_datefield1 = i_isodatetimefield1.getDateField();
			var i_datefield2 = i_isodatetimefield2.getDateField();

			i_datefield1.on({
				expand: {
					fn: function() {
						var i_menu = i_datefield1.up("menu");
						if (i_menu) {
							i_menu.doHiding = false;
						}
					}
				},
				collapse: {
					fn: function() {
						var i_menu = i_datefield1.up("menu");
						if (i_menu) {
							i_menu.doHiding = true;
						}
					}
				},
				change: {
					fn: function(i_field, newValue, oldValue) {
						if (i_field.isValid()) {
							i_datefield2.setMinValue(newValue);
						}
					}
				}
			});

			i_datefield2.on({
				expand: {
					fn: function() {
						var i_menu = i_datefield2.up("menu");
						if (i_menu) {
							i_menu.doHiding = false;
						}
					}
				},
				collapse: {
					fn: function() {
						var i_menu = i_datefield2.up("menu");
						if (i_menu) {
							i_menu.doHiding = true;
						}
					}
				},
				change: {
					fn: function(i_field, newValue, oldValue) {
						if (i_field.isValid()) {
							i_datefield1.setMaxValue(newValue);
						}
					}
				}
			});
		}
		return i_field;
	},

	GenerateCheckBoxNot: function(config) {

		var i_self = this;
		var i_checkboxNot = Ext.widget("checkboxfield", {
			anchor: "100%",
			fieldLabel: ip2.i18n({
				da: "Ikke",
				en: "Not"
			}),
			inputValue: "",
			isFormField: false
		});
		config.checkBoxNot = i_checkboxNot;
		return i_checkboxNot;
	},

	GenerateCheckBoxBlank: function(config) {

		var i_self = this;

		var i_checkboxNot = Ext.widget("checkboxfield", {
			anchor: "100%",
			fieldLabel: ip2.i18n({
				da: "Udfyldt",
				en: "Filled"
			}),
			isFormField: false
		});
		config.checkBoxBlank = i_checkboxNot;
		return i_checkboxNot;
	},

	AddListener: function(i_field, config) {

		var i_self = this;

		i_field.on({
			render: {
				fn: function (item) {
					if (i_field.inputEl) {
						i_field.inputEl.on("click", function (item) {
							var i_checkbox = i_field.checkBox;
							if (!i_checkbox.checked) {
								i_checkbox.setValue(true);
							}
						}, i_field);
					}
				}
			},
			specialkey: {
				fn: function (item, e) {
					if (e.getKey() == e.ENTER) {
						var i_menu = item.up("menu");
						config.applyFn();
					}
				}
			}
		});
	},

	HandleCheckChange: function(config, type, value) {

		var a_checkbox = config.checkboxes;
		var a_fields = config.fields;
		var n_index = 0;

		Ext.Array.each(a_checkbox, function(i_checkbox) {

			var i_field = a_fields[n_index];

			if (i_checkbox.type == type) {
				if (i_checkbox.allowChange) {
					if (type != "bt") {
						if (i_checkbox.dataType != "date") {
							i_field.setReadOnly(!value);
							if (value) {
								i_field.focus(true, 20);
								i_field.fireEvent("enable", i_field);
							}
						}
						else {
							var i_datefield = i_field.getDateField();
							var i_timefield = i_field.getTimeField();

							i_datefield.setReadOnly(!value);
							i_timefield.setReadOnly(!value);

							i_datefield.focus(true, 20);
						}
					}
					else {
						if (i_checkbox.dataType != "date") {

							var f1 = i_field.items.items[0];
							var f2 = i_field.items.items[1];
							f1.setReadOnly(!value);
							f2.setReadOnly(!value);

							if (value) {
								f1.focus(true, 20);
							}
						}
						else {
							var i_isodatetimefield1 = i_field.items.items[0];
							var i_isodatetimefield2 = i_field.items.items[1];

							var i_datefield1 = i_isodatetimefield1.getDateField();
							var i_timefield1 = i_isodatetimefield1.getTimeField();

							var i_datefield2 = i_isodatetimefield2.getDateField();
							var i_timefield2 = i_isodatetimefield2.getTimeField();

							i_datefield1.setReadOnly(!value);
							i_timefield1.setReadOnly(!value);

							i_datefield2.setReadOnly(!value);
							i_timefield2.setReadOnly(!value);

							if (value) {
								i_datefield1.focus(true, 20);
							}
						}
					}
				}
			}
			else {
				i_checkbox.allowChange = false;
				i_checkbox.setValue(false);
				if (i_checkbox.type != "bt") {
					if (i_checkbox.dataType != "date") {
						i_field.setReadOnly(true);
					}
					else {
						var i_datefield = i_field.getDateField();
						var i_timefield = i_field.getTimeField();

						i_datefield.setReadOnly(true);
						i_timefield.setReadOnly(true);
					}
				}
				else {
					if (i_checkbox.dataType != "date") {

						var f1 = i_field.items.items[0];
						var f2 = i_field.items.items[1];
						f1.setReadOnly(true);
						f2.setReadOnly(true);
					}
					else {
						var i_isodatetimefield1 = i_field.items.items[0];
						var i_isodatetimefield2 = i_field.items.items[1];

						var i_datefield1 = i_isodatetimefield1.getDateField();
						var i_timefield1 = i_isodatetimefield1.getTimeField();

						var i_datefield2 = i_isodatetimefield2.getDateField();
						var i_timefield2 = i_isodatetimefield2.getTimeField();

						i_datefield1.setReadOnly(true);
						i_timefield1.setReadOnly(true);

						i_datefield2.setReadOnly(true);
						i_timefield2.setReadOnly(true);
					}
				}
				i_checkbox.allowChange = true;
			}
			n_index++;
		});
	}
});
Ext.define("Ext.ux.grid.filter.Toolbar", {

	extend: "Ext.toolbar.Toolbar",

	alias: "widget.filterbar",

	dock: "top",

	height: 40,

	layout: {
		type: "hbox",
		"align": "center"
	},

	config: {
		defaultFilter: "",
		allowFilterMenu: true,
		allowMenu: true,
		menu: null,
		buttonReset: null,
		grid: null
	},

	defaults: {
		ui: "filter",
		height: 30
	},

	border: false,

	ui: "filter",

	listeners : {
		afterFilter: {
			fn: function(i_self, n_filters) {

				var i_buttonReset = i_self.getButtonReset();

				i_buttonReset[n_filters ? "show" : "hide"]();
			}
		}
	},

	initComponent: function() {

		var i_self = this;

		i_self.plugins = i_self.createPlugins();

		i_self.callParent(arguments);

		i_self.add(i_self.createItems());

		i_self.enableBubble([
			"afterFilter"
		]);

		return i_self;
	},

	createItems: function() {

		var i_self = this;
		var a_items = [];

		if (i_self.getAllowMenu()) {
			a_items.push(i_self.createMenu());
		}

		var i_buttonReset = Ext.widget("button", {
			itemId: "button-clear",
			iconAlign: "right",
			text: ip2.i18n({
				da: "Nulstil",
				en: "Reset"
			}),
			iconCls: "pf-navigate_cross",
			reorderable: false,
			hidden: true,
			handler: function () {
				i_self.clearFilters();
			}
		});

		a_items.push(i_buttonReset);
		a_items.push({
			xtype: "tbseparator",
			reorderable: false
		});

		i_self.setButtonReset(i_buttonReset);

		return a_items;
	},

	createMenu: function() {

		var i_self = this;

		var i_splitbutton = Ext.widget("filtermenu", {
			reorderable: false,
			arrowVisible: false,
			iconAlign: "right",
			text: ip2.i18n({
				da: "Filter",
				en: "Filter"
			}),
			iconCls: "pf-navigate_close",
			toolBar: i_self,
			itemId: "menuFilter",
			defaultFilter: i_self.getDefaultFilter()
		});
		i_self.menu = i_splitbutton;
		return i_splitbutton;
	},

	getFilterByDataIndex: function(s_dataIndex) {

		var i_self = this;
		return i_self.query("splitbutton[dataIndex=" + s_dataIndex + "]")[0];
	},

	getFilters: function() {

		var i_self = this;
		return i_self.query("splitbutton[isFilter=true]");
	},

	clearFilters: function() {

		var i_self = this;
		var i_grid = i_self.grid;
		var i_store = i_grid.getStore();
		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();
		var a_filters = i_self.getFilters();

		Ext.Array.each(a_filters, function(i_button) {
			if (i_button.overRuleable === null) {
				i_self.remove(i_button);
			}
			else {
				if (i_button.overRuleable) {
					i_self.remove(i_button);
				}
			}
		});

		a_filters = i_self.getFilters();

		delete o_extraParams.where;
		delete o_extraParams.sort;

		var o_sorters = i_store.getSorters();

		o_sorters.removeAll();

		var a_sorters = [];

		Ext.Array.each(a_filters, function(i_filter) {
			var o_sort = i_filter.getSortInfo();
			a_sorters.push(o_sort);
		});

		if (a_sorters.length > 0) {
			o_sorters.add(a_sorters);
		}
		else {

			if (i_store.isTreeStore) {
				var i_tree = i_store.ownerTree;

				var i_view = i_tree.getView();


				if (i_view.body.dom) {
					i_view.body.translate(0, 0, 0);
				}

				if (i_view.bufferedRenderer) {
					i_view.bufferedRenderer.onStoreClear();
				}
			}

			if (Ext.isFunction(i_store.clearAndLoad)) {
				i_store.clearAndLoad();
			}
			else {
				i_store.load();
			}
		}

		if (i_self.allowMenu) {
			i_self.menu.reset();
		}

		i_self.fireEvent("afterFilter", i_self, a_filters.length);
	},

	clearStatus: function(i_menu) {
		var i_self = this;
		var a_items = i_menu.items.items;
		Ext.Array.each(a_items, function(i_item) {
			if (i_item.menu != null) {
				i_item.setIconCls("");
				i_self.clearStatus(i_item.menu);
			}
			else {
				i_item.setIconCls("");
			}
		});
	},

	clearFiltersNoReload: function() {

		var i_self = this;
		var i_grid = i_self.ownerCt;
		var i_store = i_grid.getStore();
		var a_filters = i_self.getFilters();

		Ext.Array.each(a_filters, function(i_button) {
			if (i_button.overRuleable == null) {
				i_self.remove(i_button);
			}
			else {
				if (i_button.overRuleable) {
					i_self.remove(i_button);
				}
			}
		});

		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		delete o_extraParams.where;
		delete o_extraParams.sort;

		i_self.fireEvent("afterFilter", i_self, a_filters.length);
	},

	createWhere: function() {

		var i_self = this;
		var i_grid = i_self.ownerCt;
		var i_store = i_grid.getStore();
		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();
		var a_filters = i_self.getFilters();
		var s_where = "";
		var n_whereAdded = 0;

		Ext.Array.each(a_filters, function(i_filter) {
			var s_value = i_filter.getFilterValue();
			if (s_value) {
				if (n_whereAdded === 0) {
					s_where += s_value;
					n_whereAdded++;
				}
				else {
					s_where += " AND " + s_value;
				}
			}
		});

		o_extraParams.where = s_where;
	},

	getWhere: function() {

		var i_self = this;
		var a_filters = i_self.getFilters();
		var s_where = "";
		var n_whereAdded = 0;

		Ext.Array.each(a_filters, function(i_filter, n_index) {
			var s_value = i_filter.getFilterValue();
			if (s_value) {
				if (n_whereAdded === 0) {
					s_where += s_value;
					n_whereAdded++;
				}
				else {
					s_where += " AND " + s_value;
				}
			}
		});
		return s_where;
	},

	getFilterConfig: function() {

		var i_self = this;
		var a_filters = i_self.getFilters();
		var a_configs = [];

		Ext.Array.each(a_filters, function(i_button) {

			var i_config = i_button.getConfig();
			var o_sortInfo = i_button.getSortInfo();
			var a_checkbox = [];
			var a_values = [];

			Ext.Array.each(i_config.checkboxes, function(i_checkbox) {
				a_checkbox.push(i_checkbox.checked);
			});

			Ext.Array.each(i_config.fields, function(i_field) {

				if (i_field.fieldtype != "bt") {
					var value = i_field.getValue() || "";
					a_values.push(value);
				}
				else {
					var a_items = i_field.items.items;
					var i_first = a_items[0];
					var i_second = a_items[1];
					var o_value = {
						first: i_first.getValue() || "",
						second: i_second.getValue() || ""
					};
					a_values.push(o_value);
				}
			});

			var o_config = Ext.apply({}, {
				dataIndex: i_button.dataIndex,
				dataType: i_button.dataType,
				dataDateType: i_button.dataDateType || "",
				isString: i_button.isString || false,
				multiSelect: i_button.multiSelect || false,
				sortDirection: o_sortInfo.direction,
				overRuleable: true,
				dmd: i_button.dmd || "",
				checkboxes: a_checkbox,
				fieldValues: a_values,
				notValue: i_button.getNot(),
				text: i_button.text,
				values: i_button.values || []
			});

			a_configs.push(o_config);
		});
		return a_configs;
	},

	applyFilters: function(b_reset) {

		var i_self = this;
		var i_grid = i_self.grid;
		var i_store = i_grid.getStore();
		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();
		var a_filters = i_self.getFilters();
		var s_where = "";
		var o_sorters = i_store.getSorters();
		var a_sorters = [];

		var a_where = [];
		var b_needSort =  a_filters.length != o_sorters.getRange().length;

		if (!b_reset) {

			Ext.Array.each(a_filters, function (i_filter) {

				var b_found = false;
				var s_value = i_filter.getFilterValue();
				var o_sort = i_filter.getSortInfo();

				if (s_value) {
					a_where.push(s_value);
				}

				Ext.Array.each(o_sorters.getRange(), function (i_sorter) {

					if (i_sorter.getProperty() == o_sort.property) {
						b_found = true;

						if (i_sorter.getDirection() != o_sort.direction) {
							i_sorter.setDirection(o_sort.direction);
							b_needSort = true;
						}
					}
				});

				if (!b_found) {
					a_sorters.push(o_sort);
				}
			});
		}
		else {
			Ext.Array.each(a_filters, function (i_filter) {

				var s_value = i_filter.getFilterValue();
				var o_sort = i_filter.getSortInfo();

				if (s_value) {
					a_where.push(s_value);
				}

				a_sorters.push(o_sort);
			});

			o_sorters.removeAll();
		}

		s_where = a_where.join(" AND ");

		o_extraParams.where = s_where;

		if (i_store.isTreeStore) {
			var i_tree = i_store.ownerTree;

			var i_view = i_tree.getView();

			if (i_view.body.dom) {
				i_view.body.translate(0, 0, 0);
			}

			if (i_view.bufferedRenderer) {
				i_view.bufferedRenderer.onStoreClear();
			}
		}

		if (a_sorters.length > 0) {
			o_sorters.add(a_sorters);
		}
		else {
			if (b_needSort || !Ext.isEmpty(s_where)) {
				i_store.applySorters(o_sorters.getRange(), o_sorters);
			}
		}

		i_self.fireEvent("afterFilter", i_self, a_filters.length);
	},

	removeFilter: function(i_filter) {

		var i_self = this;
		i_self.remove(i_filter);

		var i_grid = i_self.ownerCt;
		var i_store = i_grid.getStore();
		var o_sorters = i_store.getSorters();
		var o_sort = i_filter.getSortInfo();
		var a_filters = i_self.getFilters();

		var a_removed = o_sorters.items.filter(function(i_sorter) {
			var b_found = false;
			if (i_sorter.getProperty() == o_sort.property) {
				b_found = true;
			}
			return b_found;
		});

		if (a_removed.length > 0 && a_filters.length > 0) {
			o_sorters.remove(a_removed);
		}

		i_self.createWhere();

		if (a_filters.length === 0) {
			i_self.clearFilters();
		}

		i_self.fireEvent("afterFilter", i_self, a_filters.length);
	},

	sortChange: function(i_column) {

		var i_self = this;
		var a_filters = i_self.getFilters();
		var b_found = false;
		var i_plugin = i_self.getPlugin("plugin-drop");

		Ext.Array.each(a_filters, function(i_filter) {

			if (i_filter.dataIndex == i_column.dataIndex ||
				i_filter.sortProperty == i_column.dataIndex ||
				i_filter.dataIndex == i_column.mapping
			) {

				var o_sort = i_filter.getSortInfo();
				b_found = true;
				if (i_column.sortState !== null) {
					if (o_sort.direction != i_column.sortState) {
						i_filter.changeSort();
					}
				}
			}
		});

		if (!b_found) {

			i_plugin.createItem({
				header: i_column
			});
		}
	},

	createPlugins: function() {

		var i_self = this;
		var a_plugins = [
			i_self.createReorderplugin(),
			i_self.createDropPlugin()
		];
		return a_plugins;
	},

	createReorderplugin: function() {

		var i_self = this;
		var o_reorder = {
			ptype: "boxreorder",
			removeOnDrop: function(element, i_button) {
				var i_dropped = Ext.getCmp(element.id);
				var b_remove = false;
				if (i_dropped && i_dropped.itemId == "button-clear") {
					b_remove = true;
					i_self.removeFilter(i_button);
				}
				return b_remove;
			},
			listeners: {
				Drop: {
					fn: function(i_self, i_toolbar, component, startIdx, idx) {
						if (startIdx != idx) {
							i_toolbar.applyFilters(true);
						}
					}
				}
			}
		};
		return o_reorder;
	},

	createDropPlugin: function() {

		var i_self = this;
		var o_dropplugin = {
			pluginId: "plugin-drop",
			ptype: "toolbardroppable",
			canDrop: function(ddSource, event, i_data) {

				var o_header = i_data.header;

				if (o_header) {

					if (!o_header.hasOwnProperty("filterable")) {
						o_header.filterable = true;
					}

					if (o_header.filterable && o_header.sortable) {
						var a_filters = i_self.getFilters();
						var b_result = true;
						Ext.Array.each(a_filters, function(o_filter) {
							if (o_filter.dataIndex == o_header.dataIndex) {
								b_result = false;
							}
						});
						return b_result;
					}
					else {
						return false;
					}
				}
				else {
					return false;
				}
			},
			createItem: function(i_data) {

				var i_grid = i_self.grid;
				var b_allowFilterMenu = i_self.getAllowFilterMenu();
				var o_dmdConfig = i_grid.getModelConfig();
				var i_header = i_data.header;
				var i_reorderer = i_grid.reorderer;
				var s_type = ip2.dbtypes2js(i_header);
				var s_datetype = "datetime";
				var o_dmd = {};
				var b_string = false;
				var b_mulitiSelect = false;
				var b_like = false;
				var s_sortProperty = i_header.sortProperty;
				var b_useRaw = i_header.useRaw || false;

				var o_dmdInfo = ip2.dmd.getInfo({
					dmd: o_dmdConfig.dmd,
					entity: o_dmdConfig.entityName,
					view: o_dmdConfig.uiName,
					context: "grid"
				});

				Ext.Array.each(o_dmdInfo.view.columns, function(o_column) {
					if (o_column.name == i_header.dataIndex) {
						i_header.xpd = o_column.xpd;
					}
				});

				if (s_type == "int") {
					s_type = "number";
				}

				if (i_header.xpd && !i_header["enum"] && !i_header.filterXpd) {
					var o_xpdInfo = ip2.getFieldXpdInfo(i_header.dataIndex, o_dmdInfo.entity, i_header);
					if (!o_xpdInfo) {
						var o_xpd = ip2.resource.get(i_header.xpd + ".xpd");
						var o_xpdProp = o_xpd.properties[i_header.xpdProp];
						o_xpdInfo = {
							xpd: o_xpd,
							definition: o_xpdProp
						};
					}
					var o_definition = o_xpdInfo.definition;
					if (o_definition) {
						if (o_definition.dmd) {
							o_dmd = o_definition.dmd;
							o_dmd.view = o_dmdConfig.uiName;
							s_type = "entity";
						}
						else if (o_definition.context) {
							if (o_definition.context.grid.uitype) {
								s_type = o_definition.context.grid.uitype;
							}
						}
						else if (o_definition.type == "isotimestamp") {
							s_type = "date";
						}
						else if (o_definition.type == "date") {
							s_type = "date";
							s_datetype = "date";
						}
						else {
							var s_db = o_definition.type || "";
							if (s_db.indexOf("varchar") != -1 || s_db.indexOf("display") != -1) {
								s_type = "string";
							}
							else if (o_definition.type == "boolean") {
								s_type = o_definition.type;
							}
							else {
								var o_xpd = o_xpdInfo.xpd;
								var a_keys = Object.keys(o_xpd.collections);
								var a_values = [];
								Ext.Array.each(a_keys, function(s_key) {
									if (s_key != "all") {
										var o_collection = o_xpd.collections[s_key];
										var o_value = {
											key: o_collection.id,
											value: ip2.xpd.translate(o_xpd, o_collection.title)
										};
										a_values.push(o_value);
									}
								});
								a_values.sort(function(o_first, o_second) {
									var n_a = (Ext.isNumber(o_first.value) ? o_first.value : 0);
									var n_b = (Ext.isNumber(o_second.value) ? o_second.value : 0);

									var n_min = Math.min(n_a, n_b);

									return n_min;
								});
								s_type = "enum";
							}
						}
					}
				}
				else if (i_header.filterXpd) {
					var o_column = {
						xpd: i_header.filterXpd
					};
					var o_xpdInfo = ip2.getFieldXpdInfo(i_header.supportProp, o_dmdInfo.entity, o_column);
					if (!o_xpdInfo) {
						var o_xpd = ip2.resource.get(i_header.xpd + ".xpd");
						var o_xpdProp = o_xpd.properties[i_header.xpdProp];
						o_xpdInfo = {
							xpd: o_xpd,
							definition: o_xpdProp
						};
					}
					var o_definition = o_xpdInfo.definition;
					if (o_definition.dmd) {
						o_dmd = o_definition.dmd;

						Ext.applyIf(o_dmd, {
							view: "portfolio"
						});

						s_type = "entity";
					}
					else if (o_definition.context) {
						if (o_definition.context.grid.uitype) {
							s_type = o_definition.context.grid.uitype;
						}
					}
					else if (o_definition.type == "isotimestamp") {
						s_type = "date";
					}
					else if (o_definition.type == "date") {
						s_type = "date";
						s_datetype = "date";
					}
					else {
						var s_db = o_definition.type || "";
						if (s_db.indexOf("varchar") != -1 || s_db.indexOf("display") != -1) {
							s_type = "string";
						}
						else if (o_definition.type == "boolean") {
							s_type = o_definition.type;
						}
						else {
							var o_xpd = o_xpdInfo.xpd;
							var a_keys = Object.keys(o_xpd.collections);
							var a_values = [];
							Ext.Array.each(a_keys, function(s_key) {
								if (s_key != "all") {
									var o_collection = o_xpd.collections[s_key];
									var o_value = {
										key: o_collection.id,
										value: ip2.xpd.translate(o_xpd, o_collection.title)
									};
									a_values.push(o_value);
								}
							});
							a_values.sort(function(o_first, o_second) {
								var n_a = (Ext.isNumber(o_first.value) ? o_first.value : 0);
								var n_b = (Ext.isNumber(o_second.value) ? o_second.value : 0);

								var n_min = Math.min(n_a, n_b);

								return n_min;
							});
							s_type = "enum";
						}
					}
				}
				else if (i_header["enum"]) {
					var o_ns = ip2.resource.get("adm.ns");
					var o_enums = o_ns.enums[i_header["enum"]].values;
					var a_keys = Object.keys(o_enums);
					var a_values = [];
					Ext.Array.each(a_keys, function(s_key) {
						var o_enum = o_enums[s_key];
						var o_value = {
							key: s_key,
							value: ip2.i18n(o_enum)
						};
						a_values.push(o_value);
					});
					b_string = true;
					s_type = "enum";
					if (i_header.xpd) {
						var o_xpdInfo = ip2.getFieldXpdInfo(i_header.dataIndex, o_dmdInfo.entity, i_header);
						var o_definition = o_xpdInfo.definition;
						b_mulitiSelect = o_definition.multiSelect || i_header.multiSelect != undefined ? i_header.multiSelect : false;
						b_like = o_definition.useLike || i_header.useLike != undefined ? i_header.useLike : false;
					}
				}

				else if (i_header.uitype != "") {
					if (i_header.uitype == "boolean") {
						s_type = i_header.uitype;
						b_string = true;
					}
					else if (i_header.uitype == "isotimestamp") {
						s_type = "date";
					}
					else if (i_header.uitype == "array") {
						s_type = i_header.uitype;
						o_dmd = {
							file: i_header.dmd,
							entity: i_header.entity,
							view: i_header.view || "portfolio"
						};
					}
				}

				var s_index = i_header.dataIndex;

				if (i_header.filter) {
					var o_filter = i_header.filter;
					if (o_filter.dmd && o_filter.entity) {
						o_dmd = Ext.apply({}, {
							file: o_filter.dmd,
							entity: o_filter.entity,
							view: o_filter.view || "portfolio"
						});
						s_type = "entity";
					}

					if (o_filter.hasOwnProperty("dataType")) {
						s_type = o_filter.dataType || "string";
					}

					if (s_type === "enum") {

						var o_ns = ip2.resource.get("adm.ns");
						var o_enums = o_ns.enums[o_filter["enum"]].values;

						Ext.Object.each(o_enums, function(s_key, value) {
							var o_value = {
								key: s_key,
								value: ip2.i18n(o_enum)
							};
							a_values.push(o_value);
						});
						b_string = true;
						s_type = "enum";
					}

					if (o_filter.hasOwnProperty("dataIndex")) {
						s_index = o_filter.dataIndex;
					}

					if (o_filter.hasOwnProperty("sortProperty")) {
						s_sortProperty = o_filter.sortProperty;
					}

					if (o_filter.hasOwnProperty("multiSelect")) {
						b_mulitiSelect = o_filter.multiSelect;
					}

					if (o_filter.hasOwnProperty("isString")) {
						b_string = o_filter.isString;
					}

					if (o_filter.hasOwnProperty("useLike")) {
						b_like = o_filter.useLike;
					}

					if (o_filter.hasOwnProperty("values")) {
						a_values = o_filter.values || [];
					}

					if (o_filter.hasOwnProperty("useRaw")) {
						b_useRaw = o_filter.useRaw || false;
					}
				}

				if (i_reorderer) {
					i_reorderer.dropZone.invalidateDrop();
				}

				if (i_header.supportProp) {
					s_index = i_header.supportProp;
				}
				if (i_header.supportIndex) {
					s_index = i_header.supportIndex;
				}
				if (i_header.mapping) {
					s_index = i_header.mapping;
				}

				var o_config = {
					text: i_header.text,
					dataIndex: s_index,
					dataType: s_type,
					dataDateType: s_datetype,
					sortProperty: s_sortProperty,
					isString: b_string,
					multiSelect: b_mulitiSelect,
					sortDirection: i_header.sortState || "ASC",
					overRuleable: true,
					allowMenu: b_allowFilterMenu,
					useLike: b_like,
					useRaw: b_useRaw,
					values: a_values,
					dmd: o_dmd,
					applyFn: function() {
						i_self.applyFilters();
					},
					removeFn: function(i_filter) {
						i_self.removeFilter(i_filter);
					}
				};

				var i_filter = Ext.ux.grid.filter.util.createFilter(o_config);

				i_self.add(i_filter);
				i_self.applyFilters();
			}
		};
		return o_dropplugin;
	},

	loadFilters: function(a_filters) {

		var i_self = this;

		i_self.clearFiltersNoReload();

		Ext.Array.each(a_filters, function(o_config) {

			var a_values = o_config.fieldValues;
			var a_checkbox = o_config.checkboxes;
			var b_not = o_config.notValue || false;

			o_config.applyFn = function() {
				i_self.applyFilters();
			};

			o_config.removeFn = function(i_filter) {
				i_self.removeFilter(i_filter);
			};

			/* REMOVE UNUSED PROPERTIES SO THEY DONT POLLUTE THE FILTER */
			delete o_config.checkboxes;
			delete o_config.fieldValues;
			delete o_config.notValue;

			var i_filter = Ext.ux.grid.filter.util.createFilter(o_config);
			i_filter.setNot(b_not);

			/* ADD PROPERTIES SO WE DONT LOSE THEM FOR FURTHER USAGES */
			o_config.checkboxes = a_checkbox;
			o_config.fieldValues = a_values;
			o_config.notValue = b_not;

			var o_filterConfig = i_filter.getConfig();
			var a_filtercheckboxs = o_filterConfig.checkboxes;
			var a_filterfields = o_filterConfig.fields;

			Ext.Array.each(a_filtercheckboxs, function(i_checkbox, n_index) {

				var i_field = a_filterfields[n_index];
				var value = a_values[n_index];

				i_checkbox.setValue(a_checkbox[n_index]);

				if (i_field.fieldtype != "bt") {
					if (i_checkbox.dataType == "enum") {
						var i_store = i_field.getStore();
						i_store.on({
							load: {
								fn: function(store, records) {
									i_field.setValue(value);
								}
							}
						});
					}
					else {
						i_field.setValue(value);
					}
				}
				else {

					var a_items = i_field.items.items;

					var i_first = a_items[0];
					var i_second = a_items[1];

					i_first.setValue(value.first);
					i_second.setValue(value.second);
				}
			});
			i_self.add(i_filter);
		});

		i_self.applyFilters();
	}
});
Ext.define("Ext.ux.grid.filter.view.Edit", {

	extend: "Ext.window.Window",

	alias: "widget.filterviewedit",

	okFn: Ext.emptyFn,
	layout: "fit",

	width: 360,
	height: 160,
	modal: true,
	"public": true,

	initComponent: function() {
		var i_self = this;
		i_self.callParent(arguments);
		i_self.add(i_self.createForm());
		return i_self;
	},

	createForm: function() {
		var i_self = this;
		var i_form = Ext.widget("form", {
			layout: "fit",
			items: i_self.createPanel(),
			buttons: i_self.createButtons()
		});
		i_self.form = i_form;
		return i_form;
	},

	createPanel: function() {
		var i_self = this;
		var i_panel = Ext.widget("panel", {
			layout: "anchor",
			bodyPadding: 5,
			items: i_self.createItems()
		});

		return i_panel;
	},

	createItems: function() {
		var i_self = this;
		var a_items = [];
		if (i_self["public"]) {

			var i_checkbox = Ext.widget("checkbox", {
				name: "PUBLIC",
				checked: false,
				fieldLabel: ip2.i18n({
					da: "Offentlig",
					en: "Public"
				}),
				anchor: "98%"
			});

			a_items.push(i_checkbox);
		}

		var i_textfield = Ext.widget("textfield", {
			name: "NAME",
			emptyText: ip2.i18n({
				da: "Skriv title på filter",
				en: "Enter name of filter"
			}),
			fieldLabel: ip2.i18n({
				da: "Navn",
				en: "Name"
			}),
			anchor: "98%"
		});

		a_items.push(i_textfield);
		return a_items;
	},

	createButtons: function() {
		var i_self = this;
		var a_items = [];
		var i_btn_ok = Ext.widget("button", {
			text: ip2.i18n({
				da: "Gem",
				en: "Save"
			}),
			handler: function(i_button) {
				var i_form = i_self.getForm();
				var o_value = i_form.getFieldValues();

				var b_public = o_value.PUBLIC || false;
				var s_name = o_value.NAME;

				if (i_self.okFn != null) {
					i_self.okFn(b_public, s_name);
				}
			}
		});

		var i_btn_cancel = Ext.widget("button", {
			text: ip2.i18n({
				da: "Annuller",
				en: "Cancel"
			}),
			handler: function(i_button) {
				i_self.close();
			}
		});

		a_items.push(i_btn_ok);
		a_items.push(i_btn_cancel);

		return a_items;
	},

	getForm: function() {
		var i_self = this;
		return i_self.form.getForm();
	}
});
Ext.define("Ext.ux.grid.filter.Menu", {
	extend: "Ext.button.Button",

	alias: "widget.filtermenu",
	currentFilter: "",
	creator: "",
	reorderable: false,
	defaultFilter: "",

	config: {
		toolBar: null,
		defaultFilter: ""
	},

	listeners: {
		afterrender: {
			fn: function(i_button) {

				var i_self = this;

				var i_menu = i_button.menu;
				var a_items = i_self.createMenuItems();
				i_menu.add(a_items);

				if (i_self.getDefaultFilter()) {
					var i_default = i_menu.down("menuitem[tag=" + i_self.getDefaultFilter() + "]");
					if (i_default) {
						i_default.handler(i_default);
					}
				}
			},
			buffer: 10
		}
	},

	requires: [
		"Ext.ux.grid.filter.view.Edit"
	],

	initComponent: function() {
		var i_self = this;

		i_self.menu = {
			items: [],
			listeners: {
				show: {
					fn: function(i_menu) {

						var i_toolbar = i_self.getToolBar();
						var a_filters = i_toolbar.getFilters();
						var i_itemSaveAs = i_menu.down("#itemSaveAs");
						var i_itemSave = i_menu.down("#itemSave");
						var s_user = ip2.navigator.user.id;

						if (a_filters.length === 0) {
							if (i_itemSaveAs) {
								i_itemSaveAs.disable();
							}
						}
						else {
							if (i_itemSaveAs) {
								i_itemSaveAs.enable();
							}
						}

						if (!i_self.currentFilter) {
							if (i_itemSave) {
								i_itemSave.disable();
							}
						}
						else {
							if (i_self.creator) {
								if (s_user != i_self.creator) {
									if (i_itemSave) {
										i_itemSave.disable();
									}
								}
								else {
									if (i_itemSave) {
										i_itemSave.enable();
									}
								}
							}
							else {
								if (i_itemSave) {
									i_itemSave.enable();
								}
							}
						}
					}
				}
			}
		};

		i_self.callParent();
	},

	createEdit: function(f_callback) {

		var i_self = this;
		var i_toolbar = i_self.getToolBar();
		var i_grid = i_toolbar.up("gridpanel");
		var s_dmd = i_grid.dmdName;

		var b_public = false;

		if (ip2.isAccessible("app." + s_dmd + ".functions.filter.saveaspublic") ||
			ip2.isAccessible("app." + s_dmd + ".functions." + i_grid.entity.name + ".filter.saveaspublic")) {
			b_public = true;
		}

		var i_window = Ext.widget("filterviewedit", {
			title: ip2.i18n({
				da: "Gem filter",
				en: "Save filter"
			}),
			okFn: f_callback,
			"public": b_public
		});
		return i_window;
	},

	createMenuItems: function() {

		var i_self = this;
		var i_grid = i_self.up("gridpanel");
		var a_columns = i_grid.columns;
		var s_key = i_grid.s_id;
		var s_unique = ip2.unique();
		var s_user = ip2.navigator.user.id;

		var o_return = i_self.getFilters(s_key, s_user, s_unique);

		var a_public_items = o_return["public"].items;
		var a_private_items = o_return["private"].items;
		var a_recently = o_return["private"].recent;

		i_self.addApplyHandler(o_return, a_columns, true);
		i_self.addApplyHandler(o_return, a_columns, false);

		var a_items = [];

		if (a_recently.length > 0) {
			var o_recent = {
				text: ip2.i18n({
					da: "Senest anvendte",
					en: "Recently used"
				}),
				disabledCls: "menu-item",
				disabled: true
			};
			a_items.push(o_recent);
			a_items.push({
				xtype: "menuseparator"
			});
			var a_return = i_self.createRecentItems(s_unique, a_recently);
			Ext.Array.each(a_return, function(i_recent) {
				a_items.push(i_recent);
			});
			a_items.push({
				xtype: "menuseparator"
			});
		}

		var o_public = {
			xtype: "menuitem",
			text: ip2.i18n({
				da: "Offentlig",
				en: "Public"
			}),
			itemId: "public_menu_" + s_unique,
			disabled: a_public_items.length === 0 ? true : false,
			iconCls: i_self.currentFilter !== "" ? i_self.isPublic ? "x-ux-filter-check" : "" : ""
		};

		var o_private = {
			xtype: "menuitem",
			text: ip2.i18n({
				da: "Privat",
				en: "Private"
			}),
			itemId: "private_menu_" + s_unique,
			disabled: a_private_items.length === 0 ? true : false,
			iconCls: i_self.currentFilter !== "" ? i_self.isPublic === false ? "x-ux-filter-check" : "" : ""
		};

		if (a_public_items.length > 0) {
			o_public.menu = {
				items: a_public_items
			};
		}

		if (a_private_items.length > 0) {
			o_private.menu = {
				items: a_private_items
			};
		}

		a_items.push(o_public);
		a_items.push(o_private);

		var i_save = Ext.widget("menuitem", {
			itemId: "itemSave",
			text: ip2.i18n({
				da: "Gem",
				en: "Save"
			}),
			disabled: i_self.currentFilter !== "" ? false : true,
			handler: function(i_button) {
				i_self.saveFilters(s_key, s_user, i_self.currentFilter, i_self.isPublic);
			}
		});
		a_items.push(i_save);
		a_items.push(i_self.createSaveAs(s_key, s_user));

		return a_items;
	},

	createRecentItems: function(s_unique, a_recent) {

		var i_self = this;
		var a_items = [];

		var s_public = ip2.i18n({
			da: "Offentlig",
			en: "Public"
		});

		var s_creator = ip2.i18n({
			da: "Oprettet af",
			en: "Created by"
		});

		var i_tpl = Ext.create("Ext.XTemplate",
			"<div>",
				"<div><span><strong>" + s_creator + "</strong>: </span><span>{creator}</span></div>",
				"<tpl if=\"this.isPublic(values.isPublic)\">",
					"<div><span><strong>Tag</strong>: </span><span>{tag}</span></div>",
				"</tpl>",
				"<div><span><strong>" + s_public + "</strong>: </span><span>{[this.getPublic(values.isPublic)]}</span></div>",
			"</div>",
			{
				isPublic: function(value) {
					return value;
				},
				getPublic: function(value) {
					return value ? "Ja" : "Nej";
				}
			}
		);

		i_tpl.compile();

		Ext.Array.each(a_recent, function(o_recent) {

			var s_text = "";
			var i_public;
			s_text = o_recent.name;

			var i_menuitem = Ext.widget("menuitem", {
				text: s_text,
				tag: o_recent.tag,
				isPublic: o_recent.isPublic,
				iconCls: i_self.currentFilter == o_recent.name ? i_self.isPublic == o_recent.isPublic ? "x-ux-filter-check" : "" : "",
				unique: s_unique,
				creator: o_recent.creator,
				handler: function(i_recent) {
					var s_unique = i_recent.unique;
					var s_tag = i_recent.tag + "-" + s_unique;
					var s_itemId = i_recent.isPublic ? "public-" + s_tag : "private-" + s_tag;
					var s_menuId = i_recent.isPublic ? "public_menu_" + s_unique : "private_menu_" + s_unique;
					var i_item = i_self.menu.down("#" + s_itemId);
					var i_menu = i_self.menu.down("#" + s_menuId);

					if (i_item) {
						i_item.handler(i_item);
					}
					if (i_menu) {
						i_menu.setIconCls("x-ux-filter-check");
					}

					i_recent.setIconCls("x-ux-filter-check");
				},
				listeners: {
					afterrender: {
						fn: function(i_item) {

							var i_el = i_item.getEl();
							var i_tip = Ext.create("Ext.tip.ToolTip", {
								target: i_el,
								html: i_tpl.apply({
									tag: i_item.tag,
									creator: i_item.creator,
									isPublic: i_item.isPublic
								})
							});
						}
					}
				}
			});
			a_items.push(i_menuitem);
		});
		return a_items;
	},

	createSaveAs: function(s_gridId, s_id) {

		var i_self = this;
		var s_key = s_gridId;
		var s_user = s_id;

		var i_menuitem = Ext.widget("menuitem", {
			itemId: "itemSaveAs",
			text: ip2.i18n({
				da: "Gem som",
				en: "Save as"
			}),
			handler: function(i_button) {
				var wnd = i_self.createEdit(function(b_public, s_name) {

					if (b_public) {

						var b_found = false;
						var o_filter;

						var o_settings = ip2.global.get(s_key + ".filters", {
							filters: []
						});

						Ext.Array.each(o_settings.filters, function(db_filter) {
							if (db_filter.name == s_name) {
								o_filter = db_filter;
								b_found = true;
							}
						});
						if (b_found) {
							if (o_filter.creator != s_user) {
								Ext.Msg.show({
									title: ip2.i18n({
										da: "Fejl",
										en: "Error"
									}),
									msg: ip2.i18n({
										da: "Du har ikke rettighed til at gemme et under dette navn (<b> " + s_name + " </b>)<br>" +
										"Da en anden bruger ( <b>" + o_filter.creator + "</b> ) har alrede oprettet et under sammen navn.<br>" +
										"Hvis du ønsker at gemme dette navn prøv da at gemme som privat stedet for..",
										en: "You do not have permissions to save under this name (<b> " + s_name + " </b>)</br>" +
										"Since another user (<b> " + o_filter.creator + "</b> ) already has created one under this name.</br>" +
										"If you want to use this name try to save as a private instead.."
									}),
									buttons: Ext.Msg.OK,
									icon: Ext.Msg.ERROR
								});
							}
							else {
								i_self.saveFilters(s_key, s_user, s_name, b_public);
								wnd.close();
							}
						}
						else {
							i_self.saveFilters(s_key, s_user, s_name, b_public);
							wnd.close();
						}
					}
					else {
						i_self.saveFilters(s_key, s_user, s_name, b_public);
						wnd.close();
					}
				});
				wnd.show();
			}
		});
		return i_menuitem;
	},

	/*********************
	*     FUNCTIONS     *
	*********************/

	addApplyHandler: function(o_return, a_columns, b_public) {
		var i_self = this;
		var i_toolbar = i_self.getToolBar();
		var n_count = 0;
		var s_name = "";
		var a_items = b_public ? o_return["public"].items : o_return["private"].items;
		var a_filters = b_public ? o_return["public"].filters : o_return["private"].filters;
		var s_key = o_return.key;

		var count = function() {
			n_count--;
			if (n_count === 0) {
				i_self.currentFilter = s_name;
				i_toolbar.applyFilters();
			}
		};

		Ext.Array.each(a_items, function(i_menuitem) {
			i_menuitem.handler = function(i_menuitem) {

				var a_configs = [];

				Ext.Array.each(a_filters, function(o_filter) {
					if (o_filter.tag == i_menuitem.tag) {
						a_configs = o_filter.configs;
						s_name = o_filter.name;
					}
				});

				i_self.setText([
					ip2.i18n({
						da: "Filter",
						en: "Filter"
					}),
					s_name
				].join(" - "));

				i_self.clearStatus(i_self.menu);
				i_self.menu.hide();

				i_menuitem.setIconCls("x-ux-filter-check");

				if (i_menuitem.parentMenu.parentItem) {
					i_menuitem.parentMenu.parentItem.setIconCls("x-ux-filter-check");
				}

				i_self.isPublic = b_public;
				i_self.creator = i_menuitem.creator;

				if (a_configs.length > 0) {

					i_toolbar.clearFiltersNoReload();

					Ext.Array.each(a_configs, function(o_config) {

						var i_column;

						Ext.Array.each(a_columns, function(o_column) {
							if (o_column.dataIndex == o_config.dataIndex) {
								o_config.text = o_column.text;
								return false;
							}
						});

						var a_values = o_config.fieldValues;
						var a_checkbox = o_config.checkboxes;
						var b_not = o_config.notValue || false;

						o_config.applyFn = function() {
							i_toolbar.applyFilters();
						};

						o_config.removeFn = function(i_filter) {
							i_toolbar.removeFilter(i_filter);
						};

						/* REMOVE UNUSED PROPERTIES SO THEY DONT POLLUTE THE FILTER */
						delete o_config.checkboxes;
						delete o_config.fieldValues;
						delete o_config.notValue;

						var i_filter = Ext.ux.grid.filter.util.createFilter(o_config);
						i_filter.setNot(b_not);

						/* ADD PROPERTIES SO WE DONT LOSE THEM FOR FURTHER USAGES */
						o_config.checkboxes = a_checkbox;
						o_config.fieldValues = a_values;
						o_config.notValue = b_not;

						var o_filterConfig = i_filter.getConfig();
						var a_filtercheckboxs = o_filterConfig.checkboxes;
						var a_filterfields = o_filterConfig.fields;
						var n_index = 0;

						Ext.Array.each(a_filtercheckboxs, function(o_checkbox) {
							var i_field = a_filterfields[n_index];
							var value = a_values[n_index];
							o_checkbox.setValue(a_checkbox[n_index]);
							if (i_field.fieldtype != "bt") {
								if (o_checkbox.dataType == "entity") {

									n_count++;

									var i_store = i_field.getStore();

									i_store.on({
										load: {
											fn: function(store, records) {
												i_field.setValue(value);
												count();
											}
										}
									});
								}
								else {
									i_field.setValue(value);
								}
							}
							else {
								var o_value = a_values[n_index];
								var a_items = i_field.items.items;
								var i_first = a_items[0];
								var i_second = a_items[1];
								i_first.setValue(o_value.first);
								i_second.setValue(o_value.second);
							}
							n_index++;
						});
						i_toolbar.add(i_filter);
						i_self.saveRecently(s_key, i_menuitem, b_public);
					});
					if (n_count === 0) {
						n_count++;
						count();
					}
				}
			};
		});
	},

	clearStatus: function(i_menu) {

		var i_self = this;
		var i_collection = i_menu.items;
		var a_items = i_collection.getRange();

		Ext.Array.each(a_items, function(i_item) {
			if (i_item.menu) {
				i_item.setIconCls("");
				i_self.clearStatus(i_item.menu);
			}
			else {
				i_item.setIconCls("");
			}
		});
	},

	copyToPrivat: function(s_name) {

		var i_self = this;
		var i_grid = i_self.up("gridpanel");
		var i_user = ip2.getUser();
		var s_user = i_user.get("USRID");
		var s_key = i_grid.s_id;

		var o_private;

		var o_settings_public = ip2.global.get(s_key + ".filters", {});

		Ext.applyIf(o_settings_public, {
			filters: []
		});

		var o_settings_private = ip2.profile.get(s_key + ".filters", {});

		Ext.applyIf(o_settings_private, {
			filters: [],
			recent: []
		});

		var b_found = false;
		var s_filter = "";

		Ext.Array.each(o_settings_private.filters, function(o_filter) {
			if (o_filter.tag == s_name) {
				s_filter = o_filter.name;
				b_found = true;
			}
		});

		if (b_found) {

			Ext.Msg.show({
				title: ip2.i18n({
					da: "Fejl",
					en: "Error"
				}),
				msg: ip2.i18n({
					da: "Du har allerede gemt et filter under det navn (<b> " + s_filter + " </b>)<br>" +
					"Hvis du ønsker at gemme dette filter, vælg da filteret først<br>" +
					"og der næst brug da <b>Gem som </b> og indtast et andet navn.",
					en: "You already have saved a filter under this name (<b> " + s_filter + " </b>)</br>" +
					"If wish to save this filter please select the filter first<br>" +
					"and then use <b>Save as<b> and choose another name."
				}),
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
		}
		else {
			Ext.Array.each(o_settings_public.filters, function(o_filter) {
				if (o_filter.tag == s_name) {
					o_private = ip2.extend({}, o_filter);
					o_private.creator = s_user;
					return false;
				}
			});

			o_settings_private.filters.push(o_private);

			ip2.profile.set(s_key + ".filters", Ext.encode(o_settings_private), function() {
				i_self.reload();
			});
		}
	},

	copyToPublic: function(s_name) {

		var i_self = this;
		var i_grid = i_self.up("gridpanel");
		var i_user = ip2.getUser();
		var s_user = i_user.get("USRID");
		var s_key = i_grid.s_id;

		var o_public;

		var o_settings_public = ip2.global.get(s_key + ".filters", {});

		Ext.applyIf(o_settings_public, {
			filters: []
		});

		var o_settings_private = ip2.profile.get(s_key + ".filters", {});

		Ext.applyIf(o_settings_private, {
			filters: [],
			recent: []
		});

		var b_found = false;
		var s_filter = "";

		Ext.Array.each(o_settings_public.filters, function(o_filter) {
			if (o_filter.tag == s_name) {
				o_public = o_filter;
				s_filter = o_public.name;
				b_found = true;
			}
		});

		if (b_found) {

			Ext.Msg.show({
				title: ip2.i18n({
					da: "Fejl",
					en: "Error"
				}),
				msg: ip2.i18n({
					da: "Du har ikke rettighed til at gemme et under dette navn (<b> " + s_filter + " </b>)<br>" +
					"Da en anden bruger ( <b>" + o_public.creator + "</b> ) har alrede oprettet et under sammen navn.<br>" +
					"Hvis du ønsker at gemme dette navn prøv da at gemme som privat stedet for..",
					en: "You do not have permissions to save under this name (<b> " + s_filter + " </b>)</br>" +
					"Since another user (<b> " + o_public.creator + "</b> ) already has created one under this name.</br>" +
					"If you want to use this name try to save as a private instead.."
				}),
				buttons: Ext.Msg.OK,
				icon: Ext.Msg.ERROR
			});
		}
		else {

			Ext.Array.each(o_settings_private.filters, function(o_filter) {

				if (o_filter.tag == s_name) {
					o_public = Ext.apply({}, o_filter);
					o_public.creator = s_user;
					return false;
				}
			});

			o_settings_public.filters.push(o_public);

			ip2.global.set(s_key + ".filters", Ext.encode(o_settings_public), function() {
				i_self.reload();
			});
		}
	},

	deleteFilter: function(s_gridId, s_name, b_public) {

		var i_self = this;
		var i_toolbar = i_self.getToolBar();
		var s_key = s_gridId;
		var o_settings;

		if (b_public) {

			o_settings = ip2.global.get(s_key + ".filters", {});

			Ext.applyIf(o_settings, {
				filters: []
			});
		}
		else {

			o_settings = ip2.global.get(s_key + ".filters", {});

			Ext.applyIf(o_settings, {
				filters: [],
				recent: []
			});
		}

		var b_found = false;

		var o_filter = Ext.Array.findBy(o_settings.filters, function(o_filter) {
			return o_filter.tag == s_name;
		});

		if (o_filter) {
			b_found = true;
			Ext.Array.remove(o_settings.filters, o_filter);
		}

		if (o_filter.name == i_self.currentFilter && b_public == i_self.isPublic) {

			i_self.currentFilter = "";

			i_self.setText([
				ip2.i18n({
					da: "Filter",
					en: "Filter"
				})
			].join(" - "));
			i_toolbar.clearFilters();
		}

		if (b_found) {
			if (b_public) {
				ip2.global.set(s_key + ".filters", Ext.encode(o_settings), function() {
					i_self.deleteRecently(s_key, s_name, b_public);
				});
			}
			else {
				ip2.profile.set(s_key + ".filters", Ext.encode(o_settings), function() {
					i_self.deleteRecently(s_key, s_name, b_public);
				});
			}
		}
	},

	deleteRecently: function(s_key, s_name, b_public) {

		var i_self = this;

		var o_settings = ip2.profile.get(s_key + ".filters", {
			filters: [],
			recent: []
		});

		var b_found = false;
		var n_idx = 0;

		Ext.Array.each(o_settings.recent, function(o_recently, n_index) {

			if (o_recently.name == s_name && o_recently.isPublic == b_public) {
				b_found = true;
				n_idx = n_index;
			}
		});

		if (b_found) {
			o_settings.recent.splice(n_idx, 1);
		}

		ip2.profile.set(s_key + ".filters", Ext.encode(o_settings), function() {
			i_self.reload();
		});
	},

	getFilters: function(s_gridId, s_id, s_unique) {

		var i_self = this;

		var a_public = [];
		var a_private = [];
		var s_user = s_id;
		var s_key = s_gridId;

		var o_settings_public = ip2.global.get(s_key + ".filters", {
			filters: []
		});

		var o_settings_private = ip2.profile.get(s_key + ".filters", {
			filters: [],
			recent: []
		});

		if (!o_settings_private.recent) {
			o_settings_private.recent = [];
		}

		var b_diffPublic = false;
		var b_diff = false;

		var s_public = ip2.i18n({
			da: "Offentlig",
			en: "Public"
		});

		var s_creator = ip2.i18n({
			da: "Oprettet af",
			en: "Created by"
		});

		var i_tpl = Ext.create("Ext.XTemplate",
			"<div>",
				"<div><span><strong>" + s_creator + "</strong>: </span><span>{creator}</span></div>",
				"<div><span><strong>Tag</strong>: </span><span>{tag}</span></div>",
			"</div>"
		);

		i_tpl.compile();

		Ext.Array.each(o_settings_public.filters, function(o_filter) {
			if (!o_filter.tag) {
				o_filter.tag = "filter-" + Ext.id();
				b_diffPublic = true;
			}
			var i_menuitem = Ext.widget("menuitem", {
				text: o_filter.name,
				tag: o_filter.tag,
				itemId: "public-" + o_filter.tag + "-" + s_unique,
				creator: o_filter.creator,
				iconCls: i_self.currentFilter == o_filter.name ? i_self.isPublic === true ? "x-ux-filter-check" : "" : "",
				listeners: {
					afterrender: {
						fn: function(i_menuitem) {
							var i_el = i_menuitem.getEl();
							var i_menu;

							var i_tip = Ext.create("Ext.tip.ToolTip", {
								target: i_el,
								html: i_tpl.apply({
									creator: i_menuitem.creator,
									tag: i_menuitem.tag
								})
							});

							i_el.on({
								contextmenu: function(e) {
									e.stopEvent();
									var s_id = this.id;
									var i_menuitem = Ext.getCmp(s_id);
									var b_hide = false;

									if (i_menu) {
										i_menu.hide();
										i_menu.destroy();
									}

									i_menu = Ext.widget("menu", {
										allowOtherMenus: true,
										items: [
											{
												text: ip2.i18n({
													da: "Slet",
													en: "delete"
												}),
												tag: i_menuitem.tag,
												isPublic: true,
												disabled: i_menuitem.creator != s_user ? true : false,
												handler: function(i_contextitem) {
													var s_name = i_contextitem.tag;
													var b_public = i_contextitem.isPublic;
													i_self.deleteFilter(s_key, s_name, b_public);
												}
											},
											{
												text: ip2.i18n({
													da: "Kopier til privat",
													en: "Copy to privat"
												}),
												tag: i_menuitem.tag,
												handler: function(i_contextitem) {
													var s_name = i_contextitem.tag;
													i_self.copyToPrivat(s_name);
												}
											}
										]
									});
									i_menu.on({
										hide: {
											fn: function(item) {
												b_hide = true;
												i_self.menu.syncHidden();
											}
										}
									});
									var i_parentMenu = i_menuitem.parentMenu;
									i_self.menu.on({
										beforehide: {
											fn: function(item) {
												return b_hide;
											}
										}
									});
									i_menu.mon(i_parentMenu, "beforehide", function(i_menuitem) {
										return b_hide;
									});

									i_menu.showAt(e.getXY());
								}
							});
						}
					}
				}
			});
			a_public.push(i_menuitem);
		});

		Ext.Array.each(o_settings_private.filters, function(o_filter) {
			if (!o_filter.tag) {
				o_filter.tag = "filter-" + Ext.id();
				b_diff = true;
			}
			var menuitem = Ext.widget("menuitem", {
				text: o_filter.name,
				tag: o_filter.tag,
				itemId: "private-" + o_filter.tag + "-" + s_unique,
				creator: o_filter.creator,
				iconCls: i_self.currentFilter == o_filter.name ? i_self.isPublic === false ? "x-ux-filter-check" : "" : "",
				listeners: {
					afterrender: {
						fn: function(i_menuitem) {
							var i_el = i_menuitem.getEl();
							var i_menu;
							i_el.on({
								contextmenu: function(e) {
									e.stopEvent();
									var s_id = this.id;
									var i_menuitem = Ext.getCmp(s_id);
									var b_hide = false;

									if (i_menu) {
										i_menu.hide();
										i_menu.destroy();
									}

									i_menu = Ext.widget("menu", {
										allowOtherMenus: true,
										items: [
											{
												text: ip2.i18n({
													da: "Slet",
													en: "delete"
												}),
												tag: i_menuitem.tag,
												isPublic: false,
												handler: function(i_contextitem) {
													var s_name = i_contextitem.tag;
													var b_public = i_contextitem.isPublic;
													i_self.deleteFilter(s_key, s_name, b_public);
												}
											},
											{
												text: ip2.i18n({
													da: "Kopier til offentlig",
													en: "Copy to public"
												}),
												tag: i_menuitem.tag,
												handler: function(i_contextitem) {
													var s_name = i_contextitem.tag;
													i_self.copyToPublic(s_name);
												}
											}
										]
									});
									i_menu.on({
										hide: {
											fn: function(item) {
												b_hide = true;
												i_self.menu.syncHidden();
											}
										}
									});
									var i_parentMenu = i_menuitem.parentMenu;
									i_self.menu.on({
										beforehide: {
											fn: function(item) {
												return b_hide;
											}
										}
									});
									i_menu.mon(i_parentMenu, "beforehide", function(i_menuitem) {
										return b_hide;
									});

									i_menu.showAt(e.getXY());
								}
							});
						}
					}
				}
			});
			a_private.push(menuitem);
		});
		Ext.Array.each(o_settings_private.recent, function(o_recent, n_index) {
			var b_found = false;
			if (o_recent.isPublic) {
				b_found = false;
				Ext.Array.each(o_settings_public.filters, function(o_filter) {
					if (o_recent.tag == o_filter.tag) {
						o_recent.creator = o_filter.creator;
						b_found = true;
						return false;
					}
				});
				if (!b_found) {
					b_diff = true;
					o_settings_private.recent.splice(n_index, 1);
				}
			}
			else {
				b_found = false;
				Ext.Array.each(o_settings_private.filters, function(o_filter) {
					if (o_recent.tag == o_filter.tag) {
						o_recent.creator = o_filter.creator;
						b_found = true;
						return false;
					}
				});
				if (!b_found) {
					o_settings_private.recent.splice(n_index, 1);
					b_diff = true;
				}
			}
		});

		if (b_diffPublic) {
			ip2.global.set(s_key + ".filters", Ext.encode(o_settings_public));
		}

		if (b_diff) {
			ip2.profile.set(s_key + ".filters", Ext.encode(o_settings_private));
		}

		var o_return = {
			"public": {
				items: a_public,
				filters: o_settings_public.filters
			},
			"private": {
				items: a_private,
				filters: o_settings_private.filters,
				recent: o_settings_private.recent
			},
			key: s_key
		};
		return o_return;
	},

	saveFilters: function(s_key, s_user, s_name, b_public) {

		var i_self = this;
		var i_toolbar = i_self.getToolBar();
		var a_filers = [];
		var a_items = [];
		var o_settings = "";

		if (b_public) {
			o_settings = ip2.global.get(s_key + ".filters", {
				filters: []
			});
		}
		else {
			o_settings = ip2.profile.get(s_key + ".filters", {
				filters: [],
				recent: []
			});
		}
		if (!b_public) {
			if (!o_settings.recent) {
				o_settings.recent = [];
			}
		}

		Ext.applyIf(o_settings, {
			filters: [],
			recent: []
		});

		var found = false;
		var db_filter;
		Ext.Array.each(o_settings.filters, function(o_filter) {
			if (o_filter.name == s_name) {
				found = true;
				db_filter = o_filter;
			}
		});

		var a_filters = i_toolbar.getFilters();
		var s_tag;
		if (!found) {
			var b_done = false;
			while (!b_done) {
				b_done = true;
				s_tag = "filter-" + Ext.id();
				Ext.Array.each(o_settings.filters, function(o_filter) {
					if (s_tag == o_filter.tag) {
						b_done = false;
						return false;
					}
				});
			}

			db_filter = {
				tag: s_tag,
				name: s_name,
				creator: s_user,
				configs: []
			};
		}
		else {
			db_filter.configs = [];
		}

		s_tag = db_filter.tag;

		Ext.Array.each(a_filters, function(i_button) {
			var i_config = i_button.getConfig();
			var o_sortInfo = i_button.getSortInfo();
			var a_checkbox = [];
			var a_values = [];
			Ext.Array.each(i_config.checkboxes, function(i_checkbox) {
				a_checkbox.push(i_checkbox.checked);
			});
			Ext.Array.each(i_config.fields, function(i_field) {
				if (i_field.fieldtype != "bt") {
					var value = i_field.getValue() || "";
					a_values.push(value);
				}
				else {
					var a_items = i_field.items.items;
					var i_first = a_items[0];
					var i_second = a_items[1];
					var o_value = {
						first: i_first.getValue() || "",
						second: i_second.getValue() || ""
					};
					a_values.push(o_value);
				}
			});
			var o_config = {
				dataIndex: i_button.dataIndex,
				dataType: i_button.dataType,
				dataDateType: i_button.dataDateType || "",
				isString: i_button.isString || false,
				multiSelect: i_button.multiSelect || false,
				sortDirection: o_sortInfo.direction,
				overRuleable: i_button.overRuleable,
				dmd: i_button.dmd || "",
				checkboxes: a_checkbox,
				fieldValues: a_values,
				notValue: i_button.getNot(),
				values: i_button.values || []
			};
			db_filter.configs.push(o_config);
		});
		if (!found) {
			o_settings.filters.push(db_filter);
		}

		var o_config = {
			name: s_name,
			tag: s_tag
		};

		i_self.currentFilter = s_name;
		i_self.isPublic = b_public;
		i_self.setText([
			ip2.i18n({
				da: "Filter",
				en: "Filter"
			}),
			s_name
		].join(" - "));

		if (b_public) {
			ip2.global.set(s_key + ".filters", Ext.encode(o_settings), function() {
				i_self.saveRecently(s_key, o_config, b_public);
			});
		}
		else {
			ip2.profile.set(s_key + ".filters", Ext.encode(o_settings), function() {
				i_self.saveRecently(s_key, o_config, b_public);
			});
		}
	},

	saveRecently: function(s_key, o_config, b_public) {

		var i_self = this;
		var o_settings = ip2.profile.get(s_key + ".filters", {
			filters: [],
			recent: []
		});

		Ext.applyIf(o_settings, {
			filters: [],
			recent: []
		});

		var b_found = false;
		var n_idx = 0;
		var o_recent;

		Ext.Array.each(o_settings.recent, function(o_recently, n_index) {
			if (o_recently.tag == o_config.tag && o_recently.isPublic == b_public) {
				b_found = true;
				n_idx = n_index;
				return false;
			}
		});
		if (b_found) {
			var a_recent = o_settings.recent.splice(n_idx, 1);
			a_recent[0].name = o_config.name || o_config.text;
			o_settings.recent.unshift(a_recent[0]);
		}
		else {
			o_recent = {
				tag: o_config.tag,
				name: o_config.name || o_config.text,
				isPublic: b_public
			};
			o_settings.recent.unshift(o_recent);
			if (o_settings.recent.length > 5) {
				o_settings.recent.pop();
			}
		}
		ip2.profile.set(s_key + ".filters", Ext.encode(o_settings), function() {
			i_self.reload();
		});
	},

	reload: function() {
		var i_self = this;
		var i_menu = this;
		i_self.menu.hide();
		i_self.menu.removeAll(true);
		var a_items = i_self.createMenuItems();
		i_self.menu.add(a_items);
	},

	reset: function() {
		var i_self = this;
		i_self.currentFilter = "";

		i_self.setText([
			ip2.i18n({
				da: "Filter",
				en: "Filter"
			}),
		].join(" - "));

		i_self.reload();
	},

	cleanUp: function() {

		var i_self = this;
		var i_grid = i_self.up("gridpanel");

		var a_public = [];
		var a_private = [];
		var s_key = i_grid.s_id;

		var o_settings_public = ip2.global.get(s_key + ".filters", {
			filters: []
		});

		var o_settings_private = ip2.profile.get(s_key + ".filters", {
			filters: [],
			recent: []
		});

		o_settings_public.filters = o_settings_public.filters.filter(function(o_filter) {
			return o_filter !== null;
		});

		o_settings_private.recent = o_settings_private.recent.filter(function(o_filter) {
			return o_filter !== null;
		});

		ip2.global.set(s_key + ".filters", Ext.encode(o_settings_public));

		ip2.profile.set(s_key + ".filters", Ext.encode(o_settings_private));
	}
});
Ext.define("Ext.ux.form.field.Search", {
	extend: "Ext.form.field.Text",
	alias: "widget.searchfield",

	triggers: {
		clear: {
			weight: 0,
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			hidden: true,
			handler: "onClearClick",
			scope: "this"
		},
		search: {
			weight: 1,
			cls: Ext.baseCSSPrefix + "form-search-trigger",
			handler: "onSearchClick",
			scope: "this"
		}
	},

	config: {
		allowSort: true,
		store: null,
		grid: null,
		paramName: "search",
		hasSearch: false
	},

	listeners: {
		afterrender: {
			fn: function(i_field) {

				var value = i_field.getValue();
				i_field.fireEvent("change", i_field, value);
			}
		},
		specialkey: {
			fn: function(i_field, i_event) {

				var i_self = this;

				if (i_event.getKey() == i_event.ENTER) {
					i_self.onSearchClick();
				}
			}
		},
		change: {
			fn: function(i_field, value) {

				var i_self = this;

				if (value) {
					i_self.getTrigger("clear").show();
				}
				else {
					i_self.getTrigger("clear").hide();
				}
			}
		}
	},

	initComponent: function() {

		var i_self = this;

		i_self.emptyText = ip2.i18n({
			da: "Søg",
			en: "Search"
		});

		var i_store = i_self.getStore();

		i_self.callParent(arguments);

		// We"re going to use filtering
		i_store.setRemoteFilter(true);
	},

	onClearClick: function() {

		var i_self = this;
		var i_grid = i_self.getGrid() || i_self.up("gridpanel");
		var i_store = i_self.getStore();

		if (i_grid) {

			var i_gridStore = i_grid.getStore();

			if (i_gridStore.getId() != i_store.getId()) {

				i_store = i_grid.getStore();
				i_self.setStore(i_store);
			}
		}

		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();
		var o_sorters = i_store.getSorters();

		i_self.setValue("");
		i_self.getTrigger("clear").hide();

		delete o_extraParams[i_self.getParamName()];

		if (i_store.isTreeStore) {
			var i_tree = i_store.ownerTree;

			var i_view = i_tree.getView();

			if (i_view.body.dom) {
				i_view.body.translate(0, 0, 0);
			}

			if (i_view.bufferedRenderer) {
				i_view.bufferedRenderer.onStoreClear();
			}


		}
		if (i_store.clearAndLoad) {
			i_store.clearAndLoad({
				callback: function() {
					if (i_self.getAllowSort()) {
						i_store.fireEvent("sort", i_store, o_sorters.getRange());
					}
				}
			});
		}
		else {
			i_store.load({
				callback: function() {
					if (i_self.getAllowSort()) {
						i_store.fireEvent("sort", i_store, o_sorters.getRange());
					}
				}
			});
		}

		i_self.fireEvent("clear", i_self);
	},

	onSearchClick: function() {

		var i_self = this;
		var i_grid = i_self.getGrid() || i_self.up("gridpanel");
		var i_store = i_self.getStore();

		if (i_grid) {

			var i_gridStore = i_grid.getStore();

			if (i_gridStore.getId() != i_store.getId()) {

				i_store = i_grid.getStore();
				i_self.setStore(i_store);
			}
		}

		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();
		var o_sorters = i_store.getSorters();
		var value = i_self.getValue();

		var s_param = i_self.getParamName();

		if (value.length > 0) {
			o_extraParams[s_param] = value;
			i_self.getTrigger("clear").show();
		}
		else {
			delete o_extraParams[s_param];
			i_self.getTrigger("clear").hide();
		}

		if (i_store.isTreeStore) {
			var i_tree = i_store.ownerTree;

			var i_view = i_tree.getView();

			if (i_view.body.dom) {
				i_view.body.translate(0, 0, 0);
			}

			if (i_view.bufferedRenderer) {
				i_view.bufferedRenderer.onStoreClear();
			}
		}

		if (i_store.clearAndLoad) {
			i_store.clearAndLoad({
				callback: function() {
					if (i_self.getAllowSort()) {
						i_store.fireEvent("sort", i_store, o_sorters.getRange());
					}
				}
			});
		}
		else {
			i_store.load({
				callback: function() {
					if (i_self.getAllowSort()) {
						i_store.fireEvent("sort", i_store, o_sorters.getRange());
					}
				}
			});
		}

		i_self.fireEvent("search", i_self);
	},

	getWhere: function() {
		return "";
	}
});
/**
 * @class Ext.ux.ToolbarDroppable
 * @extends Object
 * Plugin which allows items to be dropped onto a toolbar and be turned into new Toolbar items.
 * To use the plugin, you just need to provide a createItem implementation that takes the drop
 * data as an argument and returns an object that can be placed onto the toolbar. Example:
 * <pre>
 * Ext.create('Ext.ux.ToolbarDroppable', {
 *   createItem: function(data) {
 *     return Ext.create('Ext.Button', {text: data.text});
 *   }
 * });
 * </pre>
 * The afterLayout function can also be overridden, and is called after a new item has been
 * created and inserted into the Toolbar. Use this for any logic that needs to be run after
 * the item has been created.
 */
 Ext.define('Ext.ux.ToolbarDroppable', {
    extend: 'Object',

    alias: "plugin.toolbardroppable",

    /**
     * @constructor
     */
    constructor: function(config) {
      Ext.apply(this, config);
    },

    /**
     * Initializes the plugin and saves a reference to the toolbar
     * @param {Ext.toolbar.Toolbar} toolbar The toolbar instance
     */
    init: function(toolbar) {
      /**
       * @property toolbar
       * @type Ext.toolbar.Toolbar
       * The toolbar instance that this plugin is tied to
       */
      this.toolbar = toolbar;

      this.toolbar.on({
          scope : this,
          render: this.createDropTarget
      });
    },

    /**
     * Creates a drop target on the toolbar
     */
    createDropTarget: function() {
        /**
         * @property dropTarget
         * @type Ext.dd.DropTarget
         * The drop target attached to the toolbar instance
         */
        this.dropTarget = Ext.create('Ext.dd.DropTarget', this.toolbar.getEl(), {
            notifyOver: Ext.Function.bind(this.notifyOver, this),
            notifyDrop: Ext.Function.bind(this.notifyDrop, this)
        });
        this.toolbar.dd = this;
    },

    /**
     * Adds the given DD Group to the drop target
     * @param {String} ddGroup The DD Group
     */
    addDDGroup: function(ddGroup) {
        this.dropTarget.addToGroup(ddGroup);
    },

    /**
     * Calculates the location on the toolbar to create the new sorter button based on the XY of the
     * drag event
     * @param {Ext.EventObject} e The event object
     * @return {Number} The index at which to insert the new button
     */
    calculateEntryIndex: function(e) {
        var entryIndex = 0,
            toolbar    = this.toolbar,
            items      = toolbar.items.items,
            count      = items.length,
            xTotal     = toolbar.getEl().getXY()[0],
            xHover     = e.getXY()[0] - xTotal;

        for (var index = 0; index < count; index++) {
            var item     = items[index],
                width    = item.getEl().getWidth(),
                midpoint = xTotal + width / 2;

            xTotal += width;

            if (xHover < midpoint) {
                entryIndex = index;

                break;
            } else {
                entryIndex = index + 1;
            }
        }

        return entryIndex;
    },

    /**
     * Returns true if the drop is allowed on the drop target. This function can be overridden
     * and defaults to simply return true
     * @param {Object} data Arbitrary data from the drag source
     * @return {Boolean} True if the drop is allowed
     */
    canDrop: function(data) {
        return true;
    },

    /**
     * Custom notifyOver method which will be used in the plugin's internal DropTarget
     * @return {String} The CSS class to add
     */
    notifyOver: function(dragSource, event, data) {
        return this.canDrop.apply(this, arguments) ? this.dropTarget.dropAllowed : this.dropTarget.dropNotAllowed;
    },

    /**
     * Called when the drop has been made. Creates the new toolbar item, places it at the correct location
     * and calls the afterLayout callback.
     */
    notifyDrop: function(dragSource, event, data) {
        var canAdd = this.canDrop(dragSource, event, data);
        if (canAdd) {
           this.createItem(data);
        }

        return canAdd;
    },

    /**
     * Creates the new toolbar item based on drop data. This method must be implemented by the plugin instance
     * @param {Object} data Arbitrary data from the drop
     * @return {Mixed} An item that can be added to a toolbar
     */
    createItem: function(data) {
        //<debug>
        Ext.Error.raise("The createItem method must be implemented in the ToolbarDroppable plugin");
        //</debug>
    },

    /**
     * Called after a new button has been created and added to the toolbar. Add any required cleanup logic here
     */
    afterLayout: Ext.emptyFn
});
Ext.define("Portfolio.entity.util.DropZone", {

	extend: "Ext.container.Container",

	xtype: "portfolio-entity-dropzone",

	alias: [
		"widget.portfolio.entity.dropzone"
	],

	layout: "fit",

	config: {
		form: null,
		entity: {},
		overZone: false,
		dragging: 0,
		zone: null,
		zones: [],
		wrapperComponent: null
	},

	dropFn: Ext.emptyFn,

	style: {
		"position": "absolute",
		"padding": "5px",
		"top": "0px",
		"left": "0px",
		"right": "0px",
		"bottom": "0px",
		"font-size": "5px",
		"pointer-events": "none"
	},

	listeners: {
		afterrender: {
			fn: function() {
				var i_self = this;
				i_self.setDragging(0);

				var i_dropzone = i_self.getZone();
				var i_container = i_self.getWrapperComponent();

				i_self.mon(Ext.getBody(), "dragenter", function(i_event) {
					var n_dragging = i_self.getDragging();
					if (n_dragging === 0) {
						var i_el = i_dropzone.getEl();
						if (i_el.dom) {
							i_el.setStyle("display", "inline");
							i_el.setStyle("z-index", "1");
						}

						if (i_container) {

							var o_size = i_container.getSize();

							i_self.setSize(o_size.width, o_size.height);
							i_dropzone.setSize(o_size.width, o_size.height);
							o_size = i_self.getSize();
							i_el.setSize(o_size);
						}
					}

					n_dragging++;
					i_self.setDragging(n_dragging);
				});

				i_self.mon(Ext.getBody(), "dragleave", function(i_event) {

					var n_dragging = i_self.getDragging();
					n_dragging--;

					var i_el = i_dropzone.getEl();
					if (i_el.dom && n_dragging === 0) {
						i_el.setStyle("display", "none");
						i_el.setStyle("z-index", "0");
					}

					i_self.setDragging(n_dragging);
				});
			}
		},
		dragenter: {
			element: "el",
			fn: function (i_event) {

				var i_self = this.component;

				var n_dragging = i_self.getDragging();
				n_dragging++;
				i_self.setDragging(n_dragging);
			}
		},
		dragleave: {
			element: "el",
			fn: function (i_event) {

				var i_self = this.component;

				var n_dragging = i_self.getDragging();
				n_dragging--;
				i_self.setDragging(n_dragging);
			}
		},
		drop: {
			fn: function(i_container, a_result, o_config) {

				var i_self = this;
				var i_dropzone = i_self.getZone();
				i_self.setDragging(0);
				var i_el = i_dropzone.getEl();
				if (i_el.dom) {
					i_el.setStyle("display", "none");
					i_el.setStyle("z-index", "0");
				}

				var s_value = "";
				var a_join = [];

				var a_return = [];

				Ext.Array.each(a_result, function(o_value) {

					var s_path = o_value.FILPATH || o_value.PATH;
					var s_name = o_value.FILNAME || o_value.NAME;

					a_join.push(s_path);
					a_join.push(s_name);

					s_value = ip2.cleanPath(a_join.join("/"));
					a_return.push(s_value);
				});

				var f_callback = o_config.fn || i_self.dropFn || Ext.emptyFn;

				f_callback(a_return);
			}
		}
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		var a_zones = i_self.getZones();

		i_self.add(i_self.createPortlet(a_zones));

		return i_self;
	},

	createPortlet: function(a_entires) {

		var i_self = this;

		var i_portlet = Ext.widget("container", {
			border: 0,
			layout: {
				type: "vbox",
				padding: 0,
				align: "stretch"

			},
			style: {
				"background-color": a_entires.length ? "white" : "transparent",
				"position": "absolute",
				"padding": "5px",
				"top": "0px",
				"left": "0px",
				"right": "0px",
				"bottom": "0px",
				"font-size": "5px",
				"display": "none",
				"opacity": "0.9"
			},
			items: i_self.createColumns(a_entires)
		});

		i_self.setZone(i_portlet);

		return i_portlet;
	},

	createColumns: function(a_entires) {

		var i_self = this;

		var a_columns = [];

		a_entires = Ext.Array.filter(a_entires, function(o_value) {
			return o_value.path;
		});

		var n_count = a_entires.length;

		if (n_count % 2 === 0) {
			n_count = Math.ceil(n_count / 6);
		}
		else {
			n_count = Math.ceil(n_count / 5);
		}

		var a_items = [];

		Ext.Array.each(a_entires, function(o_config) {

			var i_result = i_self.createPortletItem(o_config);
			if (i_result) {
				a_items.push(i_result);
			}
		});

		if (a_items.length > 0) {
			var i_row = Ext.widget("container", {
				flex: 1,
				border: 0,
				layout: {
					type: "hbox",
					padding: 5,
					align: "stretch"
				},
				items: a_items
			});

			a_columns.push(i_row);
		}

		return a_columns;
	},

	createPortletItem: function(o_config) {

		var i_self = this;

		var i_portletItem = Ext.widget("container", {
			border: 0,
			draggable: false,
			closable: false,
			collapsible: false,
			layout: "fit",
			flex: 1,
			items: [
				{
					xtype: "gallerydropbox",
					flex: 1,
					path: o_config.path,
					dropText: ip2.i18n(o_config.title) + "</br><small><small>" +
					ip2.i18n(
						{
							da: "Drop for at upload fil",
							en: "Drop to upload file"
						}
					) + "</small></small>",
					extensions: o_config.extensions || ["*"],
					maxItems: o_config.maxItems || 1,
					style: {
						"position": "absolute",
						"padding": "5px",
						"top": "0px",
						"left": "0px",
						"right": "0px",
						"bottom": "0px",
						"font-size": "25px"
					},
					dropConfig: o_config,
					listeners: {
						drop: {
							fn: function(i_dropbox, a_files, i_event) {

								var i_plugin = i_dropbox.getDDPlugin();

								if (i_plugin.enableDrop) {

									var s_message = ip2.i18n({
										da: "Kontrolerer filer....",
										en: "Checking files..."
									});

									i_self.setLoading(s_message, true);

									var s_uploadpath = i_dropbox.path;

									Ext.ux.file.util.Handler.checkFiles(s_uploadpath, a_files, function(o_result) {
										i_self.setLoading(false);
										var a_update = o_result.update;
										var a_create = o_result.create;
										var b_update = false;
										var b_cancel = false;
										var b_create = false;
										var a_result = [];
										if (a_update.length > 0) {
											b_update = true;
											Ext.ux.file.util.Handler.getUIConflickWindow(i_dropbox.getEl(),
												i_self,
												i_dropbox.path,
												a_update,
												function(b_cancel, a_override, a_rename) {

													b_cancel = b_cancel;

													if (!b_cancel) {
														b_cancel = (a_override.length === 0 && a_rename.length === 0);
													}

													if (b_cancel) {
														if (!b_create) {
															i_self.setLoading(false);
															i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
														}
														return;
													}
													var a_complete = a_override.concat(a_rename);

													var a_temp = [];

													Ext.Array.each(a_complete, function(o_record) {
														a_temp.push(o_record.file);
													});

													s_message = ip2.i18n({
														da: "Overskriver fil....",
														en: "Overwriting file..."
													});

													i_self.setLoading(s_message);

													if (Ext.ux.file.util.Handler.hasFileManager()) {
														Ext.ux.file.util.Handler.updateRecordsFileInfo(s_uploadpath, a_temp, function(a_records) {
															Ext.Array.each(a_records, function(i_record) {
																a_result.push(i_record.data);
															});
															if (!b_create) {
																i_self.setLoading(false);
																i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
															}
															else {
																s_message = ip2.i18n({
																	da: "Opretter filer....",
																	en: "Creating files..."
																});
																i_self.setLoading(s_message);
															}
														});
													}
													else {
														Ext.ux.file.util.Handler.uploadFiles(s_uploadpath, a_temp, false, function(a_values) {
															Ext.Array.each(a_temp, function(o_value) {
																a_result.push({
																	PATH: s_uploadpath,
																	NAME: o_value.name
																});
															});
															if (!b_create) {
																i_self.setLoading(false);
																i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
															}
															else {
																s_message = ip2.i18n({
																	da: "Opretter filer....",
																	en: "Creating files..."
																});
																i_self.setLoading(s_message);
															}
														});
													}
												},
												false
											);
										}
										if (a_create.length > 0) {
											b_create = true;
											if (!b_update) {
												i_self.setLoading(false);
												s_message = ip2.i18n({
													da: "Opretter filer....",
													en: "Creating files..."
												});
												i_self.setLoading(s_message);
											}

											if (Ext.ux.file.util.Handler.hasFileManager()) {
												Ext.ux.file.util.Handler.createRecords(s_uploadpath, a_create, false, function(a_records) {
													b_create = false;
													Ext.Array.each(a_records, function(i_record) {
														a_result.push(i_record.data);
													});
													if (!b_update) {
														i_self.setLoading(false);
														i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
													}
													if (b_cancel) {
														i_self.setLoading(false);
														i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
													}
												});
											}
											else {
												Ext.ux.file.util.Handler.uploadFiles(s_uploadpath, a_create, false, function(a_values) {
													b_create = false;
													Ext.Array.each(a_values, function(o_value) {
														a_result.push({
															PATH: s_uploadpath,
															NAME: o_value.name
														});
													});
													if (!b_update) {
														i_self.setLoading(false);
														i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
													}
													if (b_cancel) {
														i_self.setLoading(false);
														i_self.fireEvent("drop", i_self, a_result, i_dropbox.dropConfig);
													}
												});
											}
										}
									});
								}
								i_self.setDragging(0);
								var i_dropzone = i_self.getZone();
								var i_el = i_dropzone.getEl();
								if (i_el.dom) {
									i_el.setStyle("display", "none");
									i_el.setStyle("z-index", "0");
								}
							}
						},
						dragenter: {
							fn: function(i_dropbox, o_event) {

								var i_plugin = i_dropbox.getDDPlugin();
								var a_items = o_event.dataTransfer.items || o_event.dataTransfer.files;
								var s_dmd = o_config.dmdName || "";
								i_self.setOverZone(true);

								if (a_items.length > i_dropbox.maxItems) {
									i_dropbox.addCls(i_plugin.failureCls);
									i_plugin.enableDrop = false;
								}
							}
						},
						dragleave: {
							fn: function(i_dropbox, o_event) {
								var i_plugin = i_dropbox.getDDPlugin();
								i_plugin.enableDrop = true;
								i_self.setOverZone(false);
							}
						}
					}
				}
			]
		});

		return i_portletItem;
	}
});
/**
 * @class Portfolio.entity.util.Handler
 * Utility class for handling UI Configurations used by the DMD and XPD
 */

Ext.define("Portfolio.entity.util.Handler", {

	alternateClassName: [
		"Ext.ux.util.DMDUiType"
	],

	statics: {
		preprocess: function (o_config, s_context, o_rulesJs, o_rulesXpd, o_xpd, o_data) {

			var i_self = this;
			var s_type = o_config.type;

			// Do the default preprocess for all uitypes
			var f_defaultUiPreprocess = o_rulesJs.uitype.preprocess;

			if (f_defaultUiPreprocess) {
				o_config = f_defaultUiPreprocess.call(i_self, o_config);
			}

			var o_uiTypeRule = i_self.getUiTypeRule(s_type, s_context, o_rulesJs);
			var o_uiRule = i_self.getUiRule(s_type, o_rulesXpd);

			// Do the ui specific preprocess
			if (!o_uiTypeRule) {

				// No uirule found for this - throw a message about it and
				// just return o_config
				console.warn("No uirule found for: \"", s_type, "\" in uirules.jsconfig");

				return o_config;
			}

			var f_uiPreprocess = o_uiTypeRule ? o_uiTypeRule.preprocess : null;
			if (f_uiPreprocess) {
				o_config = f_uiPreprocess.call(i_self, o_config, o_uiRule);
			}

			// Do the property specific preprocesses
			Ext.Object.each(o_config, function (s_key, value) {

				if (value !== undefined) {
					var f_defaultPropertyPreprocess = o_rulesJs.property.preprocess;
					var o_uiPropertyTypeRule = i_self.getUiPropertyTypeRule(s_key, s_context, o_rulesJs);

					// Do the default preprocess for all properties
					if (f_defaultPropertyPreprocess) {
						f_defaultPropertyPreprocess.call(i_self, o_config, s_key, value, o_xpd, o_data);

						// read value again:
						value = o_config[s_key];
					}

					// Do the property specific preprocesses
					if (o_uiPropertyTypeRule) {

						var f_uiPropertyPreprocess = o_uiPropertyTypeRule.preprocess;
						if (f_uiPropertyPreprocess) {
							f_uiPropertyPreprocess.call(i_self, o_config, s_key, value, o_xpd, o_data);
						}
					}
				}
			});

			return o_config;
		},
		postprocess: function (o_config, s_context, o_rulesJs, o_rulesXpd, o_xpd) {

			var i_self = this;
			var s_type = o_config.type;
			var a_postprocess = [];

			// Find and add common postprocess for all uitypes
			var f_defaultUiTypePostprocess = o_rulesJs.uitype.postprocess;
			if (f_defaultUiTypePostprocess) {
				a_postprocess.push(function (o_fields) {
					var i_self = this;
					f_defaultUiTypePostprocess.call(i_self, i_self, o_fields);
				});
			}

			var o_uiTypeRule = i_self.getUiTypeRule(s_type, s_context, o_rulesJs);
			var o_uiRule = i_self.getUiRule(s_type, o_rulesXpd);

			// Do the ui specific preprocess
			var f_uiPostprocess = o_uiTypeRule ? o_uiTypeRule.postprocess : null;
			if (f_uiPostprocess) {
				a_postprocess.push(function (o_fields) {
					var i_self = this;
					var a_arguments = Array.prototype.slice.call(arguments);
					a_arguments.unshift(i_self);
					f_uiPostprocess.apply(i_self, a_arguments);
				});
			}

			// Do the property specific preprocesses
			Ext.Object.each(o_config, function (s_key, value) {
				if (value !== undefined) {
					var o_rule = o_uiRule.properties[s_key];

					// Do the default preprocess for all properties
					var f_defaultPropertyPostprocess = o_rulesJs.property.postprocess;
					if (f_defaultPropertyPostprocess) {
						a_postprocess.push(function (o_fields) {
							var i_self = this;
							f_defaultPropertyPostprocess.call(i_self, i_self, i_self[s_key], o_fields, o_rule, o_xpd);
						});
					}

					var o_uiPropertyTypeRule = i_self.getUiPropertyTypeRule(s_key, s_context, o_rulesJs);

					if (o_uiPropertyTypeRule) {

						// Do the property specific preprocesses
						var f_uiPropertyPostprocess = o_uiPropertyTypeRule.postprocess;
						if (f_uiPropertyPostprocess) {
							a_postprocess.push(function (o_fields) {
								var i_self = this;
								f_uiPropertyPostprocess.call(i_self, i_self, i_self[s_key], o_fields, o_rule, o_xpd);
							});
						}
					}
				}
			});

			o_config.postprocess = a_postprocess;

			return o_config;
		},
		getPropertyConfig: function(name, o_xpdCfg, o_component, o_collection) {

			/*
			xpd_cfg = {
				type: "display",
				qwerty: 1,
				name: "John"
			}
			coll = {
				// recursive
				"apply": { "type": "varchar", "readonly": true }
			}
			property = {
				"alias": ["<% !readonly %>", "disallowcreate", "disallowCreate"],
				"apply": { "type": "varchar", "readonly": true }
			}
			*/

			if (!o_collection) {
				console.warn("no property config found for the property: \"", name, "\"", "in the /portfolio/app/ux/UIRules.js file");
				return false;
			}

			var o_property = o_collection.properties[name];

			var o_apply = o_property.apply;

			if (o_apply) {
				ip2.extend(o_component, ip2.map(o_apply, function(val) {
					if (ip2.isEvalTpl(val)) {
						return ip2.evalTpl(val, o_xpdCfg);
					}
					else {
						return val;
					}
				}));
			}

			if (!o_component.hasOwnProperty(name)) {

				o_component[name] = o_xpdCfg[name];

				var a_alias = o_property.alias;

				if (a_alias && Ext.isEmpty(o_component[name])) {

					o_component[name] = ip2.first(a_alias, function(val) {

						if (ip2.isEvalTpl(val)) {
							return ip2.evalTpl(val, o_xpdCfg);
						}
						else {
							return o_xpdCfg[val];
						}
					});
				}

				var s_dftValue = o_property.value;

				if (Ext.isEmpty(o_component[name])) {
					o_component[name] = ip2.isEvalTpl(s_dftValue) ? ip2.evalTpl(s_dftValue) : s_dftValue;
				}
			}

			o_apply = o_collection.apply;

			if (o_apply) {
				ip2.extend(o_component, ip2.map(o_apply, function(val) {
					if (ip2.isEvalTpl(val)) {
						return ip2.evalTpl(val, o_xpdCfg);
					}
					else {
						return val;
					}
				}));
			}

			if (Ext.isEmpty(o_component[name])) {
				delete o_component[name];
			}

			return true;
		},
		getUiRule: function (s_type, o_rulesXpd) {

			var o_found = null;

			var o_collections = o_rulesXpd.collections;

			var a_values = Ext.Object.getValues(o_collections);

			o_found = Ext.Array.findBy(a_values, function(o_value) {
				return o_value.name == s_type;
			});

			if (!o_found) {

				o_found = Ext.Array.findBy(a_values, function (o_value) {
					return o_value.name == "varchar";
				});
			}

			return o_found;
		},
		getUiTypeRule: function (s_type, s_context, o_rulesJs) {

			var o_found = o_rulesJs.uitype.collections[s_type];

			return o_found ? o_found[s_context] : null;
		},
		getUiPropertyTypeRule: function (s_type, s_context, o_rulesJs) {

			var o_found = o_rulesJs.property.collections[s_type];

			return o_found ? o_found[s_context] : null;
		}
	},

	createUiComponent: function (o_settings) {

		var i_cmp = this;

		var o_rulesXpd = o_settings.rulesXpd;
		var o_rulesJs = o_settings.rulesJs;
		var s_context = o_settings.context;
		var o_config = o_settings.config;
		var initialValue = o_settings.initialValue;
		var o_data = o_settings.data || {};

		var o_defaults = o_settings.defaults;
		var o_components = {};
		var o_added = [];

		if (o_config["private"]) {
			return;
		}

		// Create component config against uirules
		var o_component = i_cmp.createUiConfig(o_config, o_rulesXpd, initialValue, o_defaults);

		Ext.Object.each(o_component, function(s_key, value) {

			if (Ext.isEmpty(value)) {
				delete o_component[s_key];
			}
		});

		// maybe our name has changed?
		var s_name = o_component.name;

		var o_cmpRules = i_cmp.getUiRule(o_component.type, o_rulesXpd);

		if (o_cmpRules.addFields) {
			ip2.each(o_cmpRules.addFields, function(o_field) {

				var o_fieldConfig = ip2.map(o_field, function(value, key) {

					return ip2.isEvalTpl(value) ? ip2.evalTpl(value, o_config) : value;
				});

				var o_value = i_cmp.createUiComponent({
					config: o_fieldConfig,
					rulesXpd: o_rulesXpd,
					context: s_context,
					rulesJs: o_rulesJs
				});
				Ext.Object.each(o_value, function(s_key, o_field) {
					o_added[s_key] = o_field;
				});
			});
		}

		o_component._xpdConfig = o_config;

		// Process pre processes for component and properties
		o_component = Portfolio.entity.util.Handler.preprocess(o_component, "form", o_rulesJs, o_rulesXpd, null, o_data);

		// Add post processes for component and properties
		o_component = Portfolio.entity.util.Handler.postprocess(o_component, "form", o_rulesJs, o_rulesXpd);

		o_components[s_name] = o_component;

		Ext.Object.each(o_added, function(s_value) {
			o_components[s_value] = o_added[s_value];
		});

		return o_components;
	},

	createUiCollection: function(o_settings) {

		var i_cmp = this;
		var o_uiCollection = o_settings.collection;

		// TODO: This is only here to the preprocesser can do some language translation!!
		var o_xpd = o_settings.xpd;
		var o_rulesXpd = o_settings.rulesXpd;
		var o_rulesJs = o_settings.rulesJs;
		var s_context = o_settings.context;
		var o_value = o_settings.values || {};
		var o_defaults = o_settings.defaults;
		var s_environment = o_settings.environment;

		var o_uiComponentConfig = {};
		var o_uiComponents = {};

		if (!o_uiCollection) {

			var s_message = ip2.i18n({
				da: "Ingen \"collection\" ID",
				en: "No \"collection\" ID"
			});

			Ext.Logger.info(s_message);

			return false;
		}

		Ext.Object.each(o_uiCollection.properties, function itProps(s_name, o_uiConfig) {

			if (o_uiConfig["private"]) {
				return;
			}

			// Place name property if not present
			o_uiConfig.name = o_uiConfig.name || s_name;

			var initialValue = o_value[o_uiConfig.name];

			if (Ext.isEmpty(initialValue) && !Ext.isEmpty(o_uiConfig.value)) {
				initialValue = o_uiConfig.value;
			}

			// Find a possible environment layout object and apply as defaults only
			if (o_uiConfig.layout && o_uiConfig.layout[s_environment]) {
				ip2.defaults(o_uiConfig, o_uiConfig.layout[s_environment] || {});
			}

			// Create component config against uirules
			var o_component = i_cmp.createUiConfig(o_uiConfig, o_rulesXpd, initialValue, o_defaults);

			// maybe our name has changed?
			s_name = o_component.name;

			// and we need to look for an initial value again because maybe name has changed

			if (!o_uiConfig.extended) {
				if (o_value[s_name]) {
					o_component.value = o_value[s_name];
				}
			}
			else {
				var a_split = s_name.split("-");
				if (a_split.length > 0) {
					var value = o_value;
					Ext.Array.each(a_split, function(s_key) {
						if (Ext.isObject(value)) {
							value = value[s_key];
							if (ip2.isStringedObject(value)) {
								value = JSON.parse(value);
							}
						}
					});
					o_component.value = value;
				}
				else {
					o_component.value = o_value[s_name];
				}
			}

			var o_cmpRules = i_cmp.getUiRule(o_component.type, o_rulesXpd);

			if (o_cmpRules.addFields) {
				ip2.each(o_cmpRules.addFields, function(o_field) {
					if (o_component.i18n !== undefined) {
						o_field.i18n = o_component.i18n;
					}
					itProps(null, ip2.map(o_field, function(value, key) {

						return ip2.isEvalTpl(value) ? ip2.evalTpl(value, o_uiConfig) : value;
					}));
				});
			}

			o_component._xpdConfig = o_uiConfig;

			// Process pre processes for component and properties
			o_component = Portfolio.entity.util.Handler.preprocess(o_component, "form", o_rulesJs, o_rulesXpd, o_xpd, o_value);

			// Add post processes for component and properties
			o_component = Portfolio.entity.util.Handler.postprocess(o_component, "form", o_rulesJs, o_rulesXpd, o_xpd);

			// Add isFormField if we have it in the config,
			if (o_uiConfig.hasOwnProperty("isFormField")) {
				o_component.isFormField = o_uiConfig.isFormField;
			}

			// Add this config to the preparation object
			o_uiComponentConfig[s_name] = o_component;
		});

		// Run through the compiled o_uiComponentConfig object and instanciate the components
		Ext.Object.each(o_uiComponentConfig, function (s_name, o_config) {
			o_uiComponents[s_name] = Ext.create(o_config.uiclass, o_config);
		});

		// Now run post gathered post processes
		Ext.Object.each(o_uiComponents, function (s_key, i_component) {

			var a_postprocess = i_component.postprocess;

			Ext.Array.each(a_postprocess, function (f_process) {
				f_process.call(i_component, o_uiComponents);
			});
		});

		return o_uiComponents;
	},

	createUiConfig: function (o_xpdConfig, o_rulesXpd, initialValue, o_defaults) {

		o_defaults = o_defaults || {};

		var i_cmp = this;
		var o_component = ip2.extend({}, o_defaults);

		var s_oldType = null;
		var s_newType = o_xpdConfig.type;
		var o_rules = null;

		// Hardcode the value on the component
		if (!Ext.isEmpty(initialValue)) {
			o_component.value = initialValue;
		}

		while (s_oldType != s_newType) {

			o_rules = this.getUiRule(s_newType, o_rulesXpd);

			Portfolio.entity.util.Handler.getPropertyConfig(
				"type",
				o_xpdConfig,
				o_component,
				o_rules
			);

			s_oldType = s_newType;
			s_newType = o_component.type;
		}

		if (!o_rules) {
			Ext.Error.raise({
				description: "Type not found",
				message: {
					message: "The type \"" + o_xpdConfig.type + "\" does not exist in  /portfolio/app/ux/UIRules.js",
					src: JSON.stringify(o_xpdConfig, null, "\t")
				},
				debug: "js",
				ignore: true
			});
		}

		Ext.Object.each(o_rules.properties, function(key, value) {

			if (key == "type") {
				return;
			}

			Portfolio.entity.util.Handler.getPropertyConfig(
				key,
				o_xpdConfig,
				o_component,
				o_rules
			);
		});

		return o_component;
	},

	getUiRule: function(type, o_rulesXpd) {

		return Portfolio.entity.util.Handler.getUiRule(type, o_rulesXpd);
	},

	getFormFields: function(o_config) {

		var i_self = this;
		var a_fields = [];
		var a_xpdFields = [];
		var a_output = [];
		var a_items = [];

		var o_data = o_config.data || {};

		var s_dmd = o_config.dmd;
		var s_entity = o_config.entity;
		var s_view = o_config.view;

		var o_dmd = ip2.resource.get(s_dmd);

		var o_uirules = ip2.uirules;
		var o_uiTypeRules = ip2.loadUiTypeRules();
		var o_uiTypes = ip2.getUiTypes();

		var o_model = o_dmd.model;

		var a_entities = o_model.entities;

		var o_entity = Ext.Array.findBy(a_entities, function(o_entity) {
			return o_entity.name == s_entity;
		});

		if (o_entity) {

			var o_ui = o_entity.ui;
			var o_view = o_ui.forms[s_view] || o_ui.forms.portfolio;

			var a_columns = o_entity.columns || [];

			if (o_view.items) {
				a_items = Ext.Array.slice(o_view.items);
			}

			var a_components = [];

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

				var o_column = Ext.Array.findBy(a_columns, function(o_config) {
					return o_config.name == o_field.name;
				});

				var o_fieldClone = Ext.clone(o_field);
				var o_columnClone = o_column ? Ext.clone(o_column) : {};

				var o_result = Ext.apply(o_columnClone, o_fieldClone);

				if (o_result.uiType) {
					o_result.uitype = o_result.uiType;
					delete o_result.uiType;
				}
				if (o_result.uitype) {
					var o_uiType = o_uiTypes[o_result.uitype];
					if (o_uiType.form && o_uiType.form.type) {
						var o_type = o_uiTypes[o_result.type];
						if (o_type) {
							o_result.type = o_uiType.form.type;
						}
					}
					delete o_result.uitype;
				}

				if (!o_result.type) {
					o_result.type = "varchar";
				}

				if (o_result.hasOwnProperty("title")) {
					if (!o_result.hasOwnProperty("fieldLabel")) {
						o_result.fieldLabel = o_result.title;
					}
					else {
						o_result.title = o_result.fieldLabel;
					}
				}

				var o_collection;
				var b_found = false;
				var s_type = o_result.type;

				while (!b_found) {

					var o_current = o_uirules.collections[s_type] || {
						apply: {
							type: "varchar"
						}
					};

					if (o_current.apply && o_current.apply.type) {
						s_type = o_current.apply.type;
					}
					else if (o_current.apply && !o_current.apply.type) {
						b_found = true;
					}
					else {
						b_found = true;
					}
					if (b_found) {
						o_collection = o_current;
					}
				}

				o_result.type = s_type;

				var a_type = ip2.getFieldTypeDefinition(o_result.type);

				if (a_type.length > 0) {
					Ext.apply(o_result, {
						type: a_type[0]
					});
				}

				if (o_result.uiType) {
					delete o_result.uiType;
				}
				if (o_result.uitype) {
					delete o_result.uitype;
				}

				var o_components = i_self.createUiComponent({
					rulesXpd: o_uirules.flatten,
					rulesJs: o_uiTypeRules,
					context: "form",
					config: o_result
				});

				a_components.push(o_components);
			});

			Ext.Array.each(a_components, function(o_components) {

				Ext.Object.each(o_components, function(s_key) {

					var o_component = o_components[s_key];

					var o_xpdConfig = o_component._xpdConfig;

					if (o_component.hasOwnProperty("dmd")) {
						if (!o_component.dmd) {
							o_component = Ext.apply(Ext.clone(o_component), {
								dmd: s_dmd
							});
						}
					}

					Ext.Object.each(o_component, function(s_key, value) {

						if (Ext.isEmpty(value)) {
							delete o_component[s_key];
						}
					});

					if (o_component.hasOwnProperty("entity")) {
						if (!o_component.entity) {
							o_component = Ext.apply(Ext.clone(o_component), {
								entity: o_entity.name
							});
						}
					}

					if (o_xpdConfig.xpd) {

						var a_split = o_xpdConfig.xpd.split("/");

						var s_xpd = "";

						if (a_split.length == 1) {
							s_xpd = "xpd/" + a_split.join("") + s_xpd;
						}

						if (s_xpd.indexOf(".") < 0) {
							s_xpd = s_xpd + ".xpd";
						}

						var o_xpd = ip2.resource.get(s_xpd, true);

						var o_temp = {
							xpd: o_xpd,
							data: o_data
						};

						var a_result = i_self.getXpdDefinitions(o_temp);

						a_xpdFields = a_xpdFields.concat(a_result);

						o_component.value = Ext.encode({});

						Ext.apply(o_component, {
							type: "varchar",
							uiclass: "Ext.form.field.Text",
							xtype: "textfield",
							hidden: true,
							isDirty: function() {

								var i_field = this;

								var b_dirty = false;
								var s_value = i_field.getValue() || "{}";
								var s_originalValue = i_field.originalValue || "{}";
								var o_value = Ext.decode(s_value, true) || {};
								var o_original = Ext.decode(s_originalValue, true) || {};

								var n_value = Ext.Object.getKeys(o_value).length;
								var n_original = Ext.Object.getKeys(o_original).length;

								var b_sameCount = n_value == n_original;

								if (b_sameCount) {

									Ext.Object.each(o_value, function(s_key, value) {

										if (!o_original.hasOwnProperty(s_key)) {
											b_dirty = true;
											return false;
										}

										var originalvalue = o_original[s_key];

										var s_value = Ext.encode(value);
										var s_originalValue = Ext.encode(originalvalue);

										b_dirty = s_value !== s_originalValue;

										if (b_dirty) {
											return false;
										}
									});
								}

								return b_dirty;
							}
						});
					}

					try {
						var i_field = Ext.create(o_component.uiclass, o_component);
						a_fields.push(i_field);
					}
					catch (o_err) {
					}
				});
			});

			Ext.Array.each(a_xpdFields, function(i_field) {

				if (i_field.from) {

					var i_found = Ext.Array.findBy(a_fields, function(i_dmdField) {
						return i_dmdField.name == i_field.from.field;
					});

					if (i_found) {
						if (i_found._xpdConfig.groups) {
							i_field._xpdConfig.groups = i_field._xpdConfig.groups || [];
							i_found._xpdConfig.groups = i_found._xpdConfig.groups || [];
							i_field._xpdConfig.groups = i_field._xpdConfig.groups.concat(i_found.groups);
						}
					}
				}
			});

			var a_filtered = Ext.Array.filter(a_fields, function(i_field) {

				var i_found = Ext.Array.findBy(a_xpdFields, function(i_xpdfield) {
					return i_xpdfield.name == i_field.name;
				});

				return !i_found;
			});

			a_output = a_output.concat(a_xpdFields).concat(a_filtered);

			return a_output;
		}
	},

	getXpdDefinitions: function(o_field) {

		var i_self = this;
		var o_xpd = o_field.xpd;

		var o_data = o_field.data || {};
		var o_collection;
		var a_fields = [];
		if (o_data) {

			if (!o_data.hasOwnProperty(o_xpd.idProperty)) {

				var n_count = Ext.Object.getKeys(o_xpd.collections).length;

				if (n_count === 1) {
					o_data[o_xpd.idProperty] = o_xpd.collections[Ext.Object.getKeys(o_xpd.collections)[0]].id;
				}
			}

			o_data = Ext.ux.xpd.Handler.convertData(o_xpd, o_data);

			if (o_xpd.hasOwnProperty("cidMap")) {
				var o_cidMap = o_xpd.cidMap;

				Ext.Object.each(o_cidMap, function(s_collection, o_map) {
					Ext.Object.each(o_map, function(s_cid, n_id) {
						if (s_cid == o_data[o_xpd.idProperty]) {
							o_data[o_xpd.idProperty] = n_id;
						}
					});
				});
			}

			o_collection = o_xpd.collections[o_data[o_xpd.idProperty]];

			if (o_collection) {

				a_fields = Ext.ux.xpd.Handler.getFieldsWithValues(o_xpd, o_collection.id, o_data);
			}
		}

		return a_fields;
	}
});
Ext.define("Portfolio.pd.util.Handler", {

	singleton: true,

	mixins: [
		"Ext.mixin.Mashup"
	],

	requiredScripts: [
        "/portfolio/app/pd/css/styles.css"
	],

	constructor: function (o_config) {

		var i_self = this;

		i_self.initConfig(o_config);

		return i_self;
	},

	processData: function(o_data, a_definition) {

		var i_self = this;

		var o_return = {};

		Ext.Object.each(o_data, function(s_key, value) {

			var o_result = {};

			var o_property = Ext.Array.findBy(a_definition, function (o_definition) {
				return o_definition.name == s_key && (o_definition.type == "collection" || o_definition.type == "group");
			});

			if (!o_property) {

				o_property = Ext.Array.findBy(a_definition, function (o_definition) {
					return o_definition.name == s_key;
				});
			}

			if (o_property) {

				if (o_property.type == "collection" || o_property.type == "group") {
					o_result = i_self.createCollection(o_property, a_definition,  value);
				}
				else {
					o_result = i_self.createProperty(o_property, a_definition, value);
				}

				o_return[s_key] = o_result;
			}
		});

		return o_return;

	},

	createCollection: function (o_collection, a_definition, o_data) {

		var i_self = this;

		var o_clone = Ext.clone(o_collection);

		var a_extend = Ext.Array.from(o_collection.extend);

		if (a_extend.length > 0) {

			var a_recursion = i_self.getExtendedCollection(a_extend, a_definition);

			a_recursion.reverse();

			var o_merged = {};

			Ext.Array.each(a_recursion, function(o_extended){

				Ext.Object.each(o_extended, function(s_key, value) {

					if (Ext.isPrimitive(value)) {
						o_merged[s_key] = value;
					}
					else {
						if (Ext.isArray(value)) {

							var a_temp = Ext.Array.from(o_merged[s_key]) || [];
							var a_value = Ext.Array.from(value);

							a_temp = Ext.Array.merge(a_temp, a_value);

							o_merged[s_key] = a_temp;
						}
						else{
							if (Ext.isObject(value)) {
								o_merged[s_key] = Ext.apply(o_merged[s_key] || {}, value);
							}
						}
					}

				});
			});

			Ext.Object.each(o_clone, function (s_key, value) {

				if (Ext.isPrimitive(value)) {
					o_merged[s_key] = value;
				}
				else {
					if (Ext.isArray(value)) {

						var a_temp = Ext.Array.from(value) || [];
						var a_value = Ext.Array.from(o_merged[s_key]);

						a_temp = Ext.Array.merge(a_temp, a_value);

						o_merged[s_key] = a_temp;
					}
					else {
						if (Ext.isObject(value)) {
							o_merged[s_key] = Ext.apply(o_merged[s_key] || {}, value);
						}
					}
				}

			});

			o_clone = o_merged;

			delete o_clone.extend;

		}

		var a_items = Ext.Array.from(o_clone.items);

		var a_return = [];

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

			var o_property = item;

			if (Ext.isString(item)) {

				o_property = Ext.Array.findBy(a_definition, function (o_definition) {
					return o_definition.name == item && (o_definition.type == "collection" || o_definition.type == "group");
				});

				if (!o_property) {

					o_property = Ext.Array.findBy(a_definition, function (o_definition) {
						return o_definition.name == item;
					});
				}
			}

			if (o_property) {

				var value = o_data[o_property.name] || "";

				var o_rule = o_clone.rule || {};

				if (o_rule.apperence == "field") {
					var o_propRule = o_property.rule || {};

					Ext.apply(o_propRule, {
						prioritized: null
					});

					o_property.rule = o_propRule;
				}

				var o_output = i_self.createProperty(o_property, a_definition, value);

				a_return.push(o_output);
			}

		});

		var o_return = Ext.apply(o_clone, {
			items: a_return
		});

		var o_rule = o_clone.rule || {};

		o_rule = Ext.clone(o_rule);

		Ext.apply(o_clone, o_rule);

		delete o_clone.rule;

		o_return.apperence = o_return.apperence || "field";
		o_return.prioritized = o_data.hasOwnProperty("prioritized") ? o_data.prioritized :
								o_return.hasOwnProperty("prioritized") ? o_return.prioritized : null;

		return o_return;

	},

	createProperty: function (o_config, a_definition, value) {

		var i_self = this;

		var o_result = {};

		var o_clone = Ext.clone(o_config);

		if (o_clone.type == "collection" || o_clone.type == "group") {
			o_result = i_self.createCollection(o_clone, a_definition, value);
		}
		else {

			if (o_clone.extend) {

				var a_extended = i_self.getExtended(Ext.Array.from(o_clone.extend), a_definition);

				a_extended.reverse();

				var o_merged = {};

				Ext.Array.each(a_extended, function (o_extended) {

					Ext.Object.each(o_extended, function (s_key, value) {

						if (Ext.isPrimitive(value)) {
							o_merged[s_key] = value;
						}
						else {
							if (Ext.isArray(value)) {

								var a_temp = Ext.Array.from(o_merged[s_key]) || [];
								var a_value = Ext.Array.from(value);

								a_temp = Ext.Array.merge(a_temp, a_value);

								o_merged[s_key] = a_temp;
							}
							else {
								if (Ext.isObject(value)) {
									o_merged[s_key] = Ext.apply(o_merged[s_key] || {}, value);
								}
							}
						}

					});
				});

				Ext.Object.each(o_clone, function (s_key, value) {

					if (Ext.isPrimitive(value)) {
						o_merged[s_key] = value;
					}
					else {
						if (Ext.isArray(value)) {

							var a_temp = Ext.Array.from(o_merged[s_key]) || [];
							var a_value = Ext.Array.from(value);

							a_temp = Ext.Array.merge(a_temp, a_value);

							o_merged[s_key] = a_temp;
						}
						else {
							if (Ext.isObject(value)) {
								o_merged[s_key] = Ext.apply(o_merged[s_key] || {}, value);
							}
						}
					}

				});

				o_clone = o_merged;
				delete o_clone.extend;
			}

			var o_rule = o_clone.rule || {};

			o_rule = Ext.clone(o_rule);

			delete o_clone.rule;

			Ext.apply(o_clone, o_rule);

			Ext.apply(o_result, o_clone);

			i_self.processProperties(o_result);

			o_result.value = value;
			o_result.originalValue = value;
		}

		return o_result;
	},

	getExtended: function (a_values, a_definition) {

		var i_self = this;

		var a_return = [];

		Ext.Array.each(a_values, function(s_extend) {

			var o_property = Ext.Array.findBy(a_definition, function (o_definition) {
				return o_definition.name == s_extend || o_definition.name == s_extend &&
						(o_definition.type == "property");
			});

			if (o_property) {
				if (o_property.hasOwnProperty("extend") && !Ext.isEmpty(o_property.extend)) {

					var a_extend = Ext.Array.from(o_property.extend);

					var a_result = i_self.getExtended(a_extend, a_definition);

					a_return = a_return.concat(a_result);
					a_return.push(o_property);
				}
				else {
					a_return.push(o_property);
				}
			}
		});

		return a_return;
	},

	getExtendedCollection: function (a_values, a_definition) {

		var i_self = this;

		var a_return = [];

		Ext.Array.each(a_values, function(s_extend) {

			var o_property = Ext.Array.findBy(a_definition, function (o_definition) {
				return o_definition.id == s_extend || o_definition.name == s_extend &&
						(o_definition.type == "collection" || o_definition.type == "group");
			});

			if (o_property) {

				var o_clone = Ext.clone(o_property);

				var o_rule = o_clone.rule || {};

				Ext.apply(o_clone, o_rule);

				delete o_clone.rule;

				if (o_clone.hasOwnProperty("extend") && o_clone.extend) {

					var a_extend = Ext.Array.from(o_clone.extend);

					var a_result = i_self.getExtended(a_extend, a_definition);

					a_return = a_return.concat(a_result);
					a_return.push(o_clone);
				}
				else {
					a_return.push(o_clone);
				}
			}
		});

		return a_return;
	},

	getExtendedFormCollection: function (a_values, a_definition) {

		var i_self = this;

		var a_return = [];

		Ext.Array.each(a_values, function(s_extend) {

			var o_property = Ext.Array.findBy(a_definition, function (o_definition) {
				return (o_definition.id == s_extend || o_definition.name == s_extend) && o_definition.type == "formCollection";
			});

			if (o_property) {

				var o_clone = Ext.clone(o_property);

				var o_rule = o_clone.rule || {};

				Ext.apply(o_clone, o_rule);

				delete o_clone.rule;

				if (o_clone.hasOwnProperty("extend") && !Ext.isEmpty(o_clone.extend)) {

					var a_extend = Ext.Array.from(o_clone.extend);

					var a_result = i_self.getExtendedFormCollection(a_extend, a_definition);

					a_return = a_return.concat(a_result);

					a_return.push(o_clone);
				}
				else {
					a_return.push(o_clone);
				}
			}
		});

		return a_return;
	},

	processProperties: function(o_config) {

		var o_apply = {};

		Ext.Object.each(o_config, function(s_key, value) {

			switch (s_key) {
				case "dbtype":

					var s_type = value;

					var a_type = /\(\d*|[,.]*d\)/g.exec(value);
					var a_length = /\d+/g.exec(value);

					if (a_type) {

						s_type = value.substr(0, a_type.index);
					}

					Ext.apply(o_apply, {
						datatype: s_type,
					});

					if (a_length) {

						var n_end = value.indexOf(")");
						var n_length = n_end - a_length.index;
						var s_number = value.substr(a_length.index, n_length);

						s_number = s_number.replace(",", ".");

						s_type = s_type.toLowerCase();

						switch (s_type) {
							case "char":
							case "varchar":
								Ext.apply(o_apply, {
									maxLength: Ext.Number.parseInt(s_number),
								});
								break;
							case "dec":
							case "decimal":
							case "int":
							case "integer":
							case "smallint":
							case "bigint":
							case "int":
							case "integer":

								var n_digital;
								var s_first;

								if (s_number.indexOf(".") > -1) {

									var a_split = s_number.split(".");

									var s_digital = a_split[0];
									var s_decimal = a_split[1];

									n_digital =  Ext.Number.parseFloat(s_digital);
									var n_decimal = Ext.Number.parseFloat(s_decimal) || 0;
									var n_precision = n_decimal;


									s_first = "";
									var s_last = "";

									while(n_digital) {
										s_first += "9";
										n_digital--;
									}

									while(n_decimal) {
										s_last += "9";
										n_decimal--;
									}

									var n_maxValue = Ext.Number.parseFloat([s_first, s_last].join("."));

									Ext.apply(o_apply, {
										maxValue: n_maxValue,
										decimalPrecision: n_precision
									});

								}
								else {

									n_digital = Ext.Number.parseFloat(s_number) || 0;
									s_first = "";

									while(n_digital) {
										s_first += "9";
										n_digital--;
									}

									Ext.apply(o_apply, {
										maxValue: Ext.Number.parseInt(s_first),
										decimalPrecision: 0
									});
								}
								break;
							case "timestamp":
							case "isotimestamp":
							case "date":
								Ext.apply(o_apply, {
									maxValue: Ext.Number.parseInt(s_number),
								});

								break;
							default:
								break;
						}

					}

					delete o_config[s_key];

					break;

				default:
					break;
			}
		});

		Ext.apply(o_config, o_apply);

		return o_config;
	},

	createUI: function(o_data, a_definition) {

		var i_self = this;

		var o_processed = i_self.processData(o_data, a_definition);

		var a_items = i_self.createItems(o_processed);

		return a_items;

	},

	createItems: function(o_processed) {

		var i_self = this;

		var a_items = [];

		Ext.Object.each(o_processed, function(s_key, o_property) {

			if (o_property.type == "collection" || o_property.type == "group") {
				if (o_property.apperence == "field") {
					a_items.push(i_self.createField(o_property));
				}
				else {
					a_items.push(i_self.createGroup(o_property));
				}
			}
			else if (o_property.type == "property") {
				a_items.push(i_self.createField(o_property));
			}
		});

		return a_items;
	},

	createFormCollection: function(o_data, a_definition, b_config) {

		var i_self = this;

		var o_formCollection = Ext.Array.findBy(a_definition, function (o_definition) {
			return (o_definition.id == o_data.fcid  ||
				o_definition.name == o_data.fcid) && o_definition.type == "formCollection";
		});

		var o_clone = Ext.clone(o_formCollection);

		var o_rule = o_clone.rule || {};

		Ext.apply(o_clone, o_rule);

		delete o_clone.rule;

		var a_extend = Ext.Array.from(o_clone.extend);

		if (a_extend.length > 0) {

			var a_recursion = i_self.getExtendedFormCollection(a_extend, a_definition);

			a_recursion.reverse();

			var o_merged = {};

			Ext.Array.each(a_recursion, function(o_extended){

				Ext.Object.each(o_extended, function(s_key, value) {

					if (Ext.isPrimitive(value)) {
						o_merged[s_key] = value;
					}
					else {
						if (Ext.isArray(value)) {

							var a_temp = Ext.Array.from(o_merged[s_key]) || [];
							var a_value = Ext.Array.from(value);

							a_temp = Ext.Array.merge(a_temp, a_value);

							o_merged[s_key] = a_temp;
						}
						else{
							if (Ext.isObject(value)) {
								o_merged[s_key] = Ext.apply(o_merged[s_key] || {}, value);
							}
						}
					}

				});
			});

			Ext.Object.each(o_clone, function (s_key, value) {

				if (Ext.isPrimitive(value)) {
					o_merged[s_key] = value;
				}
				else {
					if (Ext.isArray(value)) {

						var a_temp = Ext.Array.from(value) || [];
						var a_value = Ext.Array.from(o_merged[s_key]);

						a_temp = Ext.Array.merge(a_temp, a_value);

						o_merged[s_key] = a_temp;
					}
					else {
						if (Ext.isObject(value)) {
							o_merged[s_key] = Ext.apply(o_merged[s_key] || {}, value);
						}
					}
				}

			});

			o_clone = o_merged;

			delete o_clone.extend;
		}

		var a_fields = Ext.Array.from(o_clone.fields || o_clone.items);

		var o_temp = {};

		Ext.Array.each(a_fields, function(s_field) {
			o_temp[s_field] = o_data[s_field] || "";
		});

		var o_processed = i_self.processData(o_temp, a_definition);

		return b_config ? o_processed : i_self.createItems(o_processed);

	},

	createGroup: function (o_property) {

		var i_self = this;

		var a_items = [];

		Ext.Array.each(o_property.items, function(o_item) {

			var i_field = i_self.createField(o_item);

			i_field.isFormField = false;

			a_items.push(i_field);
		});

		var i_define = Ext.define(null, {

			extend: "Ext.form.FieldSet",

			mixins: {
				field: "Ext.form.field.Field"
			},

			initComponent: function () {

				var i_field = this;

				i_field.initField();

				i_field.callParent(arguments);

				var a_items = i_field.items.getRange();

				Ext.Array.each(a_items, function(i_subfield) {
					i_subfield.on({
						change: {
							fn: function(i_subfield) {
								i_field.checkChange();
							}
						}
					});
				});
			},

			getValue: function () {

				var i_field = this;

				var o_value = {};

				if (!i_field.items.getRange) {
					return i_field.mixins.field.getValue.call(i_field);
				}

				var a_items = i_field.items.getRange();

				Ext.Array.each(a_items, function (i_subfield) {
					o_value[i_subfield.name] = i_subfield.getSubmitValue ? i_subfield.getSubmitValue() : i_subfield.getValue();
				});

				return o_value;
			},

			getSubmitData: function () {
				var i_field = this;
				var o_data = null;

				if (!i_field.disabled && i_field.submitValue) {
					o_data = {};
					o_data[i_field.getName()] = i_field.getSubmitValue();
				}
				return o_data;
			},

			getSubmitValue: function () {

				var i_field = this;

				return i_field.getValue();
			},
			setValue: function (o_value) {

				var i_field = this;

				var a_items = Ext.Array.from(i_field.items.getRange());

				Ext.Array.each(a_items, function (i_subfield) {
					i_subfield.setValue(o_value[i_subfield.name]);
				});

				i_field.mixins.field.setValue.call(i_field, o_value);
			},
			checkChange: function () {

				var i_self = this;
				var newVal;
				var oldVal;

				if (!i_self.suspendCheckChange && !i_self.destroying && !i_self.destroyed) {
					newVal = i_self.getValue();
					oldVal = i_self.lastValue;
					if (i_self.didValueChange(newVal, oldVal)) {
						i_self.lastValue = newVal;
						i_self.fireEvent("change", i_self, newVal, oldVal);
						i_self.onChange(newVal, oldVal);
					}
				}
			},
			didValueChange: function (newVal, oldVal) {

				var s_new = Ext.encode(newVal);
				var s_old = Ext.encode(oldVal);

				return s_new != s_old;
			},
			isDirty: function () {

				var i_field = this;

				var s_originalValue = Ext.encode(i_field.originalValue);
				var s_value = Ext.encode(i_field.getSubmitValue());

				return s_originalValue != s_value;
			}
		});

		if (!o_property.hasOwnProperty("active")) {
			o_property.active = true;
		}

		var i_group = i_define.create({
			title: o_property.title || o_property.label || o_property.name,
			name: o_property.name,
			items: a_items,
			cls: o_property.active ? "" : "pd-form-field-deactive",
			collapsible: true,
			collapsed: false,
			layout: "anchor",
			defaults: {
				labelWidth: 180
			}
		});

		return i_group;
	},

	createField: function (o_property) {

		var i_self = this;
		var o_clone = Ext.clone(o_property);

		if (!o_clone.hasOwnProperty("active")) {
			o_clone.active = true;
		}

		var i_field;

		if (o_clone.type == "collection" || o_clone.type == "group") {

			var a_items = [];

			var a_label = [];

			if (o_clone.hasOwnProperty("prioritized") && !Ext.isEmpty(o_clone.prioritized, true)) {
				var i_prioritized = i_self.createPrioritiezed(o_clone.prioritized);
				a_items.push(i_prioritized);
			}

			a_label.push(o_clone.fieldLabel || o_clone.label || o_clone.name);

			Ext.Array.each(o_clone.items, function (o_item) {

				var i_field = i_self.createField(o_item);

				i_field.fieldLabel = "";
				i_field.isFormField = false;

				a_items.push(i_field);
			});

			var i_define = Ext.define(null, {

				extend: "Ext.form.FieldContainer",
				mixins: {
					field: "Ext.form.field.Field"
				},

				initComponent: function() {

					var i_field = this;

					i_field.initField();

					i_field.callParent(arguments);

					var a_items = i_field.items.getRange();

					Ext.Array.each(a_items, function(i_subfield) {
						i_subfield.on({
							change: {
								fn: function(i_subfield) {
									i_field.checkChange();
								}
							}
						});
					});
				},

				getValue: function () {

					var i_field = this;

					var o_value = {};

					if (!i_field.items.getRange) {
						return i_field.mixins.field.getValue.call(i_field);
					}

					var a_items = i_field.items.getRange();

					Ext.Array.each(a_items, function (i_subfield) {
						o_value[i_subfield.name] = i_subfield.getSubmitValue ? i_subfield.getSubmitValue() : i_subfield.getValue();
					});

					return o_value;
				},

				getSubmitData: function () {
					var i_field = this;
					var o_data = null;

					if (!i_field.disabled && i_field.submitValue) {
						o_data = {};
						o_data[i_field.getName()] = i_field.getSubmitValue();
					}
					return o_data;
				},

				getSubmitValue: function () {

					var i_field = this;

					return i_field.getValue();
				},
				setValue: function (o_value) {

					var i_field = this;

					var a_items = Ext.Array.from(i_field.items.getRange());

					Ext.Array.each(a_items, function (i_subfield) {
						i_subfield.setValue(o_value[i_subfield.name]);
					});

					i_field.mixins.field.setValue.call(i_field, o_value);
				},
				checkChange: function () {

					var i_self = this;
					var newVal;
					var oldVal;

					if (!i_self.suspendCheckChange && !i_self.destroying && !i_self.destroyed) {
						newVal = i_self.getValue();
						oldVal = i_self.lastValue;
						if (i_self.didValueChange(newVal, oldVal)) {
							i_self.lastValue = newVal;
							i_self.fireEvent("change", i_self, newVal, oldVal);
							i_self.onChange(newVal, oldVal);
						}
					}
				},
				didValueChange: function(newVal, oldVal) {

					var s_new = Ext.encode(newVal);
					var s_old = Ext.encode(oldVal);

					return s_new != s_old;
				},
				isDirty: function () {

					var i_field = this;

					var s_originalValue = Ext.encode(i_field.originalValue);
					var s_value = Ext.encode(i_field.getSubmitValue());

					return s_originalValue != s_value;
				}
			});


			i_field = i_define.create({
				title: o_clone.name,
				name: o_clone.name,
				fieldLabel: a_label.join(" / "),
				cls: o_clone.active ? "" : "pd-form-field-deactive",
				items: a_items,
				layout: {
					type: "hbox"
				},
				defaults: {
					margin: "0 10 0 0"
				}
			});
		}
		else {

			var value = o_clone.value;
			var uomValue = "";

			if (Ext.isObject(value)) {
				if (value.hasOwnProperty("prioritized")) {
					o_clone.prioritized = value.prioritized;
				}
				if (value.hasOwnProperty("uom")) {
					uomValue = value.uom;
				}
			}

			var s_datatype = o_clone.datatype;

			o_clone.fieldLabel = o_clone.fieldLabel || o_clone.label || o_clone.name;

			var a_type = /\(\d*|[,.]*d\)/g.exec(s_datatype);

			if (a_type) {
				s_datatype = s_datatype.substr(0, a_type.index);
			}

			s_datatype = s_datatype ? s_datatype.toLowerCase() : "varchar";

			var s_xtype = "textfield";

			switch (s_datatype) {
				case "char":
				case "varchar":

					if (o_clone.hasOwnProperty("values") && !Ext.isEmpty(o_clone.values)) {

						var a_values = Ext.Array.from(o_clone.values);

						var a_result = [];

						Ext.Array.each(a_values, function(value) {

							if (Ext.isString(value)) {
								a_result.push({
									text: value,
									key: value
								});
							}
							else if(Ext.isObject(value)) {

								var o_value = {
									text: value.text || value.key,
									key: value.value || value.key
								};

								a_result.push(o_value);
							}
						});


						var i_store = Ext.create("Ext.data.Store", {
							data: a_result,
							fields: [
								{
									name: "text",
									type: "auto"
								},
								{
									name: "key",
									type: "auto"
								}
							],
							autoLoad: true
						});

						s_xtype = "combobox";

						Ext.apply(o_clone, {
							store: i_store,
							displayField: "text",
							valueField: "key"
						}, o_clone);
					}
					else {
						s_xtype = "textfield";
					}
					break;
				case "dec":
				case "decimal":
				case "int":
				case "integer":
				case "bigint":
				case "int":
				case "integer":

						if (o_clone.hasOwnProperty("values") && !Ext.isEmpty(o_clone.values)) {

							var a_data = Ext.Array.from(o_clone.values);

							var a_result = [];

							Ext.Array.each(a_data, function(value) {

								if (Ext.isString(value)) {
									a_result.push({
										text: value,
										key: value
									});
								}
								else if(Ext.isObject(value)) {

									var o_value = {
										text: value.text || value.key,
										key: value.value || value.key
									};

									a_result.push(o_value);
								}
							});

							var i_pStore = Ext.create("Ext.data.Store", {
								data: a_result,
								fields: [
									{
										name: "text",
										type: "auto"
									},
									{
										name: "key",
										type: "integer"
									}
								],
								autoLoad: true
							});

							s_xtype = "combobox";

							Ext.apply(o_clone, {
								store: i_pStore,
								displayField: "text",
								valueField: "key"
							});
						}
						else {
							s_xtype = "numberfield";
						}


					break;
				case "smallint":
					if (o_clone.hasOwnProperty("values") && !Ext.isEmpty(o_clone.values)) {

						var i_sStore = Ext.create("Ext.data.Store", {
							data: Ext.Array.from(o_clone.values),
							fields: [
								{
									name: "key",
									type: "auto"
								},
								{
									name: "value",
									type: "integer"
								}
							],
							autoLoad: true
						});

						s_xtype = "combobox";

						Ext.apply(o_clone, {
							store: i_sStore,
							displayField: "key",
							valueField: "value"
						});
					}
					else {

						s_xtype = "checkbox";

						Ext.apply(o_clone, {
							inputValue: 1,
							uncheckedValue: 0
						});
					}
					break;
				case "timestamp":
				case "isotimestamp":
						s_xtype = "isotimestampfield";
					break;
				case "date":
						s_xtype = "datefield";
					break;
				default:
					break;
			}

			if (o_clone.apperence) {

				switch(o_clone.apperence) {
					case "date":
						o_clone.apperence = "isotimestampfield";
						o_clone.datatype = "timestamp";
						s_xtype = "isotimestampfield";
						break;
				}
			}

			if(o_clone.hasOwnProperty("uom") && Ext.isEmpty(o_clone.uom)) {
				delete o_clone.uom;
			}

			if(o_clone.hasOwnProperty("prioritized") && Ext.isEmpty(o_clone.prioritized)) {
				delete o_clone.prioritized;
			}

			if (o_clone.hasOwnProperty("uom") || o_clone.hasOwnProperty("prioritized")) {

				var s_label = ip2.i18n(o_clone.fieldLabel);
				o_clone.fieldLabel = "";
				o_clone.originalValue = o_clone.value = value.value;

				var i_uomfield = Ext.define(null, {

					extend: "Ext.form.FieldContainer",
					mixins: {
						field: "Ext.form.field.Field"
					},

					initComponent: function() {

						var i_field = this;

						i_field.initField();

						i_field.callParent(arguments);

						var a_items = i_field.items.getRange();

						Ext.Array.each(a_items, function(i_subfield) {
							i_subfield.on({
								change: {
									fn: function(i_subfield) {
										i_field.checkChange();
									}
								}
							});
						});
					},

					getValue: function () {

						var i_field = this;

						var o_value = {};

						if (!i_field.items.getRange) {
							return i_field.mixins.field.getValue.call(i_field);
						}

						var a_items = i_field.items.getRange();

						Ext.Array.each(a_items, function (i_subfield) {
							if (i_subfield.uom) {
								o_value.value = i_subfield.getSubmitValue ? i_subfield.getSubmitValue() : i_subfield.getValue();
							}
							else {
								o_value[i_subfield.name] = i_subfield.getSubmitValue ? i_subfield.getSubmitValue() : i_subfield.getValue();
							}
						});

						return o_value;
					},

					getSubmitData: function () {
						var i_field = this;
						var o_data = null;

						if (!i_field.disabled && i_field.submitValue) {
							o_data = {};
							o_data[i_field.getName()] = i_field.getSubmitValue();
						}
						return o_data;
					},

					getSubmitValue: function () {

						var i_field = this;

						return i_field.getValue();
					},
					setValue: function (o_value) {

						var i_field = this;

						var a_items = Ext.Array.from(i_field.items.getRange());

						Ext.Array.each(a_items, function (i_subfield) {
							i_subfield.setValue(o_value[i_subfield.name]);
						});

						i_field.mixins.field.setValue.call(i_field, o_value);
					},
					checkChange: function () {

						var i_self = this;
						var newVal;
						var oldVal;

						if (!i_self.suspendCheckChange && !i_self.destroying && !i_self.destroyed) {
							newVal = i_self.getValue();
							oldVal = i_self.lastValue;
							if (i_self.didValueChange(newVal, oldVal)) {
								i_self.lastValue = newVal;
								i_self.fireEvent("change", i_self, newVal, oldVal);
								i_self.onChange(newVal, oldVal);
							}
						}
					},
					didValueChange: function(newVal, oldVal) {

						var s_new = Ext.encode(newVal);
						var s_old = Ext.encode(oldVal);

						return s_new != s_old;
					},
					isDirty: function () {

						var i_field = this;

						var s_originalValue = Ext.encode(i_field.originalValue);
						var s_value = Ext.encode(i_field.getSubmitValue());

						return s_originalValue != s_value;
					}
				});

				var i_primary = Ext.widget(s_xtype, o_clone);


				var i_uom;
				var i_prioritized;

				var a_temp = [
					i_primary
				];

				if (o_clone.hasOwnProperty("uom") && !Ext.isEmpty(o_clone.uom)) {
					i_uom = i_self.createUOM(o_clone.uom, uomValue);

					a_temp.push(i_uom);
				}

				if (o_clone.hasOwnProperty("prioritized") && !Ext.isEmpty(o_clone.prioritized, true)) {

					i_prioritized = i_self.createPrioritiezed(o_clone.prioritized);

					a_temp.unshift(i_prioritized);
				}

				i_field = i_uomfield.create({
					name: o_clone.name,
					fieldLabel: s_label,
					cls: o_clone.active ? "" : "pd-form-field-deactive",
					layout: {
						type: "hbox"
					},
					items: a_temp,
					defaults: {
						margin: "0 10 0 0"
					}
				});

			}
			else{

				Ext.apply(o_clone, {
					cls: o_clone.active ? "" : "pd-form-field-deactive",
				});

				i_field = Ext.widget(s_xtype, o_clone);
			}
		}

		i_field.resetOriginalValue();

		return i_field;
	},

	createUOM: function(value, propValue) {

		var o_config = {
			name: "uom",
			isFormField: false,
			margin: "0 0 0 0"
		};

		var s_xtype = "";

		var a_values = Ext.Array.from(value);

		var a_data = [];

		Ext.Array.each(a_values, function(value) {

			if (Ext.isString(value)) {
				a_data.push({
					text: value,
					key: value,
					active: true
				});
			}
			else if(Ext.isObject(value)) {

				var o_value = {
					text: value.text || value.key,
					key: value.value || value.key,
					active: value.active
				};

				a_data.push(o_value);
			}
		});

		var i_store = Ext.create("Ext.data.Store", {
			data: a_data,
			fields: [
				{
					name: "text",
					type: "auto"
				},
				{
					name: "key",
					type: "auto"
				},
				{
					name: "active",
					type: "auto",
					defaultValue: true
				}
			],
			idProperty: "key",
			autoLoad: true
		});

		s_xtype = "combobox";

		var i_listTpl = Ext.create("Ext.XTemplate",
			"<ul class=\"x-list-plain\">",
				"<tpl for=\".\">",
					"<tpl if=\"this.isActive(values.active)\">",
						"<li role=\"option\" class=\"x-boundlist-item\">{text}</li>",
					"<tpl else>",
						"<li role=\"option\" class=\"x-boundlist-item\"><span style=\"opacity:0.5;\">{text}<span></li>",
					"</tpl>",
				"</tpl>",
			"</ul>",
			{
				isActive: function(value) {
					return value;
				}
			}
		);

		Ext.apply(o_config, {
			store: i_store,
			displayField: "text",
			valueField: "key",
			value: propValue,
			multiSelect: false,
			tpl: i_listTpl,
			listeners: {
				change: {
					fn: function(i_field, value) {

						var i_selected = i_field.getSelectedRecord();
						var i_inputEl;
						var b_active = i_field.hasOwnProperty("active") ? i_field.active : true;

						if (i_selected) {
							b_active = i_selected.get("active");

							i_inputEl = i_field.inputEl;

							if (i_inputEl) {
								i_inputEl.setStyle("opacity", b_active ? "1" : "0.5");
							}
						}
						else {

							i_inputEl = i_field.inputEl;

							if (i_inputEl) {
								i_inputEl.setStyle("opacity", b_active ? "1" : "0.5");
							}
						}

					}
				}
			}
		});

		var i_field = Ext.widget(s_xtype, o_config);

		return i_field;
	},

	createPrioritiezed: function(value) {

		var o_config = {
			name: "prioritized",
			isFormField: false,
			value: value,
			inputValue: true,
			uncheckedValue: false
		};

		var i_field = Ext.widget("checkbox", o_config);

		return i_field;
	},

	getFormFields: function(o_formCollection, a_definition) {

		var i_self = this;

		var o_clone = Ext.clone(o_formCollection);

		var a_extend = Ext.Array.from(o_clone.extend);

		if (a_extend.length > 0) {

			var a_recursion = i_self.getExtendedFormCollection(a_extend, a_definition);

			a_recursion.reverse();

			var o_merged = {};

			Ext.Array.each(a_recursion, function(o_extended){

				Ext.Object.each(o_extended, function(s_key, value) {

					if (Ext.isPrimitive(value)) {
						o_merged[s_key] = value;
					}
					else {
						if (Ext.isArray(value)) {

							var a_temp = Ext.Array.from(o_merged[s_key]) || [];
							var a_value = Ext.Array.from(value);

							a_temp = Ext.Array.merge(a_temp, a_value);

							o_merged[s_key] = a_temp;
						}
						else{
							if (Ext.isObject(value)) {
								o_merged[s_key] = Ext.apply(o_merged[s_key] || {}, value);
							}
						}
					}

				});
			});

			Ext.Object.each(o_clone, function (s_key, value) {

				if (Ext.isPrimitive(value)) {
					o_merged[s_key] = value;
				}
				else {
					if (Ext.isArray(value)) {

						var a_temp = Ext.Array.from(value) || [];
						var a_value = Ext.Array.from(o_merged[s_key]);

						a_temp = Ext.Array.merge(a_temp, a_value);

						o_merged[s_key] = a_temp;
					}
					else {
						if (Ext.isObject(value)) {
							o_merged[s_key] = Ext.apply(o_merged[s_key] || {}, value);
						}
					}
				}

			});

			o_clone = o_merged;

			delete o_clone.extend;
		}

		var a_fields = Ext.Array.from(o_clone.fields || o_clone.items);

		return a_fields;
	},

	checkPropertyUsages: function(s_value, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		Ext.Ajax.request({
			url: [
				"/portfolio/pd/whereDoPropertyGetUsed",
				s_value
			].join("/"),
			success: function(i_response) {

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

				f_callback(o_result, true);
			},
			failure: function(o_err) {
				f_callback(o_err, false);
			}
		});
	},

	checkCollectionUsages: function(s_value, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		Ext.Ajax.request({
			url: [
				"/portfolio/pd/whereDoCollectionGetUsed",
				s_value
			].join("/"),
			success: function(i_response) {

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

				f_callback(o_result, true);
			},
			failure: function(o_err) {
				f_callback(o_err, false);
			}
		});
	}
});
Ext.define("Portfolio.pd.util.Cache", {

	singleton: true,

	config: {
        stored: {}
    },

    constructor: function(o_config) {

		var i_self = this;

		i_self.initConfig(o_config);
	},

    set: function(s_key, value) {

        var i_self = this;

        var o_stored = i_self.getStored();
        o_stored[s_key] = value;
    },

    get: function(s_key) {

        var i_self = this;

        var o_stored = i_self.getStored();
        var value = o_stored[s_key];

        return value;
    },

    load: function(s_url, s_name) {

        var i_self = this;

        s_name = s_name || s_url;

        var a_return = Ext.Array.from(i_self.get(s_name));

        if (a_return.length === 0) {

            Ext.Ajax.request({
                url: s_url,
                async: false,
                success: function(i_response) {
    
                    a_return = Ext.decode(i_response.responseText, true) || [];
                }
            });

            Ext.Array.each(a_return, function(o_config) {

                if(o_config.type == "formCollection") {

                    var o_rule = o_config.rule || {};

                    Ext.apply(o_config, o_rule);

                    delete o_config.rule;
                }
            });

            i_self.set(s_name, a_return);
        }

        return a_return;
    },
    
    clear: function() {
        
        var i_self = this;
        i_self.setStored({});
    }
});Ext.define("Ext.ux.xpd.Handler", {

	singleton: true,

	mixins: {
		DMDUiType: "Portfolio.entity.util.Handler"
	},

	getFields: function(o_xpd, s_cid) {
		var i_self = this;
		var a_xpdFields = [];
		var o_collection = Ext.clone(o_xpd.collections[s_cid]);
		var o_default = o_xpd.layout.editor.__default__;
		var n_extend = s_cid;

		i_self.getExtended(o_collection, o_xpd, n_extend);

		i_self.getRecursive(o_default, o_collection, null, o_collection.properties);

		var o_uiCollection = i_self.createUiCollection({
			collection: o_collection,
			xpd: o_xpd,
			rulesXpd: ip2.uirules.flatten,
			rulesJs: ip2.loadUiTypeRules(),
			context: "form",
			values: {},
			environment: i_self.environment || "editor",
			defaults: {
				labelWidth: 140
			}
		});

		Ext.Object.each(o_uiCollection, function(s_key, i_field) {
			a_xpdFields.push(i_field);
		});

		return a_xpdFields;
	},

	getRecursive: function(o_default, o_collection, s_name, o_value) {

		var i_self = this;
		var a_keys = Ext.Object.getKeys(o_value);
		var a_fields = [];
		Ext.Array.each(a_keys, function(s_prop) {

			var o_property = o_value[s_prop];
			if (o_property.hasOwnProperty("properties")) {
				var s_newProp = s_prop;
				if (s_name) {
					var a_temp = [s_name, s_prop];
					s_newProp = a_temp.join("-");
				}

				i_self.getRecursive(o_default, o_collection, s_newProp, o_property.properties);
				delete o_collection.properties[s_prop];
			}
			else {
				if (s_name) {
					var o_new = Ext.apply(o_property, o_default);
					o_new.extended = true;
					o_collection.properties[s_name + "-" + s_prop] = o_new;
				}
			}
		});
	},

	getExtended: function(o_original, o_collection, o_xpd, n_extend) {

		var i_self = this;
		var a_keys = Ext.Object.getKeys(o_xpd.collections);
		if (o_collection.extend) {
			var o_extended = Ext.clone(o_xpd.collections[o_collection.extend]);
			while (o_extended.extend) {
				n_extend = o_extended.extend;
				o_extended = Ext.clone(o_xpd.collections[o_extended.extend]);
			}
			var o_originalExtend = o_xpd.collections[n_extend];
			i_self.getExtended(o_originalExtend, o_extended, o_xpd, n_extend);
			Ext.Object.merge(o_collection.properties, o_extended.properties);
		}
		else {
			Ext.Array.each(a_keys, function(s_collection) {
				var o_object = Ext.clone(o_xpd.collections[s_collection]);
				var o_originalExtend = o_xpd.collections[s_collection];
				if (o_object.extend && o_object.extend == n_extend) {
					n_extend = o_object.id;
					o_original.extended = n_extend;
					Ext.Object.merge(o_collection.properties, o_object.properties);
					i_self.getExtended(o_originalExtend, o_collection, o_xpd, n_extend);
					return false;
				}
			});
		}
	},

	getFieldsWithValues: function(o_xpd, s_cid, o_value) {

		var i_self = this;
		var a_xpdFields = [];
		var o_original = o_xpd.collections[s_cid];
		var o_collection = Ext.clone(o_xpd.collections[s_cid]);
		var o_default = o_xpd.layout.editor.__default__;
		var n_extend = s_cid;

		i_self.getExtended(o_original, o_collection, o_xpd, n_extend);

		i_self.getRecursive(o_default, o_collection, null, o_collection.properties);

		var o_uiCollection = i_self.createUiCollection({
			collection: o_collection,
			xpd: o_xpd,
			rulesXpd: ip2.uirules.flatten,
			rulesJs: ip2.loadUiTypeRules(),
			context: "form",
			values: o_value,
			environment: i_self.environment || "editor",
			defaults: {
				labelWidth: 140
			}
		});

		Ext.Object.each(o_uiCollection, function(s_key, i_field) {
			a_xpdFields.push(i_field);
		});

		return a_xpdFields;
	},

	getValueFromProperties: function(o_xpd, o_data) {

		var i_self = this;
		var o_value = {};
		var o_collection = o_xpd.collections[o_data[o_xpd.idProperty]];
		var a_removeProps = [];

		o_value[o_xpd.idProperty] = o_data[o_xpd.idProperty];

		// Find all depricated values and remove them:
		if (o_collection) {
			Ext.Object.each(o_collection.properties, function(s_key, o_prop) {

				var a_asimilate = Ext.Array.from(o_prop.assimilate);

				Ext.Array.each(a_asimilate, function(o_config) {
					a_removeProps.push(o_config.field);
				});
				o_value[s_key] = o_data[s_key];
			});
		}

		// remove depricated values and dependsOn values that are not visible:
		Ext.Array.each(a_removeProps, function(s_key) {
			delete o_value[s_key];
		});

		return o_value;
	},

	convertData: function(o_xpd, o_data) {

		if (o_xpd.hasOwnProperty("convert")) {

			var o_convert = o_xpd.convert || {};

			Ext.Object.each(o_convert, function(s_property, o_value) {
				o_data[s_property] = o_value.to;
			});
		}

		return o_data;
	},

	getCollectionFromData: function(o_xpd, o_data) {
		var i_self = this;
		var o_collection = "";
		if (o_data[o_xpd.idProperty]) {
			o_collection = o_xpd.collections[o_data[o_xpd.idProperty]];
		}
		return o_collection;
	},

	getValues: function(o_xpd, a_fields, o_collection, o_data, b_usefields) {

		var i_self = this;
		var o_value = {};
		var a_removeProps = [];
		var a_extended = [];

		if (!o_collection.extend && !o_collection.extended) {
			var a_keys = Ext.Object.getKeys(o_xpd.collections);
			var o_root = o_collection;
			Ext.Array.each(a_keys, function(s_collection) {
				if (s_collection != "all") {
					var o_temp = o_xpd.collections[s_collection];
					if (o_temp.extend == o_collection.id) {
						a_extended.push(o_temp);
						o_root = o_temp;
					}
				}
			});
		}

		if (o_collection.extended && o_collection.extend) {
			var o_extend = o_xpd.collections[o_collection.extend];
			var o_extended = o_xpd.collections[o_collection.extended];
			a_extended.push(o_extend);
			a_extended.push(o_extended);
			while (o_extend.extend) {
				o_extend = o_xpd.collections[o_extend.extend];
				if (o_extend) {
					var b_found = false;
					Ext.Array.each(a_extended, function(o_sub) {
						if (o_sub.id == o_extend.id) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_extended.push(o_extend);
					}
				}
			}
			while (o_extended.extend) {
				o_extended = o_xpd.collections[o_extended.extend];
				if (o_extended) {
					var b_found = false;
					Ext.Array.each(a_extended, function(o_sub) {
						if (o_sub.id == o_extended.id) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_extended.push(o_extended);
					}
				}
			}
		}
		else if (o_collection.extended && !o_collection.extend) {
			a_extended.push(o_collection);
			var o_extended = o_xpd.collections[o_collection.extended];
			var b_found = false;
			Ext.Array.each(a_extended, function(o_sub) {
				if (o_sub.id == o_extended.id) {
					b_found = true;
					return false;
				}
			});
			if (!b_found) {
				a_extended.push(o_extended);
			}
			while (o_extended.extended) {
				o_extended = o_xpd.collections[o_extended.extended];
				if (o_extended) {
					var b_found = false;
					Ext.Array.each(a_extended, function(o_sub) {
						if (o_sub.id == o_extended.id) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_extended.push(o_extended);
					}
				}
			}
		}
		else if (!o_collection.extended && o_collection.extend) {
			a_extended.push(o_collection);
			var o_extended = o_xpd.collections[o_collection.extend];
			var b_found = false;
			Ext.Array.each(a_extended, function(o_sub) {
				if (o_sub.id == o_extended.id) {
					b_found = true;
					return false;
				}
			});
			if (!b_found) {
				a_extended.push(o_extended);
			}
			while (o_extended.extend) {
				o_extended = o_xpd.collections[o_extended.extend];
				if (o_extended) {
					var b_found = false;
					Ext.Array.each(a_extended, function(o_sub) {
						if (o_sub.id == o_extended.id) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_extended.push(o_extended);
					}
				}
			}
		}

		if (!o_data[o_xpd.idProperty]) {
			o_value[o_xpd.idProperty] = o_collection.id;
		}
		else {
			o_value[o_xpd.idProperty] = o_data[o_xpd.idProperty];
		}
		var a_collectionKeys = Ext.Object.getKeys(o_collection.properties);
		var a_cid = [];

		if (o_collection.extended) {
			a_cid.push(o_collection.id);
		}

		Ext.Array.each(a_fields, function (i_field, n_index) {

			Ext.Object.each(o_collection.properties, function(s_key) {

				if (i_field) {
					var s_name = i_field.name;

					if (i_field._xpdConfig && !i_field._xpdConfig.extended) {

						if (i_field.name == s_key) {

							if (!i_field.isDisabled) {
								console.warn("This field seems to be missing the method \"isDisabled\" ->", i_field.id, i_field.name);
							}

							if (i_field.from || (i_field.isDisabled && i_field.isDisabled())) {

								a_removeProps.push(i_field.name);
							}
							if (b_usefields) {
								o_value[i_field.name] = i_field.getValue();
							}
							else {
								if (o_data[i_field.name] != undefined) {
									o_value[i_field.name] = o_data[i_field.name];
								}
								if (i_field._xpdConfig.borrow && Ext.isString(i_field._xpdConfig.borrow)) {
									o_value[i_field._xpdConfig.borrow] = o_data[i_field._xpdConfig.borrow];
								}
							}
						}
					}
					else {
						if (i_field.from || (i_field.isDisabled && i_field.isDisabled())) {

							a_removeProps.push(i_field.name);
						}
						else {

							var a_split = s_name.split("-");
							var o_root = o_value;
							var n_count = 1;

							Ext.Array.each(a_split, function(s_key) {

								if (n_count < a_split.length) {
									if (!o_root[s_key]) {
										o_root[s_key] = {};
										o_root = o_root[s_key];
									}
									else {
										o_root = o_root[s_key];
									}
								}
								else {

									var value = i_field.getValue();
									var o_prop;
									var o_col;

									Ext.Array.each(a_extended, function(o_extended) {

										var s_join = a_split.join(".properties.");

										if (!o_prop) {
											try {
												eval("o_prop = o_extended.properties." + s_join);
											}
											catch (err) {}
										}
										if (o_prop) {
											o_col = o_extended;
											return false;
										}
									});

									if (o_prop && value) {

										if (a_cid.indexOf(o_col.id) == -1) {

											a_cid.push(o_col.id);
										}
									}
									o_root[s_key] = value;
								}
								n_count++;
							});
						}
					}
				}
			});
		});

		if (a_cid.length > 0) {

			var n_cid;

			Ext.Array.each(a_cid, function(n_id) {

				var o_collection = o_xpd.collections[n_id];

				if (o_collection.extended) {

					if (a_cid.indexOf(o_collection.extended) == -1) {
						n_cid = o_collection.id;
					}
				}
				else {
					n_cid = o_collection.id;
				}
			});
			if (n_cid) {

				o_value[o_xpd.idProperty] = n_cid;

				if (o_xpd.cidMap) {

					var a_keys = Ext.Object.getKeys(o_xpd.cidMap);

					Ext.Object.each(o_xpd.cidMap, function(s_key) {

						var o_prop = o_value[s_key];

						var o_map = o_xpd.cidMap[s_key];

						if (o_prop) {

							i_self.applyCidMap(o_xpd, o_prop, o_map, n_cid);
						}
					});
				}
			}
		}
		else {
			if (a_extended.length > 0) {

				var o_base;

				Ext.Array.each(a_extended, function(o_extended) {

					if (!o_extended.extend) {

						o_base = o_extended;

						return false;
					}
				});
				if (o_base) {

					o_value[o_xpd.idProperty] = o_base.id;

					if (o_xpd.cidMap) {

						var a_keys = Ext.Object.getKeys(o_xpd.cidMap);

						Ext.Object.each(o_xpd.cidMap, function(s_key) {

							var o_prop = o_value[s_key];
							var o_map = o_xpd.cidMap[s_key];

							if (o_prop) {

								i_self.applyCidMap(o_xpd, o_prop, o_map, o_base.id);
							}
						});
					}
				}
			}
		}

		// Find all depricated values and remove them:
		Ext.Object.each(o_collection.properties, function(s_key, o_prop) {

			var a_asimilate = Ext.Array.from(o_prop.assimilate);

			Ext.Array.each(a_asimilate, function(o_config) {
				a_removeProps.push(o_config.field);
			});
		});

		// remove depricated values and dependsOn values that are not visible:
		Ext.Array.each(a_removeProps, function(s_key) {
			delete o_value[s_key];
		});

		return o_value;
	},

	applyCidMap: function(o_xpd, o_value, o_map, n_cid) {

		var i_self = this;
		o_value[o_xpd.idProperty] = o_map[n_cid];

		var a_keys = Ext.Object.getKeys(o_map);

		Ext.Array.each(a_keys, function(s_key) {
			if (Ext.isObject(o_value[s_key])) {
				var o_prop = o_value[s_key];
				var o_tmpMap = o_map[s_key];
				i_self.applyCidMap(o_xpd, o_prop, o_tmpMap, n_cid);
			}
		});
	},

	getProperties: function(o_xpd, o_values) {

		var i_self = this;
		var o_collection = o_xpd.collections[o_values[o_xpd.idProperty]];
		var o_value = {};
		var a_removeProps = [];

		if (o_collection) {
			// Find all depricated values and remove them:
			Ext.Object.each(o_collection.properties, function(s_key, o_prop) {
				o_value[s_key] = "";
			});

			// Find all depricated values and remove them:
			Ext.Object.each(o_collection.properties, function(s_key, o_prop) {

				var a_asimilate = Ext.Array.from(o_prop.assimilate);

				Ext.Array.each(a_asimilate, function(o_config) {
					a_removeProps.push(o_config.field);
				});
			});

			// remove depricated values and dependsOn values that are not visible:
			Ext.Array.each(a_removeProps, function(s_key) {
				delete o_value[s_key];
			});

			Ext.apply(o_value, o_values);
		}

		return o_value;
	},

	createGroups: function(a_xpdFields, o_xpd, o_collection, i_dataParent) {

		var a_groups = [];
		var a_nogroup = [];
		var i_user = ip2.getUser();

		var s_language = i_user.get("USRLNG") || "en";

		var n_length = Ext.Object.getKeys(o_xpd.groups).length;

		if (n_length > 0) {
			Ext.Object.each(o_xpd.groups, function(s_key, o_group) {
				var found = false;
				if (o_group.renderIn.editor) {
					Ext.Array.each(a_groups, function(i_group) {
						if (i_group.name == s_key) {
							found = true;
							return false;
						}
					});
					if (!found) {
						var a_fields = [];
						Ext.Array.each(a_xpdFields, function(i_field) {
							var a_groups = i_field._xpdConfig.groups || [];
							if (a_groups.length > 0) {
								Ext.Array.each(a_groups, function(s_group) {
									if (s_group === s_key) {
										if (i_field.prefix) {
											i_field.name = i_field.prefix + "-" + i_field.name;
										}
										a_fields.push(i_field);
										return false;
									}
								});
							}
							else {
								var b_found = false;
								Ext.Object.each(o_collection.properties, function(s_property, o_prop) {
									if (o_prop.groups) {
										if (o_prop.name == i_field.name && o_prop.groups.indexOf(s_key) != -1 && a_fields.indexOf(i_field) == -1) {
											if (i_field.prefix) {
												i_field.name = i_field.prefix + "-" + i_field.name;
											}
											a_fields.push(i_field);
											b_found = true;
										}
									}
								});
								if (!b_found) {
									b_found = false;
									Ext.Array.each(a_nogroup, function(i_leftover) {
										if (i_leftover.name == i_field.name) {
											b_found = true;
											return false;
										}
									});
									if (!b_found) {
										a_nogroup.push(i_field);
									}
								}
							}
						});
						if (a_fields.length > 0) {

							a_fields.sort(function(a, b) {
								var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
								var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

								return n_a - n_b;
							});
							
							var b_collapsed = false;
							var b_collapsible = true;
							var n_sequence = 99999;
							var b_protected = false;
							var b_hidden = false;
							var s_type = "fieldset";
							if (o_group.renderIn.editor.layout) {
								b_collapsed = Ext.isBoolean(o_group.renderIn.editor.layout.collapsed) ? o_group.renderIn.editor.layout.collapsed : false;
								b_collapsible = Ext.isBoolean(o_group.renderIn.editor.layout.collapsible) ? o_group.renderIn.editor.layout.collapsible : true;
								n_sequence = o_group.renderIn.editor.layout.sequence || 99999;
								b_protected = Ext.isBoolean(o_group.renderIn.editor.layout["protected"]) ? o_group.renderIn.editor.layout["protected"] : false;
								s_type = o_group.renderIn.editor.layout.type || "fieldset";
								b_hidden = o_group.renderIn.editor.layout.hidden || false;
							}
							else {
								if (o_group.renderIn.editor) {
									b_collapsed = Ext.isBoolean(o_group.renderIn.editor.collapsed) ? o_group.renderIn.editor.collapsed : false;
									b_collapsible = Ext.isBoolean(o_group.renderIn.editor.collapsible) ? o_group.renderIn.editor.collapsible : true;
									n_sequence = o_group.renderIn.editor.sequence || 99999;
									b_protected = Ext.isBoolean(o_group.renderIn.editor["protected"]) ? o_group.renderIn.editor["protected"] : false;
									s_type = o_group.renderIn.editor.type || "fieldset";
									b_hidden = o_group.renderIn.editor.hidden || false;
								}
							}
							if (b_protected) {
								a_fields.unshift({
									xtype: "container",
									_protectionToggler: true,
									style: "margin:20px;text-align: center;",
									items: [
										{
											xtype: "container",
											style: "margin-bottom: 10px;",
											html: ip2.i18n({
												da: "Disse værdier er beskyttede, tryk på knappen for at kunne redigere",
												"en": "These values are protected, please press the button to edit"
											})
										},
										{
											xtype: "button",
											text: ip2.i18n({
												da: "Fjern beskyttelse",
												en: "Remove protection"
											}),
											handler: function (i_button) {

												ip2.messageBox({
													icon: Ext.Msg.WARNING,
													message: ip2.i18n({
														da: "Venligst bemærk at dette kan medføre uønskede ændringer på din hjemmeside",
														en: "Please note that this may have undesired impacts on your website"
													}),
													yesText: ip2.i18n({
														da: "Fjern",
														en: "Remove"
													}),
													yesFn: function () {
														i_button.up(s_type).setProtected(false);
													},
													noText: ip2.i18n({
														da: "Fortryd",
														en: "Cancel"
													})
												});
											},
											iconCls: "pf-edit"
										}
									]
								});
							}

							var o_groupConfig = {
								name: s_key,
								collapsible: b_collapsible,
								collapsed: b_collapsed,
								hidden: b_hidden,
								sequence: n_sequence,
								dataParent: i_dataParent,
								layout: "anchor",
								defaults: {
									anchor: "100%"
								},
								title: ip2.xpd.translate(o_xpd, o_group.title, s_language),
								_protected: b_protected,
								getProtected: function () {

									return this._protected;
								},
								setProtected: function (b_protect) {
									this._protected = b_protect ? true : false;
									this.toggleProtect(this._protected);
									return this;
								},
								toggleProtect: function (b_protect) {

									var i_cmp = this;

									var a_items = i_cmp.items.getRange();

									Ext.Array.each(a_items, function (i_item) {
										if (i_item._protectionToggler) {
											i_item[b_protect ? "show" : "hide"]();
										}
										else {
											i_item[b_protect ? "hide" : "show"]();
										}
									});
								},
								items: a_fields,
								listeners: {
									afterrender: {
										fn: function (i_group) {
											if (i_group._protected) {
												i_group.toggleProtect(this.getProtected());
											}
										},
										single: true
									}
								}
							};

							Ext.applyIf(o_groupConfig, o_group);

							var i_group = Ext.widget(s_type, o_groupConfig);

							if (i_group.dependsOn) {
								Ext.Array.each(i_group.dependsOn, function(o_depends) {
									Ext.Array.each(a_xpdFields, function(i_field) {
										if (i_field.name == o_depends.field) {

											if (o_depends.equal) {
												o_depends.equals = [o_depends.equal];
											}

											if (o_depends.notEqual) {
												o_depends.notEquals = [o_depends.notEqual];
											}

											var b_allowed = true;

											i_group.mon(i_field, "change", check);
											i_group.mon(i_field, "disable", check);
											i_group.mon(i_field, "enable", check);

											i_group.hide();

											check();

											function check() {

												b_allowed = false;

												if (!i_field.isDisabled || !i_field.isDisabled()) {
													// (Not) Equal
													if ("equals" in o_depends) {
														b_allowed = Ext.Array.some(o_depends.equals, function(equal) {
															return ip2.isEqual(i_field.getValue(), equal);
														});
													}
													else if ("notEquals" in o_depends) {
														b_allowed = Ext.Array.every(o_depends.notEquals, function(notEqual) {
															return !ip2.isEqual(i_field.getValue(), notEqual);
														});
													}

													// (Not) Empty
													if ("empty" in o_depends) {
														b_allowed = !i_field.getValue();
													}
													else if ("notEmpty" in o_depends) {
														b_allowed = i_field.getValue() ? true : false;
													}
												}

												checkChange();
											}

											function checkChange() {

												if (b_allowed) {
													i_group.show();
												}
												else {
													i_group.hide();
												}
											}
										}
									});
								});
							}
							a_groups.push(i_group);
						}
					}
				}
			});
		}
		else {
			Ext.Object.each(o_collection.properties, function(s_key, value) {

				var i_field;

				Ext.Array.each(a_xpdFields, function(i_xpdField) {
					if (i_xpdField.name == s_key) {
						i_field = i_xpdField;
						return false;
					}
				});

				if (i_field) {
					a_nogroup.push(i_field);
				}
			});
		}

		a_groups.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});
		return {
			groups: a_groups,
			nogroup: a_nogroup
		};
	}
});
Ext.define("Portfolio.entity.util.Layout", {

	singleton: true,

	create: function(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent) {
		var i_self = this;
		var i_panel = {};
		switch (o_layout.type) {
			case "border":
				i_panel = i_self.border(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				break;
			case "accordion":
				i_panel = i_self.accordion(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				break;
			case "hbox":
				i_panel = i_self.hbox(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				break;
			case "vbox":
				i_panel = i_self.vbox(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				break;
			case "fit":
				i_panel = i_self.fit(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				break;
			case "anchor":
				i_panel = i_self.anchor(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				break;
			case "tabpanel":
				i_panel = i_self.tabpanel(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				break;
			case "portal":
				i_panel = i_self.portal(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				break;
		}
		return i_panel;
	},

	border: function(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent) {

		var i_self = this;
		var a_layoutItems = o_layout.items || [];
		var a_panels = [];

		Ext.Array.each(a_layoutItems, function(o_layoutItem) {

			var b_layout = false;
			var a_items = o_layoutItem.items || [];

			if (o_layoutItem.type) {
				b_layout = true;
				var o_layout = o_layoutItem.layout || o_layoutItem;
				var i_return = i_self.create(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
				i_return.region = o_layoutItem.region;
				i_return.split = o_layoutItem.split;
				a_panels.push(i_return);
			}
			else {
				var a_children = [];

				Ext.Array.each(a_items, function(o_item, n_index) {

					if (Ext.isObject(o_item)) {
						if (o_item.type || o_item.layout) {
							b_layout = true;
							var o_layout = o_item.layout || o_item;
							var i_return = i_self.create(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);

							a_children.push(i_return);
						}
					}
					else {
						var b_found = false;
						Ext.Array.each(a_groups, function (o_group) {
							if (o_item == o_group.name) {

								Ext.applyIf(o_group, {
									sequence: n_index,
									flex: 1
								});

								a_children.push(o_group);
								b_found = true;
							}
						});
						if (!b_found) {
							Ext.Array.each(a_widgets, function (o_widget) {
								if ("widget-" + o_item == o_widget.itemId) {
									o_widget.inLayout = true;

									Ext.applyIf(o_widget, {
										sequence: n_index,
										flex: 1
									});

									a_children.push(o_widget);
								}
							});
						}
						if (!b_found) {
							Ext.Array.each(a_relations, function (i_relation) {
								if (o_item == i_relation.itemId) {
									i_relation.inLayout = true;

									Ext.applyIf(i_relation, {
										sequence: n_index,
										flex: 1
									});

									a_children.push(i_relation);
								}
							});
						}
						if (!b_found) {
							Ext.Array.each(a_affiliations, function (i_affiliation) {
								if ("affiliation-" + o_item == i_affiliation.itemId) {
									i_affiliation.inLayout = true;

									Ext.applyIf(i_affiliation, {
										sequence: n_index,
										flex: 1
									});

									a_children.push(i_affiliation);
								}
							});
						}
					}
				});

				a_children.sort(function(a, b) {
					var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
					var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

					var n_min = Math.min(n_a, n_b);

					return n_min;
				});

				var i_panel = Ext.widget("panel", {
					title: o_layoutItem.title ? ip2.i18n(o_layoutItem.title) : "",
					flex: o_layoutItem.flex,
					width: o_layoutItem.width ? o_layoutItem.width : undefined,
					height: o_layoutItem.height ? o_layoutItem.height : undefined,
					minWidth: o_layoutItem.minWidth ? o_layoutItem.minWidth : undefined,
					minHeight: o_layoutItem.minHeight ? o_layoutItem.minHeight : undefined,
					maxWidth: o_layoutItem.maxWidth ? o_layoutItem.maxWidth : undefined,
					maxHeight: o_layoutItem.maxHeight ? o_layoutItem.maxHeight : undefined,
					region: o_layoutItem.region,
					layout: {
						type: b_layout ? "fit" : "anchor"
					},
					defaults: o_layoutItem.defaults,
					items: a_children,
					collapsible: o_layoutItem.collapsible ? o_layoutItem.collapsible : false,
					collapsed: o_layoutItem.collapsed ? o_layoutItem.collapsed : false,
					bodyPadding: o_layoutItem.bodyPadding ? o_layoutItem.bodyPadding : 0,
					border: o_layoutItem.border ? o_layoutItem.border : false,
					dataParent: dataParent,
					split: o_layoutItem.split !== undefined ? o_layoutItem.split : true,
					autoScroll: b_layout ? false : true
				});
				a_panels.push(i_panel);
			}
		});

		a_panels.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var i_panel = Ext.widget("panel", {
			title: o_layout.title ? ip2.i18n(o_layout.title) : "",
			collapsible: o_layout.collapsible ? o_layout.collapsible : false,
			collapsed: o_layout.collapsed ? o_layout.collapsed : false,
			bodyPadding: o_layout.bodyPadding ? o_layout.bodyPadding : 0,
			border: o_layout.border ? o_layout.border : false,
			flex: o_layout.flex,
			width: o_layout.width ? o_layout.width : undefined,
			height: o_layout.height ? o_layout.height : undefined,
			minWidth: o_layout.minWidth ? o_layout.minWidth : undefined,
			minHeight: o_layout.minHeight ? o_layout.minHeight : undefined,
			maxWidth: o_layout.maxWidth ? o_layout.maxWidth : undefined,
			maxHeight: o_layout.maxHeight ? o_layout.maxHeight : undefined,
			split: o_layout.hasOwnProperty("split") ? o_layout.split : undefined,
			defaults: o_layout.defaults || {},
			layout: {
				type: o_layout.type
			},
			items: a_panels,
			dataParent: dataParent,
			autoScroll: o_layout.autoScroll ? o_layout.autoScroll : false
		});
		return i_panel;
	},

	hbox: function(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent) {

		var i_self = this;
		var a_items = o_layout.items;
		var a_children = [];
		Ext.Array.each(a_items, function(o_item, n_index) {
			if (Ext.isObject(o_item)) {
				if (o_item.type || o_item.layout) {
					var o_layout = o_item.layout || o_item;
					var i_return = i_self.create(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
					a_children.push(i_return);
				}
			}
			else {
				var b_found = false;
				Ext.Array.each(a_groups, function (o_group) {
					if (o_item == o_group.name) {

						Ext.applyIf(o_group, {
							sequence: n_index,
							flex: 1
						});

						a_children.push(o_group);
						b_found = true;
					}
				});
				if (!b_found) {
					Ext.Array.each(a_widgets, function (o_widget) {
						if ("widget-" + o_item == o_widget.itemId) {
							o_widget.inLayout = true;

							Ext.applyIf(o_widget, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(o_widget);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_relations, function (i_relation) {
						if (o_item == i_relation.itemId) {
							i_relation.inLayout = true;

							Ext.applyIf(i_relation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_relation);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_affiliations, function (i_affiliation) {
						if ("affiliation-" + o_item == i_affiliation.itemId) {
							i_affiliation.inLayout = true;

							Ext.applyIf(i_affiliation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_affiliation);
						}
					});
				}
			}
		});

		a_children.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var i_panel = Ext.widget("panel", {
			title: o_layout.title ? ip2.i18n(o_layout.title) : "",
			collapsible: o_layout.collapsible ? o_layout.collapsible : false,
			collapsed: o_layout.collapsed ? o_layout.collapsed : false,
			bodyPadding: o_layout.bodyPadding ? o_layout.bodyPadding : 0,
			border: o_layout.border ? o_layout.border : false,
			flex: o_layout.flex,
			width: o_layout.width ? o_layout.width : undefined,
			height: o_layout.height ? o_layout.height : undefined,
			minWidth: o_layout.minWidth ? o_layout.minWidth : undefined,
			minHeight: o_layout.minHeight ? o_layout.minHeight : undefined,
			maxWidth: o_layout.maxWidth ? o_layout.maxWidth : undefined,
			maxHeight: o_layout.maxHeight ? o_layout.maxHeight : undefined,
			split: o_layout.hasOwnProperty("split") ? o_layout.split : undefined,
			layout: {
				type: o_layout.type,
				align: "stretch"
			},
			defaults: o_layout.defaults || {},
			items: a_children,
			dataParent: dataParent,
			autoScroll: o_layout.autoScroll ? o_layout.autoScroll : false
		});
		return i_panel;
	},

	vbox: function(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent) {

		var i_self = this;
		var a_items = o_layout.items;
		var a_children = [];

		Ext.Array.each(a_items, function(o_item, n_index) {
			if (Ext.isObject(o_item)) {
				if (o_item.type || o_item.layout) {
					var o_layout = o_item.layout || o_item;
					var i_return = i_self.create(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
					a_children.push(i_return);
				}
			}
			else {
				var b_found = false;
				Ext.Array.each(a_groups, function(o_group) {
					if (o_item == o_group.name) {

						Ext.applyIf(o_group, {
							sequence: n_index,
							flex: 1
						});

						a_children.push(o_group);
						b_found = true;
					}
				});
				if (!b_found) {
					Ext.Array.each(a_widgets, function(o_widget) {
						if ("widget-" + o_item == o_widget.itemId) {
							o_widget.inLayout = true;

							Ext.applyIf(o_widget, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(o_widget);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_relations, function(i_relation) {
						if (o_item == i_relation.itemId) {
							i_relation.inLayout = true;

							Ext.applyIf(i_relation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_relation);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_affiliations, function(i_affiliation) {
						if ("affiliation-" + o_item == i_affiliation.itemId) {
							i_affiliation.inLayout = true;

							Ext.applyIf(i_affiliation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_affiliation);
						}
					});
				}
			}
		});

		a_children.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var i_panel = Ext.widget("panel", {
			title: o_layout.title ? ip2.i18n(o_layout.title) : "",
			collapsible: o_layout.collapsible ? o_layout.collapsible : false,
			collapsed: o_layout.collapsed ? o_layout.collapsed : false,
			bodyPadding: o_layout.bodyPadding ? o_layout.bodyPadding : 0,
			border: o_layout.border ? o_layout.border : false,
			flex: o_layout.flex,
			width: o_layout.width ? o_layout.width : undefined,
			height: o_layout.height ? o_layout.height : undefined,
			minWidth: o_layout.minWidth ? o_layout.minWidth : undefined,
			minHeight: o_layout.minHeight ? o_layout.minHeight : undefined,
			maxWidth: o_layout.maxWidth ? o_layout.maxWidth : undefined,
			maxHeight: o_layout.maxHeight ? o_layout.maxHeight : undefined,
			split: o_layout.hasOwnProperty("split") ? o_layout.split : undefined,
			layout: {
				type: o_layout.type,
				align: "stretch"
			},
			defaults: o_layout.defaults || {},
			items: a_children,
			dataParent: dataParent,
			autoScroll: o_layout.autoScroll ? o_layout.autoScroll : false
		});
		return i_panel;
	},

	accordion: function(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent) {

		var i_self = this;
		var a_layoutItems = o_layout.items;
		var a_panels = [];
		Ext.Array.each(a_layoutItems, function(o_layoutItem) {

			var a_children = [];
			var b_layout = false;
			var a_items = o_layoutItem.items || [];

			Ext.Array.each(a_items, function(o_item, n_index) {
				if (Ext.isObject(o_item)) {
					if (o_item.type || o_item.layout) {
						var o_layout = o_item.layout || o_item;
						var i_return = i_self.create(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
						a_children.push(i_return);
					}
				}
				else {
					var b_found = false;
					Ext.Array.each(a_groups, function (o_group) {
						if (o_item == o_group.name) {

							Ext.applyIf(o_group, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(o_group);
							b_found = true;
						}
					});
					if (!b_found) {
						Ext.Array.each(a_widgets, function (o_widget) {
							if ("widget-" + o_item == o_widget.itemId) {
								o_widget.inLayout = true;

								Ext.applyIf(o_widget, {
									sequence: n_index,
									flex: 1
								});

								a_children.push(o_widget);
							}
						});
					}
					if (!b_found) {
						Ext.Array.each(a_relations, function (i_relation) {
							if (o_item == i_relation.itemId) {
								i_relation.inLayout = true;

								Ext.applyIf(i_relation, {
									sequence: n_index,
									flex: 1
								});

								a_children.push(i_relation);
							}
						});
					}
					if (!b_found) {
						Ext.Array.each(a_affiliations, function (i_affiliation) {
							if ("affiliation-" + o_item == i_affiliation.itemId) {
								i_affiliation.inLayout = true;

								Ext.applyIf(i_affiliation, {
									sequence: n_index,
									flex: 1
								});

								a_children.push(i_affiliation);
							}
						});
					}
				}
			});

			a_children.sort(function(a, b) {
				var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
				var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

				var n_min = Math.min(n_a, n_b);

				return n_min;
			});

			var i_panel = Ext.widget("panel", {
				title: o_layoutItem.title ? ip2.i18n(o_layoutItem.title) : "",
				collapsible: o_layoutItem.collapsible ? o_layoutItem.collapsible : false,
				collapsed: o_layoutItem.collapsed ? o_layoutItem.collapsed : false,
				bodyPadding: o_layoutItem.bodyPadding ? o_layoutItem.bodyPadding : 0,
				border: o_layoutItem.border ? o_layoutItem.border : false,
				flex: o_layoutItem.flex,
				width: o_layout.width ? o_layout.width : undefined,
				height: o_layout.height ? o_layout.height : undefined,
				minWidth: o_layout.minWidth ? o_layout.minWidth : undefined,
				minHeight: o_layout.minHeight ? o_layout.minHeight : undefined,
				maxWidth: o_layout.maxWidth ? o_layout.maxWidth : undefined,
				maxHeight: o_layout.maxHeight ? o_layout.maxHeight : undefined,
				defaults: o_layoutItem.defaults || {},
				layout: {
					type: b_layout ? "fit" : "anchor"
				},
				items: a_children,
				dataParent: dataParent,
				autoScroll: o_layoutItem.autoScroll ? o_layoutItem.autoScroll : false
			});
			a_panels.push(i_panel);
		});

		var i_panel = Ext.widget("panel", {
			title: o_layout.title ? ip2.i18n(o_layout.title) : "",
			collapsible: o_layout.collapsible ? o_layout.collapsible : false,
			collapsed: o_layout.collapsed ? o_layout.collapsed : false,
			bodyPadding: o_layout.bodyPadding ? o_layout.bodyPadding : 0,
			border: o_layout.border ? o_layout.border : false,
			flex: o_layout.flex,
			width: o_layout.width ? o_layout.width : undefined,
			height: o_layout.height ? o_layout.height : undefined,
			minWidth: o_layout.minWidth ? o_layout.minWidth : undefined,
			minHeight: o_layout.minHeight ? o_layout.minHeight : undefined,
			maxWidth: o_layout.maxWidth ? o_layout.maxWidth : undefined,
			maxHeight: o_layout.maxHeight ? o_layout.maxHeight : undefined,
			defaults: o_layout.defaults || {},
			split: o_layout.hasOwnProperty("split") ? o_layout.split : undefined,
			layout: {
				type: o_layout.type
			},
			items: a_panels,
			dataParent: dataParent,
			autoScroll: o_layout.autoScroll ? o_layout.autoScroll : false
		});

		return i_panel;
	},

	fit: function(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent) {

		var i_self = this;
		var a_items = o_layout.items;
		var a_children = [];

		Ext.Array.each(a_items, function(o_item, n_index) {

			if (Ext.isObject(o_item)) {

				if (o_item.type || o_item.layout) {

					var o_layout = o_item.layout || o_item;
					var i_return = i_self.create(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
					a_children.push(i_return);
				}
			}
			else {
				var b_found = false;
				Ext.Array.each(a_groups, function (o_group) {
					if (o_item == o_group.name) {

						Ext.applyIf(o_group, {
							sequence: n_index,
							flex: 1
						});

						a_children.push(o_group);
						b_found = true;
					}
				});
				if (!b_found) {
					Ext.Array.each(a_widgets, function (o_widget) {
						if ("widget-" + o_item == o_widget.itemId) {
							o_widget.inLayout = true;

							Ext.applyIf(o_widget, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(o_widget);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_relations, function (i_relation) {
						if (o_item == i_relation.itemId) {
							i_relation.inLayout = true;

							Ext.applyIf(i_relation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_relation);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_affiliations, function (i_affiliation) {
						if ("affiliation-" + o_item == i_affiliation.itemId) {
							i_affiliation.inLayout = true;

							Ext.applyIf(i_affiliation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_affiliation);
						}
					});
				}
			}
		});

		a_children.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var i_panel = Ext.widget("panel", {
			title: o_layout.title ? ip2.i18n(o_layout.title) : "",
			collapsible: o_layout.collapsible ? o_layout.collapsible : false,
			collapsed: o_layout.collapsed ? o_layout.collapsed : false,
			bodyPadding: o_layout.bodyPadding ? o_layout.bodyPadding : 0,
			border: o_layout.border ? o_layout.border : false,
			flex: o_layout.flex,
			width: o_layout.width ? o_layout.width : undefined,
			height: o_layout.height ? o_layout.height : undefined,
			minWidth: o_layout.minWidth ? o_layout.minWidth : undefined,
			minHeight: o_layout.minHeight ? o_layout.minHeight : undefined,
			maxWidth: o_layout.maxWidth ? o_layout.maxWidth : undefined,
			maxHeight: o_layout.maxHeight ? o_layout.maxHeight : undefined,
			defaults: o_layout.defaults || {},
			split: o_layout.hasOwnProperty("split") ? o_layout.split : undefined,
			layout: {
				type: o_layout.type
			},
			items: a_children,
			dataParent: dataParent,
			autoScroll: o_layout.autoScroll ? o_layout.autoScroll : false
		});
		return i_panel;
	},

	anchor: function(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent) {

		var i_self = this;
		var a_items = o_layout.items;
		var a_children = [];

		Ext.Array.each(a_items, function(o_item, n_index) {

			if (Ext.isObject(o_item)) {

				if (o_item.type || o_item.layout) {
					var o_layout = o_item.layout || o_item;
					var i_return = i_self.create(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
					a_children.push(i_return);
				}
			}
			else {
				var b_found = false;
				Ext.Array.each(a_groups, function (o_group) {
					if (o_item == o_group.name) {

						Ext.applyIf(o_group, {
							sequence: n_index,
							flex: 1
						});

						a_children.push(o_group);
						b_found = true;
					}
				});
				if (!b_found) {
					Ext.Array.each(a_widgets, function (o_widget) {
						if ("widget-" + o_item == o_widget.itemId) {
							o_widget.inLayout = true;

							Ext.applyIf(o_widget, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(o_widget);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_relations, function (i_relation) {
						if (o_item == i_relation.itemId) {
							i_relation.inLayout = true;

							Ext.applyIf(i_relation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_relation);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_affiliations, function (i_affiliation) {
						if ("affiliation-" + o_item == i_affiliation.itemId) {
							i_affiliation.inLayout = true;

							Ext.applyIf(i_affiliation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_affiliation);
						}
					});
				}
			}
		});

		a_children.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var i_panel = Ext.widget("panel", {
			title: o_layout.title ? ip2.i18n(o_layout.title) : "",
			collapsible: o_layout.collapsible ? o_layout.collapsible : false,
			collapsed: o_layout.collapsed ? o_layout.collapsed : false,
			bodyPadding: o_layout.bodyPadding ? o_layout.bodyPadding : 0,
			border: o_layout.border ? o_layout.border : false,
			flex: o_layout.flex,
			width: o_layout.width ? o_layout.width : undefined,
			height: o_layout.height ? o_layout.height : undefined,
			minWidth: o_layout.minWidth ? o_layout.minWidth : undefined,
			minHeight: o_layout.minHeight ? o_layout.minHeight : undefined,
			maxWidth: o_layout.maxWidth ? o_layout.maxWidth : undefined,
			maxHeight: o_layout.maxHeight ? o_layout.maxHeight : undefined,
			split: o_layout.hasOwnProperty("split") ? o_layout.split : undefined,
			layout: {
				type: o_layout.type
			},
			dataParent: dataParent,
			defaults: o_layout.defaults || {
				"anchor": "100%"
			},
			items: a_children,
			autoScroll: o_layout.autoScroll ? o_layout.autoScroll : true
		});

		return i_panel;
	},

	tabpanel: function(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent) {

		var i_self = this;
		var a_items = o_layout.items;
		var a_children = [];

		Ext.Array.each(a_items, function(o_item, n_index) {

			if (Ext.isObject(o_item)) {

				if (o_item.type || o_item.layout) {
					var o_layout = o_item.layout || o_item;
					var i_return = i_self.create(o_layout, a_groups, a_widgets, a_relations, a_affiliations, dataParent);
					a_children.push(i_return);
				}
			}
			else {
				var b_found = false;
				Ext.Array.each(a_groups, function (o_group) {
					if (o_item == o_group.name) {

						Ext.applyIf(o_group, {
							sequence: n_index,
							flex: 1
						});

						a_children.push(o_group);
						b_found = true;
					}
				});
				if (!b_found) {
					Ext.Array.each(a_widgets, function (o_widget) {
						if ("widget-" + o_item == o_widget.itemId) {
							o_widget.inLayout = true;

							Ext.applyIf(o_widget, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(o_widget);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_relations, function (i_relation) {
						if (o_item == i_relation.itemId) {
							i_relation.inLayout = true;

							Ext.applyIf(i_relation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_relation);
						}
					});
				}
				if (!b_found) {
					Ext.Array.each(a_affiliations, function (i_affiliation) {
						if ("affiliation-" + o_item == i_affiliation.itemId) {
							i_affiliation.inLayout = true;

							Ext.applyIf(i_affiliation, {
								sequence: n_index,
								flex: 1
							});

							a_children.push(i_affiliation);
						}
					});
				}
			}
		});

		a_children.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var i_panel = Ext.widget("tabpanel", {
			title: o_layout.title ? ip2.i18n(o_layout.title) : "",
			collapsible: o_layout.collapsible ? o_layout.collapsible : false,
			collapsed: o_layout.collapsed ? o_layout.collapsed : false,
			bodyPadding: o_layout.bodyPadding ? o_layout.bodyPadding : 0,
			border: o_layout.border ? o_layout.border : false,
			flex: o_layout.flex,
			width: o_layout.width ? o_layout.width : undefined,
			height: o_layout.height ? o_layout.height : undefined,
			minWidth: o_layout.minWidth ? o_layout.minWidth : undefined,
			minHeight: o_layout.minHeight ? o_layout.minHeight : undefined,
			maxWidth: o_layout.maxWidth ? o_layout.maxWidth : undefined,
			maxHeight: o_layout.maxHeight ? o_layout.maxHeight : undefined,
			split: o_layout.hasOwnProperty("split") ? o_layout.split : undefined,
			layout: "fit",
			items: a_children
		});
		return i_panel;
	},

	portal: function(o_layout, a_fields, a_groups, a_widgets, a_relations, dataParent) {

		var i_self = this;
		var a_columnsitems = o_layout.items;
		var a_columns = [];

		Ext.Array.each(a_columnsitems, function(o_column) {

			var a_items = o_column.items;
			var a_children = [];
			var a_portlets = [];

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

				if (Ext.isObject(o_item)) {

					if (o_item.type || o_item.layout) {

						var o_layout = o_item.layout || o_item;
						var i_return = i_self.create(o_layout, a_fields, a_groups, a_widgets, a_relations, dataParent);

						var i_portlet = Ext.widget("portlet", {
							title: o_item.title ? ip2.i18n(o_item.title) : "",
							collapsible: o_item.collapsible ? o_item.collapsible : true,
							collapsed: o_item.collapsed ? o_item.collapsed : false,
							closable: o_item.closable ? o_item.closable : true,
							resizable: false,
							bodyPadding: o_item.bodyPadding ? o_item.bodyPadding : 0,
							border: o_item.border ? o_item.border : false,
							dataParent: dataParent,
							items: [
								i_return
							]
						});
						a_portlets.push(i_portlet);
					}
				}
			});

			var i_panel = Ext.widget("portalcolumn", {
				flex: o_column.flex,
				width: o_column.width,
				height: o_column.height,
				items: a_portlets,
				dataParent: dataParent,
				autoScroll: o_column.autoScroll ? o_column.autoScroll : true
			});

			a_columns.push(i_panel);
		});

		var i_panel = Ext.widget("portalpanel", {
			title: o_layout.title ? ip2.i18n(o_layout.title) : "",
			collapsible: o_layout.collapsible ? o_layout.collapsible : false,
			collapsed: o_layout.collapsed ? o_layout.collapsed : false,
			bodyPadding: o_layout.bodyPadding ? o_layout.bodyPadding : 0,
			border: o_layout.border ? o_layout.border : false,
			flex: o_layout.flex,
			width: o_layout.width,
			height: o_layout.height,
			layout: o_layout.type,
			items: a_columns,
			dataParent: dataParent,
			autoScroll: o_layout.autoScroll ? o_layout.autoScroll : false
		});

		return i_panel;
	}
});
Ext.define("Portfolio.entity.util.Toolbar", {

	extend: "Ext.toolbar.Toolbar",

	xtype: "portfolio-entity-toolbar",

	alias: [
		"widget.entitytoolbar",
		"widget.portfolio.entity.toolbar"
	],

	alternateClassName: [
		"Ext.ux.entity.Toolbar"
	],

	dock: "top",

	defaults: {
		margin: "0px 20px 0px 0px",
		height: 30
	},

	config: {
		grid: null,
		store: null,
		dmdInfo: null,
		model: null,
		allowNew: true,
		allowLink: true,
		allowExport: true,
		allowSearch: true,
		allowFilter: true,
		customFilter: null,
		searchField: null,
		searchCombo: true,
		entityInfo: null
	},

	listeners: {
		afterrender: {
			fn: function(i_toolbar) {

				var i_self = i_toolbar;

				var a_items = i_self.createItems();

				i_self.add(a_items);
			},
			single: true
		},
		add: {
			fn: function(i_toolbar, i_item) {

				if (i_item.isXType) {

					if (i_item.isXType("button")) {

						if (i_item.ui.indexOf("default") > -1) {

							i_item.setUI("function");
						}
					}
				}
			}
		}
	},

	requires: [
		"Ext.ux.form.field.EntityComboBox",
		"Ext.ux.form.field.Search",
		"Ext.ux.data.dmd.Proxy",
		"Ext.ux.data.dmd.Store",
		"Ext.ux.data.dmd.Reader",
		"Ext.ux.data.dmd.Writer",
		"Ext.ux.data.dmd.Types",
		"Ext.ux.themed.Button",
		"Ext.ux.themed.MenuItem"
	],

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		i_self.enableBubble([
			"editentity",
			"updateTotalCount"
		]);
	},

	createItems: function() {

		var i_self = this;
		var a_return = [];
		var a_buttons = i_self.createButtons();
		var a_functions = [];
		var i_grid = i_self.getGrid();
		var i_store = i_grid.getStore();
		var i_model = i_self.getModel();
		var a_inital = [];

		if (i_self.getAllowSearch()) {
			a_inital.push(i_self.createSearchField());
		}

		if (a_buttons.length > 0) {
			Ext.Array.each(a_buttons, function (i_button) {
				a_inital.push(i_button);
			});
		}

		var i_resultContainer = Ext.widget("container", {
			layout: "anchor",
			flex: 1
		});

		var i_searchField = Ext.widget("searchfield", {
			grid: i_grid,
			store: i_store,
			anchor: "100%",
			listeners: {
				change: {
					fn: function(i_field, value) {

						if (value) {
							i_field.onSearchClick();
						}
						else {
							if (!i_field.isDirty()) {

								i_field.onSearchClick();
							}
						}
					},
					buffer: 100
				},
				specialkey: {
					fn: function(i_field, i_event) {

						if (i_event.getKey() == Ext.event.Event.TAB) {

							i_event.stopEvent();

							var a_fields = i_resultContainer.query("checkbox") || [];

							if (a_fields.length > 0) {
								var i_focus = a_fields[!i_event.shiftKey ? 0 : a_fields.length - 1];

								i_focus.focus(false, 10);
							}
						}
					}
				}
			},
			onSearchClick: function() {

				var i_searchField = this;

				var s_value = i_searchField.getValue();

				s_value = s_value.toLowerCase();

				var i_grid = i_self.getGrid();
				var i_columnManager = i_grid.getColumnManager();
				var a_columns = i_columnManager.getColumns();

				var a_filtered = Ext.Array.filter(a_columns, function(i_column) {

					var b_searchable = i_column.hideable;

					if (s_value && b_searchable) {
						var s_text = i_column.text || "";
						s_text = s_text.toLowerCase();
						b_searchable = s_text.indexOf(s_value) > -1;
					}

					return b_searchable;
				});

				i_resultContainer.removeAll(true);

				var a_checks = [];

				Ext.Array.each(a_filtered, function(i_column) {
					var i_checkbox = Ext.widget("checkbox", {
						boxLabel: i_column.text,
						checked: i_column.isVisible(),
						dataIndex: i_column.dataIndex,
						listeners: {
							change: {
								fn: function (i_checkbox, b_checked) {

									var i_header = i_columnManager.getHeaderByDataIndex(i_checkbox.dataIndex);
									if (i_header) {
										i_header[b_checked ? "show" : "hide"]();
									}
								}
							},
							specialkey: {
								fn: function(i_checkbox, i_event) {

									if (i_event.getKey() == Ext.event.Event.TAB) {

										var a_fields = i_resultContainer.query("checkbox") || [];
										var n_index = Ext.Array.indexOf(a_fields, i_checkbox);

										if (a_fields.length - 1 == n_index && !i_event.shiftKey) {

											i_event.stopEvent();

											i_searchField.focus(true, 10);
										}
									}
								}
							}
						}
					});

					a_checks.push(i_checkbox);
				});

				i_resultContainer.add(a_checks);
			},
			onClearClick: function() {
				var i_field = this;
				i_field.setValue("");


			}
		});

		var i_searchContainer = Ext.widget("container", {
			layout: "anchor",
			bodyPadding: 20,
			items: [
				i_searchField
			]
		});

		var i_menuPanel = Ext.widget("form", {
			layout: {
				type: "vbox",
				align: "stretch"
			},
			width: 200,
			bodyPadding: 20,
			items: [
				i_searchContainer,
				i_resultContainer
			]

		});

		i_self.add(a_inital);

		i_grid.fireEvent("beforetoolbarfill", i_grid, i_self);

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

		a_return.push(i_self.createRefreshButton());

		var i_buttonColumns = Ext.widget("button", {
			iconCls: "pf-columns",
			ui: "function-action",
			tooltip: ip2.i18n({
				da: "Kolonner",
				en: "Columns"
			}),
			arrowVisible: false,
			menu: {
				items: [
					i_menuPanel
				],
				listeners: {
					beforeshow: {
						fn: function() {
	
							var i_grid = i_self.getGrid();
							var i_columnManager = i_grid.getColumnManager();
							var a_columns = i_columnManager.getColumns();
	
							Ext.suspendLayouts();
	
							i_resultContainer.removeAll(true);
	
							var a_filtered = Ext.Array.filter(a_columns, function(i_column) {
								return i_column.hideable;
							});
	
							var a_checks = [];
	
							Ext.Array.each(a_filtered, function(i_column) {
	
								var i_checkbox = Ext.widget("checkbox", {
									boxLabel: i_column.text,
									checked: i_column.isVisible(),
									dataIndex: i_column.dataIndex,
									listeners: {
										change: {
											fn: function (i_checkbox, b_checked) {
	
												var i_header = i_columnManager.getHeaderByDataIndex(i_checkbox.dataIndex);
												if (i_header) {
													i_header[b_checked ? "show" : "hide"]();
												}
											}
										},
										specialkey: {
											fn: function(i_checkbox, i_event) {
	
												if (i_event.getKey() == Ext.event.Event.TAB) {
	
													var a_fields = i_resultContainer.query("checkbox") || [];
													var n_index = Ext.Array.indexOf(a_fields, i_checkbox);
	
													if (a_fields.length - 1 == n_index && !i_event.shiftKey) {
	
														i_event.stopEvent();
	
														i_searchField.focus(true, 10);
													}
												}
											}
										}
									}
								});
	
								a_checks.push(i_checkbox);
							});
	
							i_resultContainer.add(a_checks);
	
							Ext.resumeLayouts(true);
						}
					}
				}
			},
			listeners: {
				afterrender: {
					fn: function(i_button) {

						var i_grid = i_self.getGrid();
						var i_columnManager = i_grid.getColumnManager();
						var a_columns = i_columnManager.getColumns();

						var b_visible  = a_columns.length > 0;

						i_button[b_visible ? "show":"hide"]();
					}
				}
			}
		});

		a_return.push(i_buttonColumns);

		var i_linkButton = i_self.createLinkButton(i_model.create());

		if (i_self.getAllowExport()) {
			a_functions.push(i_self.createExportButton());
		}

		if (!i_self.up("ip2widget") && i_self.getAllowLink()) {
			a_functions.push(i_linkButton);
		}

		var i_filterButton = Ext.widget("button", {
			iconCls: "pf-funnel",
			itemId: "button-filter",
			tooltip: ip2.i18n({
				da: "Filter",
				en: "Filter"
			}),
			enableToggle: true,
			ui: "function-action",
			minWidth: 32,
			hidden: !i_self.getAllowFilter(),
			toggleHandler: function(i_button, b_pressed) {

				var i_grid = i_self.getGrid();

				if (i_self.getAllowFilter()) {
					var i_filterBar = i_grid.getFilterBar();

					i_filterBar[b_pressed ? "show" : "hide"]();

					var a_filters = i_filterBar.getFilters();
					var n_count = a_filters.length;

					var s_iconCls = "pf-funnel";

					if (n_count) {
						s_iconCls = "pf-funnel_active";
					}
					else {
						s_iconCls = b_pressed ? "pf-funnel_active" :
							"pf-funnel";
					}

					i_button.setIconCls(s_iconCls);
				}
			}
		});

		i_self.on({
			afterfilter: {
				fn: function(n_filters) {

					var b_pressed = i_filterButton.pressed;

					var s_icons = "pf-funnel";

					if (n_filters) {
						s_icons = "pf-funnel_active";
					}
					else {
						s_icons = b_pressed ? "pf-funnel_active" :
							"pf-funnel";
					}

					i_filterButton.setIconCls(s_icons);
				}

			}
		});

		a_return.push(i_filterButton);

		var i_buttonFunction;

		if (a_functions.length > 1) {
			i_buttonFunction = Ext.widget("button", {
				iconCls: "pf-form_options",
				arrowVisible: false,
				itemId: "button-functions",
				ui: "function-action",
				tooltip: ip2.i18n({
					da: "Mere",
					en: "More"
				}),
				hidden: a_functions.length === 0,
				listeners: {
					afterrender: {
						fn: function (i_button) {

							var i_menu = i_button.menu;
							var a_items = i_menu.query("menuitem");

							var b_visible = a_items.length > 0;

							var b_show = false;

							Ext.Array.each(a_items, function (i_item) {
								if (!i_item.hidden) {
									b_show = true;
									return;
								}
							});

							i_button[b_visible && b_show ? "show" : "hide"]();
						}
					}
				},
				menu: {
					defaults: {
						minHeight: 30
					},
					items: a_functions,
					listeners: {
						beforeshow: {
							fn: function(i_menu) {
								
								if (i_grid.getEntityInfo) {

									var i_shift = i_menu.getComponent("menu-shift");

									if (i_shift) {
										i_menu.remove(i_shift);
									}

									var o_info = i_grid.getEntityInfo();
									var o_entity = o_info.entity || {};

									var o_ui = o_entity.ui || {};
									var o_grids = o_ui.grids || {};

									var a_grids = Ext.Object.getKeys(o_grids);

									var s_current = i_grid.getUiName();

									var a_filtered = Ext.Array.filter(a_grids, function(s_view) {
										return s_view != s_current;
									});

									var a_items = [];

									Ext.Array.each(a_filtered, function(s_key) {

										var o_view = o_grids[s_key];
										var s_title = ip2.i18n(o_view.title);

										if (o_view.listable) {
											var i_menuitem = Ext.widget("menuitem", {
												text: s_title || s_key,
												handler: function() {
													i_grid.fireEvent("changeview", s_key);
												}
											});
	
											a_items.push(i_menuitem);
										}
									});

									if (a_items.length > 0) {

										i_shift = Ext.widget("menuitem", {
											itemId: "menu-shift",
											text: ip2.i18n({
												da: "Vis",
												en: "Show"
											}),
											menu: {
												plain: true,
												items: a_items
											}
										});
	
										i_menu.add(i_shift);
									}
								}
							}
						}
					}
				}
			});
		}
		else {

			var o_initConfig = Ext.clone(i_linkButton.initialConfig);

			Ext.apply(o_initConfig, {
				ui: "function-action",
				text: "",
				tooltip: o_initConfig.text,
				hidden: !i_self.getAllowLink()
			});

			i_buttonFunction = Ext.widget("button", o_initConfig);
		}

		a_return.push(i_buttonFunction);

		a_return.push({
			xtype: "tbspacer",
			width: 20
		});

		if (i_model) {
			var i_dummy = i_model.create({});
			var o_entity = ip2.getEntityFromRecord(i_dummy);

			if (o_entity.language) {
				a_return.unshift("-");
				a_return.unshift(i_self.createLanguageField());
			}
		}

		i_self.fireEvent("afterfunctions", i_self, i_buttonFunction);

		return a_return;
	},

	createTotalLabel: function(n_total) {

		var a_items = [
			{
				xtype: "tbfill"
			},
			{
				xtype: "tbtext",
				itemId: "lbl_total",
				html: ip2.i18n({
					da: "Total: ",
					en: "Total: "
				}) + n_total
			}
		];
		return a_items;
	},

	createRefreshButton: function() {

		var i_self = this;

		var i_button = Ext.widget("button", {
			iconCls: "pf-arrow_circle",
			itemId: "button-refresh",
			ui: "function-action",
			handler: function() {

				var i_store = i_self.getStore();
				var o_sorters = i_store.getSorters();

				if (i_store.clearAndLoad) {
					i_store.clearAndLoad({
						callback: function() {
							i_store.fireEvent("sort", i_store, o_sorters.getRange());
						}
					});
				}
				else {

					if (i_store.isTreeStore)  {

						var i_rootNode = i_store.getRootNode();

						i_rootNode.collapse();
						i_rootNode.removeAll(false);

						i_store.load({
							callback: function() {
								i_rootNode.expand();
							}
						});
					}
					else {
						i_store.load({
							callback: function() {
								i_store.fireEvent("sort", i_store, o_sorters.getRange());
							}
						});
					}

				}
			}
		});

		return i_button;
	},

	createButtons: function() {

		var i_self = this;
		var a_return = [];
		var o_dmdCfg = i_self.getDmdInfo();

		var o_dmdInfo = ip2.dmd.getInfo({
			dmd: o_dmdCfg.dmd,
			entity: o_dmdCfg.entityName,
			view: o_dmdCfg.uiName,
			context: "grid"
		});

		var b_editable = true;
		var o_entity = o_dmdInfo.entity;
		var o_permission = o_entity.permission;

		if (o_permission) {
			if (o_permission.add) {
				if (o_permission.add.grid !== undefined) {
					b_editable = o_permission.add.grid;
				}
			}
		}

		if (i_self.getAllowNew()) {

			var o_view = o_dmdInfo.view;

			var o_drop = o_view.drop || {
				entities: []
			};

			var i_addButton;

			if (o_drop.entities.length < 2) {
				i_addButton = Ext.widget("button", {
					itemId: "button-add",
					text: ip2.i18n({
						en: "Create",
						da: "Opret"
					}),
					ui: "function",
					disabled: !b_editable ? true : false,
					handler: function() {
						if (i_self.addMode == "form") {

							var i_grid = i_self.getGrid();

							i_grid.handleAction(null, "create", 0);
						}
					}
				});
				a_return.push(i_addButton);
			}
			else {

				var a_items = [];

				var o_model = o_dmdInfo.dmd.model;
				var a_entities = o_model.entities;

				Ext.Array.each(o_drop.entities, function(o_value) {

					var o_entity = Ext.Array.findBy(a_entities, function(o_config) {
						return o_config.name == o_value.name;
					});

					var i_menuitem = Ext.widget("menuitem", {
						itemId: "button-add-" + o_value.name,
						text: ip2.i18n(o_entity.title),
						iconCls: "pf-add",
						disabled: !b_editable ? true : false,
						handler: function() {

							var o_config = Ext.apply({}, {
								dmd: o_value.dmd,
								entity: o_value.name,
								entityName: o_value.name,
								uiName: o_value.view || "portfolio",
								context: "form"
							});

							var i_model = ip2.model(o_config);

							var i_record = i_model.create({});

							if (i_self.addMode == "form") {
								var i_grid = i_self.getGrid();

								i_grid.handleAction(i_record, "update", 0);
							}
						}
					});

					a_items.push(i_menuitem);
				});

				var i_menu = Ext.widget("menu", {
					items: a_items
				});

				var i_button = Ext.widget("button", {
					itemId: "button-add",
					ui: "function",
					text: ip2.i18n({
						en: "Create",
						da: "Opret"
					}),
					disabled: !b_editable ? true : false,
					menu: i_menu
				});

				a_return.push(i_button);
			}
		}

		return a_return;
	},

	createLinkButton: function(i_model) {


		var i_button = Ext.widget("menuitem", {
			text: "Link",
			itemId: "button-link",
			iconCls: "pf-link",
			handler: function() {

				var i_window = Ext.widget("link.window", {
					model: i_model
				});
				i_window.show();
			}
		});

		return i_button;
	},

	createSearchField: function() {

		var i_self = this;
		var i_grid = i_self.getGrid();
		var i_store = i_grid.getStore();
		var o_dmdCfg = i_self.getDmdInfo();
		var s_view = o_dmdCfg.view ? o_dmdCfg.view : o_dmdCfg.uiName;
		var b_searchCombo = i_self.getSearchCombo();
		var o_entityInfo = i_self.getEntityInfo();

		var o_dmd = o_entityInfo.dmd;
		var o_model = o_dmd.model;
		var o_proxy = o_model.proxy || {};

		var s_xtype = b_searchCombo ? "entitycombo" : "searchfield";

		var o_fieldConfig = {
			itemId: "search",
			width: 300,
			isFormField: false,
			enableKeyEvents: true,
			grid: i_self.getGrid(),
			ui: "function-field"
		};

		var o_extra = Ext.applyIf({
			limit: 100
		}, i_grid.extraParams, {
			filter: i_grid.filter ? i_grid.filter : (i_self.customFilter ? [] : void 0)
		});

		if (b_searchCombo) {

			Ext.apply(o_fieldConfig, {
				dmd: o_dmdCfg.dmd,
				entity: o_dmdCfg.entityName,
				view: s_view,
				autoSelect: false,
				autoLoad: false,
				typeAhead: false,
				pageSize: 100,
				customFilter: i_self.customFilter
			});

			if (o_proxy.hasOwnProperty("portfolio") && !o_proxy.portfolio) {
				s_xtype = "restentitypicker";
			}
		}
		else {
			Ext.apply(o_fieldConfig, {
				extraParams: o_extra,
				enableKeyEvents: true,
				store: i_store
			});
		}

		var i_field = Ext.widget(s_xtype, o_fieldConfig);

		if (b_searchCombo) {

			i_field.onSearchClick = function() {

				var i_field = this;
				var i_grid = i_self.getGrid() ? i_self.getGrid() : i_self.up("gridpanel");
				var i_store = i_grid.getStore();
				var i_proxy = i_store.getProxy();
				var o_extraParams = i_proxy.getExtraParams();
				var o_sorters = i_store.getSorters();
				var value = i_field.getRawValue();

				if (value.length > 0) {
					o_extraParams.search = value;
				}
				else {
					delete o_extraParams.search;
				}
				if (i_store.clearAndLoad) {
					i_store.clearAndLoad({
						callback: function() {
							i_store.fireEvent("sort", i_store, o_sorters.getRange());
						}
					});
				}
				else {
					i_store.load({
						callback: function() {
							i_store.fireEvent("sort", i_store, o_sorters.getRange());
						}
					});
				}
			};

			i_field.onClearClick = function() {

				var i_grid = i_self.getGrid() ? i_self.getGrid() : i_self.up("gridpanel");
				var i_store = i_grid.getStore();
				var i_proxy = i_store.getProxy();
				var o_extraParams = i_proxy.getExtraParams();
				var o_sorters = i_store.getSorters();

				i_field.setSelection(null);
				i_field.clearValue();

				i_field.cancelSearch = false;

				if (Ext.isFunction(i_field.setUnion)) {
					i_field.setUnion("");
				}

				delete o_extraParams.search;

				if (i_store.clearAndLoad) {
					i_store.clearAndLoad({
						callback: function() {
							i_store.fireEvent("sort", i_store, o_sorters.getRange());
						}
					});
				}
				else {
					i_store.load({
						callback: function() {
							i_store.fireEvent("sort", i_store, o_sorters.getRange());
						}
					});
				}

				return i_field;
			};

			i_field.on({
				select: {
					fn: function(i_field, i_selected) {

						var i_record = Ext.isArray(i_selected) ? i_selected[0] : i_selected;

						if (i_field.selectFn) {
							i_field.selectFn(i_record);
						}
						else {
							var i_grid = i_self.getGrid() ? i_self.getGrid() : i_self.up("gridpanel");

							if (i_grid.getModelConfig && i_record) {

								var o_config = i_grid.getModelConfig();
								var s_dmd = i_grid.dmdName;
								var s_entity = o_config.entityName;

								if (ip2.isAccessible("app." + s_dmd + ".data.update") ||
									ip2.isAccessible("app." + s_dmd + ".data.read") ||
									ip2.isAccessible("app." + s_dmd + ".data.copy") ||
									ip2.isAccessible("app." + s_dmd + ".data." + s_entity + ".update") ||
									ip2.isAccessible("app." + s_dmd + ".data." + s_entity + ".read") ||
									ip2.isAccessible("app." + s_dmd + ".data." + s_entity + ".copy")) {
									i_grid.handleAction(i_record, "update", 0);
								}
							}
						}
					}
				},
				specialkey: {
					fn: function(f, e) {
						if (e.getKey() == e.ENTER) {
							if (i_field.picker) {
								if (i_field.picker.getNavigationModel()) {
									if (!i_field.picker.getNavigationModel().record) {
										i_field.cancelSearch = true;
										i_field.onSearchClick();
										i_field.collapse();
									}
								}
							}
							else {
								i_field.cancelSearch = true;
								i_field.onSearchClick();
							}
						}
					}
				},
				afterrender: {
					fn: function(i_item) {
						setTimeout(function() {
							i_field.focus(false, 100);
						}, 0);
					}
				},
				collapse: {
					fn: function(i_field) {
						if (i_field.picker) {
							if (i_field.picker.getNavigationModel()) {
								i_field.picker.getNavigationModel().record = null;
							}
						}
					}
				},
				beforequery: {
					fn: function() {

						var i_self = this;
						if (Ext.isFunction(i_self.setUnion)) {
							i_self.setUnion("");
						}

						var b_cancel = !i_self.cancelSearch;
						if (!b_cancel) {
							i_self.cancelSearch = false;
						}
						return b_cancel;
					}
				}
			});

			i_store.field = i_field;
			i_store.grid = i_grid;
		}

		i_self.setSearchField(i_field);

		return i_field;
	},

	createLanguageField: function() {

		var wsh = wsh;
		var i_self = this;
		var a_languages = wsh.getLanguages();
		var s_lang = "";

		if (navigator.appName == "Microsoft Internet Explorer") {
			s_lang = navigator.browserLanguage.split("-").shift();
		}
		else {
			s_lang = navigator.language.split("-").shift();
		}

		if (a_languages.indexOf(s_lang) == -1) {
			s_lang = wsh.i18n.getPrimary();
		}
		else {
			if (a_languages.indexOf(s_lang) !== 0) {
				var n_index = a_languages.indexOf(s_lang);
				var s_value = a_languages.splice(n_index, 1)[0];
				a_languages.unshift(s_value);
				s_lang = s_value;
			}
		}

		var a_items = [];

		Ext.Array.each(a_languages, function(s_value) {
			var o_record = {
				xtype: "menuitem",
				key: s_value,
				text: wsh.i18n.getEnum(s_value),
				iconCls: "AIL-icon AIL-icon-16 icon-flag_" + s_value,
				handler: function(i_menuitem) {
					var i_button = i_menuitem.up("#button-language");
					if (i_button) {
						i_button.setIconCls("AIL-icon AIL-icon-16 icon-flag_" + i_menuitem.key);
						i_button.key = i_menuitem.key;
					}
					var i_store = i_self.getGrid().getStore();
					i_store.load();
				}
			};
			a_items.push(o_record);
		});

		var i_menu = Ext.widget("button", {
			key: s_lang,
			itemId: "button-language",
			iconCls: "AIL-icon AIL-icon-16 icon-flag_" + s_lang,
			menu: {
				items: a_items
			}
		});

		return i_menu;
	},

	createRadioRows: function() {

		var i_self = this;
		var a_items = [];
		var o_dmdInfo = i_self.getDmdInfo();
		var s_dmd = o_dmdInfo.dmd;
		var b_all = true;

		a_items.push({
			boxLabel: ip2.i18n({
				en: "All",
				da: "Alle"
			}),
			checked: true,
			name: "rb-row",
			inputValue: 0
		});

		a_items.push({
			boxLabel: ip2.i18n({
				en: "Displayed",
				da: "Viste"
			}),
			checked: !b_all,
			name: "rb-row",
			inputValue: 1
		});

		// if (ip2.isAccessible("app." + s_dmd + ".data." + i_grid.entity.name + ".export.rows")) {
		// 	a_items.push({
		// 		boxLabel: ip2.i18n({
		// 			en: "All",
		// 			da: "Alle"
		// 		}),
		// 		checked: true,
		// 		name: "rb-row",
		// 		inputValue: 0
		// 	});
		// }
		// if (ip2.isAccessible("app." + s_dmd + ".data." + i_grid.entity.name + ".export.visiblerows")) {
		// 	a_items.push({
		// 		boxLabel: ip2.i18n({
		// 			en: "Displayed",
		// 			da: "Viste"
		// 		}),
		// 		checked: !b_all,
		// 		name: "rb-row",
		// 		inputValue: 1
		// 	});
		// }

		return a_items;
	},

	createExportButton: function () {

		var i_self = this;
		var i_store = Ext.create("Ext.data.Store", {
			fields: ["key", "value"],
			data: [
				{
					"key": 0,
					"value": ip2.i18n({
						en: "Excel",
						da: "Excel"
					})
				}
			]
		});

		var i_button = Ext.widget("menuitem", {
			text: ip2.i18n({
				en: "Export",
				da: "Eksporter"
			}),
			itemId: "buttonExport",
			iconCls: "pf-cloud_download",
			storeFormat: i_store,
			handler: function (item) {

				var i_formpanel = Ext.widget("form", {
					itemId: "formExport",
					layout: "anchor",
					items: [
						{
							xtype: "radiogroup",
							itemId: "col",
							name: "col",
							fieldLabel: ip2.i18n({
								en: "Columns",
								da: "Kolonner"
							}),
							items: [
								{
									boxLabel: ip2.i18n({
										en: "All",
										da: "Alle"
									}),
									checked: true,
									name: "rb-col",
									inputValue: 0
								},
								{
									boxLabel: ip2.i18n({
										en: "Visible",
										da: "Synlige"
									}),
									name: "rb-col",
									inputValue: 1
								}
							]
						},
						{
							xtype: "radiogroup",
							itemId: "row",
							name: "row",
							fieldLabel: ip2.i18n({
								en: "Rows",
								da: "Rækker"
							}),
							items: i_self.createRadioRows()
						},
						{
							xtype: "combobox",
							itemId: "format",
							name: "format",
							store: i_button.storeFormat,
							anchor: "100%",
							labelAlign: "left",
							fieldLabel: ip2.i18n({
								en: "Format",
								da: "Format"
							}),
							queryMode: "local",
							displayField: "value",
							valueField: "key",
							readOnly: true,
							listeners: {
								afterrender: function (item) {
									this.setValue(0);
								}
							}
						}
					]
				});

				var i_window = Ext.widget("window", {
					title: ip2.i18n({
						en: "Export data",
						da: "Eksporter data"
					}),
					ui: "message",
					closable: true,
					modal: true,
					width: 350,
					layout: "fit",
					items: [
						i_formpanel
					],
					buttons: [
						{
							text: ip2.i18n({
								en: "Export",
								da: "Eksporter"
							}),
							handler: function (button) {

								var i_window = button.up("window");
								var i_form = i_formpanel.getForm();
								var o_values = i_form.getFieldValues();
								var url = "ip2-services/ip2dmdProxy.aspx?action=export";

								var i_grid = i_self.getGrid();
								var i_filterBar = i_grid.getFilterBar();
								var i_store = i_grid.getStore();
								var i_proxy = i_store.getProxy();
								var o_extraParams = i_proxy.getExtraParams();
								var o_sorters = i_store.getSorters();
								var s_format = "CVS";

								var o_dmdCfg = i_self.getDmdInfo();
								var a_columns = [];
								var s_search = o_extraParams.search || "";

								//Extracting values from rbColumns
								var n_col = o_values["rb-col"] || 0;

								//Extracting values from rbRows
								var n_row = o_values["rb-row"] || 0;

								//Extracting values from cmbFormat
								var n_format = o_values.format || 0;

								var n_start = 0;
								var n_limit = -1;
								var a_gridcolumns = [];

								if (n_col == 1) {
									a_gridcolumns = i_grid.getColumnManager().getColumns();
								}
								else {
									a_gridcolumns = i_grid.columns;
								}

								Ext.Array.each(a_gridcolumns, function(i_column) {
									a_columns.push({
										name: i_column.dataIndex,
										label: ip2.i18n(i_column.text)
									});
								});

								if (n_row == 1) {
									n_limit = i_store.getPageSize();
								}

								var s_sort = Ext.Array.map(o_sorters.items, function (i_sorter) {
									return i_sorter.getProperty() + " " + i_sorter.getDirection() || "ASC";
								}).join(", ");

								switch (n_format) {
									case 0:
										s_format = "CVS";
										break;
									case 1:
										s_format = "XML";
										break;
								}

								var s_where = o_extraParams.where;

								if (!s_where) {
									s_where = i_filterBar ? i_filterBar.getWhere() : "";
								}

								var i_submitpanel = Ext.create("Ext.form.Panel", {
									standardSubmit: true,         // this is the important part
									url: url
								});

								i_submitpanel.submit({
									params: {
										entity: o_dmdCfg.entityName,
										context: "grid",
										uiName: o_dmdCfg.view || o_dmdCfg.uiName || "portfolio",
										dmd: o_dmdCfg.dmd,
										columns: JSON.stringify(a_columns),
										sort: s_sort,
										search: s_search,
										start: n_start,
										limit: n_limit,
										format: s_format,
										where: s_where
									}
								});

								i_window.close();
							}
						},
						{
							text: ip2.i18n({
								en: "Cancel",
								da: "Annuller"
							}),
							handler: function (item) {
								i_window.close();
							}
						}
					]
				});
				i_window.show();
			}
		});
		return i_button;
	},

	removeRefresh: function() {

		var i_self = this;
		var n_return = -1;

		var i_button = i_self.items.get("button-refresh");

		if (i_button) {
			n_return = i_self.items.indexOf(i_button);
			i_self.remove(i_button, true);
		}

		return -1;
	},

	removeExport: function() {

		var i_self = this;
		var n_return = -1;

		var i_button = i_self.items.get("buttonExport");

		if (i_button) {
			n_return = i_self.items.indexOf(i_button);
			i_self.remove(i_button, true);
		}

		return -1;
	},

	removeAdd: function() {

		var i_self = this;
		var n_return = -1;

		var i_button = i_self.items.get("button-add");

		if (i_button) {
			n_return = i_self.items.indexOf(i_button);
			i_self.remove(i_button, true);
		}

		return -1;
	},

	hideLink: function() {

		var i_self = this;
		var i_button = i_self.items.get("button-link");
		if (i_button) {
			i_button.hide();
		}
	},

	updateAllowFilter: function(b_allow) {

		var i_self = this;
		if (!i_self.isConfiguring) {
			var i_filterButton = i_self.getComponent("button-filter");

			if (i_filterButton) {
				i_filterButton[b_allow ? "show" : "hide"]();
			}
		}
	},

	updateStore: function(i_store) {

		var i_self = this;
		var i_grid = i_self.getGrid();
		var i_searchField = i_self.getSearchField();

		if (i_searchField && !i_searchField.isXType("combobox")) {
			i_searchField.store = i_store;
		}

		if (i_grid) {

			if (i_grid.hasOwnProperty("getShowTotalCount") && i_grid.getShowTotalCount()) {

				i_store.on({
					load: {
						fn: function(store, a_records) {

							var n_total = i_store.getTotalCount();

							if (i_grid.xtype == "ux.entity.tree") {

								n_total = 0;

								var i_root = i_grid.getRootNode();
								i_root.cascadeBy(function(i_node) {
									n_total++;
								});
							}

							i_self.fireEvent("updateTotalCount", n_total);
						}
					}
				});
			}
		}
	}
});
Ext.define("Portfolio.entity.controller.Form", {
	extend: "Ext.app.ViewController",

	alias: "controller.portfolio-entity-form",

	onLanguageChange: function(i_formpanel, s_language) {

		var i_controller = this;
		var i_view = i_controller.getView();

		i_view.setLanguageChange(true);
		i_view.doChangeLanguage(s_language);
		i_view.setLanguageChange(false);
	},

	onValidityChange: function(i_formpanel, b_valid) {

		var i_controller = this;
		var i_view = i_controller.getView();

		var i_actionBar = i_view.getActionbar();

		var i_saveclose = i_actionBar.items.get("saveclose");

		if (!b_valid) {
			i_saveclose.hide();
		}
		else {

			var b_dirty = i_view.isDirty();

			if (b_dirty) {
				i_view.fireEvent("dirtychange", i_view, b_dirty);
			}
		}
	},

	onDirtyChange: function(i_formpanel, b_dirty) {

		var i_controller = this;
		var i_view = i_controller.getView();

		var b_valid = i_view.isValid();

		if (b_valid) {

			var i_actionBar = i_view.getActionbar();

			var i_saveclose = i_actionBar.items.get("saveclose");

			b_dirty = i_view.isDirty();

			if (b_dirty) {
				i_saveclose.show();
			}
			else {
				i_saveclose.hide();
			}
		}
	},

	onBeforeClose: function(i_formpanel) {

		var i_controller = this;
		var i_view = i_controller.getView();

		var b_force = i_view.getForceClose();
		var b_dirty = i_view.isDirty();

		if (!b_force && b_dirty) {

			Portfolio.util.Handler.messageBox({
				closable: true,
				message: Portfolio.util.Handler.i18n({
					da: "Du er ved at lukke uden at gemme!<br>Hvordan vil du forsætte?",
					en: "You are about to close without having saved!<br>How would you like to proceed?"
				}),
				yesText: Portfolio.util.Handler.i18n({
					da: "Gem",
					en: "Save"
				}),
				yesFn: function () {
					i_view.save(function (i_record) {

						i_view.setForceClose(true);
						var i_contextParent = i_view.getContextParent();
						i_contextParent.close();
					});
				},
				noText: Portfolio.util.Handler.i18n({
					da: "Luk",
					en: "Close"
				}),
				noFn: function () {

					i_view.setForceClose(true);

					var i_contextParent = i_view.getContextParent();
					i_contextParent.close();
				}

			});
		}
		else {
			b_force = true;
		}

		return b_force;
	},

	isDirty: function() {

		var i_controller = this;
		var i_view = i_controller.getView();

		var i_tabpanel = i_view.getTabPanel();

		var o_modified = i_view.getModified();
		var a_widgets = i_view.getWidgets();
		var o_languageInfo = i_view.getLanguageInfoInformation();

		var b_dirty = false;

		if (i_tabpanel) {

			var a_tabs = i_tabpanel.items.getRange();

			var i_dirty = Ext.Array.findBy(a_tabs, function(i_tab) {

				var i_form = i_tab.getForm ? i_tab.getForm() : null;

				return i_form ? i_form.isDirty() : i_tab.isDirty ? i_tab.isDirty() : false;
			});

			if (i_dirty) {
				b_dirty = true;
			}
		}

		
		if (!b_dirty) {

			if (o_modified && o_languageInfo) {

				var a_languages = i_view.getLanguages();

				Ext.Array.each(a_languages, function(s_lang) {

					var a_modified = o_modified[s_lang] || [];

					if (a_modified.length > 0) {

						Ext.Array.each(a_modified, function(o_field) {
							if (o_field.dirty) {
								b_dirty = o_field.dirty;
								return false;
							}
						});
					}
					if (b_dirty) {
						return false;
					}
				});
			}

			if (!b_dirty) {

				Ext.Array.each(a_widgets, function(o_widget) {

					var i_widget = i_view.down("#" + o_widget.itemId);

					var i_widgetCmp = i_widget.getWidgetCmp();

					if (i_widgetCmp && i_widgetCmp.isDirty) {

						var b_widgetDirty = i_widgetCmp.isDirty();

						if (b_widgetDirty) {

							b_dirty = true;
						}
					}
				});
			}
		}

		return b_dirty;
	},

	isValid: function () {

		var i_controller = this;
		var i_view = i_controller.getView();

		var i_tabpanel = i_view.getTabPanel();

		var a_tabs = i_tabpanel.items.getRange();

		var b_valid = true;

		var i_valid = Ext.Array.findBy(a_tabs, function(i_tab) {

			var i_form = i_tab.getForm ? i_tab.getForm() : null;

			return i_form ? !i_form.isValid() : i_tab.isValid ? !i_tab.isValid() : true;
		});

		if (i_valid) {
			b_valid = true;
		}

	
		var o_languageInfo = i_view.getLanguageInfoInformation();
		var o_modified = i_view.getModified();
		var a_widgets = i_view.getWidgets();

		if (b_valid) {

			if (o_modified && o_languageInfo) {

				var a_languages = i_view.getLanguages();

				Ext.Array.each(a_languages, function(s_lang) {

					var a_modified = o_modified[s_lang] || [];

					if (a_modified.length > 0) {

						Ext.Array.each(a_modified, function(o_field) {
							if (o_field.hasOwnProperty("valid")) {
								b_valid = o_field.valid;
								return false;
							}
						});
					}

					if (!b_valid) {
						return false;
					}
				});
			}

			if (b_valid) {

				Ext.Array.each(a_widgets, function(o_widget) {

					var i_widget = i_view.down("#" + o_widget.itemId);

					var i_widgetCmp = i_widget.getWidgetCmp();

					if (i_widgetCmp && i_widgetCmp.isValid) {

						var b_widgetValid = i_widgetCmp.isValid();

						if (!b_widgetValid) {

							b_valid = false;
						}
					}
				});
			}
		}

		return b_valid;
	},

	onDelete: function() {

		var i_controller = this;
		var i_view = i_controller.getView();
		var o_model = i_view.getDmdModel();

		var i_record = i_view.getRecord();
		var i_model = i_view.getModel();
		var i_contextParent = i_view.getContextParent();

		var o_dmdInfo = i_view.getDmdInfo();
		var o_proxy = o_model.proxy;
		var o_entity = o_dmdInfo.entity;

		var i_errorTemplate = new Ext.XTemplate(Portfolio.util.Handler.i18n({
			da: "Der skete en fejl</br>Fejl:</br><strong>{message}</strong>",
			en: "An error occured</br>Error:</br><strong>{message}</strong>"
		}));

		i_errorTemplate.compile();

		Portfolio.util.Handler.messageBox({
			icon: Ext.Msg.WARNING,
			message: Portfolio.util.Handler.i18n({
				da: "Vil du slette DENNE record",
				en: "Do you want to delete THIS record..?"
			}),
			yesText: Portfolio.util.Handler.i18n({
				da: "Ja",
				en: "Yes"
			}),
			yesFn: function () {

				if (o_proxy.portfolio) {

					var a_batch = [{
						type: "delete",
						dmd: i_view.getDmd(),
						entity: o_entity.name,
						key: Portfolio.util.Handler.extractKeys(i_model, i_record)
					}];

					var s_msg = Portfolio.util.Handler.i18n({
						da: "Sletter...",
						en: "Deleting..."
					});

					i_view.setLoading(s_msg, true);

					Ext.Ajax.request({
						url: "/ip2-Services/ip2dmdproxy.aspx",
						jsonData: {
							batch: a_batch
						},
						success: function (o_response) {

							var o_result = Ext.decode(o_response.responseText, true) || {
								success: false
							};

							if (o_result.success) {
								i_view.action = "delete";
								i_view.setForceClose(true);
								i_contextParent.close();
							}
							else {

								Portfolio.util.Handler.messageBox({
									icon: Ext.Msg.WARNING,
									message: i_errorTemplate.apply({
										message: o_result.message
									}),
									yesText: Portfolio.util.Handler.i18n({
										da: "OK",
										en: "OK"
									})
								});
							}
						},
						failure: function (i_error) {


							Portfolio.util.Handler.messageBox({
								icon: Ext.Msg.WARNING,
								message: i_errorTemplate.apply({
									message: i_error.message
								}),
								yesText: Portfolio.util.Handler.i18n({
									da: "OK",
									en: "OK"
								})
							});
						}
					});
				}
				else {
					i_record.erase({
						success: function(i_record, i_operation) {

							i_view.setLoading(false);
							i_view.action = "delete";
							i_view.setForceClose(true);
							i_contextParent.close();
						},
						failure: function(i_record, i_operation) {

							i_view.setLoading(false);

							var i_error = i_operation.getError();
							var i_response = i_error.response;

							var o_response = Ext.decode(i_response.responseText);

							Portfolio.util.Handler.messageBox({
								icon: Ext.Msg.WARNING,
								message: i_errorTemplate.apply({
									message: o_response.message
								}),
								yesText: Portfolio.util.Handler.i18n({
									da: "OK",
									en: "OK"
								})
							});
						}
					});
				}
			},
			noText: Portfolio.util.Handler.i18n({
				da: "Nej",
				en: "No"
			})
		});
	},

	onPreSave: function(i_formpanel) {

		var i_controller = this;
		var i_view = i_controller.getView();
		var i_content = i_view.getContent();

		var b_dirty = i_view.isDirty();

		i_view.doSave(function(i_record) {
			i_view.updateTitle(i_record);
			i_view.setAction("update");
			i_view.fireEvent("contentSave", i_content, i_view);
			Portfolio.util.Handler.App.fireEvent("contentSave", i_content, i_view);
		});
	},

	onPostSave: function(i_formpanel) {

	},

	onSave: function(i_formpanel) {

	},

	onWidgetSave: function(i_formpanel) {

	}
});
Ext.define("Portfolio.entity.view.Form", {

	xtype: "portfolio-entity-form",

	extend: "Ext.form.Panel",

	alternateClassName: [
		"Ext.ux.entity.Form"
	],

	alias: [
		"widget.entityform",
		"widget.entity.form",
		"widget.portfolio.entity.form"
	],

	layout: "fit",

	readOnly: false,

	config: {
		action: "create",
		activeTabIndex: 0,
		actionbar: null,
		bottomBar: null,
		contextParent: null,
		content: null,
		dmd: "",
		dmdName: "",
		dmdInfo: null,
		dmdModel: null,
		dropZone: null,
		dataConfig: null,
		defaultCollection: "",
		definition: {},
		dirtyForms: [],
		entity: "",
		entityConfig: null,
		entityeditor: true,
		forceClose: false,
		keys: {},
		language: "",
		languageInfo: null,
		languages: [],
		languageChange: false,
		languageBar: null,
		languageData: {},
		languageModel: null,
		model: null,
		modified: {},
		oldData: {},
		preSaveFields: [],
		preLoadFields: [],
		relationGrids: [],
		store: null,
		saveFields: [],
		tabPanel: null,
		util: null,
		view: "portfolio",
		widgets: [],
		xpdFields: [],
		i18nValues: {},
		createTitle: true,
		saved: false,
		keyHandler: null,
		linkable: true,
		deletable: true,
		backupView: null,
		langContext: "portfolio",
		apps: []
	},

	requires: [
		"Portfolio.entity.controller.Form",
		"Portfolio.entity.util.DropZone",
		"Portfolio.entity.util.Handler",
		"Portfolio.entity.util.Layout",
		"Portfolio.pd.util.Handler",
		"Portfolio.pd.util.Cache",
		"Ext.ux.xpd.Handler"
	],

	controller: "portfolio-entity-form",

	listeners: {
		afterrender: {
			fn: function(i_panel) {

				var i_self = this;
				var i_controller = i_self.getController();

				var i_window = i_self.up("window");

				if (i_window) {

					i_window.on({
						beforeclose: i_controller.onBeforeClose,
						scope: i_controller
					});

					i_self.setContextParent(i_window);
				}
				else {
					i_self.setContextParent(i_self);
				}

				if (i_self.getRecord()) {

					i_self.fireEvent("recordready", i_self);
				}
				else {
					i_self.on({
						contentReady: {
							fn: function() {
								i_self.fireEvent("recordready", i_self);
							}
						},
						single: true
					});
				}

				i_self.addKeyEvents();
			},
			buffer: 100,
			single: true
		},
		activate: {
			fn: function(i_panel) {

				var i_self = this;

				var i_content = i_self.getContent();

				if (i_content) {
					var a_fields = i_content.query("field[isFormField=true]");

					if (a_fields.length > 0) {
						Ext.Array.each(a_fields, function(i_field) {
							if (!i_field.isDisabled() && !i_field.readOnly) {
								i_field.focus(false, 100);
								return false;
							}
						});
					}
				}

			},
			buffer: 100
		},
		beforecontentsave: {
			fn: function() {

				var i_self = this;
				var i_contextParent = i_self.getContextParent();

				i_contextParent.setLoading(ip2.i18n({
					da: "Gemmer..",
					en: "Saving..."
				}));
			}
		},
		recordReady: {
			fn: function() {

				var i_self = this;

				if (i_self.getRecord()) {

					Portfolio.util.Handler.unmask();

					if (i_self.getCreateTitle()) {
						i_self.fireEvent("updateTitle", i_self);
					}

					if (i_self.getLinkable()) {

						var i_tabpanel = i_self.getTabPanel();
						var i_contextParent = i_self.getContextParent();
						var i_record = i_self.getRecord();

						var b_window = i_contextParent.isXType("window", false);

						var i_tool = i_self.createLinkButton(i_record, b_window);

						if (b_window) {
							var i_header = i_contextParent.header;
							i_header.add(1, i_tool);
						}
						else {
							i_tabpanel.tabBar.add(i_tool);
						}

					}
				}
			}
		},
		contentReady: {
			fn: function(i_panel, i_entityForm) {

				//Portfolio.util.Handler.unmask();
			}
		},
		contentSave: {
			fn: function(i_form, i_entityForm) {

				var i_self = this;
				var i_contextParent = i_self.getContextParent();

				i_contextParent.setLoading(false);
			}
		},
		contentError: {
			fn: function(i_panel) {

				Portfolio.util.Handler.unmask();
			}
		},
		contentCancel: {
			fn: function(i_panel) {
				Portfolio.util.Handler.unmask();
			}
		},
		changelanguage: {
			fn: "onLanguageChange"
		},
		validitychange: {
			fn: "onValidityChange",
			buffer: 100
		},
		dirtychange: {
			fn: "onDirtyChange",
			buffer: 100
		},
		beforeclose: {
			fn: "onBeforeClose"
		},
		updateTitle: {
			fn: function () {

				var i_self = this;
				var i_record = i_self.getRecord();
				var i_contextParent = i_self.getContextParent();
				var i_actionbar = i_self.getActionbar();
				var o_definition = i_self.getDefinition() || {};
				var a_pd = Ext.Array.from(o_definition.pd);

				var s_view = i_self.getView();
				var o_entity = i_self.getEntityConfig();
				var o_view = i_self.getViewConfig();

				var s_action = i_self.getAction();

				if (!o_view) {
					o_view = o_entity ? o_entity.ui.grids.portfolio : {
						title: "Error"
					};

					s_action = "error";
				}

				if (s_action != "error") {
					var a_title = [];
					var a_indexes = [];

					var s_title = "";

					if (s_action == "create") {
						a_title.push(ip2.i18n({
							da: "Opretter",
							en: "Creating"
						}));
					}
					else if (s_action == "copy") {
						a_title.push(ip2.i18n({
							da: "Kopier",
							en: "Copying"
						}));
					}

					var o_title = o_view.title || o_entity.title;

					if (s_action != "create") {

						var o_gridView = o_entity.ui.grids[s_view];

						var a_columns = o_gridView.columns || [];
						var a_extra = o_gridView.extraColumns || [];
						var a_indexes = [];

						Ext.Array.each(a_columns, function(o_column) {
							if (o_column.isTitle) {
								a_indexes.push(o_column.name);
							}
						});

						Ext.Array.each(a_extra, function(o_column) {
							if (o_column.isTitle) {
								a_indexes.push(o_column.name);
							}
						});

						if (a_title.length === 0) {
							a_title.push(ip2.i18n(o_title));
							a_title.push(i_record.get(i_record.idProperty));
						}
					}

					if (a_pd.length > 0) {

						var o_pd = a_pd[0];
						var a_definitions = Ext.Array.from(o_pd.definitions);

						var o_collection = Ext.Array.findBy(a_definitions, function(o_search) {
							return (o_search.id == o_pd.fcid || o_search.name == o_pd.fcid) && o_search.type == "formCollection";
						});

						var i_content = i_self.getContent();
						if (i_content && o_collection) {

							i_content.setTitle(ip2.i18n(o_collection.label));

							var o_data = Ext.decode(i_record.get(o_pd.property), true) || {};

							Ext.Array.each(a_indexes, function(s_index) {

								var a_split = s_index.split(".");
								var value = "";

								if (a_split.length > 1) {
									a_split.shift();

									var o_temp = Ext.clone(o_data);

									while(a_split.length > 0) {
										var s_part = a_split.shift();
										if (o_temp.hasOwnProperty(s_part)) {
											o_temp = value = o_temp[s_part];
										}
									}
								}
								else {
									value = i_record.get(s_index);
								}

								a_title.push(ip2.i18n(value));

							});
						}
					}
					else {

						Ext.Array.each(a_indexes, function(s_index) {
							var value = i_record.get(s_index);
							a_title.push(ip2.i18n(value));
						});
					}

					if (a_indexes.length === 0) {
						a_title.push(ip2.i18n(o_title, ""));
					}
					
					s_title = a_title.join(" ");

					var i_textItem = i_actionbar.items.get("title");

					if (i_textItem) {
						//i_textItem.setText(s_title);
					}
				}
				else {
					s_title = ip2.i18n({
						da: "Fejl",
						en: "Error"
					});
				}

				i_contextParent.setTitle(s_title);
			}
		},
		beforedestroy: {
			fn: function (i_panel) {

				var i_self = this;
				var i_form = i_self.getForm();

				if (i_self.getSaved() || i_form.wasDirty || i_self.action == "delete") {

					var i_record = i_self.getRecord();
					Portfolio.util.Handler.App.fireEvent("entityupdate:" + i_self.getEntity(), i_record, i_self.action);
				}

				var i_keyHandler = i_self.getKeyHandler();

				if (i_keyHandler) {
					i_keyHandler.destroy();
					i_self.setKeyHandler(null);
				}

			}
		},
		savefaliure: {
			fn: function() {

				var i_self = this;

				var i_contextParent = i_self.getContextParent();
				var i_actionBar = i_self.getActionbar();
				var i_saveclose = i_actionBar.getComponent("saveclose");

				i_saveclose.show();
				i_saveclose.enable();
				i_contextParent.setLoading(false);
			}
		},
		changecollection: {
			fn: function(newValue, oldValue) {

				var i_self = this;

				i_self.setLoading(true);

				setTimeout(function() {

					var i_promise = new Ext.Promise(function(f_resolve, f_reject) {

						Ext.suspendLayouts();

						var i_tabpanel = i_self.getTabPanel();
						var a_tabs = i_tabpanel.items.getRange();
						var o_definition = i_self.getDefinition();
						var i_activeTab = i_tabpanel.getActiveTab();
						var n_index = i_tabpanel.items.indexOf(i_activeTab);
						i_self.setActiveTabIndex(n_index);

						var a_filtered = Ext.Array.filter(a_tabs, function(i_tab) {
							return i_tab.isContent;
						});

						var o_i18nValues = i_self.getI18nValues();

						var a_languages = i_self.getLanguages();
						var s_currentLang = i_self.getLanguage();

						var o_formvalues = {};

						var a_formFields = [];

						var i_model = i_self.getModel();
						var i_dmdRecord = i_model.create({});

						var i_record = i_self.getRecord();
						var o_values = {};

						Ext.Array.each(a_filtered, function(i_content) {

							var i_form = i_content.getForm();
							var a_temp = i_form.getFields().getRange();

							var a_result = Ext.Array.filter(a_temp, function(i_field) {
								return !i_field.inWidget;
							});

							a_formFields = a_formFields.concat(a_result);
						});

						Ext.Array.each(a_formFields, function(i_field) {

							if (i_field.i18n && a_languages > 1) {

								var o_value = o_i18nValues[i_field.name];
								o_value[s_currentLang] = i_field.getSubmitValue ? i_field.getSubmitValue() : i_field.getValue();

								var s_value = Ext.encode(o_value);
								o_formvalues[i_field.name] = s_value;
							}
							else {
								o_formvalues[i_field.name] = i_field.getSubmitValue ? i_field.getSubmitValue() : i_field.getValue();
							}
						});

						i_record.set(o_formvalues);


						var a_pd = Ext.Array.from(o_definition.pd);

						Ext.Array.each(a_pd, function(o_pd) {

							var a_definitions = o_pd.definitions;
							var s_property = o_pd.property;
							var s_fcid = o_pd.fcid == "mask_" ? "mask_unknown" : o_pd.fcid;

							var o_formCollection = Ext.Array.findBy(a_definitions, function(o_collection) {
								return (o_collection.id == s_fcid || o_collection.name == s_fcid) && o_collection.type == "formCollection";
							});

							var a_collectionFields = Portfolio.pd.util.Handler.getFormFields(o_formCollection, a_definitions);

							Ext.Array.each(a_collectionFields, function(s_name) {

								o_values[s_name] = i_record.get(s_name);
							});

							var o_saved = Ext.decode(i_record.get(s_property), true) || {};

							o_values = Ext.apply(o_saved, o_values);

							Ext.apply(o_values, {
								fcid: newValue
							});

							i_record.set("fcid", newValue);

							i_dmdRecord.set(i_record.getData());

							i_dmdRecord.set(i_dmdRecord.idProperty, i_record.get(i_record.idProperty));

							if (!o_values.hasOwnProperty(newValue)){
								Ext.Ajax.request({
									url: "/ip2-services/ip2transaction.aspx",
									jsonData: {
										action: "cmsCms.cmsChangeCollection",
										newCollection: newValue,
										oldCollection: s_fcid,
										properties: o_values
									},
									success: function(i_response){

										var o_result = Ext.decode(i_response.responseText, true) || o_values;

										i_dmdRecord.set(s_property, Ext.encode(o_result));

										i_self.setTabPanel(null);
										i_self.setDefinition(null);
										i_self.setContent(null);
										i_self.setXpdFields([]);

										i_self.setWidgets([]);

										i_self.setPreSaveFields([]);
										i_self.setSaveFields([]);
										i_self.setPreLoadFields([]);

										i_self.removeAll(false);

										i_self.createView(i_dmdRecord, true);

										f_resolve();
									}
								});
							}
							else {

								i_dmdRecord.set(s_property, Ext.encode(o_values));

								i_self.setTabPanel(null);
								i_self.setDefinition(null);
								i_self.setContent(null);
								i_self.setXpdFields([]);

								i_self.setWidgets([]);

								i_self.setPreSaveFields([]);
								i_self.setSaveFields([]);
								i_self.setPreLoadFields([]);

								i_self.removeAll(false);

								i_self.createView(i_dmdRecord, true);

								f_resolve();
							}

						});

					});

					i_promise.then(function() {
						i_self.setLoading(false);
						Ext.resumeLayouts(true);
					});
				}, 10);
			},
			buffer: 10
		}
	},

	initComponent: function(o_config) {

		var i_self = this;

		var s_dmd = i_self.getDmd();

		var o_dmdInfo = ip2.dmd.getInfo({
			dmd: i_self.getDmd(),
			entity: i_self.getEntity(),
			view: i_self.getView(),
			context: "form"
		});

		if (!o_dmdInfo.entity) {

			var i_template = Ext.create("Ext.XTemplate",
				"<div><strong>{title}</strong></div>",
				"<div><i><span>{message}</span></i></div>",
				"</br>",
				"<div><strong>DMD: </strong><i><span>{dmd}</span></i></div>",
				"<div><strong>ENTITY: </strong><i><span>{entity}</span></i></div>",
				"<div><strong>VIEW: </strong><i><span>{view}</span></i></div>"
			);

			i_template.compile();

			var s_html = i_template.apply({
				title: ip2.i18n({
					da: "System fejl",
					en: "System error"
				}),
				message: ip2.i18n({
					da: "Entity ikke fundet",
					en: "Entity not found"
				}),
				entity: i_self.getEntity(),
				view: i_self.getView(),
				dmd: i_self.getDmd()
			});

			Ext.apply(i_self, {
				bodyPadding: 10
			});

			i_self.callParent(arguments);

			i_self.setHtml(s_html);

			i_self.setTitle(ip2.i18n({
				da: "Fejl",
				en: "Error"
			}));

			i_self.fireEvent("contentReady", null, i_self, false);

			return;
		}

		i_self.callParent(arguments);

		var s_language = i_self.getLanguage() || ip2.getUser().get("USRLNG") || "en";

		i_self.setLanguage(s_language);

		var o_keys = i_self.getKeys();

		i_self.setDmdName(s_dmd.split("/").pop().split(".").shift());

		i_self.setDmdInfo(o_dmdInfo);

		var i_util = Ext.create("Portfolio.entity.util.Handler", {});
		i_self.setUtil(i_util);

		i_self.setEntityConfig(o_dmdInfo.entity);
		i_self.setDmdModel(o_dmdInfo.dmd.model);

		i_self.createModel();

		i_self.addDocked(i_self.createToolbar());

		var o_model = i_self.getDmdModel();

		var i_model = i_self.getModel();

		var o_i18nValues = i_self.getI18nValues();

		var o_view = i_self.getViewConfig();

		var s_context = o_view ? o_view.context : "portfolio";

		i_self.setLangContext(s_context);

		var a_languages = wsh.getLanguages(s_context);
		var a_current = i_self.getLanguages();

		if (Ext.isEmpty(a_current)) {
			i_self.setLanguages(a_languages);
		}

		var o_modified = i_self.getModified();

		Ext.Array.each(a_languages, function(s_language) {
			o_modified[s_language] = [];
		});

		var s_token = o_keys[i_model.idProperty];

		var o_proxy = o_model.proxy;

		o_proxy.portfolio = o_proxy.hasOwnProperty("portfolio") ? o_proxy.portfolio : true;

		if (s_token) {

			if (o_proxy.portfolio) {

				var i_store = i_self.createStore();

				i_store.load({
					callback: function(a_records, i_store) {

						var i_record = a_records[0];

						if (!i_record) {

							var i_template = new Ext.XTemplate(
								"No record found for:\n",
								"DMD: {dmd}\n",
								"ENTITY: {entity}\n",
								"VIEW: {view}\n",
								"KEYS: {keys}"
							);

							i_template.compile();

							Portfolio.util.Handler.unmask();

							i_self.destroy();

							Ext.Error.raise(i_template.apply({
								dmd: i_self.getDmd(),
								entity: i_self.getEntity(),
								view: i_self.getView(),
								keys: Ext.encode(i_self.getKeys())
							}));
						}

						i_self.loadLanguageData(i_record, function(o_languages) {

							if (o_languages) {

								var o_primary = o_languages[s_language] || {};

								i_record.set(o_primary);

								Ext.Array.each(a_languages, function(s_key) {

									var o_values = o_languages[s_key] || {};

									if (Ext.Object.isEmpty(o_values)) {
										o_values = Ext.apply({}, o_primary);
									}

									Ext.Object.each(o_values, function(s_property, value) {

										var o_property = o_i18nValues[s_property] || {};

										if (s_key != s_language) {
											var primary = o_primary[s_property];

											if (Ext.isEmpty(value, true)) {
												value = primary;
											}
										}

										o_property[s_key] = value;

										o_i18nValues[s_property] = o_property;
									});
								});
							}

							i_self.setI18nValues(o_i18nValues);

							i_self.loadRecord(i_record);

							i_self.createView(i_record);

							if (i_self.getAction() == "copy") {

								var i_form = i_self.getForm();

								var i_field = i_form.findField(i_record.idProperty);

								if (i_field) {
									i_field.suspendCheckChange++;
									i_field.setValue(null);
									i_field.resetOriginalValue();
									i_field.suspendCheckChange--;
								}
							}
							else {
								i_self.action = "update";
							}
						});
					}
				});
			}
			else {
				var i_entity = i_model.create(i_self.getKeys());

				i_entity.load({
					callback: function(i_record, i_operation, b_success) {

						if (!b_success) {

							var i_template = new Ext.XTemplate(
								"No record found for:\n",
								"DMD: {dmd}\n",
								"ENTITY: {entity}\n",
								"VIEW: {view}\n",
								"KEYS: {keys}"
							);

							i_template.compile();

							Portfolio.util.Handler.unmask();

							i_self.destroy();

							Ext.Error.raise(i_template.apply({
								dmd: i_self.getDmd(),
								entity: i_self.getEntity(),
								view: i_self.getView(),
								keys: Ext.encode(i_self.getKeys())
							}));
						}

						i_self.loadLanguageData(i_record, function(o_languages) {

							if (o_languages) {

								var o_primary = o_languages[s_language] || {};

								i_record.set(o_primary);

								Ext.Array.each(a_languages, function(s_key) {

									var o_values = o_languages[s_key] || {};

									if (Ext.Object.isEmpty(o_values)) {
										o_values = Ext.apply({}, o_primary);
									}

									Ext.Object.each(o_values, function(s_property, value) {

										var o_property = o_i18nValues[s_property] || {};

										if (s_key != s_language) {
											var primary = o_primary[s_property];

											if (Ext.isEmpty(value, true)) {
												value = primary;
											}
										}

										o_property[s_key] = value;

										o_i18nValues[s_property] = o_property;
									});
								});
							}

							i_self.setI18nValues(o_i18nValues);

							i_self.loadRecord(i_record);

							i_self.createView(i_record);

							if (i_self.getAction() == "copy") {

								var i_form = i_self.getForm();

								var i_field = i_form.findField(i_record.idProperty);

								if (i_field) {
									i_field.suspendCheckChange++;
									i_field.setValue(null);
									i_field.resetOriginalValue();
									i_field.suspendCheckChange--;
								}
							}
						});
					}
				});
			}
		}
		else {

			var i_record = i_model.create(i_self.getOldData());

			i_self.setOldData(null);

			if (i_self.getAction() == "copy") {

				i_record.set(i_record.idProperty, null);
			}

			i_self.loadRecord(i_record);

			i_self.doPreCreate(i_record);
		}

		i_self.enableBubble([
			"contentReady",
			"contentSave"
		]);
	},

	doPreCreate: function(i_record) {

		var i_self = this;

		var o_definition = i_self.getFieldDefinitions(i_record);
		var a_xpdConfig = o_definition.xpdConfig;

		if (a_xpdConfig.length > 0) {

			var a_collections = [];

			Ext.Array.each(a_xpdConfig, function(o_config) {
				var o_return = i_self.getXpdDefinitions(i_record, o_config);

				a_collections.push(o_return);
			});

			i_self.makeChoise(a_collections, i_record);
		}
		else if (o_definition.pd.length > 0) {

			var o_pd = o_definition.pd[0];

			if (!o_pd.created) {
				i_self.makePDChoise(o_pd, i_record);
			}
			else {
				i_self.createView(i_record);
			}

		}
		else {
			i_self.createView(i_record);
		}
	},

	doPreLoad: function(o_xpd, i_record, o_values) {

		var i_self = this;

		var o_i18nValues = i_self.getI18nValues();

		var s_language = i_self.getLanguage();

		var a_languages = i_self.getLanguages();

		var o_languageData = i_self.getLanguageData();

		var o_xpdData = Ext.ux.xpd.Handler.getProperties(o_xpd, o_values);

		var o_languageInfo = i_self.getLanguageInfoInformation();

		Ext.Array.each(a_languages, function(s_key) {

			var o_values = Ext.apply({}, o_xpdData);

			Ext.Object.each(o_values, function(s_property, value) {

				var o_property = o_i18nValues[s_property] || {};

				o_property[s_key] = value;

				o_i18nValues[s_property] = o_property;
			});

			if (o_languageInfo) {

				var i_languageModel = i_self.getLanguageModel();

				var i_languageRecord = i_languageModel.create({});

				o_languageData[s_key] = i_languageRecord.getData();
			}
		});

		i_self.setI18nValues(o_i18nValues);

		i_self.loadRecord(i_record);

		i_self.setAction("create");

		i_self.createView(i_record);
	},

	createView: function(i_record, b_recreate) {

		var i_self = this;

		var s_dmdName = i_self.getDmdName();
		var s_entity = i_self.getEntity();

		var o_definition = i_self.getFieldDefinitions(i_record);

		if (o_definition.pd.length > 0) {

			var o_pd = o_definition.pd[0];

			if (!o_pd.fcid) {
				i_self.makePDChoise(o_pd, i_record);
				return;
			}
		}


		var o_view = i_self.getViewConfig();

		var a_dmdFields = o_definition.fields;
		var a_xpdConfig = o_definition.xpdConfig;

		var a_saveFields = i_self.getSaveFields();
		var a_preSaveFields = i_self.getPreSaveFields();
		var a_preLoadFields = i_self.getPreLoadFields();
		var a_xpdFields = [];
		var a_items = [];
		var a_xpdGroups = [];
		var a_nogroup = [];
		var a_tabs = [];

		var o_relations = i_self.getRelationDefinitions(i_record);
		var a_affiliations = i_self.getAffiliations(i_record);

		var a_widgets = i_self.getWidgetDefinitions(i_record);
		var a_newWidget = i_self.getWidgetNewDefinitions(i_record);

		a_newWidget = Ext.Array.filter(a_newWidget, function(i_widget) {

			var b_result = true;
			Ext.Array.each(a_widgets, function(o_widget) {
				if (o_widget.itemId == i_widget.itemId) {
					b_result = false;
					return false;
				}
			});
			return b_result;
		});

		a_widgets = a_widgets.concat(a_newWidget);

		var a_collections = [];

		var a_languages = i_self.getLanguages();

		Ext.Array.each(a_xpdConfig, function(o_config) {

			var o_return = i_self.getXpdDefinitions(i_record, o_config);

			var o_collection = o_return.collection;

			var a_result = o_return.fields;

			var a_remove = [];

			Ext.Array.each(a_result, function(i_field) {
				var b_removed = false;
				if (i_field.xtype == "fieldcombi") {
					if (i_field.fieldcount === 0) {
						a_remove.push(i_field);
						b_removed = true;
					}
				}
				if (!b_removed) {
					if (i_field.doSave && i_field.isWidget) {
						i_field.record = i_record;
						a_saveFields.push(i_field);
					}
					if (i_field.presave) {
						a_preSaveFields.push(i_field);
					}
					if (i_field.onPreLoad) {
						a_preLoadFields.push(i_field);
					}
				}
			});

			a_result = Ext.Array.filter(a_result, function(i_field) {
				var b_keep = true;
				Ext.Array.each(a_remove, function(i_removed) {
					if (i_field.name == i_removed.name) {
						b_keep = false;
					}
				});
				return b_keep;
			});

			Ext.Array.each(a_result, function(i_field) {
				Ext.Array.each(a_dmdFields, function(i_dmdField) {
					if (i_field.from) {
						if (i_field.from.field == i_dmdField.name) {
							if (i_dmdField._xpdConfig.groups) {
								i_field._xpdConfig.groups = i_field._xpdConfig.groups || [];
								i_dmdField._xpdConfig.groups = i_dmdField._xpdConfig.groups || [];
								i_field._xpdConfig.groups = i_field._xpdConfig.groups.concat(i_dmdField._xpdConfig.groups);
							}
						}
					}
				});
			});

			Ext.Array.each(a_result, function(i_field) {
				if (i_self.readOnly || (
						!ip2.isAccessible("app." + s_dmdName + ".data.update") &&
						!ip2.isAccessible("app." + s_dmdName + ".data." + s_entity + ".update")
					)) {
					if (i_field.disable) {
						i_field.disable();
					}
				}
			});

			var o_result = Ext.ux.xpd.Handler.createGroups(a_result, o_return.xpd, o_collection, i_self);

			var a_groups = o_result.groups || [];
			var a_leftovers = o_result.nogroup || [];

			a_leftovers = Ext.Array.filter(a_leftovers, function(o_field) {
				return !o_field.inFieldCombi;
			});

			a_xpdGroups = a_xpdGroups.concat(a_groups);

			if (a_leftovers.length > 0) {
				Ext.Array.each(a_leftovers, function(i_field) {
					i_field.dataParent = i_self;
				});
				a_nogroup = a_nogroup.concat(a_leftovers);
			}

			a_xpdFields = a_xpdFields.concat(a_result);

			a_collections.push(o_collection);
		});

		a_items = a_items.concat(a_xpdGroups);

		i_self.setXpdFields(a_xpdFields);

		Ext.Array.each(a_xpdFields, function(i_field) {
			if (i_field.i18n) {

				var o_i18nValues = i_self.getI18nValues();
				var o_fieldValue = o_i18nValues[i_field.name];

				var value = i_field.value;
				var o_value = {};

				if (ip2.isStringedObject(value)) {
					o_value = Ext.decode(value, true) || {};
				}
				else {
					if (Ext.isObject(value)) {
						o_value = value;
					}
					else {
						Ext.Array.each(a_languages, function(s_lang) {
							o_value[s_lang] = value || "";
						});
					}
				}

				if (!o_fieldValue) {
					o_i18nValues[i_field.name] = o_value;
				}
			}
		});

		a_dmdFields = Ext.Array.filter(a_dmdFields, function(i_dmdField) {

			var b_add = true;

			Ext.Array.each(a_xpdFields, function(i_field) {
				if (i_field.name == i_dmdField.name) {
					b_add = false;
				}
			});

			return b_add;
		});

		var o_result = i_self.getGroupDefinitions(a_dmdFields, o_definition, i_record);
		a_items = a_items.concat(Ext.Array.slice(Ext.Array.from(o_result.groups)));
		var a_groups = Ext.Array.slice(Ext.Array.from(o_result.groups));

		if (a_items.length === 0) {
			o_result.nogroup.setHidden(false);
		}

		a_nogroup.push(o_result.nogroup);

		var a_uiTabs = o_view.tabs || [];
		var o_content = Ext.Array.findBy(a_uiTabs, function(o_tab) {
			return o_tab.contentRoot;
		}) || {
			title: ip2.i18n({
				da: "Indhold",
				en: "Content"
			}),
			bodyPadding: 20,
			autoScroll: true,
			layout: "anchor"
		};

		var o_defaults = o_content.defaults || {
			anchor: "100%",
			maxWidth: 800,
			labelWidth: 150,
			bodyPadding: 20,
			autoScroll: true
		};

		if (a_collections.length > 0) {
			var a_layouts = [];

			Ext.Array.each(a_collections, function(o_collection) {

				if (o_collection.layout && o_collection.layout.type) {

					var i_result = Portfolio.entity.util.Layout.create(o_collection.layout, a_items, a_widgets, o_relations.grids, a_affiliations, i_self);
					a_layouts.push(i_result);

					Ext.apply(o_content,  {
						layout : "fit",
						autoScroll : false,
						padding : 0
					});

					o_defaults = {
						labelWidth: 150
					};
				}

				var o_widgets = o_collection.widgets || {};

				if (!Ext.Object.isEmpty(o_widgets)) {
					a_widgets = Ext.Array.filter(a_widgets, function(o_widget) {

						var b_found = false;

						Ext.Array.each(o_collection.widgets, function(o_config) {

							if ("widget-" + o_config.name == o_widget.itemId) {

								var o_merged = Ext.apply(o_widget._config, o_config);
								Ext.apply(o_widget, o_merged);
								b_found = true;

								if (Ext.isEmpty(o_widget.value)) {
									if (o_widget.xpd) {
										o_widget.value = {
											__cid__: o_config.id
										};
									}
								}

								delete o_widget.id;
							}
						});
						return b_found;
					});
				}
				else {
					a_widgets = [];
				}
			});

			if (a_layouts.length > 0) {
				a_items = a_layouts;
			}
		}
		else {

			if (o_view.uiLayout) {
				var i_result = Portfolio.entity.util.Layout.create(o_view.uiLayout, a_items, a_widgets, o_relations.grids, a_affiliations, i_self);

				a_items = [
					i_result
				];

				Ext.apply(o_content,  {
					layout : "fit",
					autoScroll : false,
					padding : 0
				});

				o_defaults = {
					labelWidth: 150
				};
			}
		}

		a_items = a_items.concat(a_nogroup);
		a_groups = a_groups.concat(Ext.Array.slice(a_nogroup));

		var a_apps = i_self.getApps();

		Ext.Array.each(a_uiTabs, function(o_tab) {

			if (!o_tab.contentRoot && !o_tab.main) {

				var a_tabItems = Ext.Array.filter(a_groups, function(i_group) {
					return o_tab.name == i_group.tabId;
				});

				Ext.Array.each(a_tabItems, function(i_group) {
					Ext.Array.remove(a_items, i_group);
				});

				if (o_tab.uiLayout) {
					var i_result = Portfolio.entity.util.Layout.create(o_tab.uiLayout, a_tabItems, a_widgets, o_relations.grids, a_affiliations, i_self);

					a_tabItems = [
						i_result
					];
				}

				var i_tab = Ext.widget("form", Ext.applyIf({
					trackResetOnLoad: true,
					itemId: o_tab.name,
					title: ip2.i18n(o_tab.title),
					defaults: o_tab.defaults,
					layout: o_tab.layout,
					isContent: true,
					items: a_tabItems

				}, o_tab));

				i_self.addContentListeners(i_tab);

				a_tabs.push(i_tab);
			}
			else if (o_tab.type == "app-component") {

				var s_main = o_tab.main || "";

				if (s_main) {
					if (o_tab.path) {

						if (!Ext.Object.isEmpty(o_tab.path)) {

							Ext.Loader.setConfig({
								paths: o_tab.path
							});
						}
					}

					var o_config = Ext.clone(o_tab.config || {});

					Ext.applyIf(o_config, {
						transactiontype: i_self.transactiontype,
						entity: i_self.getEntity(),
						keys: i_self.getKeys(),
						record: i_self.getRecord(),
						formBind: true
					});

					var i_component = Ext.create(o_tab.main, o_config);
					i_component.sequence = o_tab.sequence;
					a_tabs.push(i_component);

					a_apps.push(i_component);
				}
			}
		});

		Ext.Array.each(a_widgets, function(o_widget) {
			if (!o_widget.inLayout) {
				var i_widget = Ext.widget("ip2widget", o_widget);
				a_tabs.push(i_widget);
			}
		});

		Ext.Array.each(o_relations.grids, function(i_relation) {
			if (!i_relation.inLayout) {
				a_tabs.push(i_relation);
			}
		});

		Ext.Array.each(a_affiliations, function(i_affiliation) {
			if (!i_affiliation.inLayout) {
				a_tabs.push(i_affiliation);
			}
		});

		Ext.suspendLayouts();

		var i_content = Ext.widget("form", Ext.applyIf({
			title: ip2.i18n(o_content.title),
			trackResetOnLoad: true,
			defaults: o_defaults,
			index: 0,
			sequence: 0,
			isContent: true,
			items: a_items
		}, o_content));

		i_self.addContentListeners(i_content);

		if (a_languages.length > 1) {

			var a_buttons = [];
			var s_currentLang = i_self.getLanguage();
			var o_languageInfo = i_self.getLanguageInfoInformation();

			if (o_languageInfo) {

				Ext.Array.each(a_languages, function(s_language) {

					var i_button = Ext.widget("button", {
						xtype: "button",
						text: wsh.i18n.getEnum(s_language),
						itemId: s_language,
						enableToggle: true,
						pressed: s_language == s_currentLang ? true : false,
						iconCls: i_self.getAction() == "update" ? "" : "ip2-icon-data-lock",
						handler: function(i_button) {

							var i_toolbar = i_self.getLanguageBar();

							var a_button = i_toolbar.query("button");

							Ext.Array.each(a_button, function(i_language) {
								if (i_language.itemId != i_button.itemId) {
									if (i_language.pressed) {
										i_language.toggle();
									}
								}
							});

							if (i_button.pressed) {
								i_self.fireEvent("changelanguage", i_self, i_button.itemId);
							}
							else {
								i_button.toggle();
							}
						}
					});

					a_buttons.push(i_button);
				});

				var i_toolbar = Ext.widget("toolbar", {
					dock: "bottom",
					items: a_buttons
				});

				i_self.addDocked(i_toolbar);
				i_self.setLanguageBar(i_toolbar);
			}
		}

		a_tabs.unshift(i_content);

		a_tabs = Ext.Array.sort(a_tabs, function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var a_features = [];

		var a_extra = i_self.createToolbarFeatures();

		Ext.Array.each(a_extra, function(o_config) {

			Ext.apply(o_config, {
				minHeight: 30
			});
		});

		if (a_extra.length > 0) {

			var a_temp = [];

			Ext.Array.each(a_extra, function(o_extra) {
				if(o_extra.isXType) {

					var o_config = Ext.clone(o_extra.initialConfig);

					if (o_extra.isXType("button", true)) {
						Ext.apply(o_config, {
							xtype: "menuitem"
						});
					}

					a_temp.push(o_config);
				}
				else {
					if (Ext.isObject(o_extra)) {
						a_temp.push(o_extra);
					}
				}

			});

			a_features.unshift({
				iconCls: "pf-form_options",
				xtype: "button",
				tooltip: ip2.i18n({
					da: "Mere",
					en: "More"
				}),
				arrowVisible: false,
				ui: "function-action",
				menu: {
					items: a_temp
				}
			});
		}

		a_features.unshift({
			xtype: "tbfill"
		});

		Ext.Array.each(a_features, function(o_config) {

			Ext.apply(o_config, {
				minWidth: 50,
				margin: "0 0 0 10"
			});
		});

		a_features.push({
			xtype: "tbspacer",
			width: 25
		});

		var i_tabpanel = Ext.widget("tabpanel", {
			layout: "fit",
			defaults: {
				iconAlign: "right"
			},
			tabBar: {
				items: a_features
			},
			items: a_tabs
		});

		i_self.setTabPanel(i_tabpanel);
		i_self.setContent(i_content);
		i_self.setWidgets(a_widgets);

		i_self.setPreSaveFields(a_preSaveFields);
		i_self.setSaveFields(a_saveFields);
		i_self.setPreLoadFields(a_preLoadFields);

		i_tabpanel.setActiveTab(i_self.getActiveTabIndex());

		i_self.add(i_tabpanel);

		Ext.Array.each(a_preLoadFields, function(i_field) {
			i_field.onPreLoad(i_record.get(i_record.idProperty));
		});

		i_self.addContentEvent(i_content);

		Ext.resumeLayouts(true);

		var o_backup = i_self.getBackupView();

		if (o_backup) {

			var o_entity = i_self.getEntityConfig();

			o_entity.ui.forms[i_self.getView()] = o_backup;
		}

		Ext.Array.each(a_apps, function(i_application) {

			var s_event = i_application.readyEvent || "entityready";

			i_application.fireEvent(s_event, i_application, i_record);
		});

		i_self.fireEvent("contentReady", i_content, i_self, b_recreate);

	},

	addContentEvent: function(i_content) {

		var i_self = this;

		var i_form = i_content.getForm();
		var a_fields = i_form.getFields().getRange();
		var a_languages = i_self.getLanguages();

		Ext.Array.each(a_fields, function(i_field) {

			i_field.on({
				dirtychange: {
					fn: function(i_field, b_dirty) {

						var s_name = i_field.name;
						var b_valid = i_field.isValid() || true;

						var o_modified = i_self.getModified();
						var o_i18nValues = i_self.getI18nValues();
						var b_formValid = i_form.isValid();

						var s_currentLang = i_self.getLanguage();
						var i_languageBar = i_self.getLanguageBar();

						var i_button;

						if (i_self.getLanguageChange()) {
							return false;
						}

						if (!i_field.i18n) {

							if (b_dirty) {

								Ext.Array.each(a_languages, function(s_language) {

									var a_modified = o_modified[s_language] = o_modified[s_language] || [];

									if (s_language !== s_currentLang) {

										var b_found = false;

										Ext.Array.each(o_modified[s_language], function(o_field, n_index) {
											if (o_field.name == s_name) {

												Ext.apply(o_field, {
													dirty: b_dirty,
													valid: b_valid
												});

												b_found = true;
												return false;
											}
										});

										if (!b_found) {

											a_modified.push({
												id: i_field.id,
												name: s_name,
												originalValue: i_field.originalValue,
												i18n: i_field.i18n || false,
												dirty: b_dirty,
												valid: b_valid,
												value: i_field.getValue()
											});
										}

										if (i_languageBar) {
											i_button = i_languageBar.getComponent(s_language);

											if (i_button && b_formValid && b_valid) {
												i_button.setIconCls("flatui icon-data-new");
											}
										}
									}
								});
							}
							else {

								Ext.Array.each(a_languages, function(s_language) {

									if (s_language !== s_currentLang) {

										var a_modified = o_modified[s_language] = o_modified[s_language];
										var a_dirtyForms = i_self.getDirtyForms();

										var a_remove = [];

										Ext.Array.each(a_modified, function(o_modified, n_index) {
											if (o_modified.name == s_name) {
												a_remove.push(o_modified);
											}
										});

										Ext.Array.each(a_remove, function(o_field) {
											Ext.Array.remove(a_modified, o_field);
										});

										if (a_modified.length === 0) {

											var b_modifed = false;

											Ext.Array.each(a_dirtyForms, function(s_form) {

												var i_dirtyform = Ext.getCmp(s_form);
												var a_modified = i_dirtyform.modified[s_language] || [];

												if (a_modified.length > 0) {

													Ext.Array.each(a_modified, function(o_field) {
														if (o_field.dirty) {
															b_modifed = true;
															return false;
														}
													});
													if (b_modifed) {
														return false;
													}
												}
											});

											if (!b_modifed) {

												if (i_languageBar) {
													i_button = i_languageBar.getComponent(s_language);

													if (i_button && b_formValid) {
														i_button.setIconCls("");
													}
												}
											}
											o_modified[s_language] = [];
										}
									}
								});
							}
							if (!b_formValid) {

								Ext.Array.each(a_languages, function(s_language) {

									if (s_language != s_currentLang) {

										var a_modified = o_modified[s_language] = o_modified[s_language];
										var b_modifed = a_modified.length > 0;

										Ext.Array.each(a_modified, function(o_field, n_index) {
											if (!o_field.valid) {
												b_modifed = false;
												return false;
											}
										});

										if (i_languageBar) {
											i_button = i_languageBar.getComponent(s_language);

											if (i_button && !b_formValid) {
												i_button.setIconCls("flatui icon-data-error");
											}
										}
									}
								});
							}
						}
						else {

							if (!b_valid) {

								Ext.Array.each(a_languages, function(s_language) {

									var a_modified = o_modified[s_language] = o_modified[s_language];

									var b_found = false;

									if (s_language != s_currentLang) {

										Ext.Array.each(a_modified, function(o_field, n_index) {
											if (o_field.name == s_name) {
												b_found = true;
												return false;
											}
										});

										var o_field = o_i18nValues[s_name] || {};
										var b_fieldvalid = false;
										var fieldValue = o_field[s_language];

										if (!b_found) {

											if (!Ext.isEmpty(fieldValue, true)) {
												i_field.suspendCheckChange++;
												var oldvalue = i_field.getValue();
												i_field.setValue(fieldValue);
												b_fieldvalid = i_field.isValid();
												i_field.setValue(oldvalue);
												i_field.suspendCheckChange--;
											}

											if (!b_fieldvalid) {

												a_modified.push({
													id: i_field.id,
													name: s_name,
													originalValue: i_field.originalValue,
													i18n: i_field.i18n || false,
													dirty: i_field.isDirty(),
													valid: b_valid || false,
													value: i_field.getValue()
												});
											}
										}

										if (!b_found && !b_fieldvalid) {

											if (i_languageBar) {
												i_button = i_languageBar.getComponent(s_language);

												if (i_button) {
													i_button.setIconCls("flatui icon-data-error");
												}
											}
										}
									}
									else {

										b_found = false;

										Ext.Array.each(a_modified, function(o_field, n_index) {
											if (o_field.name == s_name) {
												b_found = true;
												return false;
											}
										});

										if (!b_found) {

											a_modified.push({
												id: i_field.id,
												name: s_name,
												originalValue: i_field.originalValue,
												i18n: i_field.i18n || false,
												dirty: i_field.isDirty(),
												valid: b_valid !== undefined ? b_valid : true,
												value: i_field.getValue()
											});

											if (i_languageBar) {

												i_button = i_languageBar.getComponent(s_language);

												if (i_button) {
													i_button.setIconCls("flatui icon-data-error");
												}
											}
										}
									}
								});
							}
							else {

								Ext.Array.each(a_languages, function(s_language) {

									var a_modified = o_modified[s_language] = o_modified[s_language];

									if (s_language == s_currentLang) {

										var b_found = false;

										Ext.Array.each(a_modified, function(o_field) {

											if (o_field.name == s_name) {
												Ext.apply(o_field, {
													valid: true,
													dirty: i_field.isDirty(),
													value: i_field.getValue()
												});
												b_found = true;
												return false;
											}
										});

										if (!b_found) {

											o_modified[s_language].push({
												id: i_field.id,
												name: s_name,
												originalValue: i_field.originalValue,
												i18n: i_field.i18n || false,
												dirty: i_field.isDirty(),
												valid: b_valid !== undefined ? b_valid : true,
												value: i_field.getValue()
											});
										}
									}
								});
							}
						}
					}
				}
			});
		});
	},

	addContentListeners: function(i_content) {

		var i_self = this;

		i_content.on({
			dirtychange: {
				fn: function(i_form, b_dirty) {

					var i_owner = i_form.owner; // THIS ORIGEN PLACE THIS MIGHT BE FROM A WIDGET
					var i_contentForm = i_content.getForm();
					var b_valid = !i_contentForm.hasInvalidField();

					var i_languageBar = i_self.getLanguageBar();

					var a_dirtyForms = i_self.getDirtyForms();
					var a_languages = i_self.getLanguages();
					var s_currentLang = i_self.getLanguage();

					i_content.setIconCls(b_dirty ? "x-dot" : "");

					var i_button;

					if (b_valid) {
						if (i_languageBar) {
							if (i_owner && i_owner.id == i_content.id) {
								i_button = i_languageBar.getComponent(s_currentLang);
								if (i_button) {
									i_button.setIconCls(b_dirty ? "flatui icon-data-new" : "");
								}
							}
							else {
								if (b_dirty) {
									if (a_dirtyForms.indexOf(i_owner.id) == -1) {
										a_dirtyForms.push(i_owner.id);
									}
								}
								else {

									var o_modified = i_owner.modified || {};
									var b_found = false;

									Ext.Object.each(o_modified, function(s_key, a_modified) {

										Ext.Array.each(a_modified, function(o_field) {
											if (o_field.dirty) {
												b_found = true;
												return false;
											}
										});
										if (b_found) {
											return false;
										}
									});

									if (!b_found) {

										var n_index = a_dirtyForms.indexOf(i_owner.id);

										if (n_index > -1) {
											Ext.Array.remove(a_dirtyForms, i_owner.id);
										}
									}
								}

								var b_i18n = false;

								if (b_dirty) {

									var o_values = i_form.getFieldValues(true);

									Ext.Object.each(o_values, function(s_name) {
										var i_field = i_form.findField(s_name);
										if (i_field && i_field.i18n) {
											b_i18n = true;
											return false;
										}
									});
								}

								if (b_i18n) {

									var s_language = i_owner.language;
									var a_modified = i_owner.modified[s_language] || [];
									var b_formdirty = b_dirty;

									Ext.Array.each(a_modified, function(o_field) {
										if (o_field.dirty) {
											b_formdirty = o_field.dirty;
											return false;
										}
									});

									i_button = i_languageBar.getComponent(s_currentLang);

									if (i_button) {
										i_button.setIconCls(b_formdirty ? "flatui icon-data-new" : "");
									}
								}
							}
						}

						if (i_owner && i_owner.id != i_content.id) {

							Ext.Array.each(a_languages, function (s_key) {

								if (s_key === i_owner.language) {

									var a_modified = i_owner.modified[s_key];
									var b_formdirty = b_dirty;

									Ext.Array.each(a_modified, function (o_field) {
										if (o_field.dirty) {
											b_formdirty = o_field.dirty;
											return false;
										}
									});

									if (!b_formdirty) {
										i_content.setIconCls("");
									}
								}
							});
						}
					}
				}
			},
			validitychange: {
				fn: function(i_form, b_valid) {

					var i_contentForm = i_content.getForm();
					var i_languageBar = i_self.getLanguageBar();
					var s_currentLang = i_self.getLanguage();

					if (i_content && i_content.tab) {
						i_content.tab.removeCls("x-tab-error");
					}

					if (!b_valid) {
						if (i_content && i_content.tab) {
							i_content.tab.addCls("x-tab-error");
						}
					}

					if (i_languageBar) {

						var i_button = i_languageBar.getComponent(s_currentLang);

						if (i_button) {

							i_button.setIconCls(b_valid ? "flatui icon-data-new" : "flatui icon-data-error");
						}
					}

					if (b_valid) {

						var b_dirty = i_contentForm.isDirty();

						i_form.fireEvent("dirtychange", i_form, b_dirty);
					}
				}
			}
		});
	},

	createToolbar: function () {

		var i_self = this;

		var s_dmdName = i_self.getDmdName();
		var s_entity = i_self.getEntity();

		var s_language = i_self.getLanguage();

		var s_class = "AIL-icon AIL-icon-16 icon-flag_" + s_language;

		var a_items = [
			{
				xtype: "tbitem",
				itemId: "flag",
				height: 16,
				width: 23,
				cls: s_class,
				language: s_language,
				hidden: true,
				focusable: false,
				tabIndex: -1
			},
			{
				xtype: "tbtext",
				itemId: "title",
				text: "",
				focusable: false,
				tabIndex: -1,
				hidden: true
			},
		];

		// Add toolbar

		if (ip2.isAccessible("app." + s_dmdName + ".data.delete") ||
			ip2.isAccessible("app." + s_dmdName + ".data." + s_entity + ".delete")) {
			a_items.push({
				xtype: "button",
				text: ip2.i18n({
					da: "Slet",
					en: "Delete"
				}),
				tabIndex: 1,
				focusable: true,
				itemId: "delete",
				disabled: false,
				hidden: !i_self.getDeletable(),
				handler: "onDelete"
			});
		}

		a_items = a_items.concat([
			"->",
			{
				xtype: "button",
				text: ip2.i18n({
					da: "Annuller",
					en: "Cancel"
				}),
				tabIndex: 1,
				focusable: true,
				itemId: "close",
				handler: function () {

					var i_contextParent = i_self.getContextParent();
					i_contextParent.close();
				}
			},
			{
				xtype: "button",
				text: ip2.i18n({
					da: "Gem",
					en: "Save"
				}),
				itemId: "save",
				hidden: true,
				focusable: false,
				tabIndex: -1,
				handler: function (i_button) {
					i_button.disable();
					i_self.save(function (i_record) {
						i_self.resetDirty(i_record);

						i_self.setSaved(true);

						i_button.enable();

						Ext.Array.each(i_self.getRelationGrids(), function(i_grid) {

							var o_gridExtraParams = i_grid.extraParams;
							var o_keys = ip2.getRelationKeysFromRecord(i_record, i_grid.relationInfo);

							Ext.apply(o_gridExtraParams, {
								filter: ip2.keysToFilter(o_keys)
							});
							i_grid.enable();
						});
					});
				}
			},
			{
				xtype: "button",
				text: ip2.i18n({
					da: "Gem",
					en: "Save"
				}),
				itemId: "saveclose",
				ui: "primary-button",
				hidden: true,
				focusable: true,
				tabIndex: 1,
				handler: function (i_button) {
					i_button.disable();
					i_self.save(function (i_record) {

						i_self.setForceClose(true);
						var i_contextParent = i_self.getContextParent();

						i_contextParent.close();
					});
				}
			}
		]);

		var i_toolbar = Ext.widget("toolbar", {
			itemId: "actionbar",
			dock: "bottom",
			ui: "footer",
			hidden: false,
			focusable: false,
			tabIndex: -1,
			items: a_items
		});

		i_self.setActionbar(i_toolbar);

		return i_toolbar;
	},

	createToolbarFeatures: function () {

		var i_self = this;
		var i_record = i_self.getRecord();
		var o_view = i_self.getViewConfig();
		var o_features = o_view.features || {};
		var a_items = [];

		if (o_features.hasOwnProperty("menu")) {

			if (o_features.menu.src) {

				var o_menu = Portfolio.util.Handler.getEvaled({
					url: o_features.menu.src
				});

				if (o_menu) {

					var f_initialize = o_menu.onInitialize || Ext.emptyFn;

					try {
						a_items = f_initialize.call(i_self, i_self, {
							parentId: "",
							formId: i_self.id,
							records: [
								i_record
							]
						}, "form");

						a_items = Ext.Array.from(a_items);
					}
					catch (err) {}
				}
			}
		}

		return a_items;
	},

	createLinkButton: function(i_record, b_window) {

		var i_self = this;
		i_record.dmdFile = i_self.getDmd();

		return {
			xtype: b_window ? "tool" : "button",
			iconCls: "pf-link",
			ui: b_window ? "" : "function-action",
			handler: function () {

				var i_tabpanel = i_self.getTabPanel();
				var i_active = i_tabpanel.getActiveTab();
				var n_index = i_tabpanel.items.indexOf(i_active);

				var i_window = Ext.widget("link.window", {
					model: i_record,
					activeTabIndex: n_index
				});

				i_window.show();
			}
		};
	},

	createStore: function () {

		var i_self = this;
		var o_entity = i_self.getEntityConfig();
		var i_model = i_self.getModel();
		var o_model = i_self.getDmdModel();

		var o_proxy = o_model.proxy;

		o_proxy.portfolio = o_proxy.hasOwnProperty("portfolio") ? o_proxy.portfolio : true;

		var s_view = i_self.getView();

		if (!o_entity.ui.forms.hasOwnProperty(s_view)) {
			s_view = "portfolio";
		}

		var i_store = Ext.create("Ext.data.Store", {
			model: i_model,
			proxy: Portfolio.util.Handler.getProxyByEntity({
				dmd: i_self.getDmd(),
				entityName: i_self.getEntity(),
				uiName: s_view,
				context: "form"
			}),
			autoLoad: false,
			listeners: {
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();

						var o_keys = i_self.getKeys() || {};

						Ext.apply(o_extraParams, {
							action: "getRow",
							context: "form",
							dmdFile: i_self.getDmd(),
							uiName: s_view,
							key: Ext.encode(o_keys)
						});
					}
				}
			}
		});

		i_self.setStore(i_store);

		return i_store;
	},

	createModel: function () {

		var i_self = this;
		var i_model = i_self.getModel();

		if (!i_model) {

			var s_dmd = i_self.getDmd();
			var s_entity = i_self.getEntity();
			var s_view = i_self.getView();
			var o_entity = i_self.getEntityConfig();

			var o_form = o_entity.ui.forms[s_view];

			if (!o_form) {
				s_view = "portfolio";
			}

			i_model = ip2.model({
				dmd: s_dmd,
				entityName: s_entity,
				uiName: s_view,
				context: "form"
			});

			var i_proxy = Portfolio.util.Handler.getProxyByEntity({
				dmd: s_dmd,
				entityName: s_entity,
				uiName: s_view,
				context: "form"
			});

			var i_reader = i_proxy.getReader();

			i_reader.setRootProperty("");

			i_model.setProxy(i_proxy);

			i_self.setModel(i_model);
		}

		return i_model;
	},

	setActiveLanguage: function (s_lang) {

		var i_self = this;
		var i_actionbar = i_self.getActionbar();
		var i_flag = i_actionbar.items.get("flag");

		s_lang = s_lang || i_self.getLanguage();

		i_flag.getEl().dom.classList.remove("icon-flag_" + i_flag.language);
		i_flag.getEl().dom.classList.add("icon-flag_" + s_lang);
		i_flag.language = s_lang;
	},

	getViewConfig: function () {

		var i_self = this;
		var s_view = i_self.getView();
		var o_entity = i_self.getEntityConfig();
		var o_dataConfig = i_self.getDataConfig();
		var o_definition = i_self.getDefinition();

		var o_ui = o_entity.ui || {};
		var o_forms = o_ui.forms || {};

		var o_view;

		if (o_definition) {

			var a_pd = o_definition.pd || [];
			var o_pd = a_pd[0];

			if (o_pd) {

				var s_cached = [
					o_entity.name,
					o_pd.property,
					o_pd.fcid
				].join(".");

				o_view = Portfolio.pd.util.Cache.get(s_cached);

				o_view = o_view || o_entity.ui.forms[s_view];
			}
		}

		if (o_dataConfig) {
			o_view = o_dataConfig.ui.forms[s_view];
			if (!o_view) {
				o_view = o_dataConfig.ui.forms.portfolio;
			}
		}

		if (!o_view) {
			o_view = o_forms[s_view] || o_forms.portfolio;
		}

		return o_view;
	},

	updateViewConfig: function(o_view) {

		var i_self = this;
		var s_view = i_self.getView();
		var o_entity = i_self.getEntityConfig();
		var o_dataConfig = i_self.getDataConfig();

		if (o_dataConfig) {

			var o_temp = o_dataConfig.ui.forms[s_view];

			if (o_temp) {
				o_dataConfig.ui.forms[s_view] = o_view;
			}
			else {
				o_dataConfig.ui.forms.portfolio = o_view;
			}
		}
		else {
			var o_config = o_entity.ui.forms[s_view];

			if (o_config) {
				o_entity.ui.forms[s_view] = o_view;
			}
			else {
				o_entity.ui.forms.portfolio = o_view;
			}
		}

		return o_view;
	},

	getFieldDefinitions: function (i_record, b_createPd) {

		var i_self = this;

		var o_definition = i_self.getDefinition() || {};

		var o_entity = i_self.getEntityConfig();

		var a_entityColumns = o_entity.columns || [];
		
		var b_temp = false;

		var s_defaultCollection = i_self.getDefaultCollection() || "";

		if (Ext.Object.isEmpty(o_definition)) {

			var a_pd = [];

			Ext.Array.each(a_entityColumns, function(o_config) {
				
				if (o_config.pd) {

					var s_view = i_self.getView();

					var o_temp = Ext.decode(i_record.get(o_config.name), true) || {};

					var b_created = false;

					if (o_temp.hasOwnProperty("fcid")) {
						o_temp.fcid = o_temp.fcid == "mask_" ? "mask_unknown" : o_temp.fcid;
					}

					if (!o_temp.fcid && s_defaultCollection) {
						o_temp.fcid = s_defaultCollection;
					}
	
					var s_name = [
						o_entity.name,
						s_view,
						o_config.name
					].join(".");
	
					var a_definitions = Portfolio.pd.util.Cache.load(o_config.pd, s_name);
	
					a_pd.push({
						fcid: o_temp.fcid,
						property: o_config.name,
						definitions: a_definitions,
						created: b_created
					});
				}
			});

			if (!Ext.isEmpty(a_pd)) {

				o_definition.pd = a_pd

				b_temp = true;

				i_self.setDefinition(o_definition);
			}
		}
		
		var o_view = i_self.getViewConfig();

		if (b_temp) {

			o_definition = {};

			i_self.setDefinition(o_definition);
		}

		var i_util = i_self.getUtil();

		var o_uiComponents = {};

		var a_fields = [];

		var o_uiTypeRules = ip2.loadUiTypeRules();
		var o_uiRules = ip2.uirules.flatten;

		var a_viewColumns = [];
		var items = Ext.isArray(o_view.items) ? Ext.Array.slice(o_view.items) : Ext.Array.slice(o_view.items.columns);

		if (items) {
			a_viewColumns = items;
		}

		if (!Ext.Object.isEmpty(o_definition)) {

			var a_temp = Ext.Array.from(o_definition.pd);

			if (a_temp.length > 0 && b_createPd) {

				var o_pd = a_temp[0];

				a_fields = Ext.Array.from(o_definition.fields);

				var a_definitions = o_pd.definitions;

				var o_values = Ext.decode(i_record.get(o_pd.property), true);

				var s_id = o_pd.fcid = o_values.id || o_values.fcid;

				var s_cached = [
					o_entity.name,
					o_pd.property,
					s_id
				].join(".");

				var o_cached = Portfolio.pd.util.Cache.get(s_cached) || {};

				var a_values = Ext.Array.from(o_cached.items || o_view.items);

				var a_pdFields = i_self.getPdFields(Ext.apply({}, {
					uiRules: o_uiRules,
					uiTypeRules: o_uiTypeRules,
					util: i_util,
					viewColumns: a_values,
					entityColumns: a_entityColumns,
					components: o_uiComponents,
					record: i_record,
					definitions: a_definitions,
					data: o_values
				}));

				a_fields = Ext.Array.filter(a_fields, function(i_search) {

					var i_found = Ext.Array.findBy(a_pdFields, function(i_finding) {
						return i_search.name == i_finding.name;
					});

					return i_found ? false : true;
				});

				a_fields = a_fields.concat(a_pdFields);

				a_fields.sort(function(a, b) {
					var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
					var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

					return n_a - n_b;
				});

				Ext.Array.each(a_fields, function(i_field) {

					var a_postprocess = i_field.postprocess || [];

					Ext.Array.each(a_postprocess, function (f_process) {
						f_process.call(i_field, o_uiComponents, i_record);
					});
				});

				o_definition.fields = a_fields;
				o_definition.pd = a_temp;

			}

			return o_definition;
		}

		var o_languageInfo = i_self.getLanguageInfoInformation();

		var a_xpdConfig = [];
		var a_pd = [];

		var o_data = i_record.getData();

		var a_columns = a_entityColumns.concat(a_viewColumns);
		var a_handel = [];

		var s_context = i_self.getLangContext();

		Ext.Array.each(a_columns, function(o_column) {

			var o_found = Ext.Array.findBy(a_handel, function(o_config) {
				return o_config.name == o_column.name;
			});

			if (o_found) {
				o_found = Ext.Object.merge(o_found, o_column);
			}
			else {
				a_handel.push(o_column);
			}
		});

		Ext.Array.each(a_handel, function (o_viewColumn) {

			var s_key = o_viewColumn.name;

			if (o_viewColumn.type != "collection" && o_viewColumn.type != "group" && o_viewColumn.type != "property") {

				var o_entityColumn = Ext.Array.findBy(a_entityColumns, function(o_column) {
					return o_column.name == s_key;
				});

				var o_config = Ext.Object.merge({}, o_entityColumn, o_viewColumn, {
					langContext: s_context
				});

				var a_type = ip2.getFieldTypeDefinition(o_config.type);

				if (a_type.length > 0) {
					Ext.apply(o_config, {
						type: a_type[0]
					});
				}

				var o_xpd = o_config.xpd;

				if (o_xpd) {
					// Make sure we get an extension on the XPD definition
					o_config.xpd = o_config.xpd.split(".").length == 1 ? o_config.xpd += ".xpd" : o_config.xpd;
					o_config.type = "xpd";
				}

				// Clean up the uiType || uitype since it will mess up the component creation
				if (o_config.uiType) {
					delete o_config.uiType;
				}
				if (o_config.uitype) {
					delete o_config.uitype;
				}

				o_config.value = i_record.get(s_key);

				var o_components = i_util.createUiComponent({
					rulesXpd: o_uiRules,
					rulesJs: o_uiTypeRules,
					context: "form",
					config: o_config,
					data: i_record.getData()
				});

				Ext.Object.each(o_components, function(s_key, o_component) {

					if (o_component.name == o_entity.idColumn) {
						var a_primary = o_entity.primaryKey || [];
						if (a_primary.length === 0) {
							o_component.readOnly = true;
						}
					}

					if (o_config.xpd) {

						o_component.xpd = o_config.xpd;

						var o_xpd = ip2.resource.get(o_component.xpd, true);
						var o_value = o_component.value || {};
						var o_collections = o_xpd.collections;

						delete o_collections.all;

						var n_collections = Ext.Object.getKeys(o_collections).length;

						if (Ext.isEmpty(o_component.value)) {

							if (n_collections === 1) {

								o_value[o_xpd.idProperty] = o_collections[Ext.Object.getKeys(o_collections)[0]].id;
							}
							else {
								o_value = Ext.ux.xpd.Handler.getValueFromProperties(o_xpd, o_data);
							}

							o_component.value = Ext.encode(o_value);
						}

						Ext.apply(o_component, {
							type: "varchar",
							uiclass: "Ext.form.field.Text",
							xtype: "textfield",
							hidden: true,
							isDirty: function() {

								var i_field = this;

								var b_dirty = false;
								var s_value = i_field.getValue() || "{}";
								var s_originalValue = i_field.originalValue || "{}";
								var o_value = Ext.decode(s_value, true) || {};
								var o_original = Ext.decode(s_originalValue, true) || {};

								var n_value = Ext.Object.getKeys(o_value).length;
								var n_original = Ext.Object.getKeys(o_original).length;

								var b_sameCount = n_value == n_original;

								if (b_sameCount) {

									Ext.Object.each(o_value, function(s_key, value) {

										if (!o_original.hasOwnProperty(s_key)) {
											b_dirty = true;
											return false;
										}

										var originalvalue = o_original[s_key];

										var s_value = Ext.encode(value);
										var s_originalValue = Ext.encode(originalvalue);

										b_dirty = s_value !== s_originalValue;

										if (b_dirty) {
											return false;
										}
									});
								}

								return b_dirty;
							}
						});

						o_config.xpd = o_xpd;

						a_xpdConfig.push(o_config);
					}

					if (o_config.pd) {

						var s_view = i_self.getView();

						var s_name = [
							o_entity.name,
							s_view,
							o_config.name
						].join(".");

						var a_definitions = Portfolio.pd.util.Cache.load(o_config.pd, s_name);

						o_component.hidden = true;

						var o_temp = Ext.decode(i_record.get(o_config.name), true) || {};

						var b_created = false;

						if (o_temp.hasOwnProperty("fcid")) {
							o_temp.fcid = o_temp.fcid == "mask_" ? "mask_unknown" : o_temp.fcid;
						}

						if (!o_temp.fcid && s_defaultCollection) {
							o_temp.fcid = s_defaultCollection;
						}

						if (o_temp.fcid) {

							b_created = true;

							var s_cached = [
								o_entity.name,
								o_config.name,
								o_temp.fcid
							].join(".");


							var o_cached = Portfolio.pd.util.Cache.get(s_cached) || {};

							var a_values = Ext.Array.from(o_cached.items || o_view.items);

							var a_pdFields = i_self.getPdFields(Ext.apply({}, {
								uiRules: o_uiRules,
								uiTypeRules: o_uiTypeRules,
								util: i_util,
								viewColumns: a_values,
								entityColumns: a_entityColumns,
								components: o_uiComponents,
								record: i_record,
								definitions: a_definitions,
								data: o_temp
							}));

							a_fields = Ext.Array.filter(a_fields, function(i_search) {

								var i_found = Ext.Array.findBy(a_pdFields, function(i_finding) {
									return i_search.name == i_finding.name;
								});

								return i_found ? false : true;
							});

							a_fields = a_fields.concat(a_pdFields);
						}

						a_pd.push({
							fcid: o_temp.fcid,
							property: o_config.name,
							definitions: a_definitions,
							created: b_created
						});

					}

					var i_found = Ext.Array.findBy(a_fields, function(i_search) {
						return i_search.name == o_component.name;
					});

					if (!i_found) {
						var i_field = Ext.create(o_component.uiclass, o_component);

						o_uiComponents[i_field.name] = i_field;

						a_fields.push(i_field);
					}
				});
			}
		});

		a_fields.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		Ext.Array.each(a_fields, function(i_field) {

			var a_postprocess = i_field.postprocess || [];

			Ext.Array.each(a_postprocess, function (f_process) {
				f_process.call(i_field, o_uiComponents, i_record);
			});

			var o_config = Ext.Array.findBy(a_viewColumns, function(o_config) {
				return i_field.name == o_config.name;
			});

			if (o_config) {
				i_field.group = i_field.group || o_config.group;
			}

		});

		if (o_languageInfo) {

			var o_config = {
				field: o_languageInfo.propertyKey,
				xpd: ip2.resource.get(o_languageInfo.xpd, true),
				isLanguages: true
			};

			a_xpdConfig = [o_config];
		}

		o_definition = {
			fields: a_fields,
			xpdConfig: a_xpdConfig,
			pd: a_pd
		};

		i_self.setDefinition(o_definition);

		return o_definition;
	},

	getPdFields: function(o_values) {

		var i_self = this;

		var o_uiRules = o_values.uiRules;
		var o_uiTypeRules = o_values.uiTypeRules;
		var i_util = o_values.util;
		var a_viewColumns = o_values.viewColumns;
		var a_entityColumns = o_values.entityColumns;
		var o_uiComponents = o_values.components;
		var i_record = o_values.record;
		var a_definitions = o_values.definitions;
		var o_data = o_values.data;
		var o_entity = i_self.getEntityConfig();

		var a_return = [];

		var o_result = Portfolio.pd.util.Handler.createFormCollection(o_data, a_definitions, true);

		var o_process = {};
		var a_create = [];
		var a_temp = [];
		var s_context = i_self.getLangContext();

		Ext.Object.each(o_result, function(s_key, o_field) {

			var o_column = Ext.Array.findBy(a_viewColumns, function(o_item) {
				return o_item.name == s_key;
			});

			if (!o_column) {
				o_process[s_key] = Ext.clone(Ext.Object.merge(o_field, {
					langContext: s_context
				}));
			}
			else {
				a_create.push(o_column);
			}

		});

		Ext.Array.each(a_create, function(o_config) {

			var s_create = o_config.name;

			var o_entityColumn = Ext.Array.findBy(a_entityColumns, function(o_column) {
				return o_column.name == s_create;
			});

			var o_create = Ext.Object.merge({}, o_entityColumn, o_config, {
				langContext: s_context
			});

			if (o_create.apperence) {

				Ext.apply(o_create, {
					type: o_create.apperence
				});

				delete o_create.apperence;
			}
			else {
				if (o_create.type == "property") {
					o_create.type = o_create.datatype;
				}
			}

			o_create.type = o_create.type || "varchar";

			var a_type = ip2.getFieldTypeDefinition(o_create.type);

			if (a_type.length > 0) {
				Ext.apply(o_create, {
					type: a_type[0]
				});
			}

			if (o_create.uiType) {
				delete o_create.uiType;
			}
			if (o_create.uitype) {
				delete o_create.uitype;
			}

			var o_recordData = i_record.getData();

			o_create.value =  o_recordData.hasOwnProperty(s_create) ? o_recordData[s_create] : o_data.hasOwnProperty(s_create) ? o_data[s_create] : "";

			var o_components = i_util.createUiComponent({
				rulesXpd: o_uiRules,
				rulesJs: o_uiTypeRules,
				context: "form",
				config: o_create,
				data: i_record.getData()
			});

			Ext.Object.each(o_components, function(s_key, o_component) {

				if (o_component.name == o_entity.idColumn) {
					var a_primary = o_entity.primaryKey || [];
					if (a_primary.length === 0) {
						o_component.readOnly = true;
					}
				}

				var i_field = Ext.create(o_component.uiclass, o_component);

				i_field.resetOriginalValue();

				o_uiComponents[i_field.name] = i_field;

				a_return.push(i_field);
			});
		});

		var a_created = Portfolio.pd.util.Handler.createItems(o_process);

		a_temp = a_temp.concat(a_created);

		Ext.Array.each(a_created, function(i_field) {
			i_field.resetOriginalValue();
		});

		a_return = a_return.concat(a_temp);

		return a_return;
	},

	getXpdDefinitions: function(i_record, o_field) {

		var i_self = this;
		var s_data = i_record.get(o_field.name || o_field.field) || i_record.getData();
		var o_xpd = o_field.xpd;

		var o_data;
		var o_collection;
		var a_fields = [];

		var o_result = {
			fields: [],
			collection: {},
			xpd: o_xpd,
			field: o_field.name || o_field.field
		};

		if (Ext.isObject(s_data)) {
			o_data = s_data;
		}
		else if (Ext.isString(s_data)) {

			o_data = Ext.decode(s_data, true) || {};
		}

		if (o_data) {

			if (!o_data.hasOwnProperty(o_xpd.idProperty)) {

				var n_count = Ext.Object.getKeys(o_xpd.collections).length;

				if (n_count === 1) {
					o_data[o_xpd.idProperty] = o_xpd.collections[Ext.Object.getKeys(o_xpd.collections)[0]].id;
				}
			}

			o_data = Ext.ux.xpd.Handler.convertData(o_xpd, o_data);

			if (o_xpd.hasOwnProperty("cidMap")) {
				var o_cidMap = o_xpd.cidMap;

				Ext.Object.each(o_cidMap, function(s_collection, o_map) {
					Ext.Object.each(o_map, function(s_cid, n_id) {
						if (s_cid == o_data[o_xpd.idProperty]) {
							o_data[o_xpd.idProperty] = n_id;
						}
					});
				});
			}

			o_collection = o_xpd.collections[o_data[o_xpd.idProperty]];

			if (o_collection) {

				o_data = Ext.Object.merge({}, o_data, i_record.getData());

				a_fields = Ext.ux.xpd.Handler.getFieldsWithValues(o_xpd, o_collection.id, o_data);

				Ext.apply(o_result, {
					fields: a_fields,
					collection: o_collection,
					xpd: o_xpd
				});
			}
		}
		else {
			Ext.apply(o_result, {
				fields: a_fields,
				xpd: o_xpd
			});
		}

		return o_result;
	},

	getLanguageInfoInformation: function(i_record) {

		var i_self = this;
		var o_languageInfo = i_self.getLanguageInfo();

		if (!o_languageInfo) {

			var o_entity = i_self.getEntityConfig();

			if (o_entity && o_entity.widgets) {

				var a_keys = Ext.Object.getKeys(o_entity.widgets);
				var o_info = o_entity.widgets[a_keys[0]];

				if (o_info && o_info.dmd && o_info.entity) {

					var i_model = ip2.model({
						dmd: o_info.dmd,
						entityName: o_info.entity,
						uiName: o_info.view,
						context: "form"
					});

					i_model.setProxy(Portfolio.util.Handler.getProxyByEntity({
						dmd: o_info.dmd,
						entityName: o_info.entity,
						uiName: o_info.view,
						context: "form"
					}));

					var i_created = i_model.create({});

					var o_config = {
						dmd: o_info.dmd || "webshop.dmd",
						entity: o_info.entity,
						xpd: o_info.xpd || "pages.xpd",
						view: o_info.view || "portfolio",
						propertyKey: o_info.propertyKey || "PLGPROP",
						fieldKey: o_info.fieldKey || "PLGPLGTKN",
						foreignKey: o_info.foreignKey || "PLGLNGCOD",
						relationKey: o_info.relationKey || "PLGPAGTKN",
						token: i_created.idProperty || "PLGPLGTKN",
						action: i_self.getAction() || "create",
						allowChange: o_info.allowChange !== undefined ? o_info.allowChange : true
					};

					o_languageInfo = o_config;

					i_self.setLanguageInfo(o_languageInfo);
					i_self.setLanguageModel(i_model);
				}
			}
		}

		return o_languageInfo;
	},

	isDirty: function() {

		var i_self = this;
		var i_controller = i_self.getController();

		return i_controller.isDirty();
	},

	isValid: function() {

		var i_self = this;
		var i_controller = i_self.getController();

		return i_controller.isValid();
	},

	getRelationDefinitions: function (i_record) {

		var i_self = this;

		var o_model = i_self.getDmdModel();
		var s_entity = i_self.getEntity();

		var o_dataConfig = i_self.getDataConfig() || {};

		var a_relations = o_dataConfig.relations || o_model.relations || [];

		var a_grids = [];
		var a_fields = [];

		var a_result = [];

		Ext.Array.each(a_relations, function(o_relation) {
			if (o_relation.between.entity == s_entity || o_relation.and.entity == s_entity) {

				var o_result;

				if (o_relation.between.entity == s_entity) {
					o_result = o_relation;
				}
				else if (o_relation.and.entity == s_entity) {

					o_result = Ext.apply({}, {
						between: Ext.clone(o_relation.and),
						and: Ext.clone(o_relation.between),
						properties: Ext.clone(o_relation.properties),
						cid: o_relation.cid
					});
				}

				var o_found = Ext.Array.findBy(a_result, function(o_config) {
					return o_config.between.entity == o_result.between.entity && o_config.and.entity == o_result.and.entity;
				});

				if (!o_found) {
					a_result.push(o_result);
				}
			}
		});

		Ext.Array.each(a_result, function (o_relation) {

			var s_occurence = o_relation.and.occurrence;
			var b_between = true;

			if (s_occurence == "many") {
				var a_result = i_self.createRelationGrid(o_relation, i_record, o_model, true);
				if (a_result) {
					a_grids = a_grids.concat(a_result);
				}
			}
			else if (s_occurence == "one") {
				var i_field = i_self.createRelationField(o_relation, i_record, o_model, true);
				if (i_field) {
					a_fields.push(i_field);
				}
			}
		});

		return {
			grids: a_grids,
			fields: a_fields
		};
	},

	getAffiliations: function(i_record) {

		var i_self = this;

		var a_return = [];

		var o_view = i_self.getViewConfig(i_record);

		var a_affiliations = o_view.affiliations || [];

		Ext.Array.each(a_affiliations, function(o_value) {

			if (o_value.hasOwnProperty("url") && o_value.url) {

				var i_iframe = Ext.widget("webcontainer", {
					src: i_self.getAffiliationUrl(o_value.url, i_record),
					title: o_value.title,
					index: o_value.index || 0,
					itemId: "affiliation-" + o_value.name,
					disabled: !i_record.get(i_record.idProperty)
				});
				a_return.push(i_iframe);
			}
			else if (o_value.hasOwnProperty("component") && !Ext.Object.isEmpty(o_value.component)) {

				var o_config = o_value.component;

				Ext.Object.each(o_config, function(s_key, value) {
					if (Ext.isString(value) && !Ext.isEmpty(value)) {
						var i_template = Ext.create("Ext.XTemplate", value);
						i_template.compile();
						var s_out = i_template.apply(i_record.getData());
						o_config[s_key] = s_out;
					}
				});

				Ext.apply(o_config, {
					title: o_value.title || i_record.get(i_record.idProperty),
					itemId: "affiliation-" + o_value.name,
					disabled: !i_record.get(i_record.idProperty)
				});

				var i_component = Ext.widget(o_config.xtype, o_config);
				a_return.push(i_component);
			}
		});

		return a_return;
	},

	getAffiliationUrl: function(s_url, i_record) {

		var s_return = "";
		var s_templete = s_url;

		s_templete = s_templete.replace("{", "{[this.encode(values.");
		s_templete = s_templete.replace(")]}");

		var i_template = Ext.create("Ext.XTemplate",
			"<tpl>",
				s_templete,
			"</tpl>",
			{
				encode: function(value) {

					var s_return = Ext.urlEncode(value);
					return s_return;
				}
			}
		);

		i_template.compile();

		s_return = i_template.apply(i_record.getData());

		return s_return;
	},

	createRelationGrid: function (o_relation, i_record, o_model, b_between) {

		var i_self = this;

		var o_view = i_self.getViewConfig();

		var s_entity = b_between ? o_relation.and.entity : o_relation.between.entity;

		var a_entities = Ext.Object.getValues(o_model.entities);

		var o_entity = Ext.Array.findBy(a_entities, function(o_value) {
			return o_value.name == s_entity;
		});

		var s_dmd = i_self.getDmd();

		var o_layout = !Ext.Object.isEmpty(o_view.layout) ? o_view.layout : !Ext.Object.isEmpty(o_view.relation) ? o_view.relation : undefined;

		if (!o_layout) {
			return false;
		}

		var a_layouts = [];
		var a_grids = [];

		if (Ext.isObject(o_layout)) {
			Ext.Object.each(o_layout, function(s_key, o_value) {
				o_value.cid = s_key;
				a_layouts.push(o_value);
			});
		}
		else {

			if (Ext.isArray(o_layout)) {
				a_layouts = o_layout;
			}
		}

		var o_properties = o_relation.properties;

		Ext.Array.each(a_layouts, function(o_layout) {

			var b_found = false;

			if (o_layout.hasOwnProperty("cid")) {
				b_found = o_layout.cid == o_properties.cid;
			}

			if (b_between) {
				if (o_relation.and.entity == o_layout.entity) {
					b_found = true;
				}
			}
			else {
				if (o_relation.between.entity == o_layout.entity) {
					b_found = true;
				}
			}

			if (!b_found) {
				return;
			}

			var s_title = o_layout.title || o_relation.properties.title || o_entity.title;

			var o_keys = ip2.getRelationKeysFromRecord(i_record, o_relation, b_between);

			// Create the basic component definitions

			var b_create = true;

			Ext.Object.each(o_keys, function(s_key, value) {
				if (Ext.isEmpty(value)) {
					b_create = false;
				}
			});

			Ext.Object.each(o_keys, function(s_key, value) {
				o_keys[s_key] = value || -1;
			});

			var o_gridConfig = Ext.apply({}, {
				title: ip2.i18n(s_title),
				itemId: "relation-grid-" + s_entity + "-" + o_layout.view || "portfolio",
				border: false,
				layout: "fit",
				relationInfo: o_relation,
				dmd: {
					path: o_relation.properties.dmd || s_dmd,
					entityName: s_entity
				},
				uiName: o_layout.view || "portfolio",
				index: o_layout.index || 0,
				extraParams: {
					filter: ip2.keysToFilter(o_keys)
				},
				disabled: !b_create
			}, o_layout);

			var i_selected = i_record;

			var i_relation = Ext.widget("portfolio-entity-grid", o_gridConfig);

			i_relation.on({
				afterrender: {
					fn: function(i_grid) {

						var i_toolbar = i_grid.getEntityToolBar();
						var i_add = i_toolbar.items.get("button-add");
						var o_dmdConfig = i_grid.getDmdCfg();

						var s_mappedId = b_between ? o_relation.and.on[0].name : o_relation.between.on[0].name;

						i_grid.events.itemdblclick.clearListeners();

						var o_size = Portfolio.util.Handler.getWindowSize();

						var o_windowConfig = {
							modal: false,
							closable: true,
							collapsible: true,
							resizable: true,
							width: o_size.width * 0.9,
							height: o_size.height * 0.9,
							layout: "fit",
							maximizable: true
						};

						var o_window = o_layout.window || {};

						if (i_add) {
							i_add.handler = function(i_button) {

								var o_keys = {};
								o_keys[s_mappedId] = i_selected.get(i_selected.idProperty);

								Ext.apply(o_dmdConfig, {
									keys: {},
									data: o_keys
								});

								var s_action = "create";

								if (!Ext.Object.isEmpty(o_window)) {

									Ext.apply(o_windowConfig, o_layout.window);
								}

								if (i_grid.fireEvent("before" + s_action, i_grid, o_dmdConfig)) {

									var i_contextParent = i_self.getContextParent();

									var s_managerId = "";

									if (i_contextParent.zIndexManager) {

										s_managerId = i_contextParent.zIndexManager.id;
									}

									Portfolio.app.fireEvent("entityWindow", o_dmdConfig, s_action, o_windowConfig, s_managerId);
								}
							};
						}

						i_grid.on({
							itemdblclick: {
								fn: function(i_view, i_record) {

									var o_keys = {};
									o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

									if (!Ext.Object.isEmpty(o_window)) {

										Ext.apply(o_windowConfig, o_layout.window);
									}

									Ext.apply(o_dmdConfig, {
										keys: o_keys,
										listeners: {
											contentReady: {
												fn: function (i_content, i_entitypanel) {
													var i_form = i_content.getForm();

													var i_field = i_form.findField(i_record.idProperty);
													if (i_field) {
														i_field.setReadOnly(true);
													}
												}
											}
										}
									});

									var s_action = "update";

									if (i_grid.fireEvent("before" + s_action, i_grid, o_dmdConfig)) {

										var i_contextParent = i_self.getContextParent();

										var s_managerId = "";

										if (i_contextParent.zIndexManager) {

											s_managerId = i_contextParent.zIndexManager.id;
										}


										Portfolio.app.fireEvent("entityWindow", o_dmdConfig, s_action, o_windowConfig, s_managerId);
									}
								}
							}
						});
					},
					scope: this
				}
			});

			a_grids.push(i_relation);
		});

		return a_grids;
	},

	createRelationField: function (o_relation, i_record, o_model, b_between) {

		var i_self = this;

		var o_view = i_self.getViewConfig();
		var s_entity = b_between ? o_relation.and.entity : o_relation.between.entity;

		var a_entities = Ext.Object.getValues(o_model.entities);

		var o_entity = Ext.Array.findBy(a_entities, function(o_value) {
			return o_value.name == s_entity;
		});

		var s_cid = o_relation.cid || o_relation.properties.cid;
		var o_layout = o_view.layout ? o_view.layout[s_cid] : o_view.relation ? o_view.relation[s_cid] : undefined;

		if (!o_layout) {
			return false;
		}

		var o_keys = ip2.getRelationKeysFromRecord(i_record, o_relation);

		// Create the basic component definitions

		var b_create = true;

		Ext.Object.each(o_keys, function(s_key, value) {
			if (Ext.isEmpty(value)) {
				b_create = false;
			}
		});

		Ext.Object.each(o_keys, function(s_key, value) {
			o_keys[s_key] = value || -1;
		});

		if (!o_layout) {
			return false;
		}

		var s_fieldlabel = o_relation.properties.title || o_entity.title;

		Ext.Object.each(o_keys, function(s_key) {
			o_keys[s_key] = o_keys[s_key] || -1;
		});

		var i_field = Ext.widget("entitypicker", {
			fieldLabel: s_fieldlabel,
			dmd: o_relation.properties.dmd || i_self.getDmd(),
			entity: s_entity,
			view: o_layout.view || "portfolio",
			extraParams: {
				filter: ip2.keysToFilter(o_keys)
			}
		});

		return i_field;
	},

	getEntityForm: function(o_keys, o_config, b_closable, s_action, i_dataParent, f_callback) {

		var i_self = this;
		var i_user = Portfolio.util.Handler.getUser();
		f_callback = f_callback || Ext.emptyFn;

		var i_entitypanel = Ext.widget("portfolio-entity-form", {
			keys: s_action === "create" ? {} : o_keys,
			oldData: s_action === "create" ? o_keys : {},
			action: s_action,
			dmd: o_config.dmd,
			entity: o_config.entityName,
			view: o_config.uiName,
			dataParent: i_dataParent,
			context: "form",
			language: i_user.get("USRLNG") || "en",
			closable: b_closable,
			listeners: {
				contentReady: f_callback,
				scope: i_self
			}
		});

		return i_entitypanel;
	},

	getWidgetNewDefinitions: function(i_record) {

		var i_self = this;
		var o_view = i_self.getViewConfig(i_record);

		var a_widgets = [];

		Ext.Object.each(o_view.widgets, function (s_key, o_item) {

			var n_sequence = o_item.hasOwnProperty("sequence") ? o_item.sequence : o_item.hasOwnProperty("index") ? o_item.index : -1;

			var o_widget = {
				xtype: "ip2widget",
				widgetConfig: o_item,
				_config: o_item,
				itemId: "widget-" + s_key,
				title: ip2.i18n(o_item.title),
				src: o_item.path,
				border: false,
				trackerParent: i_self,
				dataParent: i_self,
				layout: o_item.layout || "fit",
				height: o_item.height || null,
				width: o_item.width || null,
				index: o_item.index || 0,
				sequence: n_sequence
			};

			a_widgets.push(o_widget);
		});

		return a_widgets;
	},

	getWidgetDefinitions: function (a_xpdConfig, i_record) {

		var i_self = this;
		var o_entity = i_self.getEntityConfig();
		var o_view = i_self.getViewConfig(i_record);

		var a_widgets = [];

		// If no widgets declared, no reason to go ahead
		if (!o_entity.widgets) {
			return a_widgets;
		}

		Ext.Object.each(o_view.layout, function (s_name, o_item) {

			var o_definition = o_entity.widgets[s_name];

			if (o_definition && o_definition.widgets) {

				Ext.Object.each(o_definition.widgets, function(s_key, o_value) {

					var o_clone = Ext.clone(o_value);

					var n_sequence = o_item.hasOwnProperty("sequence") ? o_item.sequence : o_item.hasOwnProperty("index") ? o_item.index : -1;

					var o_config = Ext.apply({
						xtype: "ip2widget",
						widgetConfig: o_clone,
						_config: o_clone,
						itemId: "widget-" + s_key,
						title: ip2.i18n(o_value.title),
						src: o_clone.path,
						border: false,
						trackerParent: i_self,
						dataParent: i_self,
						layout: "fit",
						index: o_clone.index || 0,
						sequence: n_sequence
					}, o_clone);

					delete o_config.id;

					a_widgets.push(o_config);
				});
			}
		});

		a_widgets = Ext.Array.filter(a_widgets, function(o_config) {
			return o_config.src && o_config.src.indexOf("languagexpd.widget") == -1;
		});

		return a_widgets;
	},

	getGroupDefinitions: function (a_fields, o_definition, i_record) {

		var i_self = this;
		var a_apps = i_self.getApps();

		var o_view = i_self.getViewConfig();
		var o_layout = o_view.layout || {};
		var o_system = Ext.apply({}, o_layout.portlets);

		Ext.Array.each(o_view.items, function(o_field) {

			var i_field = Ext.Array.findBy(a_fields, function(i_search) {
				return i_search.name == o_field.name;
			});

			if (i_field) {
				i_field.group = i_field.group || o_field.group;
			}
		});

		var a_groups = [];
		var a_nogroup = [];

		var i_nogroup = Ext.widget("fieldcontainer", {
			itemId: "nogroup",
			name: "nogroup",
			hidden: true,
			layout: "anchor",
			collapsible: true,
			collapsed: false,
			defaults: {
				anchor: "100%",
				labelWidth: 150
			},
			items: []
		});

		Ext.Object.each(o_view.groups, function(s_key, o_config) {

			var a_items = [];

			if (o_config.type === "collection" || o_config.type == "group") {

				var i_field = Ext.Array.findBy(a_fields, function(i_search) {
					return i_search.name == o_config.name;
				});

				if (i_field) {

					Ext.apply(i_field, {
						sequence: o_config.sequence,
						tabId: o_config.tabId
					});

					a_groups.push(i_field);
				}
			}
			else if (o_config.type === "app-component") {

				var s_main = o_config.main;
				var o_path = o_config.path || {};
				var o_values = Ext.clone(o_config.config || {});

				if (!Ext.Object.isEmpty(o_path)) {
					
					Ext.Loader.setConfig({
						paths: o_path
					});
				}

				Ext.apply(o_values, {
					transactiontype: i_self.transactiontype,
					entity: i_self.getEntity(),
					keys: i_self.getKeys(),
					record: i_self.getRecord()
				});

				var i_component = Ext.create(s_main, o_values);

				if (i_component) {

					Ext.apply(i_component, {
						sequence: o_config.sequence,
						tabId: o_config.tabId,
						name: o_config.name
					});

					a_groups.push(i_component);

					a_apps.push(i_component);
				}
			}
			else {
				var s_xtype = o_config.xtype || "fieldset";

				Ext.Array.each(a_fields, function (i_field) {
					if (i_field.group == s_key) {
						a_items.push(i_field);
					}
					else {
						if (!o_view.groups[i_field.group]) {
							a_nogroup.push(i_field);
						}
					}
				});

				a_items.sort(function(a, b) {
					var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
					var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

					var n_min = Math.min(n_a, n_b);

					return n_min;
				});

				Ext.applyIf(o_config, {
					collapsible: true,
					items: [],
					name: s_key
				});

				o_config.title = ip2.i18n(o_config.title);

				var i_group = Ext.widget(s_xtype, o_config);
				i_group.add(a_items);

				a_groups.push(i_group);

			}
		});

		if (a_groups.length == 0) {

			Ext.Array.each(a_fields, function(i_field) {
				a_nogroup.push(i_field);
			});
		}

		if (a_nogroup.length > 0) {
			i_nogroup.add(a_nogroup);
		}

		a_groups.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		Ext.Array.each(a_groups, function(o_group) {
			Ext.apply(o_group, o_system);
		});

		return {
			groups: a_groups,
			nogroup: i_nogroup
		};
	},

	makeChoise: function(a_definitions, i_record) {

		var i_self = this;
		var s_defaultCollection = i_self.getDefaultCollection();

		var b_choose = true;

		var o_data = {};

		if (a_definitions.length === 1) {

			var o_definition = a_definitions[0];
			var o_xpd = o_definition.xpd;
			var o_collections = o_xpd.collections;
			var n_collections = 0;
			var s_collection = "";

			Ext.Object.each(o_collections, function (s_key, o_value) {
				n_collections++;
				s_collection = s_key;
			});

			o_data[o_xpd.idProperty] = null;

			if (n_collections === 1) {
				o_data[o_xpd.idProperty] = o_collections[s_collection].id;
				b_choose = false;
			}
			else {
				var b_extend = false;
				var o_baseCollection;
				var a_extended = [];

				Ext.Object.each(o_xpd.collections, function(s_collection, o_collection) {
					if (o_collection.extend) {
						b_extend = true;
						if (a_extended.indexOf(o_collection.id) == -1) {
							a_extended.push(o_collection.id);
							if (a_extended.indexOf(o_collection.extend) == -1) {
								a_extended.push(o_collection.extend);
							}
							var n_extend = o_collection.extend;
							while (n_extend) {
								var o_tmp = o_collections[n_extend];
								n_extend = o_tmp.extend;
								if (n_extend && a_extended.indexOf(o_tmp.id) == -1) {
									a_extended.push(o_tmp.id);
									if (a_extended.indexOf(o_tmp.extend) == -1) {
										a_extended.push(o_tmp.extend);
									}
								}
							}
						}
					}
					else {
						if (a_extended.indexOf(o_collection.id) == -1) {
							b_extend = false;
							return false;
						}
						else {
							if (!o_collection.extend) {
								o_baseCollection = o_collection;
							}
						}
					}
				});

				if (!b_extend) {
					if (s_defaultCollection) {

						o_collection = o_xpd.collections[s_defaultCollection];

						o_data[o_xpd.idProperty] = o_collection.id;

						b_choose = false;
					}
				}
				else {
					o_data[o_xpd.idProperty] = o_baseCollection.id;
					b_choose = false;
				}
			}

			if (b_choose) {
				i_self.createPickerWindow(o_xpd, o_collections, o_definition, o_data, i_record);
			}
			else {

				i_self.addMap2Values(i_record, o_data);

				i_record.set(o_definition.field, Ext.encode(o_data));

				i_self.createView(i_record);
			}
		}
	},

	makePDChoise: function(o_pd, i_record) {

		var i_self = this;

		var a_definitions = Ext.Array.from(o_pd.definitions);

		var a_filtered = Ext.Array.filter(a_definitions, function(o_definition) {
			return o_definition.type == "formCollection" && !o_definition.isTemplate;
		});

		var i_store = Ext.create("Ext.data.Store", {
			sorters:[{
				property: "name",
				direction: "ASC"
			}],
			fields: [
				{
					name: "name",
					type: "auto"
				},
				{
					name: "label",
					type: "auto"
				}
			],
			data: a_filtered
		});

		var i_listTpl = Ext.create("Ext.XTemplate",
            "<tpl for=\".\">",
                "<li role=\"option\" class=\"x-boundlist-item\" style=\"text-overflow: ellipsis; white-space: nowrap; overflow:hidden;\">",
                    "{[this.getValue(values.label)]}",
                "</li>",
            "</tpl>",
            {
                getValue: function(value) {
                    return ip2.i18n(value, value);
                }
            }
		);
		
		var i_tpl = Ext.create("Ext.XTemplate",
			"<tpl for=\".\">",
			"{[typeof values === \"string\" ? values : this.renderer(values.label)]}",
			"<tpl if=\"xindex < xcount\">,</tpl>",
			"</tpl>",
			{
				renderer: function(value) {
                    return ip2.i18n(value, value);
                }
			}
		);

		var i_picker = Ext.widget("combobox", {
			store: i_store,
			valueField: "name",
			tpl: i_listTpl,
            displayTpl: i_tpl,
			forceSelection: true,
			typeAHead: true,
			queryMode: "local",
			queryCaching: false,
			triggerAction: "all",
			fieldLabel: ip2.i18n({
				da: "Vælg hvilken type du ønsker at oprette",
				en: "Choose which type to create"
			}),
			name: "type",
			itemId: "picker-type",
		});

		var i_window = Ext.create("Ext.window.Window", {
			title: ip2.i18n({
				da: "Vælg type",
				en: "Choose Type"
			}),
			width: 600,
			modal: true,
			closable: false,
			layout: "fit",
			itemId: "pickerWindow",
			items: [
				{
					xtype: "form",
					layout: "anchor",
					bodyPadding: 10,
					defaults: {
						anchor: "100%"
					},
					items: [
						i_picker
					]
				}
			],
			buttons: [
				{
					text: ip2.i18n({
						da: "Opret",
						en: "Create"
					}),
					itemId: "ok",
					handler: function (i_button) {

						var i_window = i_button.up("#pickerWindow");
						i_window.fireEvent("afterselect", i_window);
						i_window.close();
					}
				},
				{
					text: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					}),
					itemId: "cancel",
					handler: function (i_button) {

						var i_window = i_button.up("#pickerWindow");
						i_window.fireEvent("cancel", i_window);
					}
				}
			],
			listeners: {
				afterselect: {
					fn: function(i_window) {

						var o_property = i_record.get(o_pd.property) || {};

						if (Ext.isString(o_property)) {
							o_property = Ext.decode(o_property, true) || {};
						}

						o_property.fcid = i_picker.getValue();

						i_record.set(o_pd.property, Ext.encode(o_property));

						Portfolio.util.Handler.mask(ip2.i18n({
							da: "Opretter...",
							en: "Creating..."
						}));

						i_self.getFieldDefinitions(i_record, true);

						i_self.createView(i_record);
					}
				},
				cancel: {
					fn: function(i_window) {

						i_self.fireEvent("contentCancel", i_self);
						i_window.close();
						i_self.close();
					}
				}
			}
		});

		i_window.show();
	},

	addMap2Values: function(i_record, o_data) {

		var a_modelFields = i_record.getFields();

		Ext.Array.each(a_modelFields, function(i_modelField) {
			if (!i_modelField.identifier) {
				if (i_modelField.map2) {

					var a_map = Ext.Array.from(i_modelField.map2);

					Ext.Array.each(a_map, function(s_map) {
						if (o_data.hasOwnProperty(s_map)) {
							i_record.set(i_modelField.getName(), o_data[s_map]);
							o_data[i_modelField.getName()] = o_data[s_map];
						}
					});
				}
			}
		});
	},

	createPickerWindow: function (o_xpd, o_collections, o_definition, o_data, i_record) {

		Portfolio.util.Handler.unmask();

		var i_self = this;
		var s_idProperty = o_xpd.idProperty;
		var a_data = [];
		var a_keys = Ext.Object.getKeys(o_collections);

		if (o_xpd.filter) {

			Ext.Array.each(a_keys, function(s_key) {

				var o_collection = o_collections[s_key];

				if (i_record.get(o_xpd.filter) == o_collection.filter) {

					if (!o_collection.extend) {

						a_data.push({
							id: o_collection.id,
							title: ip2.xpd.translate(o_xpd, o_collection.title),
							sequence: o_collection.sequence
						});
					}
				}
			});
		}
		else {
			Ext.Array.each(a_keys, function(s_key) {

				var o_collection = o_collections[s_key];

				if (!o_collection.extend) {

					a_data.push({
						id: o_collection.id,
						title: ip2.xpd.translate(o_xpd, o_collection.title),
						sequence: o_collection.sequence
					});
				}
			});
		}

		a_data.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var i_store = Ext.create("Ext.data.Store", {
			fields: [
				{
					name: "id"
				},
				{
					name: "title"
				}
			],
			data: a_data
		});

		var i_picker = Ext.widget("combobox", {
			name: o_xpd.idProperty,
			hideLabel: true,
			store: i_store,
			itemId: "collectionPicker",
			minWidth: 400,
			anchor: "100%",
			style: "margin-top: 10px",
			valueField: "id",
			displayField: "title",
			forceSelection: true,
			typeAhead: true,
			minChars: 1,
			readonly: false,
			listeners: {
				afterrender: {
					fn: function (i_picker) {
						var i_first = i_picker.getStore().getAt(0);
						if (i_first) {
							i_picker.setValue(i_first.get("id"));
							i_picker.focus(false, 200);
						}
					}
				},
				specialkey: {
					fn: function(i_picker, i_event) {

						var s_key = i_event.getKey();
						var i_window = i_picker.up("#pickerWindow");

						if (s_key == i_event.ENTER) {
							if (!i_picker.isExpanded) {
								i_window.fireEvent("afterselect", i_window);
							}
						}
						if (i_event.getKey() == i_event.ESC) {
							i_window.fireEvent("cancel", i_window);
						}
					}
				}
			}
		});

		var i_window = Ext.create("Ext.window.Window", {
			title: ip2.i18n({
				da: "Vælg type",
				en: "Choose Type"
			}),
			modal: true,
			closable: false,
			layout: "fit",
			itemId: "pickerWindow",
			items: [
				{
					xtype: "form",
					itemId: "collectionForm",
					bodyPadding: "20px 20px 30px 20px",
					layout: "anchor",
					items: [
						{
							xtype: "label",
							text: ip2.i18n({
								da: "Vælg hvilken type du ønsker at oprette",
								en: "Choose which type to create"
							})
						},
						i_picker,
						{
							xtype: "checkbox",
							labelWidth: 110,
							name: "__tr__",
							inputValue: true,
							uncheckedValue: false,
							fieldLabel: ip2.i18n({
								da: "Synkroniser indhold",
								en: "Sync content"
							}),
							boxLabel: ip2.i18n({
								da: "Tekstuel indhold undtaget",
								en: "Textual content excepted"
							}),
							checked: true,
							hidden: true
						}
					]
				}
			],
			buttons: [
				{
					text: ip2.i18n({
						da: "Opret",
						en: "Create"
					}),
					itemId: "ok",
					handler: function (i_button) {

						var i_window = i_button.up("#pickerWindow");
						i_window.fireEvent("afterselect", i_window);
					}
				},
				{
					text: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					}),
					itemId: "cancel",
					handler: function (i_button) {

						var i_window = i_button.up("#pickerWindow");
						i_window.fireEvent("cancel", i_window);
					}
				}
			],
			listeners: {
				afterselect: {
					fn: function(i_window) {

						var i_form = i_window.down("#collectionForm");
						var o_values = i_form.getValues();
						var o_collection = o_collections[o_values[s_idProperty]];

						i_window.close();

						o_data[s_idProperty] = o_collection.id;

						Ext.apply(o_data, o_values);

						i_self.addMap2Values(i_record, o_values);

						i_record.set(o_definition.field, Ext.encode(o_data));

						Portfolio.util.Handler.mask(ip2.i18n({
							da: "Opretter...",
							en: "Creating..."
						}));

						i_self.doPreLoad(o_xpd, i_record, o_values);
					}
				},
				cancel: {
					fn: function(i_window) {

						i_self.fireEvent("contentError", i_self);
						i_window.close();
						i_self.close();
					}
				}
			}
		});

		i_window.show();
	},

	loadLanguageData: function(i_record, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var o_languageInfo = i_self.getLanguageInfoInformation();

		if (o_languageInfo) {

			var a_languages = i_self.getLanguages();
			var a_batch = [];

			Ext.Array.each(a_languages, function (s_language) {

				var o_keys = {};

				o_keys[o_languageInfo.relationKey] = i_record.get(i_record.idProperty);
				o_keys[o_languageInfo.foreignKey] = s_language;

				a_batch.push({
					type: "get",
					dmd: o_languageInfo.dmd,
					entity: o_languageInfo.entity,
					uiName: o_languageInfo.view,
					context: "form",
					fullresponse: true,
					key: o_keys
				});
			});

			Ext.Ajax.request({
				url: "/ip2-services/ip2dmdProxy.aspx",
				jsonData: {
					batch: a_batch
				},
				success: function (i_response) {

					Ext.USE_NATIVE_JSON = false;

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

					//Ext.USE_NATIVE_JSON = true;

					var o_value = {};
					var o_languageData = i_self.getLanguageData() || {};

					Ext.Array.each(o_result.batch, function (o_batch) {

						if (o_batch.rows.length) {

							var o_data = o_batch.rows[0];

							var s_language = o_data[o_languageInfo.foreignKey];
							var s_property = o_data[o_languageInfo.propertyKey];

							var o_property = Ext.decode(s_property, true) || {};

							o_value[s_language] = o_property;
							o_languageData[s_language] = o_data;
						}
					});

					i_self.setLanguageData(o_languageData);

					f_callback(o_value);
				}
			});
		}
		else {
			f_callback(null);
		}
	},

	doChangeLanguage: function(s_lang) {

		var i_self = this;
		i_self.setLanguageChange(true);

		var s_currentLang = i_self.getLanguage();
		var i_content = i_self.getContent();
		var i_form = i_content.getForm();
		var i_record = i_self.getRecord();
		var a_fields = i_form.getFields().items;
		var a_modified = [];
		var a_widgets = i_self.getWidgets();

		var o_i18nValue = i_self.getI18nValues();
		var a_i18nKeys = Ext.Object.getKeys(o_i18nValue);
		var a_languages = i_self.getLanguages();
		var o_modified = i_self.getModified() || {};

		Ext.Array.each(a_widgets, function(o_widget) {

			var i_widget = i_self.down("#" + o_widget.itemId);

			if (i_widget) {

				i_widget.changeLanguage(s_lang);
			}
		});

		Ext.Array.each(a_fields, function(i_field) {

			var b_dirty = i_field.isDirty();
			var b_valid = i_field.getActiveErrors ? i_field.getActiveErrors().length === 0 : true;

			if (!i_field.doSave && (b_dirty || !b_valid) && !i_field.inWidget) {

				a_modified.push({
					id: i_field.id,
					name: i_field.name,
					originalValue: i_field.originalValue,
					i18n: i_field.i18n !== undefined ? i_field.i18n : false,
					dirty: b_dirty,
					valid: b_valid,
					value: i_field.getValue()
				});
			}
		});

		if (Ext.Object.isEmpty(o_i18nValue)) {

			Ext.Array.each(a_fields, function(i_field) {

				if (i_field && !i_field.from && !i_field.inWidget) {

					var o_value = {};
					o_value[s_currentLang] = i_field.getValue();
					o_i18nValue[i_field.name] = o_value;
				}
			});
		}

		Ext.Array.each(a_languages, function(s_language) {

			Ext.Array.each(a_fields, function(i_field) {

				if (!i_field.i18n && !i_field.inWidget) {

					o_i18nValue[i_field.name] = o_i18nValue[i_field.name] || {};
					o_i18nValue[i_field.name][s_language] = i_field.getValue();
				}
				else {

					if (i_field.i18n && !i_field.inWidget) {

						if (s_language == s_currentLang) {

							o_i18nValue[i_field.name] = o_i18nValue[i_field.name] || {};
							o_i18nValue[i_field.name][s_language] = i_field.getValue();
						}
					}
				}
			});
		});

		i_self.setModified(o_modified);

		Ext.Array.each(a_modified, function(o_field) {

			Ext.Array.each(a_languages, function(s_language) {

				if (s_language != s_currentLang) {

					if (!o_field.i18n) {

						var a_modified = o_modified[s_language] = o_modified[s_language] || [];

						if (a_modified) {

							var b_found = false;
							var n_index = 0;

							Ext.Array.each(a_modified, function(o_value) {
								if (o_value.name == o_field.name) {
									b_found = true;
									return false;
								}
								n_index++;
							});

							if (!b_found) {
								a_modified.push(o_field);
							}
							else {
								a_modified[n_index] = o_field;
							}
						}
						else {

							a_modified.push(o_field);
						}
					}
				}
			});
		});

		o_modified[s_currentLang] = a_modified;

		var o_formvalues = {};

		Ext.Array.each(a_fields, function(i_field) {

			if (!i_field.inWidget) {

				o_formvalues[i_field.name] = i_field.getValue();
			}
		});

		i_record.set(o_formvalues);

		i_self.setLanguage(s_lang);

		var o_newvalues = {};

		Ext.Array.each(a_fields, function(i_field) {

			if (i_field.i18n && !i_field.inWidget) {

				o_i18nValue[i_field.name] = o_i18nValue[i_field.name] || {};
				o_newvalues[i_field.name] = o_i18nValue[i_field.name][s_lang] || "";
			}
		});

		var a_saveFields = i_self.getSaveFields();

		Ext.Array.each(a_saveFields, function(i_field) {
			delete o_value[i_field.name];
		});

		i_record.set(o_newvalues);
		i_form.setValues(o_newvalues);
		i_self.setActiveLanguage(s_lang);

		if (o_modified[s_lang]) {

			var a_modifiedLanguage = o_modified[s_lang];

			Ext.Array.each(a_modifiedLanguage, function(o_field) {

				Ext.Array.each(a_fields, function(i_field) {

					if (i_field.name == o_field.name) {

						var value = o_field.value;
						var valueOld = o_field.originalValue;

						i_field.suspendCheckChange++;
						i_field.setValue(valueOld);
						i_field.resetOriginalValue();
						i_field.wasDirty = true;
						i_field.setValue(value);
						i_field.suspendCheckChange--;
					}
				});
			});

			o_modified[s_lang] = [];
		}

		Ext.Array.each(a_fields, function(i_field) {

			if (i_field.changeLanguage) {
				i_field.changeLanguage(s_lang);
			}
		});

		var a_noneFields = i_content.query("[isFormField=false]");

		Ext.Array.each(a_noneFields, function(i_field) {

			if (i_field.changeLanguage) {
				i_field.changeLanguage(s_lang);
			}
		});

		return i_self;
	},

	save: function(f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var i_content = i_self.getContent();

		if (i_self.fireEvent("beforeContentSave", i_content, i_self)) {

			i_self.doSave(function (i_record) {

				var i_form = i_content.getForm();
				i_form.loadRecord(i_record);

				i_self.fireEvent("updateTitle", i_self);

				if (i_self.fireEvent("contentSave", i_content, i_self)) {
					Portfolio.util.Handler.App.fireEvent("contentSave", i_content, i_self);

					i_self.resetDirty(i_record);

					i_self.setSaved(true);

					Ext.Array.each(i_self.getRelationGrids(), function (i_grid) {

						var o_gridExtraParams = i_grid.extraParams;
						var o_keys = ip2.getRelationKeysFromRecord(i_record, i_grid.relationInfo);

						Ext.apply(o_gridExtraParams, {
							filter: ip2.keysToFilter(o_keys)
						});
						i_grid.enable();
					});

					f_callback(i_record);
				}
			});
		}

		return i_self;
	},

	doSave: function(f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;

		var i_tabpanel = i_self.getTabPanel();
		var a_tabs = i_tabpanel.items.getRange();
		var o_definition = i_self.getDefinition();

		var a_filtered = Ext.Array.filter(a_tabs, function(i_tab) {
			return i_tab.isContent;
		});

		var o_model = i_self.getDmdModel();
		var o_proxy = o_model.proxy;

		o_proxy.portfolio = o_proxy.hasOwnProperty("portfolio") ? o_proxy.portfolio : true;

		var o_i18nValues = i_self.getI18nValues();

		var a_languages = i_self.getLanguages();
		var s_currentLang = i_self.getLanguage();

		var o_languageInfo = i_self.getLanguageInfo();

		var o_formvalues = {};

		var a_formFields = [];
		var a_propertyHosts = [];

		var a_presaveFields = i_self.getPreSaveFields();

		Ext.Array.each(a_presaveFields, function(i_field) {
			i_field.presave();
		});

		Ext.Array.each(a_filtered, function(i_content) {

			var i_form = i_content.getForm();
			var a_temp = i_form.getFields().getRange();

			var a_result = Ext.Array.filter(a_temp, function(i_field) {
				return !i_field.inWidget ;
			});

			var a_queried = i_content.query("[propertyHost]");

			a_propertyHosts = a_propertyHosts.concat(a_queried);

			a_formFields = a_formFields.concat(a_result);
		});

		var i_model = i_self.getModel();
		var i_dmdRecord = i_model.create({});

		var o_fieldMap = i_dmdRecord.getFieldsMap();

		var i_record = i_self.getRecord();

		a_formFields = Ext.Array.filter(a_formFields, function(i_field) {

			var i_host = Ext.Array.findBy(a_propertyHosts, function(i_host) {
				return i_host.name == i_field.name;
			});

			return i_host ? false : true;
		});

		Ext.Array.each(a_formFields, function(i_field) {

			if (i_field.i18n && a_languages > 1) {

				var o_value = o_i18nValues[i_field.name];
				o_value[s_currentLang] = i_field.getSubmitValue ? i_field.getSubmitValue() : i_field.getValue();

				var s_value = Ext.encode(o_value);
				o_formvalues[i_field.name] = s_value;
			}
			else {
				o_formvalues[i_field.name] = i_field.getSubmitValue ? i_field.getSubmitValue() : i_field.getValue();
			}
		});

		i_record.set(o_formvalues);

		var o_view =  i_self.getViewConfig();
		var items = o_view.items;
		var a_configFields = Ext.isArray(items) ? items : items.columns;

		var a_props = Ext.Array.filter(a_configFields, function(o_config) {
			return o_config.isHost;
		});

		Ext.Array.each(a_props, function(o_config) {

			var o_original = i_record.get(o_config.name) || {};

			if (Ext.isString(o_original)) {
				o_original = Ext.decode(o_original, true) || {};
			}

			var o_data = {};

			var a_fields = Ext.Array.filter(a_configFields, function(o_field) {
				return o_field.hostField == o_config.name;
			});

			Ext.Array.each(a_fields, function(o_field) {
				o_data[o_field.name] = i_record.get(o_field.name);
			});

			Ext.apply(o_original, o_data);

			i_record.set(o_config.name, o_original);
		});

		Ext.Object.each(o_fieldMap, function(s_key) {
			i_dmdRecord.set(s_key, i_record.get(s_key));
		});

		var a_xpdConfig = o_definition.xpdConfig;

		var o_data = i_record.getData();

		var o_languageXpd;
		var o_collection;

		var a_pd = Ext.Array.from(o_definition.pd);

		Ext.Array.each(a_pd, function(o_pd) {

			var a_definitions = o_pd.definitions;
			var s_property = o_pd.property;
			var s_fcid = o_pd.fcid == "mask_" ? "mask_unknown" : o_pd.fcid;

			var o_formCollection = Ext.Array.findBy(a_definitions, function(o_collection) {
				return (o_collection.name == s_fcid || o_collection.id == s_fcid) && o_collection.type == "formCollection";
			});

			var a_collectionFields = Portfolio.pd.util.Handler.getFormFields(o_formCollection, a_definitions);

			var o_values = {};

			Ext.Array.each(a_collectionFields, function(s_name) {

				o_values[s_name] = i_record.get(s_name);
			});

			var o_saved = Ext.decode(i_record.get(s_property), true) || {};

			o_values = Ext.apply(o_saved, o_values);

			Ext.apply(o_values, {
				fcid: s_fcid
			});

			i_dmdRecord.set(s_property, Ext.encode(o_values));

		});

		Ext.Array.each(a_propertyHosts, function(i_field) {
			i_dmdRecord.set(i_field.propertyHost, i_field.getValue());
			i_record.set(i_field.propertyHost, i_field.getValue());
		});

		Ext.Array.each(a_xpdConfig, function(o_config) {

			var o_result = i_self.getXpdDefinitions(i_record, o_config);

			if (o_config.isLanguages) {

				o_languageXpd = o_result.xpd;
				o_collection = o_result.collection;

				return true;
			}

			var s_property = o_config.name || o_config.field;

			var o_value = Ext.ux.xpd.Handler.getValues(o_result.xpd, o_result.fields, o_result.collection, o_data);

			var o_property = Ext.decode(i_record.get(s_property), true) || {};
			Ext.applyIf(o_value, o_property);

			o_value = i_self.stripDoSaveValues(o_value);

			var s_value = Ext.encode(o_value);

			i_dmdRecord.set(s_property, s_value);
			i_record.set(s_property, s_value);
		});

		var i_saveRecord = o_proxy.portfolio ? i_dmdRecord : i_record;

		var o_info = {
			dmd: i_self.getDmd(),
			entity: i_self.getEntity()
		};

		if (o_languageInfo) {

			var a_languageRecords = [];
			var o_languageData = i_self.getLanguageData();
			var i_languageModel = i_self.getLanguageModel();

			Ext.Array.each(a_languages, function(s_language) {
				Ext.Array.each(a_formFields, function(i_field) {
					if (!i_field.i18n) {
						o_i18nValues[i_field.name] = o_i18nValues[i_field.name] || {};
						o_i18nValues[i_field.name][s_language] = i_field.getValue();
					}
					else {
						if (s_language == s_currentLang) {
							o_i18nValues[i_field.name] = o_i18nValues[i_field.name] || {};
							o_i18nValues[i_field.name][s_language] = i_field.getValue();
						}
					}
				});
			});

			Ext.Object.each(o_languageData, function(s_lang, o_values) {

				var o_record = {};

				var i_langRecord = i_languageModel.create(o_values);

				var a_modelFields = i_langRecord.getFields();

				var s_seourl = i_record.get("seourl");

				if (ip2.isStringedObject(s_seourl)) {
					var o_seourl = Ext.decode(s_seourl, true) || {};
					s_seourl = o_seourl[s_lang];
				}

				if (o_values.hasOwnProperty("SEOURL")) {
					i_langRecord.set("SEOURL", s_seourl);
				}

				if (s_currentLang == s_lang) {
					o_record = i_record.getData();
				}
				else {

					Ext.Object.each(o_i18nValues, function(s_key, o_property) {
						o_record[s_key] = o_property[s_lang];
					});
				}

				o_record = Ext.ux.xpd.Handler.getValues(o_languageXpd, a_formFields, o_collection, o_record);

				Ext.Array.each(a_modelFields, function(i_modelField) {
					if (!i_modelField.identifier && i_modelField.map2) {
						if (o_record[i_modelField.map2]) {
							i_langRecord.set(i_modelField.name, o_record[i_modelField.map2]);
						}
					}
				});

				var o_property = Ext.decode(i_langRecord.get(o_languageInfo.propertyKey), true) || {};
				Ext.applyIf(o_record, o_property);

				o_record = i_self.stripDoSaveValues(o_record);

				s_value = Ext.encode(o_record);

				i_langRecord.set(o_languageInfo.propertyKey, s_value);
				i_langRecord.set(o_languageInfo.foreignKey, s_lang);

				a_languageRecords.push(i_langRecord);
			});

			i_self.onPreSaveWidgets(i_saveRecord, function() {

				var a_apps = i_self.getApps() || [];

				Ext.Array.each(a_apps, function(i_application) {

					var s_event = i_application.saveEvent || "entitySave";

					i_application.fireEvent("before" + s_event, i_saveRecord);
				});

				i_self.fireEvent("beforesave", i_saveRecord);

				i_self.upsertRecords([i_saveRecord], o_info, function(a_records) {

					var i_formRecord = i_self.getRecord();
					var n_idProperty = i_saveRecord.get(i_saveRecord.idProperty);
					var o_languageData = i_self.getLanguageData();

					i_formRecord.set(i_saveRecord.idProperty, n_idProperty);

					Ext.Array.each(a_languageRecords, function(i_record) {

						if (i_self.getAction() == "copy") {
							i_record.set(i_record.idProperty, null);
						}

						i_record.set(o_languageInfo.relationKey, n_idProperty);
					});

					Ext.apply(o_info, {
						dmd: o_languageInfo.dmd,
						entity: o_languageInfo.entity
					});

					i_self.upsertRecords(a_languageRecords, o_languageInfo, function(a_result) {

						Ext.Array.each(a_result, function(i_record) {
							var s_lang = i_record.get(o_languageInfo.foreignKey);
							o_languageData[s_lang] = i_record.getData();
						});

						i_self.setLanguageData(o_languageData);

						i_self.doSaveFields(function() {

							i_self.doPostSave(i_saveRecord, function() {

								i_self.saveWidgets(function() {

									var n_apps = a_apps.length;

									if (n_apps > 0) {

										Ext.Array.each(a_apps, function(i_application) {

											var s_event = i_application.saveEvent || "entitySave";

											var s_complete = i_application.completeEvent || "saveComplete";

											var o_on = {};

											o_on[s_complete] = {
												fn: function() {

													n_apps--;

													if (n_apps === 0) {
														f_callback(i_formRecord);
													}
												},
												singel: true
											};

											i_application.on(o_on);

											var b_saved = i_application.fireEvent(s_event, i_application, i_record);

											if (b_saved) {

												n_apps--;

												i_application.un(o_on);

												if (n_apps === 0) {
													f_callback(i_formRecord);
												}
											}
										});
									}
									else {
										f_callback(i_formRecord);
									}
								});
							});
						});
					}, n_idProperty);
				});
			});
		}
		else {
			
			i_self.onPreSaveWidgets(i_saveRecord, function() {

				var a_apps = i_self.getApps() || [];

				Ext.Array.each(a_apps, function(i_application) {

					var s_event = i_application.saveEvent || "entitySave";

					i_application.fireEvent("before" + s_event, i_saveRecord);
				});

				i_self.fireEvent("beforesave", i_saveRecord);

				i_self.upsertRecords([i_saveRecord], o_info, function(a_records) {

					var i_formRecord = i_self.getRecord();
					var n_idProperty = i_saveRecord.get(i_saveRecord.idProperty);

					i_formRecord.set(i_saveRecord.idProperty, n_idProperty);

					i_self.doSaveFields(function() {

						i_self.doPostSave(i_saveRecord, function() {

							i_self.saveWidgets(function() {

								var n_apps = a_apps.length;

								if (n_apps >  0) {

									Ext.Array.each(a_apps, function(i_application) {

										var s_event = i_application.saveEvent || "entitySave";

										var s_complete = i_application.completeEvent || "saveComplete";

										var o_on = {};

										o_on[s_complete] = {
											fn: function() {

												n_apps--;

												if (n_apps === 0) {
													f_callback(i_formRecord);
												}
											},
											singel: true
										};

										i_application.on(o_on);

										var b_saved = i_application.fireEvent(s_event, i_application, i_record);

										if (b_saved) {

											n_apps--;

											i_application.un(o_on);

											if (n_apps === 0) {
												f_callback(i_formRecord);
											}
										}
									});
								}
								else {
									f_callback(i_formRecord);
								}
							});
						});
					});
				});
			});
		}
	},

	stripDoSaveValues: function(o_value) {

		var i_self = this;
		var a_fields = i_self.getSaveFields();

		Ext.Array.each(a_fields, function(i_field) {

			if (i_field.doSave) {
				delete o_value[i_field.name];
			}
		});

		return o_value;
	},

	onPreSaveWidgets: function(i_record, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var a_widgets = [];
		var n_widgetsLeft = 0;

		var a_widgets2Save = [];

		Ext.Array.each(a_widgets, function (o_widget) {

			var i_widget = i_self.down("#" + o_widget.itemId);
			if (i_widget) {
				a_widgets2Save.push(i_widget);
			}
		});

		n_widgetsLeft = a_widgets2Save.length;

		if (n_widgetsLeft > 0) {
			Ext.Array.each(a_widgets2Save, function(i_widget) {

				i_widget.doPreSave(i_record, function(i_record) {
					if (n_widgetsLeft === 0) {
						f_callback();
					}
				});
			});
		}
		else {
			f_callback();
		}
	},

	upsertRecords: function(a_records, o_info, f_callback, n_token) {

		var i_self = this;
		var a_batch = [];
		n_token = n_token || false;

		var i_model = a_records[0];

		var o_model = i_model.dmdModel;

		var o_proxy = o_model.proxy;

		o_proxy.portfolio = o_proxy.hasOwnProperty("portfolio") ? o_proxy.portfolio : true;

		if (o_proxy.portfolio) {

			Ext.Array.each(a_records, function (i_record) {

				var o_keys = {};

				o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

				var o_batch = Ext.apply({}, {
					type: "upsert",
					dmd: o_info.dmd,
					entity: o_info.entity,
					transactiontype: o_info.entity || i_self.transactiontype,
					key: o_keys,
					row: i_record.getData()
				});

				if (n_token) {
					o_batch.transactionkey = n_token;
				}
				a_batch.push(o_batch);
			});

			Ext.Ajax.request({
				url: "/ip2-services/ip2dmdProxy.aspx",
				jsonData: {
					batch: a_batch
				},
				success: function (i_response) {

					var o_result = Ext.decode(i_response.responseText, true) || {
						success: true,
						batch: [{
							row: []
						}]
					};

					var b_error = false;
					var a_message = [];

					if (!o_result.success) {
						b_error = true;
						a_message.push(o_result.message || o_result.msg);
					}

					Ext.Array.each(o_result.batch, function(o_batch, n_index) {

						if (o_batch.hasOwnProperty("success") && !o_batch.success) {
							b_error = true;
							a_message.push(o_batch.message || o_batch.msg);
						}

						Ext.Array.each(o_batch.row, function(o_value) {

							if (o_value.hasOwnProperty("success") && !o_value.success) {
								b_error = true;
								a_message.push(o_value.message || o_value.msg);
							}
							else {
								var i_record = a_records[n_index];
								i_record.set(o_value);
							}
						});
					});

					if (!b_error) {
						f_callback(a_records);
					}
					else {

						var s_msg = a_message.join("<br>");

						Portfolio.util.Handler.unmask();

						Portfolio.util.Handler.messageBox({
							icon: Ext.MessageBox.ERROR,
							title: ip2.i18n({
								da: "Fejl",
								en: "Error"
							}),
							closable: true,
							message: ip2.i18n({
								da: "Der skete en fejl under processen:</br> <strong>" + s_msg + "</strong>",
								en: "An error occurred durring the process:</br> <strong>" + s_msg + "</strong>"
							}),
							yesFn: function () {
								i_self.fireEvent("savefaliure", i_self, a_records);
							},
							cancelFn: function() {
								i_self.fireEvent("savefaliure", i_self, a_records);
							},
							yesText: ip2.i18n({
								da: "Ok",
								en: "OK"
							})
						});
					}
				},
				faliure: function(o_error) {
					Portfolio.util.Handler.unmask();
					i_self.fireEvent("savefaliure", i_self, a_records);
				}
			});
		}
		else {

			var n_count = a_records.length;

			var a_message = [];
			var b_error = false;

			Ext.Array.each(a_records, function(i_record) {

				i_record.save({
					callback: function(i_record, i_operation, b_success) {

						n_count--;

						if (!b_success) {

							var o_error = i_operation.error;
							var i_response = o_error.response;

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

							b_error = true;
							a_message.push(o_result.message);
						}

						if (n_count === 0) {

							if (!b_error) {
								f_callback(a_records);
							}
							else {
								var s_msg = a_message.join("<br>");

								var i_actionbar = i_self.getActionbar();

								var i_saveclose = i_actionbar.items.get("saveclose");

								Portfolio.util.Handler.unmask();

								Portfolio.util.Handler.messageBox({
									icon: Ext.MessageBox.ERROR,
									title: ip2.i18n({
										da: "Fejl",
										en: "Error"
									}),
									closable: true,
									message: ip2.i18n({
										da: "Der skete en fejl under processen:</br> <strong>" + s_msg + "</strong>",
										en: "An error occurred durring the process:</br> <strong>" + s_msg + "</strong>"
									}),
									yesFn: function () {
										i_saveclose.show();
									},
									cancelFn: function() {
										i_saveclose.show();
									},
									yesText: ip2.i18n({
										da: "Ok",
										en: "OK"
									})
								});

								i_self.fireEvent("savefaliure", i_self, a_records);
							}
						}
					}
				});
			});
		}
	},

	doSaveFields: function(f_callback) {

		var i_self = this;
		var a_fields = i_self.getSaveFields();
		var n_save = a_fields.length;

		f_callback = f_callback || Ext.emptyFn;

		if (n_save > 0) {

			Ext.Array.each(a_fields, function(i_field) {
				i_field.doSave(function() {
					n_save--;
					if (n_save === 0) {
						f_callback();
					}
				});
			});
		}
		else {
			f_callback();
		}
	},

	doPostSave: function(i_record, f_callback) {

		var i_self = this;
		var a_fields = i_self.getPreLoadFields();
		var n_save = a_fields.length;

		f_callback = f_callback || Ext.emptyFn;

		if (n_save > 0) {

			Ext.Array.each(a_fields, function(i_field) {
				i_field.onPostSave(i_record.get(i_record.idProperty), function() {
					n_save--;
					if (n_save === 0) {
						f_callback();
					}
				});
			});
		}
		else {
			f_callback();
		}
	},

	saveWidgets: function (f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var a_widgets = i_self.getWidgets();
		var n_widgetsLeft = 0;

		var a_widgets2Save = [];

		Ext.Array.each(a_widgets, function (o_widget) {

			var i_widget = i_self.down("#" + o_widget.itemId);

			if (i_widget) {
				a_widgets2Save.push(i_widget);
			}
		});

		n_widgetsLeft = a_widgets2Save.length;

		if (n_widgetsLeft > 0) {
			Ext.Array.each(a_widgets2Save, function(i_widget) {
				i_widget.doSave(function() {
					n_widgetsLeft--;
					if (n_widgetsLeft === 0) {
						f_callback();
					}
				});
			});
		}
		else {
			f_callback();
		}
	},

	resetDirty: function(i_record) {

		var i_self = this;

		var i_tabpanel = i_self.getTabPanel();

		var a_tabs = i_tabpanel.items.getRange();

		var a_filtered = Ext.Array.filter(a_tabs, function(i_tab) {
			return i_tab.isContent;
		});

		var a_languages = i_self.getLanguages();
		var o_modified = {};

		Ext.suspendLayouts();

		Ext.Array.each(a_filtered, function(i_content) {

			var i_form = i_content.getForm();
			var a_fields = i_form.getFields().getRange();

			Ext.Array.each(a_fields, function(i_field) {
				i_field.suspendCheckChange++;
			});

			Ext.Array.each(a_languages, function(s_lang) {

				var i_button = i_self.down("#" + s_lang);

				if (i_button) {
					i_button.setIconCls("");
				}
				o_modified[s_lang] = [];
			});

			Ext.Array.each(a_fields, function(i_field) {
				i_field.resetOriginalValue();
				i_field.suspendCheckChange--;
			});

		});

		i_self.setModified(o_modified);

		i_self.fireEvent("dirtychange", i_self, false);

		Ext.resumeLayouts(true);
	},

	addDropZone: function (a_zones, f_callback) {

		var i_self = this;

		f_callback = f_callback || Ext.emptyFn;

		var i_dropzone = Ext.widget("portfolio.entity.dropzone", {
			form: i_self,
			zones: a_zones,
			dropFn: function (s_value) {
				f_callback(s_value);
			}
		});

		i_self.setDropZone(i_dropzone);

		i_self.add(i_dropzone);
	},

	getAction: function() {

		var i_self = this;
		return i_self.action;
	},

	setAction: function(s_action) {

		var i_self = this;
		i_self.action = s_action;
	},

	addKeyEvents: function() {
		var i_self = this;

		var a_bindings = [
			{
				key: Ext.event.Event.S,
				shift: false,
				ctrl: true,
				fn: function (n_key, i_event) {

					if (i_self.isDirty()) {

						i_event.stopEvent();

						i_self.save(function (i_record) {

							i_self.resetDirty(i_record);

							i_self.setSaved(true);

							Ext.Array.each(i_self.getRelationGrids(), function(i_grid) {

								var o_gridExtraParams = i_grid.extraParams;
								var o_keys = ip2.getRelationKeysFromRecord(i_record, i_grid.relationInfo);

								Ext.apply(o_gridExtraParams, {
									filter: ip2.keysToFilter(o_keys)
								});

								i_grid.enable();
							});
						});
					}
				}
			}
		];

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

		i_self.setKeyHandler(i_keyMap);
	}
});
Ext.define("Portfolio.entity.view.Grid", {

	extend: "Ext.grid.Panel",

	xtype: "portfolio-entity-grid",

	alias: [
		"widget.entity.grid",
		"widget.ip2pagingGridOld"
	],

	layout: "fit",

	border: false,

	multiColumnSort: true,

	requires: [
		"Portfolio.entity.view.Form",
		"Portfolio.entity.util.Toolbar",
		"Ext.ux.ToolbarDroppable",
		"Ext.ux.file.util.Handler",
		"Ext.ux.grid.filter.util",
		"Ext.ux.grid.filter.Toolbar",
		"Ext.ux.grid.filter.Menu"
	],

	config: {
		providerID: "",
		dmd: "",
		uiName: "portfolio",
		editMode: "tab",
		dmdName: "",
		dmdCfg: null,
		defaultFilter: "",
		defaultCollection: "",
		customFilter: null,
		filterBar: null,
		entityToolBar: null,
		entity: null,
		record: null,
		dropZone: null,
		autoLoad: true,
		filterable: true,
		allowActions: true,
		allowFilterMenu: true,
		allowMenuOnFilters: true,
		allowLink: true,
		allowExport: true,
		allowSearch: true,
		selected: null,
		parentEntity: null,
		parentKeys: null,
		childPanel: null,
		rowMenu: null,
		autoSelect: true,
		remoteSort: true,
		showTotalCount: true,
		useScroller: false,
		searchCombo: true,
		templateConfig: null,
		features: [],
		menuApp: null
		
	},

	listeners: {
		afterrender: {
			fn: function() {

				var i_self = this;
				var s_uiName = i_self.getUiName();

				var o_entity = i_self.getEntity();
				var o_view = o_entity.ui.grids[s_uiName];

				if (o_view.drop) {
					var a_entry = o_view.drop.entities || [];

					if (a_entry.length > 0) {

						var i_dropzone = Ext.create("Ext.ux.grid.DropZone", {
							grid: i_self,
							entity: o_entity,
							dropFn: function(s_value, o_drop) {

								if (s_value) {

									var i_store = i_self.getStore();

									var o_config = Ext.apply({}, {
										dmd: o_drop.dmd,
										entity: o_drop.name,
										entityName: o_drop.name,
										uiName: o_drop.view || "portfolio",
										context: "form"
									});

									var i_model = Portfolio.util.Handler.model(o_config);

									var i_record = i_model.create({});

									i_record.set(o_drop.property, s_value);

									i_self.handleAction(i_record, "create", 0);
								}
							}
						});

						i_self.setDropZone(i_dropzone);
						i_self.add(i_dropzone);
					}
				}

				var a_columns = i_self.getColumnManager().getColumns();

				Ext.Array.each(a_columns, function(i_column) {

					if (i_column.search) {
						i_self.fireEvent("colToSearch", i_self, i_column);
					}
				});


				var i_actionBar = i_self.getEntityToolBar();

				var i_searchfield = i_actionBar.getComponent("search");

				if (o_view.hasOwnProperty("searchable") && !o_view.searchable) {
					if (i_searchfield) {
						i_searchfield[o_view.searchable ? "show" : "hide"]();
					}
                }

				i_self.applyReset();

				i_self.createKeyEvents();
			}
		},
		columnresize: {
			fn: function (container, col, width) {
				var i_self = this;
				i_self.fireEvent("savestate", i_self);
			}
		},
		columnmove: {
			fn: function (container, col, width) {
				var i_self = this;
				i_self.fireEvent("savestate", i_self);
			}
		},
		columnshow: {
			fn: function (container, col, width) {
				var i_self = this;
				i_self.fireEvent("savestate", i_self);
			}
		},
		columnhide: {
			fn: function (container, col, width) {
				var i_self = this;
				i_self.fireEvent("savestate", i_self);
			}
		},
		savestate: {
			fn: function() {
				var i_self = this;
				i_self.saveState();
			},
			buffer: 250
		},
		afterFilter: {
			fn: function(i_filterbar, n_filters) {

				var i_self = this;
				var i_toolbar = i_self.getEntityToolBar();
				i_toolbar.fireEvent("afterfilter", n_filters);
			}
		},
		colToSearch: {
			fn: function (i_panel, i_column) {

				var i_self = this;
				var i_actionBar = i_self.getEntityToolBar();

				var i_searchfield = i_actionBar.getComponent("search");

				if (i_searchfield) {

					var a_fields = i_actionBar.query("field[searchfield=true]");

					var i_found =  Ext.Array.findBy(a_fields, function(i_field) {
						return i_field.dataIndex == i_column.dataIndex;
					});

					if (!i_found) {
						var n_index = i_actionBar.items.indexOf(i_searchfield);
					

						if (a_fields.length > 0) {
							n_index = i_actionBar.items.indexOf(a_fields[a_fields.length - 1]);
						}

						var s_type = "textfield";

						var o_config = {
							emptyText: ip2.i18n(i_column.title),
							dataIndex: i_column.dataIndex,
							searchfield: true,
							isFormfield: false,
							ui: "function-field"
						};

						if (Ext.isObject(i_column.search)) {

							s_type = "combobox";

							var o_search = i_column.search || {};

							var i_model = ip2.model({
								dmd: o_search.dmd,
								view: o_search.view,
								entity: o_search.entity,
								context: "grid"
							});

							var i_store = Ext.create("Ext.data.Store", {
								model: i_model,
								proxy: Portfolio.util.Handler.getProxyByEntity({
									dmd: o_search.dmd,
									view: o_search.view,
									entity: o_search.entity,
									context: "grid"
								}),
								remoteSort: true,
								pageSize: 100
							});

							Ext.apply(o_config, {
								store: i_store,
								displayField: o_search.displayField || "key",
								valueField: o_search.valueField || "value",
								queryParam: "search",
								queryMode: "remote",
								triggerAction: "all",
								editable: false,
								forceSelection: false,
								queryCaching: false,
								minWidth: 180,
								grow: true,
								growToLongestValue: true,
								multiSelect: true,
								listeners: {
									specialkey: {
										fn: function (i_field, i_event) {

											var s_key = i_event.getKey();

											if (s_key == i_event.ENTER) {

												var i_store = i_self.getStore();

												if (i_store.clearAndLoad) {
													i_store.clearAndLoad();
												}
												else {
													i_store.load();
												}
											}
										}
									},
									change: {
										fn: function (i_field, value) {
											var i_store = i_self.getStore();
											i_store.clearAndLoad();
										}
									},
									autosize: {
										fn: function (i_field) {
											var i_picker = i_field.getPicker();
											i_picker.setWidth(i_field.bodyEl.getWidth());
										},
										buffer: 1
									}
								},
								triggers: {
									picker: {
										weight: 1,
										handler: "onTriggerClick",
										scope: "this"
									}
								}
							});
						}
						else {
							Ext.apply(o_config, {
								listeners: {
									specialkey: {
										fn: function (i_field, i_event) {

											var s_key = i_event.getKey();

											if (s_key == i_event.ENTER) {

												var i_store = i_self.getStore();

												if (i_store.clearAndLoad) {
													i_store.clearAndLoad();
												}
												else {
													i_store.load();
												}
											}
										}
									}
								},
							});
						}

						var i_field = Ext.widget(s_type, o_config);

						i_actionBar.add(n_index + 1, [i_field]);
					}
				}
			}
		},
		changeview: {
			fn: function(s_view) {
				
				var i_self = this;

				var s_oldView = i_self.getUiName();

				if (s_oldView != s_view) {

					var o_modelConfig = i_self.getModelConfig();
					var o_entityInfo = i_self.getEntityInfo();

					o_modelConfig.uiName = s_view;
					o_entityInfo.view = s_view;

					i_self.setUiName(s_view);
					i_self.model = null;

					i_self.getModel();

					var i_menuApp = i_self.getMenuApp();

					if (i_menuApp) {

						if (i_menuApp.destroy) {
							i_menuApp.destroy();
						}
					}
					
					i_self.setMenuApp(null);

					i_self.setProviderID([o_modelConfig.dmd, o_modelConfig.entityName, o_modelConfig.uiName, Portfolio.util.Handler.baseconfig.session.preset.origin].join("_"));

					var i_newStore = i_self.createStore();
					var a_columns = i_self.getColumns(i_newStore);
					
					var i_actionBar = i_self.getEntityToolBar();
					i_actionBar.setStore(i_newStore);
					
					i_self.reconfigure(i_newStore, a_columns);
				}
			}
		}
	},

	initComponent: function () {

		var i_self = this;

		delete i_self.view;

		i_self.getEntityInfo();

		var o_config = i_self.getModelConfig();

		i_self.setProviderID([o_config.dmd, o_config.entityName, o_config.uiName, Portfolio.util.Handler.baseconfig.session.preset.origin].join("_"));
		i_self.setDmdName(o_config.dmd.split("/").pop().split(".").shift());

		i_self.createUI();

		i_self.callParent();

		var i_header = i_self.headerCt;

		i_header.on({
			boxready: {
				fn: function(i_item) {
					if (i_self.getFilterable()) {

						var i_toolbar = i_self.getFilterBar();
						var o_entity = i_self.getEntity();

						var s_uiName = i_self.getUiName();

						if (i_toolbar) {

							var s_ddGroup = i_header.reorderer.dragZone.ddGroup;
							i_toolbar.dd.addDDGroup(s_ddGroup);

							var a_filters = o_entity.ui.grids[s_uiName].filters || [];
							var s_defaultFilter = i_self.getDefaultFilter();

							if (!s_defaultFilter && a_filters.length > 0) {
								i_toolbar.loadFilters(a_filters);
							}
						}
					}
				},
				buffer: 100
			}
		});

		i_self.createRowMenu();
		i_self.addDocked(i_self.createToolbars());
		i_self.addHandlers();
		i_self.convertCopyFn();

		i_self.enableBubble("updateTotalCount");

		return i_self;
	},

	convertCopyFn: function() {

		var i_self = this;
		var o_entity = i_self.getEntity();

		i_self.copyFn = i_self.copyFn = i_self.copyFn || o_entity.copyFn;

		var s_copyFn = i_self.copyFn = i_self.copyFn || "";

		if (s_copyFn) {
			var a_split = s_copyFn.split(".");
			var o_current = window;
			var b_found = false;
			Ext.Array.each(a_split, function(s_part) {
				o_current = o_current[s_part];
				if (o_current && Ext.isFunction(o_current)) {
					i_self.copyFn = o_current;
					b_found = true;
					return false;
				}
			});
			if (!b_found) {
				i_self.copyFn = "";
			}
		}
	},

	handleAction: function(i_record, s_action, n_mode) {

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

		s_action = s_action || "update";
		var s_dmd = i_self.getDmdName();

		o_config.defaultCollection = i_self.getDefaultCollection();

		var o_clone = Ext.clone(o_config);
		delete o_clone.container;

		if (Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.update") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.read") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.copy") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_clone.entityName + ".update") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_clone.entityName + ".read") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_clone.entityName + ".copy")) {

			var o_keys = {};

			if (i_record) {
				o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);
			}

			Ext.apply(o_clone, {
				keys: o_keys
			});

			var i_window = i_self.up("window");

			if (i_self.fireEvent("before" + s_action, i_self, o_clone)) {

				if (i_window) {
					Portfolio.app.fireEvent("entityWindow", o_clone, s_action, null, i_window.zIndexManager.id);
				}
				else {
					var i_form = i_self.up("entityform");

					if (i_form || (i_self.getEditMode() === "window" || n_mode === 1)) {
						Portfolio.app.fireEvent("entityWindow", o_clone, s_action);
					}
					else {
						Portfolio.app.fireEvent("entityedit", o_clone, s_action);
					}
				}
			}

		}
	},

	setupColumns: function(a_columns, i_store) {

		var i_self = this;
		var a_clone = Ext.Array.slice(a_columns);
		var a_return = [];
		var b_diff = false;

		var o_setting = Portfolio.util.Handler.profile.get(i_self.getProviderID() + ".setting", {
			columns: {
				order: [],
				size: []
			}
		});

		Ext.applyIf(o_setting, {
			columns: {
				order: [],
				size: []
			}
		});

		if (Ext.isArray(o_setting)) {
			o_setting = {
				columns: {
					order: [],
					size: []
				}
			};
		}

		if (a_clone.length != o_setting.columns.order.length) {
			b_diff = true;
		}
		else {
			Ext.Array.each(a_clone, function(c_column) {

				var o_found = Ext.Array.findBy(o_setting.columns.order, function(db_column) {
					return c_column.dataIndex == db_column.dataIndex;
				});

				if (!o_found) {
					b_diff = true;
				}
			});
		}

		var n_length = o_setting.columns.order.length;

		o_setting.columns.order = o_setting.columns.order.filter(function(o_column) {
			return o_column.dataIndex;
		});

		if (!b_diff) {
			b_diff = n_length != o_setting.columns.order.length;
		}

		if (o_setting.columns.order.length === 0 || b_diff) {
			a_return = i_self.saveInitialSetting(i_store);
		}
		else {
			Ext.Array.each(o_setting.columns.order, function(o_column) {
				Ext.Array.each(a_clone, function(i_clone) {
					if (o_column.dataIndex == i_clone.dataIndex) {
						if (!i_clone.hide) {
							i_clone.hidden = o_column.hidden || false;
							a_return.push(i_clone);
							return false;
						}
					}
				});
			});
			Ext.Array.each(a_return, function(i_column) {
				if (!i_column.hide) {
					Ext.Array.each(o_setting.columns.size, function(o_size) {
						if (i_column.dataIndex == o_size.dataIndex) {
							if (o_size.width !== undefined) {
								i_column.width = o_size.width;
								i_column.flex = undefined;
								return false;
							}
						}
					});
				}
				delete i_column.hide;
			});
		}
		return a_return;
	},

	addHandlers: function() {

		var i_self = this;
		var i_store = i_self.getStore();
		var o_config = i_self.getModelConfig();

		if (i_self.getAutoLoad()) {
			if (!i_self.getDefaultFilter()) {
				i_store.load({
					params: {
						start: 0
					}
				});
			}
		}

		i_self.mon(Portfolio.util.Handler.App, "entityupdate:" + o_config.entityName, function(i_record, s_action) {

			if (!i_self.destroyed) {
				var a_records = Ext.Array.from(i_record);

				var n_count = a_records.length;

				var i_view = i_self.getView();

				var o_info = i_self.getEntityInfo();

				var o_dmd = o_info.dmd;
				var o_model = o_dmd.model;

				var o_proxy = o_model.proxy;

				o_proxy.portfolio = o_proxy.hasOwnProperty("portfolio") ? o_proxy.portfolio : true;

				if (n_count > 0 && s_action == "update") {

					i_view.setLoading(true);

					Ext.Array.each(a_records, function (i_record) {

						var n_index = i_store.findBy(function (i_search) {
							return i_record.get(i_record.idProperty) == i_search.get(i_record.idProperty);
						});

						if (n_index > -1) {

							var i_viewRecord = i_store.getAt(n_index);

							if (o_proxy.portfolio) {
								i_self.getUpdatedRecord(i_record, function (o_data) {

									i_store = i_self.getStore();

									if (i_store) {
										i_viewRecord.set(o_data);
										i_viewRecord.commit(true);
										n_count--;

										if (n_count === 0) {

											i_store.fireEvent("datachanged", i_store);
											i_store.fireEvent("refresh", i_store);

											i_view.refreshNode(i_viewRecord);
											i_view.setLoading(false);
										}
									}
								});
							}
							else {

								var i_storeProxy = i_store.getProxy();
								var i_recordProxy = i_viewRecord.getProxy();

								i_viewRecord.self.setProxy(i_storeProxy);

								i_viewRecord.load({
									success: function(i_loaded, i_operation) {
										i_viewRecord.set(i_loaded.getData());

										i_viewRecord.commit(true);
										i_view.refreshNode(i_viewRecord);
										n_count--;

										if (n_count === 0) {
											i_view.setLoading(false);
										}

										i_viewRecord.self.setProxy(i_recordProxy);
									},
									failure: function(err) {
										n_count--;

										if (n_count === 0) {
											i_view.setLoading(false);
										}

										i_viewRecord.self.setProxy(i_recordProxy);
									}
								});
							}
						}
						else {
							n_count--;
							if (n_count === 0) {
								i_view.setLoading(false);
							}
						}
					});
				}
				else {
					i_store.load();
				}
			}

			
		});
	},

	createStore: function() {

		var i_self = this;
		var b_autoLoad = i_self.getAutoLoad();
		var i_model = i_self.getModel();
		var a_sorters;
		var s_uiName = i_self.getUiName();

		var o_entity = i_self.getEntity();
		var o_info = i_self.getEntityInfo();

		if (o_info.view.sort) {

			a_sorters = Ext.Array.map(o_info.view.sort.split(","), function (s_value) {
				var s = Ext.Array.filter(s_value.split(" "), Boolean);
				return {
					property: s[0],
					direction: s[1] ? s[1] : "ASC"
				};
			});
		}

		if (o_info.view.hasOwnProperty("remoteSort")) {
			i_self.setRemoteSort(o_info.view.remoteSort);
		}

		if (i_self.getDefaultFilter()) {
			b_autoLoad = false;
		}

		var a_features = i_self.getFeatures();

		var a_extFeatures = Ext.Array.from(o_info.view.extfeatures);

		a_features = a_features.concat(i_self.createFeatures(a_extFeatures));

		var b_buffered = a_features.length > 0 ? false : true;

		var s_storeType = b_buffered ? "Ext.data.BufferedStore" : "Ext.data.Store";

		var i_store = Ext.create(s_storeType, {
			model: i_model,
			proxy: Portfolio.util.Handler.getProxyByEntity(i_self.getModelConfig()),
			remoteSort: i_self.getRemoteSort(),
			autoSync: false,
			sorters: a_sorters,
			ops: [],
			first: true,
			pageSize: o_info.view.pageSize || 100,
			purgePageCount: o_info.view.hasOwnProperty("purgePageCount") ? o_info.view.purgePageCount : 0,
			prevSearch: "",
			autoLoad: b_autoLoad,
			listeners: {
				beforeload: {
					fn: function (i_store, i_operation) {

						var i_proxy = i_store.getProxy();
						var o_sorters = i_store.getSorters();
						var o_extraParams = i_proxy.getExtraParams();
						var a_sort = [];
						var a_where = [];
						var s_sort = "";

						delete o_extraParams.where;

						a_where = a_where.filter(function(s_value) {
							return s_value;
						});

						var i_toolbar = i_self.getToolbar();
						var i_filterbar = i_self.getFilterBar();

						var i_columnManager = i_self.getColumnManager();

						var i_search;

						if (i_toolbar) {
							i_search = i_toolbar.down("#search");
						}

						Ext.Array.each(o_sorters.items, function(o_sort) {

							var i_header = i_columnManager.getHeaderByDataIndex(o_sort.getProperty());

							if (i_header) {
								var s_sorter = (i_header.mapping ? i_header.mapping : o_sort.getProperty()) + " " + o_sort.getDirection();
								a_sort.push(s_sorter);
							}
						});

						var i_grouper = i_store.getGrouper();

						if (i_grouper) {
							i_proxy.setGroupParam("");
							a_sort.unshift(i_grouper.getProperty() + " " + i_grouper.getDirection());
							delete o_extraParams.group;
						}
						else {
							i_proxy.setGroupParam("group");
						}

						if (a_sort.length > 0) {
							i_proxy.setSortParam("");
						}
						else {
							i_proxy.setGroupParam("sort");
						}

						s_sort = a_sort.join(", ");

						if (o_entity.language) {
							var i_pickerLocal = i_self.getToolbar().down("#button-language");
							if (i_pickerLocal) {
								o_extraParams.language = i_pickerLocal.key;
								o_extraParams.languageColumn = o_entity.language.column;
							}
						}

						if (i_filterbar) {
							var s_filterWhere = i_filterbar.getWhere();
							if (s_filterWhere) {
								a_where.push(s_filterWhere);
							}
						}
						if (i_search) {
							o_extraParams.search = i_search.getRawValue();
							if (i_search.getWhere()) {
								var s_searchWhere = i_search.getWhere();
								a_where.push(s_searchWhere);
								o_extraParams.search = "";
							}
						}

						if (i_self.extraParams) {
							var o_extra = i_self.extraParams || {};
							if (o_extra.hasOwnProperty("where")) {
								var s_extraWhere = o_extra.where;
								a_where.push(s_extraWhere);
							}
							Ext.apply(o_extraParams, o_extra);
						}
						else {
							delete o_extraParams.filter;
						}

						if (s_sort) {
							Ext.apply(o_extraParams, {
								sort: s_sort,
							});
						}

						var a_searchfields = i_toolbar.query("field[searchfield=true]");

						var i_template = new Ext.XTemplate(
							"{dataIndex} {[this.getStatement(values.value)]}",
							{
								getStatement: function (values) {

									var a_result = [];
									var n_length = values.length;

									Ext.Array.each(values, function (s_value) {
										if (s_value) {

											var s_result = "";

											if (n_length == 1) {
												s_result = "'%" + s_value.trim() + "%'";
											}
											else {
												s_result = "'" + s_value.trim() + "'";
											}

											a_result.push(s_result);
										}
									});

									var s_statement = n_length > 1 ?
										" IN " + "(" + a_result.join(", ") + ")" : "like " + a_result.join("");

									return s_statement;
								}
							}
						);

						Ext.Array.each(a_searchfields, function (i_field) {

							var s_dataIndex = i_field.dataIndex;
							var value = i_field.getValue();

							var a_values = Ext.Array.from(value).filter(function (value) {
								return value;
							});

							if (Ext.isString(value)) {
								a_values = value.split(",");
							}

							if (a_values.length > 0) {
								a_where.push(i_template.apply({
									dataIndex: s_dataIndex,
									value: a_values
								}));
							}
						});

						if (a_where.length > 0) {
							Ext.apply(o_extraParams, {
								where: a_where.join(" AND ")
							});
						}

						if (i_self.getUseScroller()) {
							Ext.apply(o_extraParams, {
								scroll: i_self.getUseScroller()
							});
						}

						Ext.apply(o_extraParams, {
							action: "getRows",
							dir: ""
						});
					}
				},
				load: {
					fn: function (i_store, a_records) {

						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();
						var i_view = i_self.getView();

						var i_selected = i_self.getSelected();

						a_records = a_records || [];

						var i_optionsColumns = i_self.getColumnManager().getHeaderByDataIndex("options");

						if (i_optionsColumns) {
							i_optionsColumns.setText(i_store.getTotalCount());
						}

						if (!i_self.getAutoSelect()) {
							return;
						}

						if (a_records.length) {

							if (i_selected) {

								var b_found = false;

								Ext.Array.each(a_records, function(i_record) {
									if (i_record.get(i_record.idProperty) == i_selected.get(i_selected.idProperty)) {
										b_found = true;
										i_self.setSelected(i_record);
										i_view.select(i_record, true);
										return false;
									}
								});

								if (!b_found) {
									i_self.setSelected(null);
								}
							}
							else {
								if (a_records.length > 0) {
									i_selected = a_records[0];
									i_self.setSelected(i_selected);
									i_view.select(i_selected, false);
								}
							}
						}
					}
				}

			},
			setNewRecordId: Ext.emptyFn
		});

		var i_proxy = i_store.getProxy();
		var o_extraParams = i_proxy.getExtraParams();

		Ext.apply(o_extraParams, {
			dmdFile: i_model.dmdFile,
			uiName: s_uiName,
			context: "grid",
			action: "getRows"
		});

		var o_view = o_entity.ui.grids[s_uiName];

		if (o_view) {

			o_extraParams = Ext.Object.mergeIf(o_extraParams, o_view.extraParams, {
				filter: []
			});

			if (o_extraParams.filter) {
				if (i_self.getCustomFilter()) {
					var value = i_self.getCustomFilter();
					if (Ext.isObject(value)) {
						if (!Ext.Object.isEmpty(value)) {
							o_extraParams.filter.push(i_self.getCustomFilter());
						}
					}
					else if (Ext.isArray(value)) {
						o_extraParams.filter = o_extraParams.filter.concat(value);
					}
					else {
						delete o_extraParams.filter;
					}
				}
				else {
					delete o_extraParams.filter;
				}
			}

			Ext.Object.each(o_extraParams, function(s_key, value) {
				o_extraParams[s_key] = typeof value == "object" && value !== null ? JSON.stringify(value) : value;
			});
		}

		if (i_self.getChildPanel()) {
			o_extraParams.parentEntity = i_self.getParentEntity();
			o_extraParams.parentKeys = i_self.getParentKeys();
		}

		return i_store;
	},

	createTemplateStore: function() {

		var i_self = this;
		var b_autoLoad = i_self.getAutoLoad();
		var i_model = i_self.getModel();

		var i_proxy = ip2.getProxyByEntity(i_self.getModelConfig());

		i_proxy.setActionMethods({
			read: "POST"
		});

		i_proxy.setParamsAsJson(true);

		i_proxy.setExtraParams({});

		

		i_proxy.extractResponseData = function(i_response) {

			var i_proxy = this;
			var i_reader = i_proxy.getReader();

			var o_data = i_response.responseJson || Ext.decode(i_response.responseText, true);

			var o_result = {};

			o_result[i_reader.getRootProperty()] = [];
			o_result[i_reader.getTotalProperty()] = 0;

			if (Ext.isArray(o_data.batch)) {
				o_result = o_data.batch[0];
			}

			return o_result;
		};

		var i_store = Ext.create("Ext.data.Store", {
			model: i_model,
			proxy: i_proxy,
			remoteSort: i_self.getRemoteSort(),
			autoSync: false,
			ops: [],
			first: true,
			pageSize: 100,
			prevSearch: "",
			autoLoad: b_autoLoad,
			listeners: {
				load: {
					fn: function (i_store, a_records) {

						var i_view = i_self.getView();
						var i_selected = i_self.getSelected();

						if (!i_self.getAutoSelect()) {
							return;
						}

						if (a_records.length > 0) {

							if (i_selected) {

								var b_found = false;

								Ext.Array.each(a_records, function(i_record) {

									if (i_record.get(i_record.idProperty) == i_selected.get(i_selected.idProperty)) {
										b_found = true;
										i_self.setSelected(i_record);
										i_view.select(i_record, true);
										return false;
									}
								});

								if (!b_found) {
									i_self.setSelected(null);
								}
							}
							else {
								i_selected = a_records[0];
								i_self.setSelected(i_selected);
								i_view.select(i_selected, false);
							}
						}
					}
				}
			}
		});

		i_self.store = i_store;

		return i_store;
	},

	createUI: function() {

		var i_self = this;
		var o_entity = i_self.getEntity();
		var o_templateConfig = i_self.getTemplateConfig();
		var o_view = o_entity.ui.grids[i_self.getUiName()];
		var b_editable = o_view.editable || false;
		var i_store = o_templateConfig ? i_self.createTemplateStore() : i_self.createStore();
		var a_columns = i_self.getColumns(i_store);
		var o_sorters = i_store.getSorters();
		o_sorters.setMultiSortLimit(a_columns.length - 1);

		if (o_sorters.$sortable) {
			o_sorters.$sortable.setMultiSortLimit(a_columns.length - 1);
		}

		var a_plugins = Ext.Array.from(i_self.plugins);
		var a_viewPlugins = Ext.Array.from(o_view.plugins);
		a_viewPlugins = a_viewPlugins.concat(Ext.Array.from(o_view.gridplugins));

		a_plugins = a_plugins.concat(a_viewPlugins);

		var a_features = i_self.getFeatures();

		var a_extFeatures = Ext.Array.from(o_view.extfeatures);

		a_features = a_features.concat(i_self.createFeatures(a_extFeatures));

		var i_plugin = Ext.create("Ext.grid.plugin.CellEditing", {
			pluginId: "celledit",
			clicksToEdit: 1,
			listeners: {
				beforeedit: {
					fn: function(i_editor, i_context) {

						return b_editable;
					}
				},
				edit: {
					fn: function(i_editor) {

						var i_context = i_editor.context;
						var i_grid = i_context.grid;
						var i_record = i_context.record;
						var i_store = i_grid.getStore();
						var i_proxy = i_store.getProxy();
						var i_view = i_grid.getView();

						var o_info = i_self.getEntityInfo();
						var o_dmd = o_info.dmd;
						var o_model = o_dmd.model;

						var o_proxy = o_model.proxy;

						o_proxy.portfolio = o_proxy.hasOwnProperty("portfolio") ? o_proxy.portfolio : true;

						if (o_proxy.portfolio) {

							if (i_context) {

								var i_column = i_context.column;
								var o_initialConfig = i_column.initialConfig;

								var o_editor = o_initialConfig.editor;

								if (i_record) {

									i_self.getFormRecord(i_record, function(i_formRecord) {

										var s_property = o_editor.map2 || i_context.field;

										i_formRecord.set(s_property, i_context.value);

										i_self.upsertRecord(i_formRecord, function() {

											i_self.getUpdatedRecord(i_record, function(o_data) {
												
												i_store = i_self.getStore();
												if (i_store) {
													i_store.fireEvent("datachanged", i_store);
													i_store.fireEvent("refresh", i_store);

													i_record.set(o_data);
													i_record.commit(true);
													
													i_view.refreshNode(i_record);
												}
											});
										});
									});
								}
							}
						}
						else {

							i_view.refresh();

							i_record.self.setProxy(i_proxy);

							i_record.save({
								callback: function(i_result, i_operation, b_success) {

									var a_message = [];

									if (!b_success) {

										var i_error = i_operation.getError();

										var i_response = i_error.response;

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

										if (o_result.message) {
											a_message.push(o_result.message);
										}
									}

									i_record.self.setProxy(i_proxy);

									if (a_message.length > 0) {

										var s_msg = a_message.join("<br>");

										Portfolio.util.Handler.messageBox({
											icon: Ext.MessageBox.ERROR,
											title: ip2.i18n({
												da: "Fejl",
												en: "Error"
											}),
											closable: true,
											message: ip2.i18n({
												da: "Der skete en fejl under processen:</br> <strong>" + s_msg + "</strong>",
												en: "An error occurred durring the process:</br> <strong>" + s_msg + "</strong>"
											}),
											yesText: ip2.i18n({
												da: "Ok",
												en: "OK"
											})
										});
									}
								}
							});
						}
					}
				}
			}
		});

		i_plugin.getEditor = (function(f_old) {
			return function() {

				var args = [].slice.call(arguments);

				var i_editor = f_old.apply(this, args);

				var i_field = i_editor.field;

				if (i_field.xtype === "isotimestampfield") {
					i_editor.alignment = "tl";
				}

				if (i_field.xtype == "combobox" || i_field.xtype == "entitypicker" || i_field.xtype == "uploadpicker") {

					i_editor.onFocusLeave = (function(f_old) {
						return function() {
							var i_editor = this;
							var i_field = i_editor.field;
							if (!i_field.isExpanded && !i_field.isUploading && !i_field.isHandling) {
								f_old.apply(this, arguments);
							}
						};
					})(i_editor.onFocusLeave);

					i_field.on({
						focus: {
							fn: function(i_field) {
								i_field.expand();
							}
						}
					});
				}

				if (i_field.xtype === "i18ntextfield" || i_field.xtype === "i18nhooktextfield") {
					i_editor.alignment = "tl";
					if (!i_editor.isChanged) {
						i_editor.isChanged = true;
						i_editor.onFocusLeave = (function(f_old) {
							return function(e) {
								var i_self = this;
								var i_field = this.field;
								if (!i_field.isChanging) {
									f_old.apply(this, arguments);
								}
							};
						})(i_editor.onFocusLeave);
					}
				}

				return i_editor;
			};
		})(i_plugin.getEditor);

		a_plugins.push(i_plugin);

		var i_selectionModel = i_self.selModel;

		if (!i_selectionModel) {

			i_selectionModel = Ext.apply({}, {
				type: o_view.rowmodel || "rowmodel",
				mode: o_view.mode || "MULTI",
				enableKeyNav: true,
				pruneRemoved: false
			});
		}

		Ext.Object.merge(i_self, {
			store: i_store,
			columns: i_self.setupColumns(a_columns, i_store),
			rowHeight: i_self.rowHeight,
			selModel: i_selectionModel,
			plugins: a_plugins,
			features: a_features,
			numFromEdge: 4,
			listeners: {
				destroy: {
					fn: function () {
						if (i_self.getRowMenu()) {
							i_self.getRowMenu().destroy();
						}
					}
				},
				itemdblclick: {
					fn: function (i_view, i_record, i_item, n_index, i_event, o_options) {

						i_self.handleAction(i_record, "update", 0);
					}
				},
				sortchange: {
					fn: function(i_header, i_column, s_direction) {
						if (i_self.getFilterBar()) {
							i_self.getFilterBar().sortChange(i_column);
						}
					}
				},
				select: {
					fn: function (i_view, i_record) {

						i_self.setSelected(i_record);

						var a_selected = i_self.getSelectionModel().getSelection();

						var i_toolbar = i_self.getEntityToolBar();

						i_toolbar.fireEvent("rowselect", i_toolbar, a_selected);

					}
				},
				selectionchange: {
					fn: function (i_view, i_selected) {

						if (i_selected) {

							var a_records = [];

							if (Ext.isFunction(i_selected.getRecords)) {

								a_records = i_selected.getRecords();

								i_self.setSelected(a_records[0]);
							}
							else {

								var i_record = i_selected.startCell ? i_selected.startCell.record : false;

								if (i_record) {
									a_records = [
										i_record
									];
								}
								
							}
							i_self.fireEvent(a_records.length ? "select" : "deselect", i_view, a_records[0]);
						}
					}
				},
				deselect: {
					fn: function() {
						var a_selected = i_self.getSelectionModel().getSelection();

						var i_toolbar = i_self.getEntityToolBar();

						i_toolbar.fireEvent("rowdeselect", i_toolbar, a_selected);
					}
				},
				itemcontextmenu: {
					fn: function (i_view, i_record, i_html, n_index, i_event) {

						var i_rowMenu = i_self.getRowMenu();
						var i_selModel = i_self.getSelectionModel();

						i_event.stopEvent();

						i_self.setRecord(i_record);

						var a_coords = i_event.getXY();

						if (!i_selModel.isSelected(n_index)) {
							i_view.select(n_index);
						}
						
						if (i_rowMenu) {

							i_rowMenu.fireEvent("beforeaction", i_rowMenu);

							var i_delete = i_rowMenu.down("#itmDelete");
							var n_status = i_record.get("BCKSTS");

							if (n_status) {
								if (n_status == 1900) {
									i_delete.setDisabled(false);
								}
								else {
									i_delete.setDisabled(true);
								}
							}

							if (o_view.features && o_view.features.menu && o_view.features.menu.src) {

								var o_menu = ip2.getEvaled({
									url: o_view.features.menu.src
								});

								if (o_menu) {

									var i_selectionModel = i_self.getSelectionModel();

									var a_records = i_selectionModel.getSelection();

									var o_config = {
										records: a_records,
										parentId: i_self.getId(),
										grid: i_self
									};

									var a_items = o_menu.onInitialize(i_rowMenu, o_config, "grid");

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

										var i_menuItm = i_rowMenu.down("#" + i_item.itemId);

										if (i_menuItm) {
											i_rowMenu.remove(i_menuItm);
										}
									});

									i_rowMenu.add(a_items);
								}
							}

							var a_items = i_rowMenu.items.getRange();

							if (a_items.length >  0) {
								i_rowMenu.showAt([a_coords[0], a_coords[1]]);
							}
						}
					}
				}
			},
			viewConfig: {
				trackOver: true,
				loadMask: true,
				variableRowHeight: false
			}
		});
	},

	getColumns: function(i_store) {

		var i_self = this;
		var o_entity = i_self.getEntity();
		i_store = i_store || i_self.getStore();
		var i_proxy = i_store.getProxy();

		var i_model = i_proxy.getModel();

		var s_dmd = i_self.getDmdName();

		var b_allowMenu = (Portfolio.util.Handler.isAccessible("app." + s_dmd + ".functions.columns.menu") ||
							Portfolio.util.Handler.isAccessible("app." + s_dmd + ".functions." + o_entity.name + ".columns.menu"));
		var b_draggable = (Portfolio.util.Handler.isAccessible("app." + s_dmd + ".functions.columns.arrange") ||
							Portfolio.util.Handler.isAccessible("app." + s_dmd + ".functions." + o_entity.name + ".columns.arrange"));

		var b_sortable = true;

		// Get the definitions we need to build the columns array for the grid

		var o_view = o_entity.ui.grids[i_self.getUiName()];
		var o_fields = o_entity.columns;

		var a_columns = o_view.columns || [];
		var a_extraColumns = Ext.Array.from(o_view.extraColumns);

		a_columns = a_columns.concat(a_extraColumns);

		a_columns.sort(function(a, b) {
			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		var a_fields = i_model.getFields();
		var a_return = [];

		var o_uitypes = Portfolio.util.Handler.getUitypes();

		var a_entityColumns = [];

		if (Ext.isObject(o_fields)) {
			Ext.Object.each(o_fields, function(s_key, o_value) {
				var o_temp = Ext.apply({
					name: s_key
				}, o_value);
				a_entityColumns.push(o_temp);
			});
		}
		else {
			Ext.Array.each(o_fields, function(o_value) {
				a_entityColumns.push(o_value);
			});
		}

		if (o_view.hasOwnProperty("sortable")) {
			b_sortable = o_view.sortable;
		}

		a_columns = Ext.Array.filter(a_columns, function(o_column) {
			return !o_column.hide;
		});

		Ext.Array.each(a_columns, function(o_uiColumn) {

			var o_column = Ext.apply({
				flex: 1
			}, o_uiColumn);

			var s_name = o_column.name;

			var o_field = {
				column: {}
			};


			o_field = Ext.Array.findBy(a_fields, function(o_value) {
				return o_value.name == o_column.name;
			});

			if (o_uiColumn.width) {
				delete o_column.flex;
			}

			Ext.applyIf(o_column, o_field.column);

			// Translate the column header
			if (o_column.header) {
				if (Ext.isObject(o_column.header)) {
					o_column.header = Portfolio.util.Handler.i18n(o_column.header);
				}
				else {
					o_column.header = Portfolio.util.Handler.dmdTranslate(i_model.prototype, o_column.header);
				}
			}

			if (o_column.title) {
				o_column.header = ip2.i18n(o_column.title, o_column.header);
			}

			// remove editor if we dont have it in our base column
			if (!o_uiColumn.hasOwnProperty("editor")) {
				delete o_column.editor;
			}

			var o_entityColumn = Ext.Array.findBy(a_entityColumns, function(o_value) {
				return o_value.name == o_column.name;
			});

			Ext.applyIf(o_column, o_entityColumn);

			if (o_column.from && !Ext.String.startsWith(o_column.from, "(")) {
				o_column.mapping = o_column.as || o_column.from + "_" + o_column.name;
			}

			var o_xpdInfo = Portfolio.util.Handler.getFieldXpdInfo(o_column.name, o_entity, o_column);

			if (o_xpdInfo) {
				Portfolio.util.Handler.applyFieldXpdInfo(o_column, o_xpdInfo);
			}

			if (o_column.uitype) {

				var o_uitype = o_uitypes[o_column.uitype];

				if (o_uitype && o_uitype.grid) {
					Ext.apply(o_column, o_uitype.grid || {});
				}
			}

			if (o_column.mapping) {
				Ext.applyIf(o_column, {
					draggable: b_draggable,
					menuDisabled: !b_allowMenu,
					sortable:  b_sortable,
					filterable: true
				});
			}
			else {
				Ext.apply(o_column, {
					draggable: b_draggable,
					menuDisabled: !b_allowMenu,
					sortable: b_sortable
				});
			}

			if (o_column.hasOwnProperty("showned")) {
				o_column.hidden = !o_column.showned;
			}

			o_column.dataIndex = o_column.as || s_name;

			a_return.push(o_column);
		});

		if (!i_self.columnsConfig) {
			i_self.columnsConfig = a_return;
		}

		Ext.Array.each(a_return, function(o_config) {

			if (o_config.summaryType == "percentage") {
				Ext.apply(o_config, {
					summaryRenderer: function(value, o_summaryValues, s_field, o_metaData) {

						var n_percentage = 0;

						var i_record = o_metaData.record;

						var i_model = i_store.getModel();

						var i_field = i_model.getField(s_field);

						var o_config = i_field.summary;

						if (o_config.sumField && o_config.devideField) {

							var n_sum = i_record.get(o_config.sumField);
							var n_devide = i_record.get(o_config.devideField);

							n_percentage = ((n_devide / n_sum) * 100);

							if (isNaN(n_percentage)) {
								n_percentage = 0;
							}
							else {
								n_percentage = n_percentage.toFixed(1);
							}

							value = n_percentage + " %";
						}

						return value;
					}
				});
			}

			Ext.apply(o_config, {
				listeners: {
					afterrender: {
						fn: function (i_column) {

							Ext.create("Ext.tip.ToolTip", {
								target: i_column.getEl(),
								html: ip2.i18n(i_column.header),
								anchor: true,
								defealtAlign: "b50-t50",
								listeners: {
									beforeshow: {
										fn: function (i_tip) {

											var o_initialConfig = i_column.initialConfig;

											var s_value = ip2.i18n(o_initialConfig.header);
											i_tip.update(s_value);
										}
									}
								}
							});
						}
					}
				}
			});

			delete o_config.hide;
		});

		a_return.push({
			xtype: "actioncolumn",
			align: "center",
			dataIndex: "options",
			menuDisabled: true,
			hideable: false,
			sortable: false,
			groupable: false,
			text: "0",
			defaults: {
				margin: "auto"
			},
			items: [
				{
					xtype: "button",
					iconCls: "pf-options",
					tooltip: ip2.i18n({
						da: "Mere",
						en: "More"
					}),
					width: 20,
					ui: "function-action",
					isActionDisabled: function(i_column, n_row, n_col, i_action) {
						var o_events = i_self.events || {
							itemcontextmenu: {}
						};

						var a_listeners = Ext.Array.from(o_events.itemcontextmenu.listeners);
						var b_disabled = a_listeners.length === 0;

						if (b_disabled) {

							if (Ext.isFunction(i_action.hide)) {
								i_action.hide();
							}
							else {
								i_action.hidden = true;
							}
						}

						return false;
					},
					handler: function (i_grid, n_row, n_column, i_item, i_event, i_record, i_row) {

						var o_events = i_self.events || {
							itemcontextmenu: {}
						};

						var a_listeners = Ext.Array.from(o_events.itemcontextmenu.listeners);

						if (!Ext.isEmpty(a_listeners)) {

							var i_view = i_self.view;
							i_view.select(i_record);

							Ext.Array.each(a_listeners, function(i_listener) {
								i_listener.fn.call(i_self, i_view, i_record, i_row, n_row, i_event);
							});
						}
					}
				}
			]
		});


		return a_return;
	},

	createRowMenu: function() {

		var i_self = this;

		var i_menu = Ext.create("Ext.menu.Menu", {
			allowOtherMenus: false,
			items: [],
			plain: true,
			listeners: {
				beforeaction: {
					fn: function(i_menu) {

						var i_menuApp = i_self.getMenuApp();
						var a_items = i_self.getRowMenuItems();
						var s_view = i_self.getUiName();

						var o_entityInfo = i_self.getEntityInfo();
						var o_entity = o_entityInfo.entity;
						var o_ui = o_entity.ui;
						var o_grids = o_ui.grids;
						var o_view = o_grids[s_view];
						var o_menu = o_view.menu || {};
						var s_event = "";

						var i_selected = i_self.getSelection()[0]; 

						if (!i_menuApp) {
							
							if (!Ext.Object.isEmpty(o_menu) && o_menu.main) {

								var s_main = o_menu.main;
								var o_path = o_menu.path || {};

								if (!Ext.Object.isEmpty(o_path)) {
									
									Ext.Loader.setConfig({
										paths: o_path
									});
								}

								i_menuApp = Ext.create(s_main, {});

								i_self.setMenuApp(i_menuApp);

								s_event = o_menu.event || "beforemenu";
								i_menuApp.fireEvent(s_event, i_menuApp, i_selected, a_items, i_self);
							}
						}
						else {
							
							s_event = o_menu.event || "beforemenu";
							i_menuApp.fireEvent(s_event, i_menuApp, i_selected, a_items, i_self);
						}

						i_menu.removeAll(true);

						i_menu.add(a_items);

					}
				}
			}
		});

		i_self.setRowMenu(i_menu);
	},

	getRowMenuItems: function() {

		var i_self = this;
		var o_entity = i_self.getEntity();
		var i_selectionModel = i_self.getSelectionModel();
		var s_dmd = i_self.getDmdName();

		var a_items = [];

		if (Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.update") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.read") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_entity.name + ".update") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_entity.name + ".read")) {

			var i_edit = Ext.widget("menuitem", {
				itemId: "item-edit",
				text: Portfolio.util.Handler.i18n({
					da: "Rediger",
					en: "Edit"
				}),
				handler: function (view, record, item, index, e) {
					var a_records = i_selectionModel.getSelection();
					var i_record = a_records[0];
					i_self.handleAction(i_record, "update", 0);
				}
			});

			a_items.push(i_edit);
		}

		if (Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.delete") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_entity.name + ".delete")) {

			var i_delete = Ext.widget("menuitem", {
				text: Portfolio.util.Handler.i18n({
					da: "Slet",
					en: "Delete"
				}),
				itemId: "itmDelete",
				handler: function () {
					var records = i_selectionModel.getSelection();
					i_self.deleteRow(records);
				}
			});
			a_items.push(i_delete);
		}

		if (Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.copy") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_entity.name + ".copy")) {

			var i_copy = Ext.widget("menuitem", {
				text: Portfolio.util.Handler.i18n({
					da: "Kopier",
					en: "Copy"
				}),
				itemId: "itmCopy",
				handler: function () {
					var a_records = i_selectionModel.getSelection();
					var i_record = a_records[0];
					if (i_self.copyFn) {
						i_self.setLoading(Portfolio.util.Handler.i18n({
							da: "Kopier data...",
							en: "Copying data..."
						}));
						i_self.copyFn(i_record, function() {
							i_self.setLoading(false);
							var i_store = i_self.getStore();
							i_store.load();
						});
					}
					else {
						i_self.handleAction(i_record, "copy", 0);
					}
				}
			});
			a_items.push(i_copy);
		}

		return a_items;
	},

	getModel: function() {

		var i_self = this;
		var i_model;
		if (!i_self.model) {
			var o_config = i_self.getModelConfig();
			i_model = Portfolio.util.Handler.model(o_config);
			i_self.model = i_model;
		}
		else {
			i_model = i_self.model;
		}

		return i_model;
	},

	getModelConfig: function() {

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

		if (!o_config) {

			o_config = Ext.apply({}, {
				dmd: i_self.getDmd().path,
				entityName: i_self.getDmd().entity || i_self.getDmd().entityName,
				context: "grid",
				uiName: i_self.getUiName()
			});

			i_self.setDmdCfg(o_config);

			if (Ext.isObject(i_self.dmd)) {
				i_self.setDmd(i_self.getDmd().path);
				delete i_self.dmd;
			}
		}

		return o_config;
	},

	getEntityInfo: function() {

		var i_self = this;
		var o_entity;
		var o_entityInfo = i_self.entityInfo;

		if (!o_entityInfo) {

			var o_modelConfig = i_self.getModelConfig();

			var o_config = Portfolio.util.Handler.dmd.getInfo({
				dmd: o_modelConfig.dmd,
				entity: o_modelConfig.entityName,
				view: i_self.getUiName(),
				context: "grid"
			});

			o_entityInfo = o_config;
			o_entity = o_config.entity;
			i_self.entityInfo = o_entityInfo;

			var o_view = o_config.view;

			i_self.setEditMode(o_view.editMode || "tab");

			i_self.setEntity(o_entity);
		}

		return o_entityInfo;
	},

	getToolbar: function() {

		var i_self = this;
		var i_toolbar = i_self.getEntityToolBar();
		return i_toolbar;
	},

	createToolbar: function() {

		var i_self = this;
		var i_model = i_self.getModel();
		var i_store = i_self.getStore();
		var o_config = i_self.getModelConfig();
		var o_entityInfo = i_self.getEntityInfo();
		var s_dmd = i_self.getDmdName();
		var o_entity = i_self.getEntity();

		var o_view = o_entity.ui.grids[i_self.getUiName()];
		var s_searchType = o_view.searchtype ? o_view.searchtype : "";

		var b_allowNew = (
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.create") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_entity.name + ".create")
		);

		var b_allowExport = (
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data.export") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".data." + o_entity.name + ".export")
		);

		if (b_allowExport) {
			b_allowExport = i_self.getAllowExport();
		}

		var b_search = i_self.getSearchCombo();

		if (s_searchType) {
			b_search = s_searchType == "combo";
		}

		var i_toolbar = Ext.widget("entitytoolbar", {
			model: i_model,
			dmdInfo: o_config,
			store: i_store,
			grid: i_self,
			itemId: "maintoolbar",
			dock: "top",
			customFilter: i_self.getCustomFilter(),
			addMode: "form",
			allowNew: b_allowNew,
			allowSearch: i_self.getAllowSearch(),
			allowExport: b_allowExport,
			allowLink: i_self.getAllowLink(),
			searchCombo: b_search,
			entityInfo: o_entityInfo
		});

		i_self.setEntityToolBar(i_toolbar);

		return i_toolbar;
	},

	createFilterBar: function() {

		var i_self = this;
		var o_entity = i_self.getEntity();
		var s_dmd = i_self.getDmdName();
		var b_filterMenu = i_self.getAllowMenuOnFilters();

		var b_allowMenu = (
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".functions.filter") ||
			Portfolio.util.Handler.isAccessible("app." + s_dmd + ".functions." + o_entity.name + ".filter.use")
		);

		if (b_allowMenu) {
			b_allowMenu = i_self.getAllowFilterMenu();
		}

		var i_filterbar = Ext.widget("filterbar", {
			dock: "top",
			grid: i_self,
			allowMenu: b_allowMenu,
			allowFilterMenu: b_filterMenu,
			hidden: true,
			defaultFilter: i_self.getDefaultFilter() || ""
		});
		i_self.setFilterBar(i_filterbar);

		return i_filterbar;
	},

	createToolbars: function() {

		var i_self = this;
		var a_return = [];
		if (i_self.getAllowActions()) {
			a_return.push(i_self.createToolbar());
		}
		if (i_self.getFilterable()) {
			a_return.push(i_self.createFilterBar());
		}

		return a_return;
	},

	/**
	 * saveInitialSetting..
	 * Saves the the state off the grid if the state of the never has been saved before or
	 * if the grid columns count in the dmd is changed
	 * grid: me.grid  THIS IS THE GRID THAT IS MADE DURING THE initComponent.
	 **/
	saveInitialSetting: function (i_store) {

		var i_self = this;
		var o_setting = {
			columns: {
				order: [],
				size: []
			}
		};
		var a_return = [];

		var a_columns = i_self.getColumns(i_store);

		Ext.Array.each(a_columns, function(o_column) {

			var o_copy = Ext.apply({}, {
				dataIndex: o_column.dataIndex || o_column.name,
				hidden: o_column.hidden
			});
			if (!o_column.hide) {
				a_return.push(o_column);
			}
			o_setting.columns.order.push(o_copy);
		});

		Portfolio.util.Handler.profile.set(i_self.getProviderID() + ".setting", JSON.stringify(o_setting));

		return a_return;
	},

	saveState: function() {

		var i_self = this;
		var s_id = i_self.getProviderID();

		if (!i_self.isDestroyed) {
			var a_columns = i_self.columnsConfig.slice(0);
			var a_headerColumns = i_self.getColumnManager().getColumns();

			a_headerColumns = Ext.Array.filter(a_headerColumns, function(i_col) {
				return i_col.dataIndex !== "";
			});

			var o_setting = Portfolio.util.Handler.profile.get(s_id + ".setting", {
				columns: {
					order: [],
					size: []
				}
			}); // USE THIS WHEN YOU WANT TO LOAD THE MODEL FROM DB

			Ext.applyIf(o_setting, {
				columns: {
					order: [],
					size: []
				}
			});

			o_setting.columns.order = [];
			o_setting.columns.size = [];

			Ext.Array.each(a_headerColumns, function(i_column) {
				o_setting.columns.order.push({
					dataIndex: i_column.dataIndex,
					hidden: i_column.hidden
				});
			});

			Ext.Array.each(a_columns, function(i_column) {
				var b_found = false;
				Ext.Array.each(a_headerColumns, function(i_header) {
					if (i_header.dataIndex == i_column.dataIndex) {
						b_found = true;
					}
				});
				if (!b_found) {
					o_setting.columns.order.push({
						dataIndex: i_column.dataIndex,
						hidden: i_column.hidden
					});
				}
			});

			Ext.Array.each(a_headerColumns, function(i_column) {
				o_setting.columns.size.push({
					dataIndex: i_column.dataIndex,
					width: i_column.width
				});
			});

			Ext.Array.each(a_columns, function(i_column) {
				var b_found = false;
				Ext.Array.each(a_headerColumns, function(i_header) {
					if (i_header.dataIndex == i_column.dataIndex) {
						b_found = true;
					}
				});
				if (!b_found) {
					o_setting.columns.size.push({
						dataIndex: i_column.dataIndex,
						width: i_column.width
					});
				}
			});

			Portfolio.util.Handler.profile.set(s_id + ".setting", JSON.stringify(o_setting));
		}
	},

	applyReset: function () {

		var i_self = this;
		var i_menu = i_self.headerCt.getMenu();

		i_menu.on({
			beforeshow: {
				fn: function(i_menu) {

					var i_reset = i_menu.getComponent("btnReset");

					if (!i_reset) {
						i_menu.add(i_self.createResetButton());
					}
				}
			}
		});
	},

	createResetButton: function () {

		var i_self = this;

		var i_button = Ext.widget("menuitem", {
			itemId: "btnReset",
			iconCls: "pf-arrow_circle2",
			text: Portfolio.util.Handler.i18n({
				en: "Reset",
				da: "Nulstil"
			}),
			handler: function () {
				i_self.resetSetting();
			}
		});
		return i_button;
	},

	createSearchButton: function () {

		var i_self = this;

		var i_button = Ext.widget("menuitem", {
			itemId: "btn_search",
			iconCls: "icon-gear",
			text: Portfolio.util.Handler.i18n({
				en: "Search",
				da: "Søg"
			}),
			handler: function (i_menuitem) {

				var i_column = i_menuitem.up("gridcolumn");

				i_self.fireEvent("colToSearch", i_self, i_column);
			}
		});
		return i_button;
	},

	resetSetting: function () {

		var i_self = this;
		var a_reconfig = i_self.saveInitialSetting();

		i_self.reconfigure(undefined, a_reconfig);
	},

	deleteRow: function (a_records) {

		var i_self = this;
		var i_store = i_self.getStore();
		var o_modelConfig = i_self.getModelConfig();
		var o_entityInfo = i_self.getEntityInfo();
		var o_dmd = o_entityInfo.dmd;
		var o_model = o_dmd.model;
		var o_proxy = o_model.proxy || {};

		o_proxy.portfolio = o_proxy.hasOwnProperty("portfolio") ? o_proxy.portfolio : true;

		var o_entity = i_self.getEntity();

		var s_message = a_records.length == 1 ? Portfolio.util.Handler.i18n({
			da: "Ønsker du virkelig at slette?",
			en: "Do you really wish to delete?"
		}) : Portfolio.util.Handler.i18n({
			da: "Ønsker du virkelig at slette de " + a_records.length + " valgte?",
			en: "Do you really wish to delete the " + a_records.length + " selected?"
		});

		ip2.messageBox({
			title: ip2.i18n({
				da: "Bekræft sletning",
				en: "Confirm deleting"
			}),
			icon: Ext.MessageBox.INFO,
			message: s_message,
			yesFn: function() {

				if (o_proxy.portfolio) {
					var a_batch = [];

					Ext.Array.each(a_records, function (i_record) {

						var o_keys = {};

						o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

						a_batch.push({
							type: "delete",
							dmd: o_modelConfig.dmd,
							entity: o_entity.name,
							key: o_keys
						});
					});

					s_message = Portfolio.util.Handler.i18n({
						da: "Sletter...",
						en: "Deleting..."
					});

					i_self.setLoading(s_message);

					Ext.Ajax.request({
						url: "/ip2-Services/ip2dmdproxy.aspx",
						jsonData: {
							batch: a_batch
						},
						success: function (o_response) {
							i_self.setLoading(false);

							i_store.load();
							i_self.fireEvent("afterdelete", i_store, a_records);
						}
					});
				}
				else {
					i_store.erase({
						records: a_records,
						callback: function() {
							i_self.setLoading(false);

							i_store.load();

							i_self.fireEvent("afterdelete", i_store, a_records);
						}
					});
				}
			},
			yesText: ip2.i18n({
				da: "Ok",
				en: "OK"
			}),
			cancelText: ip2.i18n({
				da: "Annuller",
				en: "Cancel"
			})
		});
	},

	upsertRecord: function(i_record, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var i_model = i_self.getModel();
		var o_entity = i_self.getEntity();
		var a_records = Ext.Array.from(i_record);
		var a_batch = [];

		Ext.Array.each(a_records, function(i_record) {

			var o_keys = {};

			o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

			var o_batch = {
				type: "upsert",
				dmd: i_model.dmdFile,
				entity: o_entity.name,
				transactiontype: o_entity.name,
				key: o_keys,
				transactionkey: i_record.get(i_record.idProperty),
				row: i_record.getData()
			};

			a_batch.push(o_batch);
		});

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {
				f_callback();
			},
			failure: function(o_error) {
				f_callback();
			}
		});
	},

	getUpdatedRecord: function(i_record, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var i_model = i_self.getModel();
		var o_entity = i_self.getEntity();

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			params: {
				action: "getRows",
				context: "grid",
				dmdFile: i_model.dmdFile,
				uiName: i_self.getUiName(),
				model: o_entity.name,
				where: [
					i_record.idProperty,
					i_record.get(i_record.idProperty)
				].join(" = ")
			},
			success: function (o_response) {

				var o_result = Ext.decode(o_response.responseText, true) || {
					success: false,
					rows: [{}]
				};

				if (!o_result.rows) {
					o_result.rows = [{}];
				}

				var o_data = o_result.rows[0];

				var i_store = i_self.getStore();
				if (i_store) {
					var i_proxy = i_store.getProxy();
					var i_reader = i_proxy.getReader();
	
					var a_extracted = i_reader.extractData([o_data], {});
	
					var i_extracted = a_extracted[0];
	
					var o_extracted = i_extracted.getData();
	
					f_callback(o_extracted);
				}
				else {
					f_callback({});
				}
			},
			failure: function() {
				f_callback({});
			}
		});
	},

	getFormRecord: function(i_record, f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var i_model = i_self.getModel();
		var o_entity = i_self.getEntity();

		var i_formModel = ip2.model({
			dmd: i_model.dmdFile,
			view: i_self.getUiName(),
			entity: o_entity.name,
			context: "form"
		});

		var o_keys = {};
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			params: {
				action: "getRow",
				context: "form",
				dmdFile: i_model.dmdFile,
				uiName: "portfolio",
				model: o_entity.name,
				key: Ext.encode(o_keys)
			},
			success: function (o_response) {

				var o_result = Ext.decode(o_response.responseText, true) || {
					success: false,
					rows: [{}]
				};

				if (!o_result.rows) {
					o_result.rows = [{}];
				}

				var o_data = o_result.rows[0];

				var i_record = i_formModel.create(o_data);

				f_callback(i_record);
			},
			failure: function() {

				var i_record = i_formModel.create({});

				f_callback(i_record);
			}
		});
	},

	createFeatures: function(a_features) {

		a_features = Ext.Array.filter(a_features, function(s_feature) {
			return s_feature;
		});

		var a_return = [];

		Ext.Array.each(a_features, function(s_feature) {

			var o_feature = {
				ftype: s_feature
			};
			switch(s_feature) {
				case "grouping":

					var i_template  = Ext.create("Ext.XTemplate",
						"<strong><span>{name} </span><span style=\"",
							"float:right;",
							"padding-left:10px;",
							"width: 90px;",
							"text-align: center;",
							"\">{[this.getCount(values)]}</span></strong>",
						{
							getCount: function(values) {
								return Ext.Array.from(values.rows).length;
							}
						}
					);

					Ext.apply(o_feature, {
						groupHeaderTpl: i_template,
						startCollapsed: true,
						groupByText: ip2.i18n({
							da: "Gruppér",
							en: "Group by"
						}),
						showGroupsText: ip2.i18n({
							da: "Vis gruppering",
							en: "Show grouping"
						})
					});

					break;
			}

			a_return.push(o_feature);
		});

		return a_return;
	},

	createKeyEvents: function() {

		var i_self = this;

		var a_bindings = [
			{
				key: Ext.event.Event.ENTER,
				fn: function (n_key, i_event) {

					var i_selected = i_self.getSelection()[0];

					if (i_selected) {
						i_self.handleAction(i_selected, "update", 0);
					}
				}
			},
		];

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

		i_self.on({
			beforedestroy: {
				fn: function() {
					i_keyMap.destroy();
				},
				single: true
			}
		});
	}
});
Ext.define("Portfolio.entity.view.Preview", {

	xtype: "portfolio-entity-preview",

	extend: "Ext.window.Window",

	alias: [
		"widget.previewwindow",
		"widget.entity.preview"
	],

	layout: "fit",

	width: 800,

	height: 600,

	constrain: true,

	modal: true,

	resizable: false,

	maximizable: false,

	minimizable: false,

	config: {
		previewState: 0,
		rotation: 0,
		toolbar: null
	},

	initComponent: function() {

		var i_self = this;
		var o_size = i_self.getWindowSize(i_self.getPreviewState());

		i_self.width = o_size.width;
		i_self.height = o_size.height;

		i_self.callParent();
		i_self.addDocked(i_self.createToolbar());
	},

	createToolbar: function() {

		var i_self = this;

		var i_toolbar = Ext.widget("toolbar", {
			itemId: "bar_action",
			docked: "top",
			items: i_self.createButtonsActions()
		});

		i_self.setToolbar(i_toolbar);

		return i_toolbar;
	},

	createButtonsActions: function() {

		var i_self = this;

		var a_buttons = [
			i_self.createButton("reload"),
			"-",
			i_self.createButton("desktop"),
			i_self.createButton("tablet"),
			i_self.createButton("mobile"),
			"-",
			i_self.createRotationButton()
		];

		return a_buttons;
	},

	createButton: function(s_type) {

		var i_self = this;
		var n_state = i_self.getPreviewState();
		var n_rotation = i_self.getRotation();
		var o_config;

		switch (s_type) {
			case "reload":
				o_config = Ext.apply({}, {
					iconCls: "pf-refresh",
					tooltip: ip2.i18n({
						en: "Refresh content",
						da: "Opfrisk indhold"
					}),
					ui: "function-action",
					handler: function () {
						i_self.reload();
					}
				});
				break;
			case "desktop":
				o_config = Ext.apply({}, {
					text: ip2.i18n({
						en: "Desktop",
						da: "Desktop"
					}),
					iconCls: "pf-windows",
					enableToggle: true,
					pressed: n_state === 0 ? true : false,
					ui: "function",
					handler: function (i_button) {

						var o_size = i_self.getWindowSize(0);

						i_self.setTitle(ip2.i18n({
							en: "Preview",
							da: "Preview"
						}) + " - " + i_button.text);

						i_self.doReload(i_button, o_size, false);

						i_self.setPreviewState(0);
					}
				});
				break;
			case "tablet":
				o_config = Ext.apply({}, {
					text: ip2.i18n({
						en: "Tablet",
						da: "Tablet"
					}),
					enableToggle: true,
					pressed: n_state == 1 ? true : false,
					iconCls:"pf-graphics_tablet",
					ui: "function",
					handler: function (i_button) {

						var o_size;
						var n_rotation = i_self.getRotation();

						if (n_rotation === 0) {
							o_size = i_self.getWindowSize(1);
						}
						else {
							o_size = i_self.getWindowSize(3);
						}

						i_self.setTitle(ip2.i18n({
							en: "Preview",
							da: "Preview"
						}) + " - " + i_button.text);

						i_self.doReload(i_button, o_size, true);

						i_self.setPreviewState(1);
					}
				});
				break;
			case "mobile":
				o_config = {
					text: ip2.i18n({
						en: "Mobile",
						da: "Mobil"
					}),
					enableToggle: true,
					pressed: n_state == 2 ? true : false,
					iconCls: "pf-mobilephone3",
					ui: "function",
					handler: function (i_button) {

						var o_size;
						var n_rotation = i_self.getRotation();

						if (n_rotation === 0) {
							o_size = i_self.getWindowSize(2);
						}
						else {
							o_size = i_self.getWindowSize(4);
						}

						i_self.setTitle(ip2.i18n({
							en: "Preview",
							da: "Preview"
						}) + " - " + i_button.text);

						i_self.doReload(i_button, o_size, true);

						i_self.setPreviewState(2);
					}
				};
				break;
		}
		return Ext.widget("button", o_config);
	},

	createRotationButton: function () {

		var i_self = this;
		var n_state = i_self.getPreviewState();

		var o_config = {
			text: ip2.i18n({
				en: "Rotate",
				da: "Roter"
			}),
			itemId: "button_rotation",
			isRotate: true,
			enableToggle: true,
			iconCls: "pf-document_orientation_portrait",
			ui: "function",
			pressed: false,
			hidden: n_state === 0 ? true : false,
			tooltip: ip2.i18n({
				en: "Toggle between Portrait & Landscape",
				da: "Skift mellem visning som Portræt og Landskab"
			}),
			listeners: {
				toggle: function (i_button, b_pressed) {

					var o_size;
					var n_state = i_self.getPreviewState();
					var i_iconEl = i_button.btnIconEl;

					switch (n_state) {
						case 1:
							if (!b_pressed) {
								o_size = i_self.getWindowSize(1);
							}
							else {
								o_size = i_self.getWindowSize(3);
							}
							break;
						case 2:
							if (!b_pressed) {
								o_size = i_self.getWindowSize(2);
							}
							else {
								o_size = i_self.getWindowSize(4);
							}
							break;
					}
					if (!b_pressed) {
						i_self.rotation = 0;
						i_button.setIconCls("pf-document_orientation_landscape");
					}
					else {
						i_self.rotation = 1;
						i_button.setIconCls("pf-document_orientation_portrait");
					}

					i_self.setWidth(o_size.width);
					i_self.setHeight(o_size.height);
					i_self.center();
				}
			}
		};
		return Ext.widget("button", o_config);
	},

	getWindowSize: function(type) {

		var o_wndsize = Portfolio.util.Handler.getWindowSize();
		var hi = o_wndsize.height;
		var wid = o_wndsize.width;

		var o_size = {
			width: 0,
			height: 0
		};
		switch (type) {
			case 0:  // Desktop
				o_size.width = Math.max((wid * 0.9), 992);
				o_size.height = (hi * 0.9);
				break;
			case 1:  // Tablet standing
				o_size.width = Math.min(800, (wid * 0.9));
				o_size.height = Math.min(1280, (hi * 0.9));
				break;
			case 3: // Table
				o_size.width = Math.min(1280, (wid * 0.9));
				o_size.height = Math.min(800, (hi * 0.9));
				break;
			case 2: // Mobile standig
				o_size.width = 375;
				o_size.height = 667;
				break;
			case 4: // Mobile
				o_size.width = 667;
				o_size.height = 375;
				break;
		}

		o_size.width += 10;
		return o_size;
	},

	handleButtons: function(i_button, size) {

		var i_self = this;

		i_self.setWidth(size.width);
		i_self.setHeight(size.height);
		i_self.center();

		var i_toolbar = i_self.getToolbar();
		var a_buttons = i_toolbar.query("button");

		Ext.Array.each(a_buttons, function(i_action) {
			if (i_action.id != i_button.id && !i_action.isRotate) {
				if (i_action.pressed) {
					i_action.toggle();
				}
			}
		});

		i_self.reload();
	},

	reload: function() {

		var i_self = this;
		var i_webcontainer = i_self.down("webcontainer");

		if (i_webcontainer) {

			var i_iframe = i_webcontainer.getIframe();
			var i_element = i_iframe.getEl();
			i_element.dom.src = i_element.dom.src;
		}
	},

	doReload: function(o_button, o_size, b_showrotation) {

		var i_self = this;
		var i_rotation = i_self.down("#button_rotation");

		i_rotation.setVisible(b_showrotation);

		i_self.handleButtons(o_button, o_size);
	}

});
Ext.define("Portfolio.entity.store.Reader", {

	extend: "Ext.data.reader.Json",

	alias: "reader.tree.dmd",

	root: "rows",

	totalProperty: "totalRows",

	nameProperty: "name",

    fields: null,
    
    onMetaChange: function(meta) {

        var me = this,
            fields = meta.fields,
            model, newModel, clientIdProperty, proxy;
        
        me.metaData = meta;
        
        if (meta.root) {
            me.setRootProperty(meta.root);
        }
        if (meta.totalProperty) {
            me.setTotalProperty(meta.totalProperty);
        }
        if (meta.successProperty) {
            me.setSuccessProperty(meta.successProperty);
        }
        if (meta.messageProperty) {
            me.setMessageProperty(meta.messageProperty);
        }
        clientIdProperty = meta.clientIdProperty;
        if (fields) {
            newModel = Ext.define(null, {
                extend: "Ext.data.TreeModel",
                fields: fields,
                clientIdProperty: clientIdProperty
            });
            me.setModel(newModel);
            proxy = me.getProxy();
            if (proxy) {
                proxy.setModel(newModel);
            }
        } else if (clientIdProperty) {
            model = me.getModel();
            if (model) {
                model.self.prototype.clientIdProperty = clientIdProperty;
            }
        }
    }
});
Ext.define("Portfolio.entity.store.Tree", {

	xtype: "portfolio-entity-store-tree",

	extend: "Ext.data.TreeStore",

	alias: [
		"store.ux.entity.treestore",
		"store.portfolio.entity.store.tree"
	],

	requires: [
		"Portfolio.entity.store.Reader"
	],

	alternateClassName: [
		"Ext.ux.entity.TreeStore",
	],

	constructor: function (config) {

		var o_config = Ext.Object.merge(config);
		o_config.proxy = config.proxy || {};

		var i_store = this;
		var o_proxy = {
			type: "ajax",
			url: "/ip2-services/ip2dmdProxy.aspx?" + Ext.urlEncode({
				model: o_config.entity,
				action: "getRows",
				context: o_config.context || "grid",
				uiName: o_config.view || "portfolio",
				dmdFile: o_config.dmd
			}),
			reader: {
				type: "tree.dmd",
				$configStrict: false,
				rootProperty: "rows",
				totalProperty: "totalRows",
				model: config.model
			}
		};

		var o_info = ip2.dmd.getInfo({
			dmd: o_config.dmd,
			entity: o_config.entity,
			view: o_config.view || "portfolio",
			context: o_config.context || "grid"
		});

		o_proxy.entityInfo = o_info;

		Ext.Object.merge(o_config.proxy, o_proxy);

		i_store.callParent([o_config]);
	},

	read: function () {
		this.keep = true;
		return this.load.apply(this, arguments);
	},

	config: {
		sequence: ""
	},

	listeners: {
		beforeload: {
			fn: function (i_store, i_operation) {

				var i_node = i_operation.node;
				var s_where = "";
				var i_tree = i_store.ownerTree;
				var s_keep = "";
				var b_filter = false;
				var i_actionbar;
				var i_filterbar;
				var i_searchField;
				var i_languagePicker;

				var s_language = ip2.getUser().get("USRLNG");

				if (i_tree) {
					i_actionbar = i_tree.getActionBar();
					i_filterbar = i_tree.getFilterBar();
					i_searchField = i_actionbar.down("#search");
					i_languagePicker = i_actionbar.down("#button-language");
				}

				var i_proxy = i_store.getProxy();
				var o_entity = i_proxy.entityInfo.entity;

				var o_extraParams = i_proxy.getExtraParams();

				delete o_extraParams.search;
				delete o_extraParams.where;

				var a_sort = [];
				var s_sort = "";

				//s_where = s_where + i_node.get(i_store.childID);

				if (i_store.keep && !i_node.isRoot()) {
					s_keep = s_where;
				}

				var o_sorters = i_store.getSorters();

				Ext.Array.each(o_sorters.items, function (o_sort) {
					var s_sorter = o_sort.getProperty() + " " + o_sort.getDirection();
					a_sort.push(s_sorter);
				});

				s_sort = a_sort.join(", ");
				o_extraParams.sort = s_sort;

				if (i_filterbar) {
					if (i_filterbar.getWhere()) {
						b_filter = true;
						s_where = i_filterbar.getWhere();
					}

					var a_filters = i_filterbar.getFilters();

					o_sorters.loading = isNaN(o_sorters.updating) ? 1 : o_sorters.updating++;

					Ext.Array.each(a_filters, function(i_filter) {
						var o_sort = i_filter.getSortInfo();
						var b_found = false;
						ip2.each(o_sorters.items, function (i_sorter) {
							if (i_sorter.getProperty() == o_sort) {
								b_found = true;
							}
						});
						if (!b_found) {
							o_sorters.add(o_sort);
						}
					});

					o_sorters.loading = isNaN(o_sorters.updating) ? 0 : o_sorters.updating--;
				}

				if (i_searchField) {
					o_extraParams.search = i_searchField.getRawValue();
					if (!b_filter && o_extraParams.search) {
						s_where = "";
					}
					if (i_searchField.getWhere()) {
						if (!ip2.isEqual(s_where, i_searchField.getWhere())) {
							if (s_where) {
								s_where = s_where + " AND " + i_searchField.getWhere();
							}
							else {
								s_where = i_searchField.getWhere();
							}
						}
					}
				}

				if (s_keep) {
					var a_temp = [s_keep];

					if (s_keep.toLowerCase() != s_where.toLowerCase()) {
						a_temp.push(s_where);
						a_temp = a_temp.filter(function (value) {
							return value;
						});
					}
					s_where = a_temp.join(" AND ");
				}

				if (!i_node.isRoot()) {
					if (i_languagePicker && o_entity.language) {
						o_extraParams.language = i_languagePicker.key;
						o_extraParams.languageColumn = o_entity.language.column;
					}
					else {
						o_extraParams.language = s_language;
					}
				}
				else {
					delete o_extraParams.language;
					delete o_extraParams.languageColumn;

				}

				var a_where = [
					s_where
				];

				if (i_node.get(i_node.idProperty) > 0) {
					a_where.push(
						i_store.parentID + " = " + i_node.get(i_node.idProperty)
					);
				}

				a_where = Ext.Array.filter(a_where, function (s_value) {
					return s_value;
				});

				s_where = a_where.join(" AND ");

				if (i_store.getSequence()) {
					a_sort.push(i_store.getSequence() + " ASC");
					s_sort = a_sort.join(", ");
					o_extraParams.sort = s_sort;
				}

				o_extraParams.where = s_where;

				i_store.keep = false;
			}
		}
	}
});
Ext.define("Portfolio.entity.view.Tree", {
	extend: "Ext.tree.Panel",

	xtype: "portfolio-entity-tree",

	alternateClassName: [
		"Ext.ux.entity.Tree"
	],

	alias: [
		"widget.ux.entity.tree",
		"widget.portfolio.entity.tree"
	],

	config: {
		dmd: null,
		entity: null,
		viewName: null,
		context: "grid",
		model: null,
		parentID: "",
		childID: "",
		textProperty: "",
		sequence: "",
		actionBar: null,
		filterBar: null,
		dmdName: "",
		allowEdit: true,
		allowAdd: true,
		allowLink: true,
		allowFilter: true,
		allowSearch: true,
		allowExport: true,
		allowDelete: true,
		showBreadcrumb: false,
		autoLoad: true,
		breadcrumbBar: null,
		searchCombo: true
	},

	useArrows: true,

	defaultRootId: "id",

	requires: [
		"Portfolio.entity.store.Tree",
		"Portfolio.entity.util.Toolbar"
	],

	initComponent: function() {

		var i_self = this;
		i_self.initializeDefaults();
		var i_model = i_self.createModel();
		var a_columns = i_self.createColumns();
		i_self.columns = a_columns;

		i_self.idProperty = i_self.defaultRootId = i_model.idProperty;

		i_self.store = i_self.createStore();

		if (i_self.getSequence()) {
			i_self.viewConfig = i_self.createViewConfig();
		}

		i_self.callParent();

		i_self.addDocked(i_self.createActionBar());
		i_self.addDocked(i_self.createFilterBar());

		if (i_self.getShowBreadcrumb()) {
			i_self.addDocked(i_self.createBreadCrumbBar());
		}

		i_self.on({
			sortchange: {
				fn: function(i_header, i_column, s_direction) {
					if (i_self.getFilterBar()) {
						i_self.getFilterBar().sortChange(i_column);
					}
				},
				buffer: 10
			},
			itemclick: {
				fn: function(i_view, i_selected) {

					if (i_self.getShowBreadcrumb()) {
						var i_toolbar = i_self.getBreadcrumbBar();
						if (i_toolbar) {
							i_toolbar._needsSync = true;
							i_toolbar.updateSelection(i_selected);
							i_toolbar._needsSync = false;
						}
					}
				}
			},
			itemcontextmenu: {
				fn: function(i_view, i_node, i_item, n_index, i_event) {

					i_event.preventDefault();

					var a_coords = i_event.getXY();
					var a_items = i_self.getMenuItems(i_node, i_self.getAllowAdd(), i_self.getAllowEdit(), i_self.getAllowDelete());

					var i_menu = Ext.widget("menu", {
						items: a_items
					});

					i_menu.showAt(a_coords[0], a_coords[1]);
				}

			},
			afterFilter: {
				fn: function (i_filterbar, n_filters) {

					var i_self = this;
					var i_toolbar = i_self.getActionBar();
					i_toolbar.fireEvent("afterfilter", n_filters);
				}
			}
		});

		var o_config = i_self.getModelConfig();;

		var i_store = i_self.getStore();

		i_self.mon(Portfolio.util.Handler.App, "entityupdate:" + o_config.entityName, function(i_record) {

			var i_selected = i_self.getSelection()[0];

			if (i_selected) {

				var i_parent = i_selected.isRoot() ? i_selected : i_selected.parentNode;

				if (i_selected.isRoot()) {

					var i_view = i_self.getView();

					if (i_view.body.dom) {
						i_view.body.translate(0, 0, 0);
					}

					if (i_view.bufferedRenderer) {
						i_view.bufferedRenderer.onStoreClear();
					}
				}

				if (i_parent) {
					i_parent.collapse();
					i_parent.removeAll(false);

					i_store.read({
						node: i_parent,
						callback: function(i_store) {
							i_parent.expand();
						}
					});
				}
			}
		});

		var i_header = i_self.headerCt;

		i_header.on({
			boxready: {
				fn: function(i_item) {
					if (i_self.getAllowFilter()) {

						var i_toolbar = i_self.getFilterBar();

						if (i_toolbar) {
							var s_ddGroup = i_header.reorderer.dragZone.ddGroup;
							i_toolbar.dd.addDDGroup(s_ddGroup);
						}
					}
				},
				buffer: 100
			}
		});
	},

	initializeDefaults: function() {

		var i_self = this;

		var o_dmd = ip2.resource.get(i_self.getDmd());
		var o_model = o_dmd.model;

		var o_entity = Ext.Array.findBy(o_model.entities, function(o_value) {
			return o_value.name == i_self.getEntity();
		});

		var s_parenID = i_self.getParentID();
		var s_childID = i_self.getChildID();

		if (!s_parenID) {
			s_parenID = o_entity.parentID;
			i_self.setParentID(s_parenID);
		}

		if (!s_childID) {
			s_childID = o_entity.childID;
			i_self.setChildID(s_childID);
		}

		i_self.createModel();
	},

	getMenuItems: function(i_node, b_add, b_edit, b_delete) {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_record = i_node;
		var i_model = i_self.getModel();
		var o_config = i_self.getModelConfig();
		var s_dmd = i_self.getDmdName();
		var s_entity = i_self.getEntity();
		var a_items = [];

		if (b_add && ip2.isAccessible("app." + s_dmd + ".data.create") ||
			ip2.isAccessible("app." + s_dmd + ".data." + s_entity + ".´create")) {

			var i_add = Ext.widget("menuitem", {
				text: ip2.i18n({
					da: "Tilføj",
					en: "Add"
				}),
				itemId: "icon-add",
				iconCls: "pf-add",
				handler: function (i_button) {

					var i_newRecord = i_model.create({});
					i_newRecord.set(i_self.getParentID(), i_record.get(i_self.getChildID()));

					var o_data = Ext.clone(o_config);

					Ext.apply(o_data, {
						keys: {},
						context: "form",
						data: i_newRecord.getData()
					});

					Portfolio.app.fireEvent("entityedit", o_data, "create");
				}
			});

			a_items.push(i_add);
		}

		if (!i_record.isRoot()) {
			if (b_edit && (ip2.isAccessible("app." + s_dmd + ".data.update") ||
				ip2.isAccessible("app." + s_dmd + ".data.read") ||
				ip2.isAccessible("app." + s_dmd + ".data." + s_entity + ".update") ||
				ip2.isAccessible("app." + s_dmd + ".data." + s_entity + ".read"))) {

				var i_edit = Ext.widget("menuitem", {
					text: ip2.i18n({
						da: "Rediger",
						en: "Edit"
					}),
					itemId: "item-edit",
					iconCls: "pf-edit",
					handler: function (i_button) {

						var i_window = i_self.up("window");

						var o_clone = Ext.clone(o_config);

						var s_action = "update";

						var o_keys = {};

						if (i_record) {
							o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);
						}
			
						Ext.apply(o_clone, {
							keys: o_keys
						});

						if (i_self.fireEvent("before" + s_action, i_self, o_clone)) {

							if (i_window) {
								Portfolio.app.fireEvent("entityWindow", o_clone, s_action, null, i_window.zIndexManager.id);
							}
							else {
								var i_form = i_self.up("entityform");

								if (i_form) {
									Portfolio.app.fireEvent("entityWindow", o_clone, s_action);
								}
								else {
									Portfolio.app.fireEvent("entityedit", o_clone, s_action);
								}
							}
						}
					}
				});

				a_items.push(i_edit);
			}

			if (b_delete && ip2.isAccessible("app." + s_dmd + ".data.delete") ||
				ip2.isAccessible("app." + s_dmd + ".data." + s_entity + ".delete")) {

				var i_delete = Ext.widget("menuitem", {
					text: ip2.i18n({
						da: "Slet",
						en: "Delete"
					}),
					itemId: "itmDelete",
					iconCls: "pf-delete",
					handler: function () {

						i_self.deleteRecord(i_record, function() {

							var i_selected = i_self.getSelection()[0];

							var i_parent = i_selected.isRoot() ? i_selected : i_selected.parentNode;
							i_parent.collapse();
							i_parent.removeAll(false);

							i_store.read({
								node: i_parent,
								callback: function(i_store) {
									i_parent.expand();
								}
							});
						});
					}
				});
				a_items.push(i_delete);
			}
		}

		var i_refresh = Ext.widget("menuitem", {
			iconCls: "pf-refresh",
			text: ip2.i18n({
				da: "Opfrisk",
				en: "Refresh"
			}),
			handler: function() {

				var i_selected = i_self.getSelection()[0];

				i_selected.collapse();
				i_selected.removeAll(false);

				i_store.read({
					node: i_selected,
					callback: function(i_store) {
						i_selected.expand();
					}
				});
			}
		});

		a_items.push(i_refresh);

		return a_items;
	},

	createModel: function() {

		var i_self = this;
		var i_model = i_self.getModel();
		if (!i_model) {
			var o_config = Ext.apply({}, {
				dmd: i_self.getDmd(),
				entityName: i_self.getEntity(),
				uiName: i_self.getViewName(),
				context: i_self.getContext()
			});

			var s_dmdname = i_self.getDmd().split("/").pop().split(".").shift();

			i_model = ip2.model(o_config, null, true);

			i_self.setModel(i_model);
			i_self.setDmdName(s_dmdname);
		}

		return i_model;
	},

	createStore: function() {

		var i_self = this;

		var i_model = i_self.createModel();

		var i_root = i_self.root;

		var o_root = i_root || Ext.apply({}, {
			allowDrop: false,
			allowDrag: false,
			loaded: false
		});

		if (!i_root) {
			o_root[i_model.idProperty] = 0;

			o_root[i_self.getTextProperty()] = ip2.i18n({
				da: "...",
				en: "..."
			});
		}

		var i_store = Ext.create("Portfolio.entity.store.Tree", {
			model: i_model,
			dmd: i_self.getDmd(),
			entity: i_self.getEntity(),
			view: i_self.getViewName(),
			parentID: i_self.getParentID(),
			childID: i_self.getChildID(),
			root: o_root,
			idProperty: i_model.idProperty,
			remoteFilter: true,
			remoteSort: true,
			autoLoad: i_self.getAutoLoad(),
			sequence: i_self.getSequence(),
			listeners: {
				load: {
					fn: function(i_store, a_records) {

						if (i_self.getShowBreadcrumb()) {
							var i_toolbar = i_self.getBreadcrumbBar();
							if (i_toolbar) {
								var i_selectionModel = i_self.getSelectionModel();
								var a_selection = i_selectionModel.getSelection();
								if (a_selection.length > 0) {
									var i_selected = a_selection[0];
									i_toolbar._needsSync = true;
									i_toolbar.updateSelection(i_selected);
									i_toolbar._needsSync = false;
								}
							}
						}
					}
				}
			}
		});

		return i_store;
	},

	createColumns: function() {

		var i_self = this;
		var o_dmd = ip2.resource.get(i_self.getDmd());
		var o_model = o_dmd.model;
		var s_entity = i_self.getEntity();
		var s_view = i_self.getViewName();
		var a_viewColumns = [];
		var a_entityColumns = [];
		var a_result = [];

		var o_entity = Ext.Array.findBy(o_model.entities, function(o_value) {
			return o_value.name == s_entity;
		});

		if (o_entity) {

			Ext.Array.each(o_entity.columns, function(o_value) {
				var o_clone = Ext.clone(o_value);
				a_entityColumns.push(o_clone);
			});

			if (o_entity.ui.grids[s_view]) {

				var o_view = o_entity.ui.grids[s_view];

				var a_temp = Ext.Object.getValues(o_view.columns);

				Ext.Array.each(a_temp, function(o_value) {
					var o_clone = Ext.clone(o_value);
					a_viewColumns.push(o_clone);
				});
			}
		}

		var b_found = false;

		Ext.Array.each(a_viewColumns, function(o_viewColumn) {

			var o_column = Ext.apply({}, Ext.clone(o_viewColumn));

			Ext.Array.each(a_entityColumns, function(o_entityColumn) {
				if (o_column.name == o_entityColumn.name) {
					Ext.apply(o_column, o_entityColumn);
					return false;
				}
			});

			if (!b_found && o_column.isTitle && !o_column.hide) {
				o_column.xtype = "treecolumn";
				b_found = true;
			}

			Ext.applyIf(o_column, {
				dataIndex: o_column.name,
				text: ip2.i18n(o_column.title) || o_column.name,
				flex: o_column.flex || 1,
				draggable: true,
				liveDrag: true
			});

			if (!o_column.hide) {
				a_result.push(o_column);
			}
		});

		if (!b_found && o_entity) {

			Ext.Array.each(a_result, function(o_value) {

				if (o_value.dataIndex == o_entity.idColumn) {
					o_value.xtype = "treecolumn";
				}
			});
		}

		return a_result;
	},

	getModelConfig: function() {

		var i_self = this;

		return {
			dmd: i_self.getDmd(),
			entityName: i_self.getEntity(),
			context: i_self.getContext(),
			uiName: i_self.getViewName()
		};
	},

	createActionBar: function() {

		var i_self = this;
		var i_store = i_self.getStore();
		var i_model = i_self.createModel();

		var i_toolbar = Ext.widget("entitytoolbar", {
			model: i_model,
			dmdInfo: i_self.getModelConfig(),
			store: i_store,
			grid: i_self,
			itemId: "maintoolbar",
			dock: "top",
			allowNew: false,
			hasExport: false,
			allowLink: i_self.getAllowLink(),
			allowSearch: i_self.getAllowSearch(),
			allowExport: i_self.getAllowExport(),
			allowFilter: i_self.getAllowFilter(),
			addMode: "form",
			searchCombo: i_self.getSearchCombo(),
			entityInfo: i_self.getEntityInfo(),
		});

		i_self.setActionBar(i_toolbar);
		return i_toolbar;
	},

	createFilterBar: function() {

		var i_self = this;
		var i_model = i_self.getModel();
		var s_dmd = i_self.getDmdName();
		var s_entity = i_self.getEntity();

		var b_allowMenu = (
			ip2.isAccessible("app." + s_dmd + ".functions.filter") ||
			ip2.isAccessible("app." + s_dmd + ".functions." + s_entity + ".filter.use")
		);

		var i_filterbar = Ext.widget("filterbar", {
			dock: "top",
			grid: i_self,
			allowMenu: false,
			defaultFilter: i_self.defaultFilter || "",
			hidden: true
		});

		i_self.setFilterBar(i_filterbar);

		return i_filterbar;
	},

	createBreadCrumbBar: function() {

		var i_self = this;
		var i_store = i_self.getStore();

		var i_toolbar = Ext.widget("breadcrumb", {
			dock: "top",
			store: i_store,
			showIcons: false,
			showMenuIcons: true,
			selection: i_store.getRoot(),
			displayField: i_self.getDisplayField(),
			listeners: {
				selectionchange: {
					fn: function(i_toolbar, i_selected) {
						i_self.setSelection(i_selected);
					}
				}
			}
		});

		i_self.setBreadcrumbBar(i_toolbar);

		return i_toolbar;
	},

	getDisplayField: function () {

		var i_self = this;
		var i_model = i_self.getModel();
		var a_columns = i_model.getFields() || i_self.columns;
		var s_field = "";

		Ext.Array.each(a_columns, function(o_column) {
			if (o_column.isTitle) {
				s_field = o_column.name;
				return false;
			}
		});

		return s_field;
	},

	deleteRecord: function (i_record, f_callback) {

		var i_self = this;

		var i_model = i_self.getModel();

		var s_question = ip2.i18n({
			da: "Ønsker du virkelig at slette?",
			en: "Do you really wish to delete?"
		});

		Ext.MessageBox.show({
			title: ip2.i18n({
				da: "Bekræft sletning",
				en: "Confirm deleting"
			}),
			msg: s_question,
			buttons: Ext.MessageBox.OKCANCEL,
			fn: function (btn) {

				if (btn == "ok") {

					var a_batch = [];
					var o_keys = {};

					o_keys[i_model.idProperty] = i_record.get(i_model.idProperty);

					a_batch.push({
						type: "delete",
						dmd: i_self.getDmd(),
						entity: i_self.getEntity(),
						key: o_keys
					});

					var s_message = ip2.i18n({
						da: "Sletter...",
						en: "Deleting..."
					});

					i_self.setLoading(s_message, true);

					Ext.Ajax.request({
						url: "/ip2-Services/ip2dmdproxy.aspx",
						jsonData: {
							transaction: {
								batch: a_batch
							}
						},
						success: function (o_response) {

							i_self.setLoading(false);
							if (Ext.isFunction(f_callback)) {
								f_callback();
							}
						}
					});
				}
			}, icon: Ext.MessageBox.WARNING
		});
	},

	createViewConfig: function() {

		var i_self = this;

		var o_config = Ext.apply({}, {
			plugins: {
				ptype: "treeviewdragdrop",
				dropGroup: "entitytree",
				dragGroup: "entitytree",
				appendOnly: false,
				dropZone: {
					isValidDropPoint: function(i_node, s_position, i_dragZone, i_event, o_data) {

						var i_dropzone = this;
						var i_view = i_dropzone.view;
						var i_overRecord = i_view.getRecord(i_node);

						return s_position !== "append";
					}
				}
			},
			listeners: {
				beforedrop: {
					fn: function(i_node, o_data, i_overModel, s_dropPosition, i_dropHandler, e) {

						var i_store = i_self.getStore();
						var i_record = o_data.records[0];
						var s_sequnce = i_store.getSequence();

						var i_before = i_overModel.previousSibling;
						var i_after = i_overModel.nextSibling;

						var n_over = i_overModel.get(s_sequnce);
						var n_extra = 0;
						var n_sequnce;

						if (s_dropPosition === "before") {
							if (i_before) {
								n_extra = i_before.get(s_sequnce);
							}

							n_sequnce = ((n_extra + n_over) / 2);
						}
						if (s_dropPosition === "after") {
							if (i_after) {
								n_extra = i_after.get(s_sequnce);
							}
							else {
								n_extra = n_over + 1;
							}
							n_sequnce = ((n_over + n_extra) / 2);
						}

						i_record.set(s_sequnce, n_sequnce);
					}
				},
				drop: {
					fn: function(i_node, o_data, i_overModel, s_dropPosition, eOpts) {

						var i_record = o_data.records[0];
						i_self.upsertRecord(i_record);
					}
				}
			}
		});

		return o_config;
	},

	upsertRecord: function(i_record) {

		var i_self = this;
		var o_keys = {};

		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		var a_batch = [{
			type: "upsert",
			dmd: i_self.getDmd(),
			entity: i_self.getEntity(),
			key: o_keys,
			row: i_record.getData()
		}];

		Ext.Ajax.request({
			url: "/ip2-Services/ip2dmdproxy.aspx",
			jsonData: {
				batch: a_batch
			},
			success: function (o_response) {}
		});
	},

	getEntityInfo: function() {

		var i_self = this;
		var o_entityInfo = i_self.entityInfo;

		if (!o_entityInfo) {

			var o_config = Portfolio.util.Handler.dmd.getInfo({
				dmd: i_self.getDmd(),
				entity: i_self.getEntity(),
				context: "grid",
				view: i_self.getViewName()
			});
			i_self.entityInfo = o_entityInfo = o_config;
		}

		return o_entityInfo;
	}
});
Ext.define("Portfolio.entity.view.Panel", {

	xtype: "portfolio-entity-panel",

	extend: "Ext.panel.Panel",

	alias: [
		"widget.entity.panel",
		"widget.ip2pagingGrid"
	],

	alternateClassName: [
		"Ext.ux.entity.Grid"
	],

	layout: {
		type: "hbox",
		align: "stretch"
	},

	config: {
		previewPanel: null,
		grid: null,
		previewConfig: {},
		uiName: "portfolio",
		dmdInfo: null,
		extraParams: {}
	},

	requires: [
		"Portfolio.entity.view.Grid",
		"Portfolio.entity.view.Preview"
	],

	initComponent: function () {

		Ext.tip.QuickTipManager.init();

		var i_self = this;
		i_self.callParent(arguments);

		var o_initial = Ext.apply({}, i_self.initialConfig);

		var o_dmdInfo = Portfolio.util.Handler.dmd.getInfo({
			dmd: o_initial.dmd.path,
			entity: o_initial.dmd.entityName,
			view: o_initial.dmd.uiName || i_self.uiName,
			context: "grid"
		});

		i_self.setDmdInfo(Ext.apply({}, o_dmdInfo));

		if (i_self.getExtraParams()) {
			o_dmdInfo.extraParams = i_self.getExtraParams();
		}

		i_self.createlayout();
	},

	createlayout: function () {

		var i_self = this;
		var o_dmdInfo = i_self.getDmdInfo();
		var o_view = o_dmdInfo.view;
		var o_features = o_view.features;
		var o_entity = o_dmdInfo.entity;
		var i_grid = i_self.createGrid();

		var a_items = [
			i_grid
		];

		if (o_features) {

			var o_preview = o_features.preview;

			if (o_preview) {

				var o_toolbarConfig = o_preview.toolbar;
				var i_toolbar = i_grid.getToolbar();
				var s_dmd = i_grid.dmdName;
				var i_preivewButton;

				if (Portfolio.util.Handler.isAccessible("app." + s_dmd + ".functions.preview") ||
					Portfolio.util.Handler.isAccessible("app." + s_dmd + ".functions." + o_entity.name + ".preview")) {

					var a_requires = Ext.Array.from(o_preview.requires);

					if (a_requires.length > 0) {
						Ext.syncRequire(a_requires);
					}

					var s_xtype = o_preview.xtype || "panel";

					var i_previewPanel = Ext.widget(s_xtype, {
						layout: "fit",
						split: true,
						flex: 1,
						hidden: !o_preview.active
					});

					i_self.setPreviewPanel(i_previewPanel);

					if (o_toolbarConfig) {
						var i_previewBar = i_self.createActionBar(o_toolbarConfig.sizes);
						i_previewPanel.addDocked(i_previewBar);
					}

					i_grid.on({
						select: {
							fn: function(i_store, i_record) {

								var i_previewPanel = i_self.getPreviewPanel();

								var a_events = Ext.Array.from(o_preview.events);

								if (a_events.length > 0) {

									Ext.Array.each(a_events, function(s_event) {
										i_previewPanel.fireEvent(s_event, i_previewPanel, i_record);
									});
								}
								else {

									Ext.Ajax.request({
										url: "/ip2-services/ip2transaction.aspx",
										method: "POST",
										jsonData:{
											action: "cmsCms.cmsGetCurrentSite"
										},
										success: function(i_response) {

											var o_settings = Ext.decode(i_response.responseText, true);

											if (o_settings) {

												var o_system = o_settings.system || o_settings;

												var o_config = Ext.Object.mergeIf({}, o_preview, {
													record: i_record,
													http_host: o_system.host,
													layout: "fit",
													multilanguage: false,
													url: o_preview.src || o_preview.url
												});

												i_self.setPreviewConfig(o_config);

												var i_created = Portfolio.util.Handler.callWidget(o_config);

												i_previewPanel.removeAll(true);

												i_previewPanel.add(i_created);
											}
										},
										failure: function() {
											
											Ext.Ajax.request({
												url: "/ip2-services/wshproxy.aspx?action=getsite",
												success: function(i_response) {
		
													var o_settings = Ext.decode(i_response.responseText, true);
		
													if (o_settings) {
		
														var o_config = Ext.Object.mergeIf({}, o_preview, {
															record: i_record,
															http_host: o_settings.http_host,
															layout: "fit",
															multilanguage: o_settings.language_usingmulti,
															url: o_preview.src || o_preview.url
														});
		
														i_self.setPreviewConfig(o_config);
		
														var i_created = Portfolio.util.Handler.callWidget(o_config);
		
														i_previewPanel.removeAll(true);
		
														i_previewPanel.add(i_created);
													}
												},
												failure: function() {
													
												}
											});
										}
									});
								}
							},
							buffer: 250
						}
					});


					if (i_toolbar) {

						i_toolbar.on({
							afterfunctions: {
								fn: function(i_toolbar, i_buttonFunctions) {
									var i_menu = i_buttonFunctions.menu;

									i_preivewButton = i_self.createPreviewButton(o_preview.active, i_menu);

									if (i_menu) {
										i_menu.add(i_preivewButton);
									}
									else {
										i_toolbar.add(i_preivewButton);
									}

								}
							}
						});
					}

					a_items.push(i_previewPanel);
				}
			}
		}

		i_self.setGrid(i_grid);
		i_self.add(a_items);
	},

	createActionBar: function (o_sizes) {

		var i_self = this;

		var i_toolbar = Ext.widget("toolbar", {
			docked: "top",
			items: i_self.createActions(o_sizes)
		});

		return i_toolbar;
	},

	createActions: function(o_config) {

		var i_self = this;
		var a_buttons = [];
		var o_sizes = o_config || {};

		if (o_sizes.desktop) {
			a_buttons.push(i_self.createSizeButton("desktop"));
		}
		if (o_sizes.tablet) {
			a_buttons.push(i_self.createSizeButton("tablet"));
		}
		if (o_sizes.mobile) {
			a_buttons.push(i_self.createSizeButton("mobile"));
		}
		return a_buttons;
	},

	createSizeButton: function (type) {

		var i_self = this;
		var o_config;

		switch (type) {
			case "desktop":
				o_config = Ext.apply({}, {
					iconCls: "floating_window",
					text: Portfolio.util.Handler.i18n({
						en: "Desktop",
						da: "Desktop"
					}),
					tooltip: Portfolio.util.Handler.i18n({
						en: "Open in floating window",
						da: "Åben i flydende vindue"
					}),
					handler: function (i_button) {

						var o_config = i_self.getPreviewConfig();

						if (o_config) {

							i_self.createWindow(0, i_button.text, o_config);
						}
					}
				});
				break;
			case "tablet":
				o_config = Ext.apply({}, {
					iconCls: "floating_window",
					text: Portfolio.util.Handler.i18n({
						en: "Tablet",
						da: "Tablet"
					}),
					tooltip: Portfolio.util.Handler.i18n({
						en: "Open in floating window",
						da: "Åben i flydende vindue"
					}),
					handler: function (i_button) {

						var o_config = i_self.getPreviewConfig();

						if (o_config) {

							i_self.createWindow(1, i_button.text, o_config);
						}
					}
				});
				break;
			case "mobile":
				o_config = Ext.apply({}, {
					iconCls: "floating_window",
					text: Portfolio.util.Handler.i18n({
						en: "Mobile",
						da: "Mobil"
					}),
					tooltip: Portfolio.util.Handler.i18n({
						en: "Open in floating window",
						da: "Åben i flydende vindue"
					}),
					handler: function (i_button) {

						var o_config = i_self.getPreviewConfig();

						if (o_config) {

							i_self.createWindow(2, i_button.text, o_config);
						}
					}
				});
				break;
		}
		return Ext.widget("themedbutton", o_config);
	},

	createGrid: function () {

		var i_self = this;

		var o_config = Ext.clone(i_self.initialConfig);

		delete o_config.listeners;

		var o_dmdInfo = i_self.getDmdInfo();

		var o_result = Ext.Object.merge({}, o_config, o_dmdInfo, {
			split: true,
			closable: false,
			flex: 1,
			title: ""
		});

		delete o_result.id;

		var i_grid = Ext.widget("portfolio-entity-grid", o_result);

		i_self.setGrid(i_grid);

		return i_grid;
	},

	createWindow: function (s_type, s_title, o_config) {

		var i_window = Ext.widget("portfolio-entity-preview", {
			title: Portfolio.util.Handler.i18n({
				en: "Preview",
				da: "Preview"
			}) + " - " + s_title,
			previewState: s_type
		});

		var o_copyCfg = Ext.clone(o_config);

		var i_created = Portfolio.util.Handler.callWidget(o_copyCfg);

		i_window.add(i_created);

		i_window.show();

		return i_window;
	},

	createPreviewButton: function (b_active) {

		var i_self = this;

		var i_button = Ext.widget("menuitem", {
			iconCls: "pf-eye",
			pressed: b_active || false,
			enableToggle: true,
			text: Portfolio.util.Handler.i18n({
				da: "Preview",
				en: "Preview"
			}),
			ui: "function",
			handler: function(i_button) {

				var i_previewPanel = i_self.getPreviewPanel();

				var b_visible = i_previewPanel.isVisible();

				i_previewPanel[b_visible ? "hide" : "show"]();
			}
		});

		return i_button;
	}
});
Ext.define("Portfolio.entity.plugin.Summary", {

    extend: "Ext.plugin.Abstract",

	alias: [
        "plugin.entity-grid-summary"
    ],

	config: {
        grid: null,
    },
    
    constructor: function(o_config) {

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

	init: function(i_grid) {

		var i_self = this;
        i_self.setGrid(i_grid);
        i_self.addButton();
	},

	addButton: function() {

        var i_self = this;
        var i_grid = i_self.getGrid();
        var i_view = i_grid.getView();
        var i_store = i_grid.getStore();
        var i_model = i_store.getModel();

        var i_feature = i_view.featuresMC.getRange().find(function(i_record){
            return i_record.ftype == "grouping";
        });

        if (i_feature) {

            i_self.createTemplate(i_feature);

            i_grid.on({
                afterrender: {
                    fn: function() {

                        var i_menu = i_grid.headerCt.getMenu();

                        var i_groupingToogleItem = i_menu.getComponent("groupToggleMenuItem");

                        i_groupingToogleItem.on({
                            checkchange: {
                                fn: function(i_item, b_checked) {

                                    var i_summary = i_menu.getComponent("button-summary");

                                    if (i_summary) {
                                        i_summary[b_checked ? "show" : "hide"]();
                                    }
                                }
                            }
                        });

                        i_menu.on({
                            beforeshow: {
                                fn: function(i_menu) {

                                    i_feature = i_view.featuresMC.getRange().find(function(i_record){
                                        return i_record.ftype == "grouping";
                                    });

                                    var i_summary = i_menu.getComponent("button-summary");
                                    var i_activeColumn = i_menu.activeHeader;

                                    var i_field = i_model.getField(i_activeColumn.dataIndex);

                                    var a_items = [];

                                    if (i_summary) {
                                        i_menu.remove(i_summary);
                                    }

                                    if (i_field.type == "number" || i_field.type == "int") {
                                        a_items = [{
                                            xtype: "menucheckitem",
                                            itemId: "sum",
                                            text: ip2.i18n({
                                                da: "Sum",
                                                en: "Sum"
                                            }),
                                            checked: i_activeColumn.sum,
                                            checkHandler: function(i_item, b_checked) {
                                                 var i_column = i_menu.activeHeader;
                                                i_column.sum = b_checked;
                                                i_view.refresh();
                                            }
                                        },
                                        {
                                            xtype: "menucheckitem",
                                            itemId: "min",
                                            text: ip2.i18n({
                                                da: "Minimum",
                                                en: "Minimum"
                                            }) + "<span style=\"margin-left: 2px;\" class=\"pf-sort_down\"></span>",
                                            checked: i_activeColumn.min,
                                            checkHandler: function(i_item, b_checked) {
                                                 var i_column = i_menu.activeHeader;
                                                i_column.min = b_checked;
                                                i_view.refresh();
                                            }
                                        },
                                        {
                                            xtype: "menucheckitem",
                                            itemId: "max",
                                            text: ip2.i18n({
                                                da: "Maximum",
                                                en: "Maximum"
                                            }) + "<span style=\"margin-left: 2px;\" class=\"pf-sort_up\"></span>",
                                            checked: i_activeColumn.max,
                                            checkHandler: function(i_item, b_checked) {
                                                 var i_column = i_menu.activeHeader;
                                                i_column.max = b_checked;
                                                i_view.refresh();
                                            }
                                        },
                                        {
                                            xtype: "menucheckitem",
                                            itemId: "avg",
                                            text: ip2.i18n({
                                                da: "Gennemsnit",
                                                en: "Average"
                                            }) + "<span style=\"margin-left: 2px;\" class=\"pf-sort_up_down\"></span>",
                                            checked: i_activeColumn.avg,
                                            checkHandler: function(i_item, b_checked) {
                                                 var i_column = i_menu.activeHeader;
                                                i_column.avg = b_checked;
                                                i_view.refresh();
                                            }
                                        }].concat(a_items);

                                        i_summary = Ext.widget("menuitem", {
                                            itemId: "button-summary",
                                            text: ip2.i18n({
                                                da: "Summering",
                                                en: "Summary"
                                            }),
                                            iconCls: "pf-sum",
                                            menu: {
                                                items: a_items
                                            }
                                        });
    
                                        var n_index = i_menu.items.indexOf(i_groupingToogleItem);
    
                                        i_menu.add(n_index + 1, i_summary);
                                    }
                                    
                                }
                            }
                        });
                    }
                }
            });            
        }
    },
    
    createTemplate: function(i_feature) {

        var i_self = this;
        var i_grid = i_self.getGrid();

        var i_calctemplate = Ext.create("Ext.XTemplate",
            "<tpl>",
                "<span style=\"margin-left: 5px;\">{value}<span>",
                "<tpl if=\"class\">",
                    "<span style=\"font-size:12px;\"class={class}></span>",
                "</tpl>",
            "</tpl>"
        );

        var i_renderTpl  = Ext.create("Ext.XTemplate",
            "<strong><span>{name}</span></strong>",
            "<span style=\"margin-left: 20px; font-weight:400;\">{extra}<span>",
            "<strong><span style=\"",
                "float:right;",
                "padding-left:10px;",
                "width: 90px;",
                "text-align: center;",
                "\">{count}</span></strong>"
        );

        var i_template = Ext.create("Ext.XTemplate",
            "{[this.getText(values, parent)]}",
            {
                getText: function(o_values, i_parent) {

                    
                    var a_rows = Ext.Array.from(o_values.rows);
                    var i_store = i_grid.getStore();
                    var i_model = i_store.getModel();

                    var i_columnManager = i_grid.getColumnManager();

                    var a_colunns = i_columnManager.getColumns();

                    var a_result = [];

                    Ext.Array.each(a_colunns, function(i_column) {

                        var a_temp = [];
                        var s_dataIndex = i_column.dataIndex;

                        var i_field = i_model.getField(s_dataIndex);

                        var s_format = "000,0";

                        var n_value = i_field ? i_field.dec : 0;

                        if (n_value > 0) {
                            s_format += "." + Ext.util.Format.repeat(n_value, "0", "");
                        }
                        
                        if (i_column.sum) {

                            var n_sum = 0;

                            Ext.Array.each(a_rows, function(i_record) {
                                n_sum += i_record.get(s_dataIndex);
                            });

                            a_temp.push(i_calctemplate.apply({
                                class: "",
                                value: Ext.util.Format.number(n_sum, s_format)
                            }));
                        }

                        if (i_column.min) {

                            var n_min = 9999999999;

                            Ext.Array.each(a_rows, function(i_record) {
                                n_min = Math.min(n_min, i_record.get(s_dataIndex));
                            });

                            a_temp.push(i_calctemplate.apply({
                                class: "pf-sort_down",
                                value: Ext.util.Format.number(n_min, s_format)
                            }));
                        }

                        if (i_column.max) {

                            var n_max = -1;

                            Ext.Array.each(a_rows, function(i_record) {
                                n_max = Math.max(n_max, i_record.get(s_dataIndex));
                            });

                            a_temp.push(i_calctemplate.apply({
                                class: "pf-sort_up",
                                value: Ext.util.Format.number(n_max, s_format)
                            }));
                        }

                        if (i_column.avg) {

                            var n_total = 0;

                            Ext.Array.each(a_rows, function(i_record) {
                                n_total += i_record.get(s_dataIndex);
                            });

                            a_temp.push(i_calctemplate.apply({
                                class: "pf-sort_up_down",
                                value: Ext.util.Format.number(Math.round(n_total / a_rows.length), s_format)
                            }));
                        }

                        a_temp = Ext.Array.filter(a_temp, function(value) {
                            return value;
                        });

                        if (a_temp.length > 0) {
                            a_result.push(
                                i_column.text + " " + a_temp.join(" ") + " "
                            );
                        }
                    });

                    return i_renderTpl.apply({
                        name: o_values.name,
                        extra: a_result.join("&nbsp;/&nbsp;&nbsp;"),
                        count: a_rows.length
                    });
                }
            }
        );

        i_feature.groupHeaderTpl = i_template;
    }
});
/**
 * @class Ext.ux.xpd.Panel
 *
 * @extends Ext.panel.Panel
 *
 * @alias xpdeditorpanel
 */

Ext.define("Ext.ux.xpd.Panel", {

	mixins: {
		DMDUiType: "Portfolio.entity.util.Handler"
	},

	extend: "Ext.form.Panel",

	alias: [
		"widget.xpdeditorpanel",
		"widget.xpdpanel"
	],

	/**
	 * @config
	 */

	dataParent: null,

	xpd: "",

	language: "da",
	languages: null,

	environment: "editor",

	listAs: "fieldset",

	layout: "anchor",

	/**
	 * @properties
	 */

	value: null,

	xpdObject: null,

	xpdCollection: null,

	xpdFields: null,

	trackResetOnLoad: true,

	defaults: {
		anchor: "100%"
	},

	autoScroll: true,

	initComponent: function() {

		var i_self = this;
		var o_config = i_self.initialConfig;

		Ext.apply(i_self, ip2.pick(o_config, [
			"dataParent",
			"xpd",
			"listAs",
			"language",
			"environment",
			"name"
		]));

		Ext.apply(i_self, {
			languages: o_config.languages || ["en"]
		});

		i_self.callParent();

		i_self.initValue();

		i_self.initXpd();

		i_self.initUi();

		return i_self;
	},

	initValue: function () {

		var i_self = this;

		var o_value = {};

		if (i_self.value) {
			o_value = Ext.apply({}, i_self.value);

			Ext.Object.each(o_value, function(s_key, value) {
				if (Ext.isEmpty(value)) {
					delete o_value[s_key];
				}
			});
		}

		i_self.value = o_value;

		return i_self;
	},

	initXpd: function () {

		var i_self = this;
		var s_xpd = i_self.xpd;
		var o_xpd = i_self.xpdObject;
		var o_value = i_self.value;
		var s_id;
		var o_flat;

		if (!o_xpd) {
			o_xpd = ip2.resource.get(s_xpd);
			i_self.xpdObject = o_xpd;
		}

		s_id = o_value[o_xpd.idProperty];

		o_flat = ip2.xpd.flatten(o_xpd, null, true);
		i_self.xpdCollection = o_flat.collections[s_id];

		if (!i_self.xpdCollection) {
			console.warn("Ext.ux.xpd.Panel:initXpd: cannot find collection for cid \"" + s_id + "\" and value " + Ext.encode(o_value));
		}

		return i_self;
	},

	initUi: function () {

		var i_self = this;
		var o_value = i_self.value || {};

		var n_labelWidth = i_self.xpdObject.labelWidth || 170;

		// Create the UI collection from XPD collection
		// These are instanciated objects
		var o_uiCollection = i_self.createUiCollection({
			collection: i_self.xpdCollection,
			xpd: i_self.xpdObject,
			rulesXpd: ip2.uirules.flatten,
			rulesJs: ip2.loadUiTypeRules(),
			context: "form",
			values: o_value,
			environment: i_self.environment,
			defaults: {
				labelWidth: n_labelWidth
			}
		});

		i_self.xpdFields = o_uiCollection;

		Ext.Object.each(o_uiCollection, function (s_key, i_field) {
			if (i_self.record) {
				i_field.record = i_self.record;
			}
			else {
				if (i_self.dataParent) {
					i_field.record = i_self.dataParent.getRecord();
				}
			}
			i_self.mon(i_field, "added", function() {
				// We need to be on nextTick so that our parent can get a time to be attached to its parent
				setTimeout(function() {
					i_field.enableBubble("xpdfieldadded");
					i_field.fireEvent("xpdfieldadded", i_field);
				}, 5);
			});
		});

		// Create the groups needed (if any) for this uiCollection
		// Will omit group if only 1 group needed
		var a_groups = (function () {

			var a_return = [];

			Ext.Object.each(o_uiCollection, function (s_key, o_item) {

				var o_xpdConfig = o_item._xpdConfig;

				if (o_xpdConfig.groups && o_xpdConfig.groups.length) {

					// Add these groups to the groups array if not alreay present
					Ext.Array.each(o_xpdConfig.groups, function (s_group) {

						if (Ext.Array.indexOf(a_return, s_group) == -1) {

							var b_definition = i_self.xpdObject.groups[s_group];
							var b_renderIn = b_definition && b_definition.renderIn[i_self.environment];

							if (b_renderIn) {
								a_return.push(s_group);
							}
						}
					});
				}
			});

			return a_return.length >= 1 ? a_return : [];
		})();

		// If we have groups - Add them and add fields
		// Use "listAs" property to add
		var a_groupComponents;

		if (a_groups.length) {

			switch (i_self.listAs.toLowerCase()) {

				case "accordion":

					a_groupComponents = i_self.createUiGroups(a_groups, {
						xtype: "panel"
					});

					i_self.add({
						xtype: "panel",
						layout: "accordion",
						height: 500,
						layoutConfig: {
							titleCollapse: true,
							animate: true,
							activeOnTop: true
						},
						items: [a_groupComponents]
					});
					break;

				default:

					a_groupComponents = i_self.createUiGroups(a_groups, {
						xtype: "fieldset",
						collapsible: true,
						layout: "anchor",
						defaults: {
							anchor: "100%"
						}
					});

					i_self.add(a_groupComponents);

					break;
			}
		}

		// Create the container map object to hold groups
		// Groups are an array of fields
		var o_container = {
			nogroup: []
		};

		// Run through all group components and create their array
		// in the container object
		if (a_groupComponents) {
			Ext.Array.each(a_groupComponents, function (i_group) {
				o_container[i_group.itemId] = [];
			});
		}

		// Create the container object with group arrays
		Ext.Object.each(o_uiCollection, function (s_key, i_field) {

			var o_config = i_field._xpdConfig;

			// Set nogroup as default group
			var a_containerGroup = o_container.nogroup;

			// Find the right group to put this field in if any
			if (o_config.groups && o_config.groups.length) {
				Ext.Array.some(o_config.groups, function (s_group) {
					if (o_container[s_group]) {
						// We found a group, set it as the one we push to!
						a_containerGroup = o_container[s_group];
						return false;
					}
				});
			}

			a_containerGroup.push(i_field);
		});

		// Sort and place the container array fields
		Ext.Object.each(o_container, function (s_key, a_fields) {

			if (a_fields.length) {

				// Sort the fields, then place them
				a_fields.sort(function(a, b) {
					var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
					var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

					var n_min = Math.min(n_a, n_b);

					return n_min;
				});

				// Now apply to right container
				var i_container = (s_key == "nogroup") ? i_self : i_self.down("fieldset#" + s_key);

				i_container.add(a_fields);

				if (i_container.dependsOn) {

					Ext.Array.each(i_container.dependsOn, function(o_depends) {
						Ext.Object.each(o_uiCollection, function(s_key, i_field) {
							if (s_key == o_depends.field) {

								if (o_depends.equal) {
									o_depends.equals = [o_depends.equal];
								}

								if (o_depends.notEqual) {
									o_depends.notEquals = [o_depends.notEqual];
								}

								var b_allowed = true;

								i_container.mon(i_field, "change", check);
								i_container.mon(i_field, "disable", check);
								i_container.mon(i_field, "enable", check);

								i_container.hide();

								check();

								function check() {

									b_allowed = false;

									if (!i_field.isDisabled || !i_field.isDisabled()) {
										// (Not) Equal
										if ("equals" in o_depends) {
											b_allowed = Ext.Array.some(o_depends.equals, function(equal) {
												return ip2.isEqual(i_field.getValue(), equal);
											});
										}
										else if ("notEquals" in o_depends) {
											b_allowed = Ext.Array.every(o_depends.notEquals, function(notEqual) {
												return !ip2.isEqual(i_field.getValue(), notEqual);
											});
										}

										// (Not) Empty
										if ("empty" in o_depends) {
											b_allowed = !i_field.getValue();
										}
										else if ("notEmpty" in o_depends) {
											b_allowed = i_field.getValue() ? true : false;
										}
									}

									checkChange();
								}

								function checkChange() {

									if (b_allowed) {
										i_container.show();
									}
									else {
										i_container.hide();
									}
								}
							}
						});
					});
				}
			}
		});
	},

	getWidgetComponents: function () {

		var i_self = this;
		var o_fields = i_self.xpdFields;
		var o_widgets = {};

		Ext.Object.each(o_fields, function (s_key, i_field) {
			if (i_field.isWidget) {
				o_widgets[s_key] = i_field;
			}
		});

		return o_widgets;
	},

	createUiGroups: function (a_groups, o_settings) {

		var i_self = this;
		var o_xpd = i_self.xpdObject;
		var a_config = [];

		Ext.Array.each(a_groups, function (s_group) {

			// Get the definition from the XPD
			var o_definition = o_xpd.groups[s_group];
			var o_environment = o_definition.renderIn[i_self.environment] || {};

			// Backwards compatibility with old setup of group environment
			// Looked like so { "renderIn": { "editor": { "layout": { "..": "..." } } } }
			// Is now also supporting { "renderIn": { "editor": { "..": "..." } } }
			// So we are defaulting the whole renderInd object instead of its "layout" object
			// if no "layout" object can be found
			var o_layout = o_environment.layout;

			if (!o_environment.layout) {
				o_layout = o_environment || {};
			}

			var o_config = ip2.extend({
				xtype: "fieldset",
				itemId: s_group,
				title: i_self.translate(o_definition.title),
				layout: "anchor"
			}, o_settings, o_layout);

			var o_group = i_self.createUiGroup(o_config);

			a_config.push(o_group);
		});

		// Sort the groups array based on index position
		a_config.sort(function(a, b) {

			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		return a_config;
	},
	createUiGroup: function (o_settings) {

		var i_self = this;
		var o_uiGroup;

		o_uiGroup = Ext.Object.merge(o_settings, {
			_protected: o_settings["protected"],
			getProtected: function () {

				return this._protected;
			},
			setProtected: function (b_protect) {
				this._protected = b_protect ? true : false;
				this.toggleProtect(this._protected);
				return this;
			},
			toggleProtect: function (b_protect) {

				var i_self = this;

				i_self.items.each(function (i_item) {
					if (i_item._protectionToggler) {
						i_item[b_protect ? "show" : "hide"]();
					}
					else {
						i_item[b_protect ? "hide" : "show"]();
					}
				});
			},
			items: [
				{
					xtype: "container",
					_protectionToggler: true,
					style: "margin:20px;text-align: center;",
					items: [
						{
							xtype: "container",
							style: "margin-bottom: 10px;",
							html: ip2.i18n({
								da: "Disse værdier er beskyttede, tryk på knappen for at kunne redigere",
								en: "These values are protected, please press the button to edit"
							})
						},
						{
							xtype: "button",
							text: ip2.i18n({
								da: "Fjern beskyttelse",
								en: "Remove protection"
							}),
							handler: function (i_self) {

								ip2.messageBox({
									icon: Ext.Msg.WARNING,
									message: ip2.i18n({
										da: "Venligst bemærk at dette kan medføre uønskede ændringer på din hjemmeside",
										en: "Please note that this may have undesired impacts on your website"
									}),
									yesText: ip2.i18n({
										da: "Fjern",
										en: "Remove"
									}),
									yesFn: function () {
										i_self.up(o_settings.xtype).setProtected(false);
									},
									noText: ip2.i18n({
										da: "Fortryd",
										en: "Cancel"
									})
								});
							},
							iconCls: "pf-edit"
						}
					]
				}
			],
			listeners: {
				afterrender: {
					fn: function (i_self) {
						i_self.toggleProtect(this.getProtected());
					},
					single: true
				}
			}
		});

		return o_uiGroup;
	},

	getCheckChangeValue: function () {

		var i_self = this;
		var o_value = i_self.value;

		var a_removeProps = [];

		// Iterate all fields, but do not collection from fields!
		Ext.Object.each(i_self.xpdFields, function (s_key, i_field) {

			if (!i_field.isDisabled) {
				console.warn("This field seems to be missing the method \"isDisabled\" ->", i_field.id, i_field.name);
			}

			if (!i_field.from && (!i_field.isDisabled || !i_field.isDisabled()) && i_field.getValue) {

				var o_json;
				var value = i_field.getValue();

				// We do not want double stringed values!
				try {
					o_json = JSON.parse(value);
				}
				catch (e) {}

				// Prevent: JSON.parse("123.456") === 123.456 // See String -> Num casting
				// Prevent JSON.parse("100.100") === 100.1 // We are losing the last 00
				o_value[s_key] = o_json && !ip2.isNumber(o_json) ? o_json : value;
			}
			else {
				a_removeProps.push(s_key);
			}
		});

		// Find all depricated values and remove them:
		if (i_self.xpdCollection) {
			Ext.Object.each(i_self.xpdCollection.properties, function(s_key, o_property) {
				if (o_property.assimilate) {
					Ext.Object.each(o_property.assimilate, function(s_key, o_config) {
						a_removeProps.push(o_config.field);
					});
				}
			});
		}

		// remove depricated values and dependsOn values that are not visible:
		Ext.Array.each(a_removeProps, function(s_key) {
			if (o_value.hasProperty(s_key)) {
				delete o_value;
			}
		});

		return o_value;
	},

	getValue: function () {

		var i_self = this;
		var o_value = i_self.value;

		var a_removeProps = [];

		// Iterate all fields, but do not collection from fields!
		Ext.Object.each(i_self.xpdFields, function (s_key, i_field) {

			if (!i_field.isDisabled) {
				console.warn("This field seems to be missing the method \"isDisabled\" ->", i_field.id, i_field.name);
			}

			if (!i_field.from && !i_field.isWidget && i_field.getValue) {

				var o_json;
				var value = i_field.getValue();

				// We do not want double stringed values!
				try {
					o_json = JSON.parse(value);
				}
				catch (e) {}

				// Prevent: JSON.parse("123.456") === 123.456 // See String -> Num casting
				// Prevent JSON.parse("100.100") === 100.1 // We are losing the last 00
				o_value[s_key] = o_json && !ip2.isNumber(o_json) ? o_json : value;
			}
			else {
				a_removeProps.push(s_key);
			}
		});

		// Find all depricated values and remove them:
		if (i_self.xpdCollection) {
			Ext.Object.each(i_self.xpdCollection.properties, function(s_key, o_property) {
				if (o_property.assimilate) {
					Ext.Object.each(o_property.assimilate, function(s_key, o_config) {
						a_removeProps.push(o_config.field);
					});
				}
			});
		}

		// remove depricated values and dependsOn values that are not visible:
		Ext.Array.each(a_removeProps, function(s_key) {
			if (s_key in o_value) {
				delete o_value[s_key];
			}
		});

		return o_value;
	},

	setValue: function (o_val) {

		var i_self = this;
		var o_value = ip2.defaults({}, o_val);

		Ext.Object.each(i_self.xpdFields, function (s_key, i_field) {

			if (!i_field._xpdConfig.from) {

				var value = o_value[s_key];

				i_field.setValue(value, s_key, o_value);
			}
		});

		i_self.value = o_val;

		return i_self;
	},

	resetOriginalValue: function () {

		var i_self = this;
		var i_form = i_self.getForm();
		var o_values = i_form.getFieldValues();

		i_form.setValues(o_values);

		return i_self;
	},

	translate: function(s_value) {

		var i_self = this;
		var o_xpd = i_self.xpdObject;
		var s_language = ip2.session.getLanguage();

		return ip2.xpd.translate(o_xpd, s_value, s_language);
	}
});
Ext.define('Ext.ux.xpd.Field', {

	extend: 'Ext.form.FieldContainer',

	alias: [
		'widget.xpdeditorfield',
		'widget.xpdfield'
	],

	mixins: {
		field: 'Ext.form.field.Field'
	},

	requires: [
		"Ext.ux.xpd.Panel"
	],

	/**
	 * @cfg
	 */

	dataParent: null,

	listAs: 'fieldset',

	xpd: '',

	xpdCollection: null,
	idProperty: '',

	name: 'xpdeditorfield',

	language: 'da',
	languages: null,

	environment: 'editor',

	value: '',
	baseValue: '',

	action: 'new',

	xpdComponent: null,

	xpdFields: null,

	layout: 'fit',

	preventMark: true,

	_error: null,

	_initializingValue: true,

	doSaveFields: [],

	initComponent: function() {

		var i_cmp = this;
		i_cmp.doSaveFields = [];
		var o_config = i_cmp.initialConfig;
		var o_xpd = ip2.resource.get(o_config.xpd, true);

		i_cmp.xpdCollection = o_xpd;
		i_cmp.idProperty = i_cmp.xpdCollection.idProperty;

		Ext.apply(i_cmp, {
			languages: o_config.languages || ['en'],
			isFormField: true
		});

		i_cmp.callParent(arguments);

		// Create the xpdpanel or collection picker in case no value was given
		i_cmp.initXpdController();

		i_cmp.initField();

		ip2.each(i_cmp.xpdFields, function(i_field) {
			if (i_field.doSave) {
				i_cmp.doSaveFields.push(i_field);
			}
		});

		return i_cmp;
	},

	initValue: function () {

		var i_cmp = this;
		var s_value = i_cmp.getValue();

		i_cmp.value = s_value;

		i_cmp.mixins.field.initValue.call(i_cmp);

		i_cmp._initializingValue = false;
	},

	initXpdController: function () {

		var i_cmp = this;
		var s_value = i_cmp.value;
		var s_idProperty = i_cmp.xpdCollection.idProperty;
		var o_value;
		var o_baseValue;

		// Value is present - create the XPD component with fields
		if (s_value) {

			o_value = i_cmp.valueToRaw(s_value);
			o_baseValue = {};

			o_baseValue[s_idProperty] = o_value[s_idProperty];
			i_cmp.baseValue = Ext.encode(o_baseValue);

			i_cmp.addXpdComponent(o_value);
		}

		// No value is present - create the picker IF there are more than one collection!
		else {

			var o_collections = i_cmp.xpdCollection.collections;

			var n_collections = 0;

			Ext.Object.each(o_collections, function (s_key, o_collection) {
				n_collections = s_key != 'all' ? n_collections + 1 : n_collections;
			});

			if (n_collections > 1) {
				i_cmp.addXpdPicker();
			}

			else {

				var n_id;
				o_value = {};

				Ext.Object.each(o_collections, function (s_key, o_collection) {
					if (s_key != 'all') {
						n_id = o_collection.id;
					}
				});

				o_value[s_idProperty] = n_id;

				s_value = Ext.encode(o_value);

				i_cmp.value = s_value;
				i_cmp.baseValue = s_value;

				i_cmp.addXpdComponent(o_value);
			}
		}

		return i_cmp;
	},

	getXpdComponent: function () {

		var i_cmp = this;

		return i_cmp.xpdComponent;
	},

	addXpdComponent: function (o_value) {

		var i_cmp = this;
		var i_xpdComponent;

		var i_dataParent = i_cmp.dataParent || null;

		var i_record;

		if (i_dataParent) {
			i_record = i_dataParent.getRecord();
		}
		else {
			i_record = i_cmp.record || i_cmp.parentRecord;
		}

		i_xpdComponent = i_cmp.add({
			xtype: 'xpdeditorpanel',
			border: false,
			value: o_value,
			dataParent: i_cmp.dataParent,
			listAs: i_cmp.listAs,
			xpd: i_cmp.xpd,
			language: i_cmp.language,
			environment: i_cmp.environment,
			record: i_record,
			layout: "anchor",
			autoScroll: true
		});

		Ext.Object.each(i_xpdComponent.xpdFields, function (s_key, i_field) {
			i_field.preventMark = true;
		});

		i_cmp.xpdComponent = i_xpdComponent;
		i_cmp.xpdFields = i_xpdComponent.xpdFields;

		// Route change, dirtychange and validitychange
		ip2.each(i_cmp.xpdFields, function (i_field) {
			i_field.on('change', function () {
				i_cmp.checkChange();
			});
			i_field.on('validitychange', function () {
				i_cmp.checkChange();
			});
		});

		return i_xpdComponent;
	},

	addXpdPicker: function () {

		var i_cmp = this;
		var o_xpd = i_cmp.xpdCollection;
		var o_collections = i_cmp.xpdCollection.collections;
		var s_idProperty = i_cmp.idProperty;

		i_cmp.add({
			xtype: 'container',
			itemId: 'pickercontainer',
			layout: {
				type: 'vbox',
				align: 'center',
				pack: 'center'
			},
			width: '100%',
			height: 140,
			items: [
				{
					xtype: 'fieldset',
					title: ip2.i18n({
						da: 'Vælg type',
						en: 'Choose Type'
					}),
					padding: 20,
					items: [
						{
							xtype: 'quickcombo',
							name: s_idProperty,
							itemId: s_idProperty,
							emptyText: 'Pick a collection',
							forceSelection: true,
							valueField: 'id',
							width: 400,
							margin: '0 0 15 0',
							displayField: 'name',
							fields: ['id', 'name'],
							isFormField: false,
							data: (function () {

								var a_return = [];

								Ext.Object.each(o_collections, function (s_key, o_collection) {
									if (s_key != 'all') {
										a_return.push({
											'id': o_collection.id,
											'name': ip2.xpd.translate(o_xpd, o_collection.title, i_cmp.language)
										});
									}
								});

								return a_return;
							})(),
							listeners: {
								'afterrender': {
									fn: function (i_self) {
										var i_record = i_self.getStore().getAt(0);
										i_self.select(i_record);
									},
									single: true
								}
							}
						},
						{
							xtype: 'container',
							style: 'text-align: right;',
							items: [
								{
									xtype: 'button',
									text: 'OK',
									minWidth: 100,
									handler: function () {

										var i_self = this;
										var i_container = i_self.up('#pickercontainer');
										var i_picker = i_container.down('#' + s_idProperty);
										var n_value = i_picker.getValue();
										var o_value = {};
										var s_value;

										o_value[s_idProperty] = n_value;
										s_value = i_cmp.rawToValue(o_value);

										i_cmp.suspendCheckChange++;

										var i_xpdComponent = i_cmp.addXpdComponent(o_value);
										i_cmp.setValue(s_value);

										if (i_cmp._No_cid_Value) {
											i_cmp._No_cid_Value[s_idProperty] = n_value;
											i_xpdComponent.setValue(i_cmp._No_cid_Value);
											delete i_cmp._No_cid_Value;
										}

										i_cmp.resetOriginalValue();

										i_cmp.suspendCheckChange--;

										i_container.destroy();
									}
								}
							]
						}
					]
				}
			]
		});

		return i_cmp;
	},
	removeXpdPicker: function () {

		var i_cmp = this;
		var i_picker = i_cmp.down('#pickercontainer');

		if (i_picker) {
			i_picker.destroy();
		}

		return i_cmp;
	},

	disable: function () {

		var i_cmp = this;
		var o_fields = i_cmp.xpdFields || {};

		Ext.Object.each(i_cmp.xpdFields, function (s_key, i_field) {
			i_field.disable();
		});

		return i_cmp.callParent(arguments);
	},
	enable: function () {

		var i_cmp = this;
		var o_fields = i_cmp.xpdFields || {};

		Ext.Object.each(i_cmp.xpdFields, function (s_key, i_field) {
			i_field.enable();
		});

		return i_cmp.callParent(arguments);
	},

	focus: function (b_select) {

		var i_cmp = this;
		var o_fields = i_cmp.xpdFields;

		if (!o_fields || o_fields && !Ext.Object.getSize(o_fields)) {
			i_cmp.down('quickcombo').focus(b_select);
		}
		else {

			var n_min;
			var i_first;
			Ext.Object.each(o_fields, function (s_key, i_field) {

				var n_index = i_field.index || i_field.sequence;

				if (!n_min || (n_index < n_min)) {
					if (i_field.isVisible() && !i_field.isHidden() && !i_field.isDisabled() && !i_field.readOnly) {
						i_first = i_field;
						n_min = n_index;
					}
				}
			});

			if (i_first) {
				i_first.focus(b_select);
			}
		}
	},

	errorReport: function (err, s_source) {

		var i_cmp = this;
		var b_diff = (s_source != i_cmp._error);

		if (!i_cmp._error || b_diff) {

			var o_error = {
				urlText: ip2.i18n({
					da: 'Du forsøger at afkode en invalid JSON streng',
					en: 'You are trying to decode an invalid JSON string'
				}),
				url: 'test',
				message: ip2.i18n({
					da: 'Der skete en fejl da JSON validerings programmet fandt en fejl i en tekst streng der skulle parses',
					en: 'An error occured as the JSON validation engine found an error in a string supplied for parsing'
				})
			};

			var s_title = ip2.i18n({
				da: 'JSON validerings fejl',
				en: 'JSON validation error'
			});

			Ext.Error.raise({
				description: s_title,
				message: o_error,
				ignore: true
			});
		}
	},

	valueToRaw: function (s_value) {

		var i_cmp = this;
		var o_value;

		if (s_value) {
			o_value = Ext.decode(s_value);
		}
		else {
			o_value = {};
		}

		return o_value;
	},
	rawToValue: function (o_raw) {

		return Ext.encode(o_raw);
	},
	getRawValue: function () {

		var i_cmp = this;
		var i_xpdComponent = i_cmp.xpdComponent;
		var o_value = {};

		if (i_xpdComponent) {
			o_value = i_xpdComponent.getValue();
		}

		return o_value;
	},
	getValue: function () {

		var i_cmp = this;
		var i_xpdComponent = i_cmp.xpdComponent;
		var s_value = i_cmp.value;

		if (i_xpdComponent) {
			var o_value = i_xpdComponent.getValue();
			s_value = i_cmp.rawToValue(o_value);
		}

		return s_value;
	},
	setValue: function (value) {

		var i_cmp = this;
		var i_xpdComponent = i_cmp.xpdComponent;
		var b_initializing = i_cmp._initializingValue;

		var o_value;
		var s_value = value || i_cmp.baseValue;
		var b_hasId = true;

		if (i_xpdComponent && s_value) {

			o_value = i_cmp.valueToRaw(s_value);

			// Do not bother setting the values on to the
			// XPD component if we are initializing
			if (!b_initializing) {
				i_xpdComponent.setValue(o_value);
			}
		}
		else if (s_value) {
			o_value = i_cmp.valueToRaw(s_value);
			if (o_value[i_cmp.idProperty]) {
				i_xpdComponent = i_cmp.addXpdComponent(o_value);
			}
			else {
				i_cmp._No_cid_Value = o_value;
				b_hasId = false;
			}
		}

		// If we have a value and the picker is still there, remove it!
		if (s_value && b_hasId) {
			i_cmp.removeXpdPicker();
		}

		i_cmp.mixins.field.setValue.call(i_cmp, value);

		return i_cmp;
	},
	resetOriginalValue: function () {

		var i_cmp = this;
		var i_xpdComponent = i_cmp.xpdComponent;
		var s_value = i_cmp.getValue();

		if (i_xpdComponent) {

			var o_value = i_cmp.valueToRaw(s_value);

			i_xpdComponent.setValue(o_value);
			i_xpdComponent.resetOriginalValue();
		}

		i_cmp.mixins.field.resetOriginalValue.call(i_cmp);

		return i_cmp;
	},
	isValid: function () {

		var i_cmp = this;
		var b_valid = true;

		ip2.each(i_cmp.xpdFields, function (i_field) {

			i_field.preventMark = false;

			if (i_field.isValid && !i_field.isValid()) {
				b_valid = false;
			}

			i_field.preventMark = true;
		});

		return b_valid;
	},
	isDirty: function () {

		var i_cmp = this;
		var b_dirty = false;

		// If field is disabled - then no need to check
		if (i_cmp.disabled) {
			return b_dirty;
		}

		// Get the originalvalue as object
		var s_original = i_cmp.originalValue;
		var s_value = i_cmp.getValue();

		if (s_original && s_value) {
			var o_value = JSON.parse(s_value);
			var o_original = JSON.parse(s_original);

			var a_valueKeys = Ext.Object.getKeys(o_value);
			var a_originalKeys = Ext.Object.getKeys(o_original);

			if (a_valueKeys.length > a_originalKeys.length) {
				b_dirty = true;
			}
			else {
				ip2.each(a_originalKeys, function(s_key) {
					var value = o_value[s_key];
					var originalvalue = o_original[s_key];
					if (Ext.isObject(value) && Ext.isObject(originalvalue) || (Ext.isArray && (Ext.isArray(s_value) && Ext.isArray(s_ovalue)))) {
						var s_value = JSON.stringify(value);
						var s_ovalue = JSON.stringify(originalvalue);
						if (!ip2.isEqual(s_value, s_ovalue)) {
							b_dirty = true;
						}
					}
					else {
						if (!ip2.isEqual(value, originalvalue)) {
							b_dirty = true;
						}
					}
				});
			}
		}
		else {
			b_dirty = true;
		}

		return b_dirty;
	},
	clearInvalid: function () {

		var i_cmp = this;
		var o_fields = i_cmp.xpdFields;

		if (o_fields && Ext.Object.getSize(o_fields)) {
			Ext.Object.each(o_fields, function (s_key, i_field) {
				if (i_field.el && i_field.el.dom) {
					i_field.clearInvalid();
				}
				else {
					i_field.on('afterrender', function () {
						i_field.clearInvalid();
					}, i_field, { single: true });
				}
			});
		}

		return i_cmp;
	},
	doSave: function(f_callback) {

		var i_self = this;
		var n_tig = 0;
		var f_check = function() {
			n_tig--;
			if (n_tig == 0) {
				f_callback();
			}
		};

		n_tig = i_self.doSaveFields.length;

		if (n_tig > 0) {
			ip2.each(i_self.doSaveFields, function(i_field) {
				i_field.doSave(function() {
					f_check();
				});
			});
		}
		else {
			f_callback();
		}
	},

	getErrors: function() {

		var i_self = this;
		var a_keys = Ext.Object.getKeys(i_self.xpdFields);
		var a_return = [];
		Ext.Array.each(a_keys, function(s_field) {
			var i_field = i_self.xpdFields[s_field];
			var value = i_field.getRawValue ? i_field.getRawValue() : i_field.getValue();
			if (value === null || value === undefined) {
				value = "";
			}
			var a_errors = i_field.getErrors(value);
			a_return = a_return.concat(a_errors);
		});
		return a_return;
	},

	checkChange: function() {
		var me = this;
		var newVal;
		var oldVal;
		if (!me.suspendCheckChange) {
			newVal = me.getValue();
			oldVal = me.lastValue;
			if (!me.isDestroyed && !ip2.isEqual(newVal, oldVal)) {
				me.lastValue = newVal;
				me.fireEvent('change', me, newVal, oldVal);
				me.onChange(newVal, oldVal);
			}
		}
	}
});
Ext.define("Ext.ux.folderorganizer.XpdEditor", {

	extend: "Ext.window.Window",

	action: "create",

	alias: "widget.xpd.editor.window",

	modal: true,

	collapsible: false,

	layout: {
		type: "fit"
	},

	idColumn: null,
	widgets: null,
	doSaveFields: null,

	config: {
		languageService: ""
	},

	tools: [
		{
			id: "link",
			cls: "pf-link",
			handler: function() {

				var i_tool = this;
				var i_xpdEditor = i_tool.up("window");
				var i_model = i_xpdEditor.record;

				i_model.widget = true;
				i_model.xpd = i_xpdEditor.xpd._name;
				i_model.dmdFile = i_xpdEditor.dmdFile;

				var i_window = Ext.widget("link.window", {
					model: i_model
				});

				i_window.show();
			},
			listeners: {
				afterrender: {
					fn: function(i_tool) {

						var i_image = i_tool.el.down("img");
						if (i_image) {
							i_image.setStyle("width", 0);
							i_image.setStyle("height", 0);
						}
					}
				}
			}
		}
	],

	requires: [
		"Ext.ux.container.Ip2Widget"
	],

	initComponent: function() {

		var i_cmp = this;
		var o_config = i_cmp.initialConfig;
		Ext.apply(i_cmp, {
			title: "",
			idColumn: o_config.idColumn || i_cmp.idColumn,
			action: o_config.action || i_cmp.action,
			constrain: true,
			width: 800,
			height: 600,
			collapsible: false,
			dmdFile: i_cmp.dmdFile || "dmd/webshop.dmd"
		});
		i_cmp.doSaveFields = [];
		i_cmp.widgets = [];

		i_cmp.callParent(arguments);

		var i_form = i_cmp.createFormConfig(i_cmp.action);

		i_cmp.add(i_form);

		i_cmp.preSave = i_cmp.preSave || function(a_modified, f_callback) {
			if (Ext.isFunction(f_callback)) {
				f_callback();
			}
		};

		return i_cmp;
	},

	createFormConfig: function (s_action) {

		var a_items = [];

		s_action = s_action || "update";

		var i_cmp = this;
		var o_config;

		var i_record = i_cmp.record;
		var s_prop = i_cmp.propertyNameMapping.PROPERTIES;

		// Since we do not have a real record when creating, we can not use get()
		var xpdValue = i_record.data[s_prop] || "{}";

		var i_xpdEditor = Ext.create("Ext.ux.xpd.Field", {
			xpd: i_cmp.xpd._name,
			value: xpdValue,
			environment: i_cmp.environment || "folderorganizer",
			action: s_action,
			record: i_cmp.record
		});

		i_cmp.on("xpdfieldadded", function(i_field) {
			if (i_field.doSave) {
				i_cmp.doSaveFields.push(i_field.id);
			}
		});

		var o_xpdValues = JSON.parse(xpdValue);
		var s_title = "";
		var s_lang = ip2.navigator.currentUser.usrlng || "da";

		if (i_cmp.action == "update") {
			o_xpdValues.title = o_xpdValues.title || { da: "", en: "" };
			o_xpdValues.name = o_xpdValues.name || { da: "", en: "" };
			s_title = ip2.i18n(o_xpdValues.title);
			if (!s_title) {
				s_title = ip2.i18n(o_xpdValues.name);
			}
		}
		else {
			var s_value = i_cmp.xpd.flatten.collections[o_xpdValues.__cid__].title;
			s_title = ip2.xpd.translate(i_cmp.xpd, s_value, s_lang);
		}

		i_cmp.title = ip2.i18n(i_cmp.getI18N(i_cmp.action)) + " - " + s_title + ": " + i_record.get(i_record.idProperty);

		i_cmp.xpdEditor = i_xpdEditor;

		var i_content = Ext.widget("panel", {
			itemId: "content",
			title: ip2.i18n({
				da: "Indhold",
				en: "Content"
			}),
			layout: "fit",
			bodyPadding: 15,
			items: [i_xpdEditor]
		});

		a_items.push(i_content);

		var i_tabpanel = Ext.widget("tabpanel", {
			layout: "fit",
			defaults: {
				iconAlign: "right",
			},
			items: a_items,
			border: false
		});

		var i_form = Ext.widget("form", {
			layout: "fit",
			itemId: "contentForm",
			items: [i_tabpanel],
			trackResetOnLoad: true,
			buttons: [
				{
					xtype: "button",
					text: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					}),
					itemId: "close",
					handler: function () {
						i_cmp.close();
					}
				},
				{
					xtype: "button",
					text: ip2.i18n({
						da: "Gem",
						en: "Save"
					}),
					hidden: true,
					itemId: "save",
					ui: "primary-button",
					handler: function() {
						var msg = ip2.i18n({
							da: "Gemmer",
							en: "Saving"
						});
						i_cmp.setLoading(msg);
						i_cmp._doSave(function() {
							var a_dirty = [];
							ip2.each(i_cmp.xpdEditor.xpdComponent.xpdFields, function(i_field) {
								if (i_field.isDirty()) {
									a_dirty.push({
										name: i_field.name,
										value: i_field.value
									});
								}
							});
							i_cmp.preSave(a_dirty, function() {
								i_cmp.doSave(i_cmp.record, i_cmp.node, i_cmp.xpdEditor.getValue(), function(i_record, o_error) {
									if (i_record) {
										i_cmp.doLanguageService(i_cmp.record, function() {
											i_cmp.form.loadRecord(i_record);
											i_cmp._doSaveWidgets(function() {
												i_cmp.setLoading(false);
												i_cmp.close();
											});
										});
									}
									else {

										var s_msg = o_error.message;

										i_cmp.setLoading(false);

										ip2.messageBox({
											icon: Ext.MessageBox.ERROR,
											title: ip2.i18n({
												da: "Fejl",
												en: "Error"
											}),
											closable: true,
											message: ip2.i18n({
												da: "Der skete en fejl under processen: <strong>" + s_msg + "</strong>",
												en: "An error occurred durring the process: <strong>" + s_msg + "</strong>"
											}),
											yesText: ip2.i18n({
												da: "Ok",
												en: "OK"
											})
										});
									}
								});
							});
						});
					}
				}
			],
			listeners: {
				dirtychange: {
					fn: function(i_form, b_dirty) {

						var i_save = i_cmp.down("#save");
						var i_content = i_cmp.down("#content");
						var i_contentForm = i_cmp.down("#contentForm");

						var b_valid = i_form.isValid();

						if (b_valid) {
							b_dirty = i_contentForm.isDirty();

							i_save[b_dirty ? "show" : "hide"]();

							i_content.setIconCls(b_dirty ? "flatui icon-data-new" : "");
						}
					}
				},
				validitychange: {
					fn: function(i_form, b_valid) {

						var i_save = i_cmp.down("#save");
						var i_content = i_cmp.down("#content");
						var i_contentForm = i_cmp.down("#contentForm");

						if (!b_valid) {

							i_content.setIconCls("flatui icon-data-error");

							i_save[b_valid ? "hide" : "show"]();
						}
						else {
							var b_dirty = i_contentForm.isDirty();
							i_contentForm.fireEvent("dirtychange", i_contentForm, b_dirty);
						}
					}
				},
				afterrender: {
					fn: function (i_self) {

						var i_xpd = i_cmp.xpdEditor;

						i_xpd.resetOriginalValue();
					}
				}
			}
		});

		i_form.loadRecord(i_record);
		i_form.entity = i_cmp.entity || "";

		if (o_xpdValues.__cid__) {
			var o_collections = i_cmp.xpd.flatten.collections[o_xpdValues.__cid__];
			if (o_collections.widgets && Ext.isArray(o_collections.widgets)) {
				Ext.Array.each(o_collections.widgets, function(o_widget) {
					Ext.apply(o_widget, {
						widgetConfig: o_widget,
						_config: o_widget,
						title: ip2.i18n(o_widget.title),
						src: o_widget.path,
						border: false,
						dataParent: i_form,
						itemId: "widget_" + ip2.unique(),
						layout: "fit",
						index: o_widget.index || 0
					});
					var i_widget = Ext.widget("ip2widget", o_widget);
					if (i_widget.doSave) {
						i_cmp.widgets.push(i_widget.id);
					}
					i_tabpanel.add(i_widget);
				});
			}
		}
		i_cmp.form = i_form;

		return i_form;
	},

	getI18N: function(key) {
		return (ip2.folderorganizer) ? ip2.folderorganizer.getTextValue(key) : key;
	},

	doLanguageService: function(i_record, f_callback) {

		var i_self = this;
		if (i_self.getLanguageService()) {
			Ext.Ajax.request({
				url: i_self.getLanguageService(),
				jsonData: i_record.data,
				success: function(o_response) {

					var o_result = Ext.decode(o_response.responseText, true) || {
						success: false,
						message: "Could not parse response"
					};
					if (!o_result.success) {
						Ext.Error.handle({
							restart: false,
							message: {
								message: o_result.message
							},
							debug: "error",
							description: i_self.title +
							ip2.i18n({
								da: " fejl",
								en: " errror"
							})
						});
					}
					if (Ext.isFunction(f_callback)) {
						f_callback();
					}
				},
				failure: function(o_err) {

					var o_request = o_err.request;

					var s_message = [o_request.options.url, o_err.statusText]. join(": ");

					Ext.Error.handle({
						restart: false,
						message: {
							message: s_message
						},
						debug: "error",
						description: i_self.title +
						ip2.i18n({
							da: " fejl",
							en: " errror"
						})
					});
					if (Ext.isFunction(f_callback)) {
						f_callback();
					}
				}
			});
		}
		else {
			if (Ext.isFunction(f_callback)) {
				f_callback();
			}
		}
	},

	_doSave: function(f_callback) {

		var i_self = this;
		var n_ticker = 0;
		var a_fields = i_self.doSaveFields;

		if (a_fields.length > 0) {
			ip2.each(a_fields, function(s_field) {
				var i_field = Ext.getCmp(s_field);
				if (i_field) {
					n_ticker++;
					i_field.doSave(function() {
						n_ticker--;
						if (n_ticker == 0) {
							f_callback();
						}
					});
				}
			});
		}
		else {
			f_callback();
		}
	},
	_doSaveWidgets: function(f_callback) {

		var i_self = this;
		var n_ticker = 0;
		var a_widgets = i_self.widgets || [];

		if (a_widgets.length > 0) {
			Ext.Array.each(a_widgets, function(s_id) {
				var i_widget = Ext.getCmp(s_id);
				if (i_widget) {
					n_ticker++;
					i_widget.doSave(function() {
						n_ticker--;
						if (n_ticker == 0) {
							f_callback();
						}
					});
				}
			});
		}
		f_callback();
	}
});
Ext.define("Ext.ux.form.field.TreePicker", {

	extend: "Ext.form.field.Picker",

	alias: [
		"widget.ux.form.field.treepicker",
		"widget.treepicker"
	],

	alternateClassName: [
		"Ext.ux.form.TreePicker"
	],

	config: {
		columns: null,
		url: "",
		store: null,
		listConfig: {},
		displayField: "value",
		valueField: "key",
		lastLoaded: null,
		multiSelect: false
	},

	editable: false,

	triggers: {
		clear: {
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			weight: 1,
			handler: "onClearClick",
			hidden: true,
			scope: "this"
		},
		picker: {
			weight: 3,
			handler: "onTriggerClick",
			scope: "this"
		}
	},

	listeners: {
		afterrender: {
			fn: function(i_field) {

				var i_self = this;
				var i_clearTrigger = i_self.getTrigger("clear");

				if (i_clearTrigger) {
					var value = i_self.getValue();

					var b_show = !Ext.isEmpty(value);

					i_clearTrigger[b_show ? "show" : "hide"]();
				}
			}
		},
		change: {
			fn: function(i_field, value) {

				var i_self = this;
				var i_clearTrigger = i_self.getTrigger("clear");

				if (i_clearTrigger) {

					var b_show = !Ext.isEmpty(value);

					i_clearTrigger[b_show ? "show" : "hide"]();
				}
			}
		}
	},

	initComponent: function() {

		var i_self = this;

		i_self.createStore();

		i_self.callParent(arguments);
	},

	createStore: function() {

		var i_self = this;

		var o_root = {
			expanded: true
		};

		o_root[i_self.getValueField()] = "00000000000000";

		var i_store = Ext.create("Ext.data.TreeStore", {
			proxy: {
				type: "ajax",
				url: i_self.getUrl(),
				paramsAsJson: true,
				reader: {
					type: "json",
					rootProperty: "rows",
					totalProperty: "totalRows"
				},
				actionMethods: {
					read: "POST"
				}
			},
			root: o_root
		});

		i_self.setStore(i_store);
	},

	createPicker: function() {

		var i_self = this;

		var i_picker;

		var o_listConfig = i_self.getListConfig() || {};

		var a_columns = i_self.getColumns() || [
			{
				xtype: "treecolumn",
				dataIndex: i_self.getDisplayField(),
				flex: 1,
				menuDisabled: true,
				listeners: {
					afterrender: {
						fn: function(i_column) {

							i_column.setHeight(0);
						}
					}
				}
			}
		];

		Ext.apply(o_listConfig, {
			columns: a_columns,
			useArrows: true,
			rootVisible: false,
			maxHeight: 300,
			height: 300
		});

		var o_options = Ext.Object.merge({
			selModel: {
				mode: i_self.getMultiSelect() ? "MULTI" : "SINGLE"
			},
			floating: true,
			hidden: true,
			header: false,
			ownerCt: i_self,
			store: i_self.getStore(),
			listeners: {
				itemclick: {
					fn: function(i_tree, i_record) {

						i_tree.fireEvent("select", i_tree, i_record);

						var a_selection = i_tree.getSelection();

						i_self.setValue(a_selection);

						if (!i_self.getMultiSelect()) {
							i_self.collapse();
						}
					}
				},
				select: {
					fn: function(i_tree, i_record) {

						var a_selection = i_tree.getSelection();

						Ext.Array.each(a_selection, function(i_record) {

							var i_temp = i_record;

							var s_value = "";

							var a_values = [];

							while (i_temp && !i_temp.isRoot()) {

								var value = i_temp.get(i_self.getValueField());

								i_temp = i_temp.parentNode;

								a_values.push(value);
							}

							a_values.reverse();

							i_record.set(i_self.getDisplayField(), a_values.join(" - "));
						});
					}
				},
				deselect: {
					fn: function(i_tree, i_record) {
						i_record.set(i_self.getDisplayField(), "");
					}
				},
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();

						var i_node = i_operation.node;

						var n_node = i_node.get(i_self.getValueField()) || "00000000000000";

						Ext.apply(o_extraParams, {
							parent: n_node
						});

						i_self.setLastLoaded(i_node);
					}
				},
				load: {
					fn: function(i_store, a_records) {

						var i_tree = i_store.ownerTree;
						var i_loaded = i_self.getLastLoaded();

						Ext.Array.each(a_records, function(i_record) {
							if (!i_record.get("expandable")) {
								i_record.set("leaf", true);
								i_record.commit();
							}
						});

						if (i_loaded) {
							i_tree.ensureVisible(i_loaded);
						}
					}
				}

			}
		}, i_self.listConfig);

		i_picker = i_self.picker = Ext.widget("treepanel", o_options);

		var i_navigationModel = i_picker.getNavigationModel();

		var o_bindings = Ext.apply({}, {
			enter: {
				scope: i_self,
				fn: function(n_key, i_event) {

					var i_picker = i_self.getPicker();

					var a_selection = i_picker.getSelection();

					i_self.setValue(a_selection);

					i_self.collapse();
				}
			},
			esc: {
				scope: i_self,
				fn: function(n_key, i_event) {

					i_self.collapse();
				}
			}
		});

		i_navigationModel.keyNav.addBindings(o_bindings);

		if (!i_picker.initialConfig.maxHeight) {
			i_picker.on({
				beforeshow: i_self.onBeforePickerShow,
				scope: i_self
			});
		}

		return i_picker;
	},

	setValue: function(value) {

		var i_self = this;

		var i_picker = i_self.getPicker();

		var i_store = i_picker.getStore();

		var a_value = Ext.Array.from(value);

		var s_rawValue = "";

		var a_display = [];

		Ext.Array.each(a_value, function(value) {

			if (value) {
				if (value.isModel) {
					s_rawValue = value.get(i_self.getDisplayField());
				}
				else {
					var i_record = null;

					i_record = i_store.findRecord(i_self.getDisplayField(), value);

					if (!i_record) {
						i_record = i_store.findRecord(i_self.getValueField(), value);
					}

					if (i_record) {
						s_rawValue = i_record.get(i_self.getDisplayField());
						i_picker.getSelectionModel().select(i_record, false, true);
					}
				}

				a_display.push(s_rawValue);
			}
		});

		i_self.setRawValue(a_display.join(", "));

		i_self.fireEvent("change", i_self, i_self.getValue());
	},

	getValue: function() {

		var i_self = this;
		var i_picker = i_self.getPicker();

		var a_selection = i_picker.getSelection();

		var i_selected = a_selection[0];

		var a_value = [];

		Ext.Array.each(a_selection, function(i_record) {
			a_value.push(i_record.get(i_self.getValueField()));
		});

		if (a_value.length === 0) {
			var s_rawValue = i_self.getRawValue();
			a_value = s_rawValue.split(",");
		}

		return a_value.filter(function(value) {
			return !Ext.isEmpty(value);
		});
	},

	getSubmitValue: function() {

		var i_self = this;
		var i_picker = i_self.getPicker();

		var a_selection = i_picker.getSelection();

		var i_selected = a_selection[0];

		var a_value = [];

		Ext.Array.each(a_selection, function(i_record) {
			a_value.push(i_record.get(i_self.getValueField()));
		});

		if (a_value.length === 0) {
			var s_rawValue = i_self.getRawValue();
			a_value = s_rawValue.split(",");
		}

		return a_value;
	},

	setRawValue: function(rawValue) {
		this.callParent([rawValue]);
	},

	onBeforePickerShow: function(picker) {

		var me = this;
		var heightAbove = me.getPosition()[1] - Ext.getBody().getScroll().top;
		var heightBelow = Ext.Element.getViewportHeight() - heightAbove - me.getHeight();

		picker.maxHeight = Math.max(heightAbove, heightBelow) - 5;
	},

	onClearClick: function() {

		var i_self = this;

		var i_tree = i_self.getPicker();

		i_tree.getSelectionModel().deselectAll();

		i_self.setValue([]);
	}
});
Ext.define("Ext.form.field.Month", {

	extend: "Ext.form.field.Date",

	alias: "widget.monthfield",

	requires: [
		"Ext.picker.Month"
	],

	alternateClassName: [
		"Ext.form.MonthField",
		"Ext.form.Month"
	],

	config: {
		selectedMonth: null
	},

	createPicker: function() {

		var i_self = this;
		var f_format = Ext.String.format;

		var i_body = Ext.getBody();

		var i_picker = Ext.create("Ext.picker.Month", {
			pickerField: i_self,
			ownerCt: i_self.ownerCt,
			renderTo: i_body,
			floating: true,
			hidden: true,
			focusOnShow: true,
			minDate: i_self.minValue,
			maxDate: i_self.maxValue,
			disabledDatesRE: i_self.disabledDatesRE,
			disabledDatesText: i_self.disabledDatesText,
			disabledDays: i_self.disabledDays,
			disabledDaysText: i_self.disabledDaysText,
			format: i_self.format,
			showToday: i_self.showToday,
			startDay: i_self.startDay,
			minText: f_format(i_self.minText, i_self.formatDate(i_self.minValue)),
			maxText: f_format(i_self.maxText, i_self.formatDate(i_self.maxValue)),
			listeners: {
				select: {
					scope: i_self,
					fn: i_self.onSelect
				},
				monthdblclick: {
					scope: i_self,
					fn: i_self.onSelect
				},
				yeardblclick: {
					scope: i_self,
					fn: i_self.onSelect
				},
				OkClick: {
					scope: i_self,
					fn: i_self.onOKClick
				},
				CancelClick: {
					scope: i_self,
					fn: i_self.onCancelClick
				}
			},
			keyNavConfig: {
				esc: function() {
					i_self.collapse();
				}
			}
		});

		return i_picker;
	},

	onCancelClick: function() {

		var i_self = this;
		i_self.setSelectedMonth(null);
		i_self.collapse();
	},

	onOKClick: function() {

		var i_self = this;

		var a_values = i_self.picker.getValue();
		
		var i_date = new Date();
		i_date.setMonth(a_values[0]);
		i_date.setYear(a_values[1]);

		i_self.setValue(i_date);
		i_self.collapse();
	},

	onSelect: function(i_field, i_date) {

		var i_self = this;
		i_self.setSelectedMonth(new Date((i_date[0] + 1) + "/1/" + i_date[1]));
	},

	onBlur: Ext.emptyFn,

	onFocusLeave: Ext.emptyFn
});if (!Ext.ClassManager.isCreated("Portfolio.message.model.Error")) {

	Ext.define("Portfolio.message.model.Error", {
		extend: "Ext.data.Model",
		fields: [
			{
				name: "id"
			},
			{
				name: "description"
			},
			{
				name: "message"
			},
			{
				name: "completeStackTrace"
			},
			{
				name: "errorType"
			},
			{
				name: "isRestException"
			},
			{
				name: "src"
			},
			{
				name: "lineNo"
			},
			{
				name: "date", type: "date"
			},
			{
				name: "urlText"
			},
			{
				name: "url "
			},
			{
				name: "debugType"
			},
			{
				name: "params"
			}
		]
	});
}
Ext.define("Portfolio.message.view.Main", {

	extend: "Ext.grid.Panel",

	xtype: "portfolio-message-grid",

	title: ip2.i18n({
		da: "Log & beskeder",
		en: "Log & Messages"
	}),

	requires: [
		"Portfolio.message.model.Error"
	],

	listeners: {
		itemdblclick: {
			fn: function(i_view, i_record) {

				var i_self = this;
				i_self.fireEvent("viewerror", i_record);
			}
		}
	},

	header: {
		listeners: {
			click: {
				fn: function(i_header) {
					var i_panel = i_header.up("panel");
					i_panel.toggleCollapse();
				}
			}
		}
	},

	ui: "menu-navigation",

	initComponent: function() {

		var i_self = this;

		var i_store = i_self.createStore();
		var a_columns = i_self.createColumns();

		Ext.apply(i_self, {
			store: i_store,
			columns: a_columns
		});

		i_self.callParent(arguments);
	},

	createStore: function() {

		var i_self = this;

		var i_store = Ext.create("Ext.data.Store", {
			model: "Portfolio.message.model.Error",
			proxy: {
				type: "memory"
			}
		});

		return i_store;
	},

	createColumns: function() {

		var i_self = this;

		var a_columns = [
			{
				header: ip2.i18n({
					da: "Tidspunkt",
					en: "Time"
				}),
				sortable: true,
				dataIndex: "date",
				width: 130,
				renderer: Ext.util.Format.dateRenderer("Y.m.d   H:m:s")
			},
			{
				header: ip2.i18n({
					da: "Beskrivelse",
					en: "Description"
				}),
				sortable: true,
				flex: 1,
				dataIndex: "description"
			},
			{
				header: ip2.i18n({
					da: "Tekst",
					en: "Text"
				}),
				sortable: true,
				flex: 1,
				dataIndex: "urlText"
			},
			{
				header: ip2.i18n({
					da: "Url",
					en: "Url"
				}),
				sortable: true,
				flex: 1,
				dataIndex: "url"
			},
			{
				header: ip2.i18n({
					da: "Linje no.",
					en: "Line No."
				}),
				sortable: true,
				flex: 1,
				dataIndex: "lineNo"
			}
		];

		return a_columns;
	}
});
Ext.define("Portfolio.util.Message", {

	singleton: true,

	alternateClassName: [
		"ip2.message"
	],

	config: {
		grid: null,
		model: null,
		showErrors: false,
		oldText: ""
	},

	init: Ext.emptyFn,

	requires: [
		"Portfolio.message.view.Main"
	],

	constructor: function(o_config) {

		var i_self = this;

		i_self.initConfig(o_config);

		i_self.initError();

		return i_self;
	},

	initGrid: function (o_config) {

		var i_self = this;

		Ext.apply(o_config, {
			listeners: {
				viewerror: {
					fn: function(i_record) {
						i_self.onView(i_record);
					}
				},
				itemcontextmenu: {
					fn: function (i_view, i_record, item, index, e, options) {

						e.preventDefault();

						var a_coords = e.getXY();
						var i_contextMenu = i_self.getContextMenu(i_record);

						i_contextMenu.showAt(a_coords);
					}
				}
			}
		});

		var i_grid = Ext.widget("portfolio-message-grid",
			o_config
		);

		var i_store = i_grid.getStore();
		var i_model = i_store.getModel();

		i_self.setGrid(i_grid);
		i_self.setModel(i_model);

		Ext.GlobalEvents.fireEvent("messageReady", i_self);

		return i_grid;
	},

	getContextMenu: function (i_record) {

		var i_self = this;
		var i_grid = i_self.getGrid();

		var i_menu = Ext.widget("menu", {
			items: [
				{
					xtype: "menuitem",
					text: ip2.i18n({
						da: "Vis",
						en: "Show"
					}),
					iconCls: "pf-magnifying_glass",
					handler: function() {
						i_self.onView(i_record);
					}
				},
				{
					xtype: "menuitem",
					text: ip2.i18n({
						da: "Ryd",
						en: "Clear"
					}),
					iconCls: "pf-delete",
					handler: function() {

						i_grid.getStore().removeAll();

						if (i_self.getShowErrors()) {
							i_grid.setTitle(i_self.getOldText());
							i_self.setOldText("");
							i_grid.header.setIcon("");
						}
					}
				}
			]
		});

		return i_menu;
	},

	onView: function(i_record) {

		var i_self = this;
		var s_url = i_record.get("url");
		var s_debugType = i_record.get("debugType");
		var s_mode = "javascript";
		var s_stack = i_record.get("completeStackTrace");

		var s_description = i_record.get("description");
		var s_date = i_record.get("date");

		var s_title = [
			"<strong>" + s_description + "</strong>",
			" (",
				Ext.util.Format.date(s_date, "Y.m.d   H:m:s"),
			")"
		].join("");

		switch (s_debugType) {
			case "js":
				s_mode = "javascript";
				break;
			case "json":
				s_mode = "json";
				break;
		}

		var i_stackArea = Ext.widget("panel", {
			title: "Stacktrace",
			layout: "fit",
			flex: 1,
			collapsed: false,
			collapsible: true,
			collapseDirection: "right",
			split: true
		});

		var i_messageArea = Ext.widget("panel", {
			title: "Message",
			layout: "fit",
			flex: 2,
			collapsed: false,
			collapsible: true,
			collapseDirection: "left",
			split: true
		});

		var i_contentArea = Ext.widget("panel", {
			layout: {
				type: "hbox",
				align: "stretch"
			},
			border: false,
			defaults: {
				margin: "0 5 0 0"
			},
			flex: 1
		});

		var i_stackTrace = Ext.widget("acetextarea", {
			hideLabel: true,
			mode: "javascript",
			name: "completeStackTrace",
			useWorker: false,
			margin: "0 0 0 0",
			listeners: {
				editorready: {
					fn: function() {

						var i_field = this;

						i_field.setValue(s_stack);
					},
					buffer: 100
				}
			}
		});

		var i_editor = Ext.widget("acetextarea", {
			hideLabel: true,
			name: "src",
			mode: s_mode,
			useWorker: false,
			flex: 1,
			listeners: {
				editorready: {
					fn: function() {

						var i_aceEditor = this;

						var n_line = i_record.get("lineNo");
						var o_params = i_record.get("params") || "";

						if (s_url) {
							Ext.Ajax.request({
								url: s_url,
								success: function(i_response) {

									var s_src = i_response.responseText;
									i_aceEditor.setValue(s_src);
									i_aceEditor.gotoLine(n_line);
								}
							});
						}
						else {
							i_aceEditor.setValue(o_params);
						}
					},
					buffer: 100
				}
			}
		});

		i_messageArea.add(i_editor);
		i_stackArea.add(i_stackTrace);

		i_contentArea.add([i_messageArea, i_stackArea]);

		var i_form = Ext.widget("form", {
			layout: {
				type: "vbox",
				align: "stretch"
			},
			border: false,
			record: i_record,
			bodyStyle: {
				background: "transparent"
			},
			bodyPadding: 10,
			items: [
				{
					xtype: "fieldset",
					layout: "anchor",
					defaults: {
						anchor: "100%",
						xtype: "textfield",
						readOnly: true,
						labelWidth: 160
					},
					title: ip2.i18n({
						da: "Informationer",
						en: "Information"
					}),
					items: [
						{
							fieldLabel: ip2.i18n({
								da: "Tekst",
								en: "Text"
							}),
							name: "description"
						},
						{
							fieldLabel: ip2.i18n({
								da: "Url",
								en: "Url"
							}),
							itemId: "url",
							name: "url"
						},
						{
							fieldLabel: ip2.i18n({
								da: "Besked",
								en: "Message"
							}),
							name: "message"
						},
						{
							fieldLabel: ip2.i18n({
								da: "Linie nummer",
								en: "Line Number"
							}),
							name: "lineNo"
						},
						{
							xtype: "hidden",
							name: "debugType"
						}
					]
				},
				i_contentArea
			]
		});

		var o_size = ip2.getWindowSize();

		var i_window = Ext.widget("window", {
			title: s_title,
			layout: "fit",
			width: o_size.width * 0.8,
			height: o_size.height * 0.9,
			resizable: true,
			listeners: {
				afterrender: {
					fn: function (i_self) {

						i_form.loadRecord(i_record);
					},
					single: true
				}
			},
			items: [
				i_form
			],
			buttonAlign: "right",
			buttons: [
				{
					text: ip2.i18n({
						da: "Luk",
						en: "Close"
					}),
					handler: function() {
						i_window.close();
					}
				}
			]
		});

		if (!s_stack) {
			i_stackArea.setCollapsed(true);
		}

		i_window.show();
	},

	AddJs: function(err) {

		var i_self = this;
		var message = err;

		message.Message = err.message;
		i_self.Add("Script error", message, "js");
	},

	AddLog: function(prop, log) {

		var i_self = this;
		var message;
		var url;

		url = Object.prototype.toString.call(log);
		try {
			message = JSON.stringify(log, null, 4);
		}
		catch (err) {
			message = "Cannot convert circular structure to string.";
		}
		i_self.Add(prop, {
			message: message,
			url: url
		}, "log");
	},

	AddAjax: function(i_response) {

		var o_result = {};
		var i_self = this;

		try {
			o_result = Ext.decode(i_response.responseText, true) || {};
			if (o_result.Message) {
				var p = o_result.Message.indexOf("\r");
				var s_title = (p > 0) ? o_result.Message.substring(0, p) : o_result.Message;
				i_self.Add(s_title, o_result, "ajax");
			}
			else {
				o_result.Message = i_response.responseText;
				i_self.Add(i_response.status + ": " + i_response.statusText, message, "ajax");
			}
		}
		catch (err) {
			o_result.Message = i_response.responseText;
			i_self.Add(i_response.status + ": " + i_response.statusText, message, "ajax");
		}
	},

	ProxyException: function (i_proxy, i_response, i_operation) {

		var i_self = this;
		var o_message = {};
		var s_title = "";

		if (i_operation.error) {
			o_message = i_operation.getError();
		}
		else if (i_response) {

			o_message = Ext.decode(i_response.responseText, true);

			if (o_message) {
				s_title = ip2.i18n("serverSideDBerror").replace(/:/g, "");
			}
		}

		i_self.Add(s_title, o_message);
	},

	Add: function(s_description, o_error, s_debugType) {

		o_error = o_error || {
			message: "",
			stack: ""
		};

		Ext.applyIf(o_error, {
			message: "",
			Message: ""
		});

		s_debugType = s_debugType || "js";

		var i_self = this;
		var i_grid = i_self.getGrid();

		if (i_grid) {

			var i_store = i_grid.getStore();

			var s_message = o_error.Message ? o_error.Message : o_error.message || "";

			var s_src = o_error.src || o_error.url || "";

			var i_model = i_self.getModel();

			var i_record = i_model.create({
				description: s_description,
				message: s_message,
				completeStackTrace: o_error.completeStackTrace || o_error.CompleteStackTrace || "",
				errorType: o_error.ErrorType || "",
				isRestException: o_error.IsRestException || "",
				src: s_src,
				lineNo: o_error.lineNo || "",
				date: new Date(),
				urlText: o_error.urlText || s_message,
				url: s_src,
				params: o_error.params,
				debugType: s_debugType
			});

			i_store.add(i_record);

			var s_title = s_description + ' ' + ip2.i18n({
				da: "klik her for flere detaljer",
				en: "click here for more details"
			});



			if (i_self.getShowErrors()) {

				i_grid.header.setIcon("/system/shared/collection/icons/16x16/plain/sign_warning.png");

				var s_oldText = i_grid.getTitle();

				var s_stored = i_self.getOldText();

				if (!s_stored) {
					i_self.setOldText(s_oldText);
				}

				i_grid.setTitle(s_title);
			}
		}
	},

	initError: function() {

		var i_self = this;

		window.onerror = function(s_message, s_url, n_lineno, n_colno, o_error) {

			// THIS IS ANGULAR HACK TO HANDLE ZONE ALREADY LOADED ERROR

			if (!/Zone already]/.test(s_message)) {

				i_self.Add(o_error.name, {
					message: s_message,
					url: s_url,
					lineNo: n_lineno,
					completeStackTrace: o_error.stack
				}, "js");
			}

			Portfolio.util.Handler.unmask();

			Portfolio.app.fireEvent("applicationError", o_error);

			return true;
		};
	}
});
Ext.define("Portfolio.center.view.Main", {

	xtype: "portfolio-centertabs",

	extend: "Ext.tab.Panel",

	layout: "fit",

	region: "center",

	minTabWidth: 100,

	stateId: "portfolio-center-main",

	stateful: false,

	requires: [
		"Ext.ux.BoxReorderer",
		"Ext.ux.TabReorderer",
		"Ext.ux.TabCloseMenu"
	],

	plugins: [
		"tabclosemenu",
		"tabreorderer"
	],

	config: {
		dropZone: null,
		applications: new Ext.util.Collection(),
		addCount: 0,
		appQue: new Ext.util.Collection(),
		activateTab: 0,
		windows: []
	},

	stateEvents: [
		"add",
		"remove",
		"tabchange",
		"stateupdate"
	],

	ui: "centertabs",

	listeners: {
		afterrender: {
			fn: function(i_tabpanel) {

				var i_self = i_tabpanel;

				var i_tabBar = i_tabpanel.getTabBar();

				var i_dropzone = new Ext.dd.DropZone(i_tabBar.getEl(), {
					ddGroup: "tree2fav",
					getTargetFromEvent: function(i_event) {
						return i_tabBar;
					},
					onNodeOver: function(i_target, i_soruce, i_event, o_data) {

						var s_return = Ext.dd.DropZone.prototype.dropAllowed;
						var a_records = o_data.records;

						var a_tabs = i_target.items.getRange();

						var b_allowed = true;

						Ext.Array.each(a_tabs, function(i_tab) {

							if (i_event.within(i_tab.getEl())) {
								b_allowed = false;
								return false;
							}
						});

						Ext.Array.each(a_records, function(i_node) {
							if (!i_node.isLeaf()) {
								b_allowed = false;
								return false;
							}
						});

						if (!b_allowed) {
							s_return = Ext.dd.DropZone.prototype.dropNotAllowed;
						}

						return s_return;
					},
					onNodeDrop: function(i_target, i_source, i_event, o_data) {

						var a_tabs = i_target.items.getRange();

						var b_found = false;

						Ext.Array.each(a_tabs, function(i_tab) {

							if (i_event.within(i_tab.getEl())) {
								b_found = true;
								return false;
							}
						});

						if (!b_found) {
							var a_records = o_data.records;
							var i_record = a_records[0];
							i_self.fireEvent("startapplication", i_record);
						}

						return !b_found;
					}
				});

				i_self.setDropZone(i_dropzone);

				i_self.initKeys();
			},
			buffer: 100
		},
		applicationReady: {
			fn: function (i_panel, i_child, b_window) {

				var i_self = this;
				var n_count = i_self.getAddCount();
				var i_appQue = i_self.getAppQue();
				var n_activate = i_self.getActivateTab();

				if (i_child) {
					i_appQue.add(i_child);
				}

				n_count--;

				if (n_count === 0) {

					var a_items = i_appQue.getRange();

					if (Ext.isBoolean(b_window) && b_window) {

						i_self.detachApplication(a_items, false);

					}
					else {

						Ext.suspendLayouts();

						i_self.add(a_items);

						if (a_items.length == 1) {

							i_child = a_items[0];

							if (i_child) {
								if (i_child.startActive) {
									i_self.setActiveTab(i_child);
								}
							}
						}
						else {
							i_self.setActiveTab(n_activate);
						}

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

							i_item.tab.on({
								afterrender: {
									fn: function () {
										i_item.tab.tt = Ext.create("Ext.tip.ToolTip", {
											target: i_item.tab.getEl(),
											html: "",
											anchor: true,
											defaultAlign: "b50-t50",
											showDelay: 10,
											listeners: {
												beforeshow: {
													fn: function (i_tip) {

														var i_collection = i_self.items.getRange();

														var n_index = i_collection.indexOf(i_item);

														if (n_index > - 1) {
															i_tip.update("Alt + " + (n_index + 1));
														}
														else {
															return false;
														}

													}
												}
											}
										});
									},
									single: true
								},
								dblclick: {
									element: "el",
									fn: function (i_event) {
										i_self.fireEvent("toWindow", i_item);
									}
								}
							});
						});

						i_self.setActivateTab(0);

						Ext.resumeLayouts(true);

						i_self.fireEvent("applicationAdded", i_self, a_items);
					}

					i_appQue.clear();
				}

				i_self.setAddCount(n_count);
			}
		},
		startapplication: {
			fn: function(i_record, b_window) {

				var i_self = this;
				var i_applications = i_self.getApplications();

				var o_properties;
				var o_data;

				var a_values = Ext.Array.from(i_record);

				var n_addCount = i_self.getAddCount();

				n_addCount = n_addCount + a_values.length;

				i_self.setAddCount(n_addCount);

				Ext.Array.each(a_values, function(i_record) {

					if (i_record.isModel) {
						o_properties = Ext.apply({}, i_record.get("properties") || {});
						o_data = i_record.getData();

						if (Ext.Object.isEmpty(o_properties)) {
							o_properties = o_data;
						}
					}
					else {
						o_data = o_properties = Ext.apply({}, i_record);
					}

					var s_url = o_data.url || o_properties.url || o_data.link;
					var s_title = Portfolio.util.Handler.i18n(o_properties.title || o_data.text || o_data.title);

					if (o_properties.hasOwnProperty("startActive")) {
						o_data.startActive = o_properties.startActive;
					}
					else {
						o_data.startActive = Ext.isBoolean(o_data.startActive) ? o_data.startActive : true;
					}

					if (Ext.isObject(s_title)) {
						s_title = Portfolio.util.Handler.i18n(s_title);
					}

					var i_child;
					var b_forced = o_data.force || false;

					if (!b_forced) {

						Ext.Array.each(i_applications.getRange(), function(o_config) {

							var o_configData = o_config.data || {};
							var o_configProperties = o_configData.properties || {};

							var s_configData = Ext.encode(o_configData);
							var s_configProperties = Ext.encode(o_configProperties);

							var s_data = Ext.encode(o_data);
							var s_properties = Ext.encode(o_properties);

							if (Ext.Object.isEmpty(o_configProperties) && Ext.Object.isEmpty(o_properties)) {
								if (s_data == s_configData) {
									i_child = o_config.active;
								}
								else if (o_configData.url == s_url) {
									i_child = o_config.active;
								}
							}
							else {
								if (s_properties == s_configProperties) {
									i_child = o_config.active;
								}
								else if (s_url && o_configData.url == s_url) {

									var o_temp = i_record.isModel ? Ext.clone(o_properties) : Ext.clone(o_data);
									var o_configClone = i_record.isModel ? Ext.clone(o_configProperties) : Ext.clone(o_configData);

									Ext.Object.each(o_temp, function(s_key, value) {

										if (Ext.isPrimitive(value)) {
											if (Ext.isEmpty(value)) {
												delete o_temp[s_key];
											}
										}
										else if (Ext.isArray(value)) {
											if (value.length === 0) {
												delete o_temp[s_key];
											}
										}
										else if (Ext.isObject(value)) {
											if (Ext.Object.isEmpty(value)) {
												delete o_temp[s_key];
											}
										}
									});

									Ext.Object.each(o_configClone, function(s_key, value) {

										if (Ext.isPrimitive(value)) {
											if (Ext.isEmpty(value)) {
												delete o_configClone[s_key];
											}
										}
										else if (Ext.isArray(value)) {
											if (value.length === 0) {
												delete o_configClone[s_key];
											}
										}
										else if (Ext.isObject(value)) {
											if (Ext.Object.isEmpty(value)) {
												delete o_configClone[s_key];
											}
										}
									});

									var s_temp = Ext.encode(o_temp);
									var s_clone = Ext.encode(o_configClone);

									if (s_temp == s_clone) {
										i_child = o_config.active;
									}
									else {
										delete o_temp.url;
										delete o_temp.link;

										if (Ext.Object.isEmpty(o_temp)) {
											i_child = o_config.active;
										}
										else {

											delete o_configClone.url;

											if (Ext.Object.isEmpty(o_configClone)) {
												i_child = o_config.active;
											}
										}
									}
								}
								else if (s_data == s_configProperties) {
									i_child = o_config.active;
								}
								else if (s_properties == s_configProperties) {
									i_child = o_config.active;
								}
							}

							if (i_child) {
								return false;
							}
						});
					}
					else {
						o_properties.force = b_forced;
					}

					if (!i_child) {

						Portfolio.util.Handler.mask();

						if (s_url) {

							var s_params = s_url.split("?").pop();
							var o_params = Ext.urlDecode(s_params);

							if (/\B#\w+/.test(s_url)) {
								n_addCount--;
								i_self.setAddCount(n_addCount);

								Portfolio.Router.instance.redirectTo(s_url, true);
							}
							else if (!/\.(js|widget)/.test(s_url)) {

								if (o_data.target == "_blank") {

									window.open(s_url, "_blank");

									Portfolio.util.Handler.unmask();
								}
								else {
									Ext.require("Portfolio.ux.container.Iframe", function() {

										var i_created = Ext.widget("portfolio-ux-container-iframe", {
											title: s_title,
											src: s_url,
											closable: true
										});

										i_self.afterRequire(i_created, o_data, b_window);
									});
								}
							}
							else if (/\.(widget)/.test(s_url)) {

								if (/\.*portfolioMenu/.test(s_url)) {
									Ext.require("Portfolio.menu.view.Editor", function() {
	
										var i_created = Ext.widget("portfolio-menu-editor", {
											title: s_title,
											dmd: "dmd/portfolio.dmd",
											entity: "NAVMNUET00",
											viewName: "portfolio",
											context: "grid",
											parentID: "MNUPNTTKN",
											childID: "MNUMNUTKN",
											closable: true
										});
	
										i_self.afterRequire(i_created, o_data, b_window);
									});
								}
								else {
									i_child = ip2.callWidget(o_properties);

									if (i_child) {

										if (i_child.addDocked) {

											if (o_properties.hasOwnProperty("allowLink")) {

												if (o_properties.allowLink) {

													var a_items = [
														{
															xtype: "tbfill"
														},
														{
															xtype: "button",
															iconCls: "pf-link",
															itemId: "button-link",
															handler: function(i_button) {

																var s_name = s_url.split(".").shift();

																var i_window = Ext.widget("link.window", {
																	model: {
																		widget: {
																			name: s_name
																		}
																	}
																});

																i_window.show();
															}
														}
													];

													var i_toolbar = Ext.widget("toolbar", {
														dock: "bottom",
														items: a_items,
														itemId: "linkbar"
													});

													i_child.addDocked(i_toolbar);
												}
											}
										}

										s_title = s_title || ip2.i18n(i_child.getTitle());
										i_child.setTitle(s_title);
										i_self.afterRequire(i_child, o_data, b_window);
									}
									else {
										Portfolio.util.Handler.unmask();
									}
								}
							}
							else if (/(run-dmd.js).*/.test(s_url)) {

								Ext.require("Portfolio.entity.view.Panel", function() {

									var i_created = Ext.widget("portfolio-entity-panel", {
										title: s_title,
										dmd: {
											path: o_params.dmd || "dmd/webshop.dmd",
											entityName: o_params.entity
										},
										uiName: o_params.view || "portfolio",
										defaultFilter: o_params.filter,
										defaultCollection: o_params.collection,
										closable: true
									});

									i_self.afterRequire(i_created, o_data, b_window);
								});
							}
							else if (/(run-dmd-tree).*/.test(s_url)) {

								Ext.require("Portfolio.entity.view.Tree", function() {

									var i_created = Ext.widget("portfolio-entity-tree", {
										title: s_title,
										dmd: o_params.dmd,
										entity: o_params.entity,
										viewName: o_params.view || "portfolio",
										parentID: o_params.parentID,
										childID: o_params.childID,
										textProperty: o_params.textProperty,
										sequence: o_params.sequence,
										closable: true
									});

									i_self.afterRequire(i_created, o_data, b_window);
								});
							}
							else if (/(run-dynapp).*/.test(s_url)) {

								Ext.require("Portfolio.dynapp.App", function() {

									var i_created = Ext.create("Portfolio.dynapp.App", {
										title: s_title,
										options: {
											library: o_params.lib || o_params.library || "",
											file: o_params.file
										},
										closable: true
									});

									i_self.afterRequire(i_created, o_data, b_window);
								});
							}
							else if (/(run-registry).*/.test(s_url)) {

								Ext.require("Portfolio.registry.App", function() {

									var i_created = Ext.create("Portfolio.registry.App", {
										title: s_title,
										options: {
											library: o_params.lib || o_params.library || "",
											file: o_params.file
										},
										closable: true
									});

									i_self.afterRequire(i_created, o_data, b_window);
								});
							}
							else if (/(start-dmd).*/.test(s_url)) {

								Ext.require("Portfolio.designer.view.Main", function() {

									var i_created = Ext.create("Portfolio.designer.view.Main", {
										title: s_title,
										closable: true
									});

									i_self.afterRequire(i_created, o_data, b_window);
								});
							}
							else {
								i_child = ip2.callWidget(o_properties);
								if (i_child) {
									i_child.setTitle(s_title);
									i_self.afterRequire(i_child, o_data, b_window);
								}
								else {
									Portfolio.util.Handler.unmask();
								}
							}
						}
						else {

							var o_widget;

							if (o_properties.hasOwnProperty("appFolder") || o_properties.hasOwnProperty("main")) {
								o_properties.startActive = o_data.startActive;
								i_self.openApplication(o_properties);
							}
							else if (o_properties.hasOwnProperty("widget")) {

								eval("o_widget = " + o_properties.widget);

								o_widget = o_widget || {
									xtype: "panel"
								};

								Ext.applyIf(o_widget, {
									title: ip2.i18n(o_properties.title)
								});

								i_self.fireEvent("applicationAdd", o_widget.xtype, o_widget, o_data, b_window);
							}
							else if (o_data.hasOwnProperty("widget")) {

								s_title = ip2.i18n(o_data.title || o_data.text);

								eval("o_widget = " + o_data.widget);

								o_widget = o_widget || {
									xtype: "panel"
								};

								if (s_title) {
									Ext.applyIf(o_widget, {
										title: s_title
									});
								}

								i_self.fireEvent("applicationAdd", o_widget.xtype, o_widget, o_data, b_window);
							}
							else if (o_data.hasOwnProperty("component")) {

								s_title = ip2.i18n(o_data.title || o_data.text);

								o_widget = o_data.component || {};

								i_self.fireEvent("applicationAdd", o_widget.xtype, o_widget, o_data, b_window);
							}
							else if (o_data.entity && o_data.dmd) {

								Ext.require("Portfolio.entity.view.Form", function() {

									var i_record = Portfolio.util.Handler.getUser();


									var i_created = Ext.widget("portfolio-entity-form", {
										keys: o_data.keys,
										action: o_data.action,
										dmd: o_data.dmd,
										entity: o_data.entity,
										view: o_data.view,
										oldData: o_data.oldData || o_data.data || null,
										context: "form",
										language: i_record.get("USRLNG") || "en",
										closable: true,
										defaultCollection: o_data.defaultCollection || "",
										transactiontype: o_data.transactiontype || o_data.entityName,
										activeTabIndex: o_data.activeTabIndex || 0,
										linkable: o_data.hasOwnProperty("linkable") ? o_data.linkable : true,
										deletable: o_data.hasOwnProperty("deletable") ? o_data.deletable : true,
										listeners: {
											contentReady: {
												fn: function(i_content, i_entityPanel, b_recreate) {
													if (!b_recreate) {
														i_self.afterRequire(i_entityPanel, o_data, b_window);
													}
												},
												buffer: 100
											},
											contentCancel: {
												fn: function(i_entityPanel) {
													i_self.onCancel(i_entityPanel);
												},
												single: true
											}
										}
									});

									if (o_data.hasOwnProperty("listeners") && Ext.isObject(o_data.listeners)) {
										i_created.on(o_data.listeners);
									}
								});
							}
							else if (o_data.xtype) {
								i_self.fireEvent("applicationAdd", o_data.xtype, o_data, null, b_window);
							}
						}
					}
					else {

						n_addCount--;

						i_self.setAddCount(n_addCount);

						i_self.setActiveTab(i_child);
					}
				});
			}
		},
		entityedit: {
			fn: function(o_keys, o_config, s_action) {

				var i_self = this;

				var o_data = Ext.apply({}, {
					action: s_action,
					keys: o_keys,
					entity: o_config.entityName || o_config.entity,
					view: o_config.uiName || o_config.view,
					dmd: o_config.dmd,
					defaultCollection: o_config.defaultCollection,
					transactiontype: o_config.entityName,
					activeTabIndex: o_config.activeTabIndex || 0,
					oldData: o_config.data || null,
					listeners: o_config.listeners || null,
					linkable: o_config.hasOwnProperty("linkable") ? o_config.linkable : true,
					deletable: o_config.hasOwnProperty("deletable") ? o_config.deletable : true
				});

				i_self.fireEvent("startapplication", o_data);
			}
		},
		entityWindow: {
			fn: function(o_keys, o_config, s_action, o_windowConfig, s_managerId) {

				var i_self = this;

				var i_record = Portfolio.util.Handler.getUser();

				Ext.require("Portfolio.entity.view.Form", function() {

					var i_entityPanel = Ext.widget("portfolio-entity-form", {
						keys: o_keys,
						action: s_action,
						dmd: o_config.dmd,
						header: false,
						entity: o_config.entityName || o_config.entity,
						view: o_config.uiName || o_config.view,
						oldData: o_config.data || null,
						context: "form",
						language: i_record.get("USRLNG") || "en",
						closable: false,
						createTitle: o_config.createTitle ? o_config.createTitle : true,
						defaultCollection: o_config.defaultCollection || "",
						transactiontype: o_config.transactiontype || o_config.entityName || o_config.entity,
						activeTabIndex: o_config.activeTabIndex || 0,
						linkable: o_config.hasOwnProperty("linkable") ? o_config.linkable : true,
						deletable: o_config.hasOwnProperty("deletable") ? o_config.deletable : true,
						listeners: {
							contentReady: {
								fn: function(i_entityPanel) {
									Portfolio.util.Handler.unmask();
								},
								single: true
							},
							contentCancel: {
								fn: function(i_entityPanel) {
									i_self.onCancel(i_entityPanel);
								},
								single: true
							}
						}
					});

					if (o_config.hasOwnProperty("listeners") && Ext.isObject(o_config.listeners)) {
						i_entityPanel.on(o_config.listeners);
					}

					delete o_config.container;

					i_self.afterRequire(i_entityPanel, o_config, true, function() {

						i_self.detachApplication([i_entityPanel], false, o_windowConfig, s_managerId);

					});

				});
			}
		},
		applicationAdd: {
			fn: function (s_main, o_config, o_data, b_window) {

				var i_self = this;
				var i_application;
				var i_user = ip2.getUser();

				o_data = o_data || o_config;

				var n_count = i_self.getAddCount();

				if (n_count == 0) {
					n_count++;
					i_self.setAddCount(n_count);
					o_data.startActive = true;
				}

				Portfolio.util.Handler.mask("Loading...");

				Ext.apply(o_config, {
					closable: true,
					reorderable: true
				});

				if (/^\w+\.\w+/.test(s_main)) {

					if (s_main.toLowerCase() == "icecap.view.main" || o_config.xtype.toLowerCase() == "icecap-panel") {
						Ext.apply(o_config, {
							bodyCls: "centertabs-panel",
							activeLanguage: i_user.get("USRLNG") || "da"
						});
					}

					Ext.require(s_main, function() {

						i_application = Ext.create(s_main, o_config);

						if (i_application) {
							i_self.afterRequire(i_application, o_data, b_window);
						}
						else {
							Portfolio.util.Handler.unmask();
						}
					});
				}
				else {

					if (s_main.toLowerCase() == "icecap.view.main" || o_config.xtype.toLowerCase() == "icecap-panel") {
						Ext.apply(o_config, {
							bodyCls: "centertabs-panel",
							activeLanguage: i_user.get("USRLNG") || "da"
						});
					}

					i_application = Ext.widget(s_main, o_config);

					if (i_application) {
						i_self.afterRequire(i_application, o_data, b_window);
					}
					else {
						Portfolio.util.Handler.unmask();
					}
				}
			}
		},
		addContainer: {
			fn: function (i_instance, b_window) {

				var i_self = this;

				var o_data = i_instance.initialConfig || {};

				Ext.applyIf(o_data, {
					xtype: i_instance.xtype
				});

				i_self.fireEvent("startapplication", o_data, b_window);
			}
		},
		applicationError: {
			fn: function() {

				var i_self = this;

				var n_count = i_self.getAddCount();
				n_count--;

				if (n_count < 0) {
					n_count = 0;
				}

				i_self.setAddCount(n_count);

				Ext.resumeLayouts(true);
			}
		},
		toWindow: {
			fn: function (i_item, o_windowConfig) {
				var i_self = this;
				i_self.detachApplication(i_item, o_windowConfig);
			}
		},
		toTab: {
			fn: function (i_item, o_data) {
				var i_self = this;
				i_self.attachApplication(i_item, o_data);
			}
		},
		compare: {
			fn: function (i_tab, i_compare) {

				var i_self = this;
				i_self.detachApplication([i_tab, i_compare], true);
				Portfolio.app.fireEvent("resizewindows", true);
			}
		},
	},

	initComponent: function() {

		var i_self = this;

		i_self.callParent(arguments);

		i_self.mon(Portfolio.app, "startapplication", function(o_config, b_window) {
			i_self.fireEvent("startapplication", o_config, b_window);
		});

		i_self.mon(Portfolio.app, "entityedit", function(o_config, s_action) {
			i_self.fireEvent("entityedit", o_config.keys, o_config, s_action);
		});

		i_self.mon(Portfolio.app, "entityWindow", function(o_config, s_action, o_windowConfig, s_managerId) {
			i_self.fireEvent("entityWindow", o_config.keys, o_config, s_action, o_windowConfig, s_managerId);
		});

		i_self.mon(Portfolio.app, "applicationAdd", function (s_main, o_config, b_window) {
			i_self.fireEvent("applicationAdd", s_main, o_config, b_window);
		});

		i_self.mon(Portfolio.app, "addContainer", function (i_instance, b_window) {
			i_self.fireEvent("addContainer", i_instance, b_window);
		});

		i_self.mon(Portfolio.app, "applicationError", function(o_error) {
			i_self.fireEvent("applicationError", o_error);
		});

		i_self.mon(Portfolio.app, "toWindow", function (i_item, o_windowConfig) {
			i_self.fireEvent("toWindow", i_item, o_windowConfig);
		});

		i_self.mon(Portfolio.app, "toTab", function (i_item, o_data) {
			i_self.fireEvent("toTab", i_item, o_data);
		});

		i_self.mon(Portfolio.app, "compare", function (i_tab, i_compare) {
			i_self.fireEvent("compare", i_tab, i_compare);
		});


		Ext.getWin().on("message", function(i_event) {

			var i_bEvent = i_event.browserEvent ? i_event.browserEvent : i_event;

			if (i_bEvent.origin == location.origin) {

				var o_data = Ext.decode(i_bEvent.data, true) || {};

				if (o_data.event) {

					var o_config = o_data.config;

					i_self.fireEvent(o_data.event, o_config);
				}
			}
		});
	},

	initKeys: function() {

		var i_self = this;

		var a_bindings = [
			{
				key: Ext.event.Event.Z,
				alt: true,
				ctrl: false,
				fn: function(n_key, i_event) {
					i_event.stopEvent();

					var a_range = Ext.WindowManager.zIndexStack.getRange();

					if (a_range.length > 0) {

						var i_next = Ext.WindowManager.zIndexStack.getAt(0);

						Ext.WindowManager.bringToFront(i_next, false);

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

						if (i_panel) {
							i_panel.focus();
						}
					}
				}
			},
			{
				key: Ext.event.Event.ONE,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(1);
				}
			},
			{
				key: Ext.event.Event.TWO,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(2);
				}
			},
			{
				key: Ext.event.Event.THREE,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(3);
				}
			},
			{
				key: Ext.event.Event.FOUR,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(4);
				}
			},
			{
				key: Ext.event.Event.FIVE,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(5);
				}
			},
			{
				key: Ext.event.Event.SIX,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(6);
				}
			},
			{
				key: Ext.event.Event.SEVEN,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(7);
				}
			},
			{
				key: Ext.event.Event.EIGHT,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(8);
				}
			},
			{
				key: Ext.event.Event.NINE,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();
					i_self.handleKeys(9);
				}
			},
			{
				key: Ext.event.Event.F3,
				alt: true,
				ctrl: false,
				fn: function (n_key, i_event) {

					i_event.stopEvent();

					var i_activeElement = Ext.get(Ext.Element.getActiveElement());
					var i_component = i_activeElement.component;

					var b_handel = false;

					if (i_component) {

						var i_window;

						if (i_component.isXType("window")) {
							i_window = i_component;
						}
						else {
							i_window = i_component.up("window");
						}

						if (i_window) {
							b_handel = true;
							i_window.close();
						}
					}

					if (!b_handel) {

						var i_active = i_self.getActiveTab();

						if (i_active) {
							var n_active = i_self.items.indexOf(i_active);

							n_active--;

							if (n_active > -1) {
								i_self.setActiveTab(n_active);
							}

							i_active.close();
						}
					}
				}
			}
		];

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

		return i_keyMap;
	},

	handleKeys: function(n_key) {

		var i_self = this;

		var n_length = i_self.items.getCount();

		var n_active = n_key - 1;

		i_self.setActiveTab(n_active);
	},

	openApplication: function(o_application) {

		var i_self = this;

		var s_appName = o_application.appName || o_application.main;
		var s_mainView = o_application.main || s_appName + ".view.Main";

		var o_temp = o_application.appConfig || {};

		var o_appConfig = Ext.apply(o_temp, {
			title: ip2.i18n(o_application.title),
			closable: true
		});

		if (!s_appName) {

			Portfolio.util.Handler.messageBox({
				title: "Error",
				icon: Ext.Msg.ERROR,
				message: ip2.i18n({
					da: "Manglende app navn",
					en: "Missing app name"
				}),
				yesText: "Ok"
			});

			return null;
		}

		var f_destroy = function() {

			var a_items = i_self.items.getRange();
			var n_count = 0;

			Ext.Array.each(a_items, function(i_container) {
				if (i_container.appName === s_appName) {
					n_count++;
				}
			});

			if (n_count === 0) {

				var i_namespace = Ext.namespace(s_appName);

				if (i_namespace) {

					var i_application = i_namespace.getApplication();

					if (i_application) {

						i_application.destroy();

						Ext.undefine(s_appName + ".$application")
						;
						delete Ext.app.namespaces[s_appName];
					}
				}
			}
		};

		var i_user = ip2.getUser();

		if (!Ext.app.namespaces[s_appName]) {

			var a_requires = Ext.Array.from(o_application.requires);
			var a_scripts = Ext.Array.from(o_application.requiredScripts);

			a_requires = Ext.Array.clone(a_requires);
			a_scripts = Ext.Array.clone(a_scripts);

			if (!Ext.Array.contains(a_requires, s_mainView)) {
				a_requires.push(s_mainView);
			}

			a_requires = Ext.Array.filter(a_requires, function(value) {
				return value;
			});

			a_scripts = Ext.Array.filter(a_scripts, function(value) {
				return value;
			});

			var s_appPath = o_application.appFolder;
			var o_packages = o_application.packages;

			if (!o_packages && !s_appPath) {

				Portfolio.util.Handler.messageBox({
					title: "Error",
					icon: Ext.Msg.ERROR,
					message: ip2.i18n({
						da: "Paths eller appFolder skal være tilstede",
						en: "Paths or appFolder must be present"
					}),
					yesText: "Ok"
				});

				return null;
			}

			if (!o_packages) {
				o_packages = {};
				o_packages[s_appName] = o_application.appFolder;
			}



			var o_config = Ext.apply({}, {
				appFolder: s_appPath,
				name: s_appName,
				requires: a_requires,
				paths: o_packages,
				mixins: [
					"Ext.mixin.Mashup"
				],
				requiredScripts: a_scripts,
				launch: function() {

					if (s_mainView.toLowerCase() == "icecap.view.main") {
						Ext.apply(o_appConfig, {
							bodyCls: "centertabs-panel",
							activeLanguage: i_user.get("USRLNG") || "da",
							appName: s_appName
						});
					}

					var i_mainView = Ext.create(s_mainView, o_appConfig);

					i_self.afterRequire(i_mainView, o_application);

					if (i_mainView.isXType) {

						i_mainView.appName = s_appName;

						i_mainView.on({
							destroy: {
								fn: f_destroy
							},
							contentCancel: {
								fn: function(i_entityPanel) {
									i_self.onCancel(i_entityPanel);
									f_destroy.call(i_self);
								},
								single: true
							}
						});
					}
					else {
						setTimeout(function() {
							f_destroy();
						}, 100);
					}
				}
			});

			if (!o_config.appFolder) {
				delete o_config.appFolder;
			}

			Ext.application(o_config);
		}
		else {

			if (o_application.force) {

				if (s_mainView.toLowerCase() == "icecap.view.main") {
					Ext.apply(o_appConfig, {
						bodyCls: "centertabs-panel",
						activeLanguage: i_user.get("USRLNG") || "da"
					});
				}

				var i_mainView = Ext.create(s_mainView, o_appConfig);

				i_self.afterRequire(i_mainView, o_application);

				if (i_mainView.isXType) {

					i_mainView.appName = s_appName;

					i_mainView.on({
						destroy: {
							fn: f_destroy
						},
						contentCancel: {
							fn: function(i_entityPanel) {
								i_self.onCancel(i_entityPanel);
								f_destroy.call(i_self);
							},
							single: true
						}
					});
				}
				else {
					setTimeout(function() {
						f_destroy();
					}, 100);
				}
			}
			else {
				var a_containers = i_self.items.getRange();
				var i_application;

				Ext.Array.each(a_containers, function(i_container) {
					if (i_container.$className === s_mainView) {
						i_application = i_container;
						return false;
					}
				});

				if (i_application) {
					i_self.setActiveTab(i_application);
				}

				var n_count = i_self.getAddCount();

				n_count--;

				i_self.setAddCount(n_count);

				Portfolio.util.Handler.unmask();
			}
		}
	},

	afterRequire: function (i_child, o_data, b_window, f_callback) {

		Portfolio.util.Handler.unmask();

		f_callback = f_callback || Ext.emptyFn;

		var i_self = this;
		var a_allowed = ["panel", "container", "tappanel", "gridpanel"];

		var b_add = i_child.isXType ? i_child.isXType("container") : Ext.Array.contains(a_allowed, i_child.xtype);

		if (b_add) {

			i_child.startActive = o_data.startActive;

			var i_applications = i_self.getApplications();
			var s_id = Ext.id(null, "app-");

			if (i_child.itemId) {
				delete i_child.itemId;
			}

			i_applications.add({
				id: s_id,
				data: o_data,
				active: i_child
			});

			i_child.closable = true;
			i_child.reorderable = true;

			i_child.on({
				destroy: {
					fn: i_self.removeApplication,
					scope: i_self
				}
			});
		}

		if (Ext.emptyFn != f_callback) {
			f_callback.call(i_self);
		}
		else {
			i_self.fireEvent("applicationReady", i_self, b_add ? i_child : null, b_window);
		}

	},

	onCancel: function() {

		var i_self = this;

		var n_count = i_self.getAddCount();

		n_count--;

		i_self.setAddCount(n_count);
	},

	getState: function() {

		var i_self = this;

		var o_state = {
			tabs: [],
			activeTabIndex: -1
		};

		var i_applications = i_self.getApplications();
		var a_items = i_applications.getRange();

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

			var i_panel = o_config.active;

			var o_data = Ext.clone(o_config.data);

			if (i_panel) {

				var o_stateInfo = i_panel.getState();

				var o_appConfig = o_stateInfo.appConfig || o_stateInfo;

				if (o_data.hasOwnProperty("component")) {

					var o_component = o_data.component;
					Ext.apply(o_component, o_appConfig);
				}
				else {

					if (o_data.hasOwnProperty("appFolder") || o_data.hasOwnProperty("main")) {
						Ext.apply(o_data, o_stateInfo);
					}
					else {
						Ext.apply(o_data, o_appConfig);
					}
				}
			}

			o_state.tabs.push(o_data);
		});

		if (a_items.length > 0) {
			o_state.activeTabIndex = i_self.items.indexOf(i_self.getActiveTab());
		}

		return o_state;
	},

	applyState: function(o_state) {

		var i_self = this;
		var o_nullState = Ext.state.Manager.get("portfolio-center-main-null");

		if (o_nullState) {
			Ext.state.Manager.clear("portfolio-center-main-null");
		}

		Ext.applyIf(o_state, {
			tabs: [],
			activeTabIndex: -1
		});

		var a_states = Ext.Array.from(o_state.tabs);

		if (a_states.length > 0 && i_self.stateful) {

			var n_activate = o_state.activeTabIndex || 0;

			i_self.on({
				applicationAdded: {
					fn: function(i_self, a_items) {
						i_self.setActiveTab(n_activate);
					},
					single: true
				}
			});

			i_self.fireEvent("startapplication", a_states);

			Ext.GlobalEvents.fireEvent("centerReady", i_self);
		}
	},

	detachApplication: function (items, b_comparing, o_windowConfig, s_managerId) {

		var i_self = this;
		var i_applications = i_self.getApplications();

		o_windowConfig = o_windowConfig || {};

		var a_item = Ext.Array.from(items);

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

			var o_application = Ext.Array.findBy(i_applications.getRange(), function (o_config) {

				return o_config.active == i_item ? o_config : false;
			});

			if (o_application) {

				var o_data = o_application.data || {};

				if (i_item.tab && i_item.tab.tt) {
					i_item.tab.tt.destroy();

					delete i_item.tab.tt;
				}

				var o_restoreState = o_data.restoreState || {};

				delete o_data.o_restoreState;

				var o_size = Portfolio.util.Handler.getWindowSize();
				var n_height = o_windowConfig.height || o_size.height * 0.6;
				var n_width = o_windowConfig.width || o_size.width * 0.6;

				if (o_restoreState.hasOwnProperty("size")) {

					o_size = o_restoreState.size;
					n_height = o_size.height;
					n_width = o_size.width;
				}

				if (i_item.isXType("icecap-panel")) {
					n_width = null;
					n_height = null;
				}

				var i_topmost = Ext.WindowManager.topMost;

				Portfolio.app.fireEvent("beforedetached", o_windowConfig);

				var i_window = Ext.widget("window", Ext.applyIf({
					layout: "fit",
					height: n_height,
					width: n_width,
					constrain: true,
					maximizable: true,
					stateData: Ext.clone(o_application.data),
					comparing: b_comparing,
					listeners: {
						destroy: {
							fn: function (i_window) {

								var a_windows = i_self.getWindows();
								Ext.Array.remove(a_windows, i_window);

								i_self.setWindows(a_windows);
							}
						},
						afterrender: {
							fn: function (i_window) {

								var i_header = i_window.header;

								if (i_header && i_window.stateData) {

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

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

											var o_restoreState = {
												size: o_size,
												position: i_window.getPosition()
											};

											if (i_panel) {

												var o_stateData = i_window.stateData || {};

												Ext.apply(o_stateData, {
													restoreState: o_restoreState
												});

												i_panel.setTitle(i_window.title);

												Portfolio.app.fireEvent("toTab", i_panel, i_window.stateData);

												i_window.close();
											}
										}
									});

									i_header.add(1, i_tabTool);

									i_item.fireEvent("detach", i_item);

									i_item.show();
								}
							}
						}
					},
					items: [
						i_item
					]
				}, o_windowConfig));

				i_window.on({
					maximize: {
						fn: function() {
							i_window.setSize(i_window.constrainTo.getSize());
						}
					}
				});

				if (i_item.bodyCls) {
					i_item.removeBodyCls(i_item.bodyCls);
				}

				i_item.removeListener("destroy", i_self.removeApplication, i_self);

				i_item.on({
					beforedestroy: {
						fn: i_self.removeFromWindow,
						scope: i_self
					}
				});

				var a_windows = i_self.getWindows();

				if (!o_windowConfig.title) {
					i_window.setTitle(i_item.title);

					i_item.setTitle("");

				}

				if (o_restoreState.hasOwnProperty("position")) {

					var a_position = o_restoreState.position;

					i_window.showAt(a_position);
				}
				else {
					if (i_topmost) {

						var a_xy = i_topmost.getXY();

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

						i_window.show();
					}

				}
				a_windows.push(i_window);

				i_self.setWindows(a_windows);

				i_applications.removeByKey(o_application.id);

				Portfolio.app.fireEvent("applicationdetached", i_window, s_managerId);
			}
		});

	},

	attachApplication: function (i_item, o_data) {

		var i_self = this;
		var i_applications = i_self.getApplications();

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

		i_applications.add({
			id: s_id,
			data: o_data ? o_data : i_item.initialConfig,
			active: i_item
		});

		i_item.setClosable(true);
		i_item.reorderable = true;

		if (i_item.initialConfig.bodyCls) {
			i_item.addBodyCls(i_item.initialConfig.bodyCls);
		}

		i_item.removeListener("beforedestroy", i_self.removeFromWindow, i_self);

		i_item.on({
			destroy: {
				fn: i_self.removeApplication,
				scope: i_self
			}
		});

		Ext.suspendLayouts();

		var i_active = i_self.add(i_item);

		Ext.resumeLayouts(true);

		i_self.setActiveItem(i_active);

		i_active.tab.tt = Ext.create("Ext.tip.ToolTip", {
			target: i_active.tab.getEl(),
			html: "",
			anchor: true,
			defealtAlign: "b50-t50",
			showDelay: 10,
			listeners: {
				beforeshow: {
					fn: function (i_tip) {

						var i_collection = i_self.items.getRange();

						var n_index = i_collection.indexOf(i_item);

						if (n_index > - 1) {
							i_tip.update("Alt + " + (n_index + 1));
						}
						else {
							return false;
						}

					}
				}
			}
		});

		i_active.tab.on({
			dblclick: {
				element: "el",
				fn: function (i_event) {
					i_self.fireEvent("toWindow", i_item);
				}
			}
		});
	},

	removeApplication: function(i_component) {

		var i_self = this;
		var i_applications = i_self.getApplications();

		var o_application = Ext.Array.findBy(i_applications.getRange(), function (o_config) {

			return o_config.active == i_component ? o_config : false;
		});

		if (o_application) {
			i_applications.removeByKey(o_application.id);
		}
	},

	removeFromWindow: function(i_component) {

		var i_window = i_component.up("window");

		if (i_window) {
			i_window.close();
		}
	}

});
if (!Ext.ClassManager.isCreated("Portfolio.menu.model.System")) {
	Ext.define("Portfolio.menu.model.System", {
		extend: "Ext.data.Model",

		alternateClassName: [
			"treeMenu"
		],

		fields: [
			{
				name: "id"
			},
			{
				name: "rrn",
				type: "int"
			},
			{
				name: "type"
			},
			{
				name: "system",
				type: "int"
			},
			{
				name: "applicationGroup",
				type: "int"
			},
			{
				name: "application",
				type: "int"
			},
			{
				name: "text"
			},
			{
				name: "url"
			},
			{
				name: "iconCls"
			},
			{
				name: "leaf",
				type: "boolean"
			},
			{
				name: "expanded",
				type: "boolean"
			}
		],
		idProperty: "id"
	});
}
Ext.define("Portfolio.menu.view.System", {

	xtype: "portfolio-menu-system",

	extend: "Ext.panel.Panel",

	requires: [
		"Portfolio.menu.model.System"
	],

	config: {
		system: null,
		tree: null,
		keyBinding: null
	},

	tools: [{
		type: "refresh",
		handler: function (i_event, i_element, i_header) {

			var i_panel = i_header.up("portfolio-menu-system");
			i_panel.doReload();
		}
	}],

	listeners: {
		afterrender: {
			fn: function(i_panel) {

				if (!i_panel.collapsed) {
					i_panel.doReload();
				}
			},
			single: true
		},
		beforeexpand: {
			fn: function(i_panel) {

				var i_tree = i_panel.getTree();
				var i_store = i_tree.getStore();

				if (!i_store.isLoaded()) {
					i_panel.doReload();
				}
			},
			single: true
		},
		shortcut: {
			fn: function() {
				var i_self = this;
				i_self.doShortCut();
			}
		}
	},

	ui: "menu-navigation",

	initComponent: function() {

		var i_self = this;
		i_self.store = i_self.createStore();
		i_self.callParent(arguments);

		i_self.add(i_self.createTree());

		i_self.enableBubble("startapplication");

		return i_self;
	},

	createTree: function () {

		var i_self = this;
		var i_user = Portfolio.util.Handler.getUser();
		var i_store = i_self.createStore();

		var o_config = i_self.getSystem() || {};

		var i_tree = Ext.widget("treepanel", {
			useArrows: true,
			singleExpand: false,
			border: false,
			animate: false,
			rootVisible: false,
			store: i_store,
			viewConfig: {
				plugins: {
					copy: true,
					ptype: "treeviewdragdrop",
					enableDrag: true,
					enableDrop: false,
					dragGroup: "tree2fav"
				}
			},
			listeners: {
				load: {
					fn: function(i_store, a_records) {

						var i_tree = i_self.getTree();

						i_tree.setLoading(false);

						var i_root = i_tree.getRootNode();

						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();

						var i_select;

						var a_bindings = [];

						if (o_extraParams.hasOwnProperty("search")) {

							if (o_extraParams.search) {

								i_select = i_root.findChildBy(function(i_record) {
									return i_record.isLeaf();
								}, i_tree, true);
							}
						}

						if (i_select) {
							i_tree.view.select(i_select, false, true);
							i_tree.view.focusNode(i_select, 10);
						}

						Ext.Array.each(a_records, function(i_record) {

							if (i_record.isLeaf()) {

								var o_properties = i_record.get("properties") || {};
								var o_binding = o_properties.binding;
								var b_execute = i_record.get("execute") || false;

								if (o_binding && o_binding.keyCode) {
									o_binding.record = i_record;

									a_bindings.push(o_binding);
								}

								if (b_execute) {
									i_self.fireEvent("startapplication", i_self, i_record);
								}

							}
						});

						i_self.addBindings(a_bindings);
					}
				},
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_tree = i_self.getTree();
						i_tree.setLoading();

						var n_system = o_config.system || o_config.id;

						var i_node = i_operation.node;
						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();

						delete o_extraParams.system;

						if (!i_node.isRoot()) {
							delete o_extraParams.search;
						}

						var s_loader = i_node.get("url");

						if (i_node.isRoot()) {
							s_loader = o_config.url;
						}

						if (!s_loader) {
							i_proxy.setUrl("/ip2-services/ip2transaction.aspx");

							Ext.apply(o_extraParams, {
								action: "ip2NavProxy.listMenuNodes",
								language: i_user.get("USRLNG") || "en",
								userToken: i_user.get("USRUSRTKN")
							});
							if (i_node.isRoot()) {
								Ext.apply(o_extraParams, {
									system: n_system
								});
							}
						}
						else {

							Ext.apply(o_extraParams, {
								system: n_system,
								language: i_user.get("USRLNG") || "en",
								userToken: i_user.get("USRUSRTKN")
							});

							i_proxy.setUrl(s_loader);
						}
					}
				},
				itemclick: {
					fn: function(i_view, i_record) {

						if (i_record.isLeaf()) {
							i_self.fireEvent("startapplication", i_self, i_record);
						}
						else {
							i_record.expand();
						}
					}
				},
				itemcontextmenu: {
					fn: function(i_tree, i_node, i_element, n_index, i_event) {

						var i_menu;
						var a_items = [];

						i_event.preventDefault();

						var a_xy = i_event.getXY();

						if (!i_node.isLeaf()) {

							var i_refresh = Ext.widget("menuitem", {
								iconCls: "pf-refresh",
								text: ip2.i18n({
									da: "Oprisk",
									en: "Refresh"
								}),
								parent: i_node,
								handler: function(button) {

									if (i_node) {

										if (i_node.get("loaded")) {
											i_node.collapse();
											i_node.removeAll(false);

											i_store.load({
												node: i_node,
												callback: function(a_records, i_store) {
													i_node.expand();
												}
											});
										}
										else {
											i_node.expand();
										}
									}
								}
							});

							a_items.push(i_refresh);
						}
						else {
							var i_open = Ext.widget("menuitem", {
								iconCls: "pf-gearwheel",
								text: ip2.i18n({
									da: "Åben ny",
									en: "Open new"
								}),
								handler: function(button) {

									i_node.set("force", true);

									i_self.fireEvent("startapplication", i_self, i_node);

									i_node.set("force", null);
								}
							});

							a_items.push(i_open);
						}

						if (a_items.length > 0) {
							i_menu = Ext.widget("menu", {
								items: a_items
							});
							i_menu.showAt(a_xy[0], a_xy[1]);
						}
					}
				}
			}
		});

		i_self.setTree(i_tree);

		if (o_config.searchable) {

			var i_toolbar = Ext.widget("toolbar", {
				dock: "top",
				layout: "fit",
				items: [
					{
						xtype: "searchfield",
						store: i_store,
						allowSort: false
					}
				]
			});

			i_tree.addDocked(i_toolbar);
		}

		return i_tree;
	},

	createStore: function() {

		var i_self = this;

		var i_store = Ext.create("Ext.data.TreeStore", {
			autoLoad: false,
			model: "Portfolio.menu.model.System",
			proxy: {
				type: "ajax",
				url: "/ip2-services/ip2transaction.aspx",
				paramsAsJson: true,
				reader: {
					type: "json",
					totalProperty: "totalRows"
				},
				timeout: (( 5 * 60) * 1000),
				actionMethods: {
					read: "POST"
				}
			},
			listeners: {
				load: {
					fn: function(i_store, a_records) {

						var i_tree = i_self.getTree();
						var i_view = i_tree.getView();

						Ext.Array.each(a_records, function(i_node) {

							var s_text = "";

							var title = i_node.get("title") || i_node.get("text");

							if (Ext.isObject(title)) {
								s_text = ip2.i18n(title);
							}
							else {
								s_text = title;
							}

							i_node.set("text", s_text);

							var s_icon = i_node.get("icon");

							if (s_icon === "null") {
								i_node.set("icon", null);
							}

							if (i_node.parentNode && i_node.parentNode.isRoot()) {
								var o_data = i_node.getData();

								if (!o_data.hasOwnProperty("collapsed")) {
									if (!i_node.isLeaf()) {
										if (!i_node.get("expanded")) {
											i_node.expand();
										}
										else {
											i_node.collapse();
											i_node.expand();
										}
									}
								}
								else {
									if (!i_node.get("collapsed")) {
										if (!i_node.get("expanded")) {
											i_node.expand();
										}
										else {
											i_node.collapse();
											i_node.expand();
										}
									}
								}
							}

							i_node.commit();
						});

						i_view.refresh();
					}
				}
			}
		});

		return i_store;
	},

	doReload: function() {

		var i_self = this;

		var i_keyBinding = i_self.getKeyBinding();

		if (i_keyBinding) {

			var a_bindings = i_keyBinding.bindings;

			Ext.Array.each(a_bindings, function(i_binding) {
				i_keyBinding.removeBinding(i_binding);
			});
		}

		var i_tree = i_self.getTree();

		var i_store = i_tree.getStore();

		var i_root = i_tree.getRootNode();

		i_root.collapse();
		i_root.removeAll(false);

		i_store.load({
			node: i_root,
			callback: function(a_records, i_store) {
				i_root.expand();
			}
		});
	},

	addBindings: function(a_bindings) {

		var i_self = this;

		var i_keyBinding = i_self.getKeyBinding();

		if (i_keyBinding) {

			var a_processed = i_keyBinding.bindings || [];

			var a_add = [];

			Ext.Array.each(a_bindings, function(o_config) {

				var i_found = Ext.Array.findBy(a_processed, function(i_binding) {

					var i_return;
					if (o_config.keyCode == i_binding.key) {

						if (o_config.alt == i_binding.altKey) {

							if (o_config.ctrl == i_binding.ctrlKey) {

								if (o_config.shift == i_binding.shift) {

									i_return = i_binding;
								}
							}
						}
					}
					return i_return;
				});

				if (!i_found) {
					a_add.push(o_config);
				}
			});

			Ext.Array.each(a_add, function(o_config) {

				var i_record = o_config.record;
				delete o_config.record;

				var o_binding = {
					alt: o_config.alt,
					ctrl: o_config.ctrl,
					key: o_config.keyCode,
					handler: function(n_key, i_event) {

						i_event.stopEvent();
						i_self.fireEvent("startapplication", i_self, i_record);
					}
				};

				i_keyBinding.addBinding(o_binding);
			});
		}
		else {

			var a_result = [];

			Ext.Array.each(a_bindings, function(o_config) {

				var i_record = o_config.record;

				delete o_config.record;

				var o_binding = {
					alt: o_config.alt,
					ctrl: o_config.ctrl,
					key: o_config.keyCode,
					handler: function(n_key, i_event) {

						i_event.stopEvent();

						i_self.fireEvent("startapplication", i_self, i_record);
					}
				};

				a_result.push(o_binding);
			});

			var i_keyMap = Ext.create("Ext.util.KeyMap", {
				target: Ext.getDoc().el,
				binding: a_result
			});

			i_self.setKeyBinding(i_keyMap);
		}
	},

	doShortCut: function() {

		var i_self = this;

		var i_tree = i_self.getTree();

		if (i_tree) {

			var i_root = i_tree.getRootNode();
			var i_store = i_tree.getStore();

			var i_searchfield = i_tree.down("searchfield");

			if (i_searchfield) {

				i_searchfield.focus(10, true);
			}
			else {
				if (!i_store.isLoaded()) {

					i_store.on({
						load: {
							fn: function (i_store, a_records) {

								var i_select = i_root.findChildBy(function (i_record) {
									return !i_record.isRoot();
								}, i_tree, true);

								if (i_select) {
									i_tree.view.select(i_select, false, true);
									i_tree.view.focusNode(i_select, 10);
								}
							},
							singel: true
						}
					});
				}
				else {
					var i_select = i_root.findChildBy(function (i_record) {
						return !i_record.isRoot();
					}, i_tree, true);

					if (i_select) {
						i_tree.view.select(i_select, false, true);
						i_tree.view.focusNode(i_select, 10);
					}
				}
			}
		}
	}
});
Ext.define("Portfolio.menu.view.Favorite", {

	xtype: "portfolio-menu-favorite",

	extend: "Ext.panel.Panel",

	config: {
		systemId: "",
		tree: null
	},

	layout: "anchor",
	floatable: false,

	ui: "menu-navigation",

	initComponent: function() {

		var i_self = this;

		i_self.callParent();

		var s_id = ip2.baseconfig.session.preset.origin;

		i_self.setSystemId(s_id);

		var o_global = Portfolio.util.Handler.global.get(s_id + ".favorites-settings", {
		});

		var o_settings = Portfolio.util.Handler.profile.get(s_id + ".favorites-settings", {
		});

		var s_title = ip2.i18n(o_global.title || {
			da: "Favoritter",
			en: "Favorites"
		});

		i_self.setTitle(s_title);

		i_self.add(i_self.createTree());

		i_self.initKeyEvents(o_global);
	},

	createTree: function() {

		var i_self = this;

		var s_id = i_self.getSystemId();

		var i_store = Ext.create("Ext.data.TreeStore", {
			model: "treeMenu",
			proxy: {
				type: "memory"
			},
			data: []
		});

		var i_tree = Ext.create("Ext.tree.TreePanel", {
			useArrows: true,
			border: false,
			animate: false,
			rootVisible: false,
			anchor: "100% 100%",
			frame: false,
			store: i_store,
			viewConfig: {
				plugins: {
					ptype: "treeviewdragdrop",
					enableDrag: true,
					enableDrop: true,
					dropGroup: "tree2fav",
					dragGroup: "tree2fav",
					allowContainerDrops: true,
					appendOnly: false,
					dropZone: {

						isValidDropPoint: function(i_node, s_position, i_dragZone, i_event, o_data) {

							var i_view = this;
							var a_records = o_data.records;
							var b_allowed = true;

							Ext.Array.each(a_records, function(i_record) {
								if (!i_record.isLeaf()) {
									b_allowed = false;
								}
							});

							if (b_allowed && i_view.id != o_data.view.id) {

								var o_favorites = Portfolio.util.Handler.profile.get(s_id + ".favorites", {
									nodes: []
								});

								Ext.Array.each(o_favorites.nodes, function(o_record) {
									Ext.Array.each(a_records, function(i_record) {
										if (i_record.get("id") == o_record.id) {
											b_allowed = false;
										}
									});
								});
							}

							return b_allowed;
						},

						onContainerOver: function(i_target, i_event, o_data) {

							var i_dragdrop = this;
							var a_records = o_data.records;
							var b_allowed = true;

							Ext.Array.each(a_records, function(i_record) {
								if (!i_record.isLeaf()) {
									b_allowed = false;
								}
							});

							if (b_allowed && i_dragdrop.id != o_data.view.id) {

								var o_favorites = Portfolio.util.Handler.profile.get(s_id + ".favorites", {
									nodes: []
								});

								Ext.Array.each(o_favorites.nodes, function(o_record) {
									Ext.Array.each(a_records, function(i_record) {
										if (i_record.get("id") == o_record.id) {
											b_allowed = false;
										}
									});
								});
							}
							return b_allowed ? i_dragdrop.dropAllowed : i_event.getTarget("." + i_dragdrop.indicatorCls) ? i_dragdrop.currentCls : i_dragdrop.dropNotAllowed;
						},

						onContainerDrop: function(i_dragZone, i_event, o_data) {

							var i_dragdrop = this;
							var a_records = o_data.records;
							var b_allowed = true;

							Ext.Array.each(a_records, function(i_record) {
								if (!i_record.isLeaf()) {
									b_allowed = false;
								}
							});

							if (b_allowed && i_dragdrop.id != o_data.view.id) {

								var o_favorites = Portfolio.util.Handler.profile.get(s_id + ".favorites", {
									nodes: []
								});

								Ext.Array.each(o_favorites.nodes, function(o_record) {
									Ext.Array.each(a_records, function(i_record) {
										if (i_record.get("id") == o_record.id) {
											b_allowed = false;
										}
									});
								});
							}

							if (i_dragdrop.allowContainerDrops && b_allowed) {
								i_dragdrop.valid = true;
								i_dragdrop.currentPosition = "append";
								i_dragdrop.overRecord = this.view.store.getRoot();
								i_dragdrop.onNodeDrop(i_dragdrop.overRecord, i_dragZone, i_event, o_data);
							}
							return b_allowed;
						}
					}
				},
				listeners: {
					beforedrop: {
						fn: function(i_node, o_data, i_overModel, s_dropPosition, f_dropHandler, i_event) {

							var i_view = this;

							var o_favorites = Portfolio.util.Handler.profile.get(s_id + ".favorites", {
								nodes: []
							});

							var b_found = false;
							var a_records = o_data.records;

							o_data.copy = true;

							Ext.Array.each(o_favorites.nodes, function(o_record) {

								Ext.Array.each(a_records, function(i_record) {

									if (i_record.get("id") == o_record.id) {
										b_found = true;
										o_data.copy = false;
										return false;
									}
								});

								if (b_found) {
									return false;
								}
							});
						}
					},
					drop: {
						fn: function(i_node, o_data, i_overModel, s_posistion) {

							var a_records = o_data.records;
							i_self.doSave(a_records, i_overModel, s_posistion);
						}
					}
				}
			},
			listeners: {
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_node = i_operation.node;

						if (i_node.get("type")) {

							var i_proxy = i_store.getProxy();
							var o_extraParams = i_proxy.getExtraParams();

							Ext.apply(o_extraParams, {
								url: "/ip2-services/ip2navigator.aspx?func=getAccordionMenu",
								type: i_node.get("type"),
								system: i_node.get("system"),
								applicationGroup: i_node.get("applicationGroup"),
								application: i_node.get("application")
							});
						}
					}
				},
				itemcontextmenu: {
					fn: function(i_tree, i_node, i_element, n_index, i_event) {

						i_event.stopEvent();

						if (!i_node.isRoot()) {

							var a_items = [];

							var i_open = Ext.widget("menuitem", {
								iconCls: "pf-gearwheel",
								text: ip2.i18n({
									da: "Åben ny",
									en: "Open new"
								}),
								handler: function(i_button) {

									i_node.set("force", true);

									Portfolio.app.fireEvent("startapplication", i_node);

									i_node.set("force", null);
								}
							});

							var i_delete = Ext.widget("menuitem", {
								iconCls: "pf-delete",
								text: ip2.i18n({
									da: "Slet",
									en: "Delete"
								}),
								handler: function(i_button) {

									if (i_node) {

										var i_parent = i_node.parentNode;

										i_self.doDelete(i_node, function(a_nodes) {

											i_parent.removeAll(false);

											if (a_nodes.length) {

												i_parent.appendChild(a_nodes);
												i_parent.expand();
											}
										});
									}
								}
							});

							a_items.push(i_open);
							a_items.push(i_delete);

							var i_menu = Ext.widget("menu", {
								items: a_items
							});

							i_menu.showAt(i_event.getXY());
						}
					}
				},
				itemclick: {
					fn: function (i_view, i_node, i_element, n_index, i_event) {

						if (!i_node.isRoot()) {
							Portfolio.app.fireEvent("startapplication", i_node);
						}
					}
				}
			}
		});

		var i_root = i_tree.getRootNode();
		i_root.appendChild(i_self.getData());

		i_self.setTree(i_tree);

		return i_tree;
	},

	doSave: function(a_records, i_overModel, s_posistion) {

		var i_self = this;
		var s_id = i_self.getSystemId();

		var o_favorites = Portfolio.util.Handler.profile.get(s_id + ".favorites", {
			nodes: []
		});

		var b_found = false;
		var n_index = 0;
		var o_record;

		if (i_overModel.isRoot()) {

			Ext.Array.each(o_favorites.nodes, function(o_record) {

				Ext.Array.each(a_records, function(i_record) {

					if (i_record.get("id") == o_record.id) {
						b_found = true;
						return false;
					}
					n_index++;
				});

				if (b_found) {
					return false;
				}
			});

			if (b_found) {
				o_record = o_favorites.nodes.splice(n_index, 1)[0];
				o_favorites.nodes.push(o_record);
			}
			else {
				Ext.Array.each(a_records, function(i_record) {
					var o_record = i_record.getData();
					o_favorites.nodes.push(o_record);
				});
			}
		}
		else {

			var n_recordIndex = 0;
			var b_recordFound = false;

			Ext.Array.each(o_favorites.nodes, function(o_record) {
				if (i_overModel.get("id") == o_record.id) {
					b_found = true;
					return false;
				}
				n_index++;
			});

			Ext.Array.each(o_favorites.nodes, function(o_record) {
				Ext.Array.each(a_records, function(i_record) {
					if (i_record.get("id") == o_record.id) {
						b_recordFound = true;
						return false;
					}
					n_recordIndex++;
				});

				if (b_recordFound) {
					return false;
				}
			});

			if (!b_found && !b_recordFound) {
				Ext.Array.each(a_records, function(i_record) {
					var o_data = i_record.data;
					o_favorites.nodes.push(o_data);
				});
			}
			else {
				if (s_posistion == "after") {

					if (b_recordFound) {

						n_insert = n_index;
						o_record = o_favorites.nodes.splice(n_recordIndex, 1)[0];
						o_favorites.nodes.splice(n_insert, 0, o_record);
					}
					else {

						n_insert = n_index;

						Ext.Array.each(a_records, function(i_record) {
							var o_record = i_record.data;
							o_favorites.nodes.splice(n_insert, 0, o_record);
						});
					}
				}
				else {
					if (n_index !== 0) {

						if (b_recordFound) {

							n_insert = n_index;
							o_record = o_favorites.nodes.splice(n_recordIndex, 1)[0];
							o_favorites.nodes.splice(n_insert, 0, o_record);
						}
						else {

							n_insert = n_index;

							Ext.Array.each(a_records, function(i_record) {

								var o_record = i_record.data;
								o_favorites.nodes.splice(n_insert, 0, o_record);
							});
						}
					}
					else {

						if (b_recordFound) {

							o_record = o_favorites.nodes.splice(n_recordIndex, 1)[0];
							o_favorites.nodes.unshift(o_record);
						}
						else {

							Ext.Array.each(a_records, function(i_record) {
								var o_record = i_record.data;
								o_favorites.nodes.unshift(o_record);
							});
						}
					}
				}
			}
		}

		Portfolio.util.Handler.profile.set(s_id + ".favorites", Ext.encode(o_favorites));

		return o_favorites;
	},

	doDelete: function(i_node, f_callback) {

		var i_self = this;
		var s_id = i_self.getSystemId();

		var o_favorites = Portfolio.util.Handler.profile.get(s_id + ".favorites", {
			nodes: [],
			title: "",
			binding: {
				alt: false,
				ctrl: false,
				shift: false,
				key: null
			}
		});

		var b_found = false;
		var n_index = 0;

		Ext.Array.each(o_favorites.nodes, function(o_record) {
			if (o_record.id == i_node.get("id")) {
				b_found = true;
				return false;
			}
			n_index++;
		});

		if (b_found) {
			o_favorites.nodes.splice(n_index, 1);
		}

		Portfolio.util.Handler.profile.set(s_id + ".favorites", Ext.encode(o_favorites), function() {
			var a_nodes = i_self.getData();
			f_callback(a_nodes);
		});
	},

	getData: function() {

		var i_self = this;

		var s_id = i_self.getSystemId();

		var o_favorites = Portfolio.util.Handler.profile.get(s_id + ".favorites", {
			nodes: []
		});

		Ext.applyIf(o_favorites, {
			nodes: []
		});

		return o_favorites.nodes;
	},

	getApplication: function(i_node, b_force) {

		var i_model = ip2.getModel({
			dmd: "dmd/portfolio.dmd",
			entity: "NAVMNUET00",
			context: "form",
			view: "portfolio"
		});

		b_force = b_force || false;

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			params: {
				action: "getRow",
				context: "form",
				dmdFile: "dmd/portfolio.dmd",
				uiName: "portfolio",
				model: "NAVMNUET00",
				where: i_model.idProperty + " = " + i_node.get("id")
			},
			success: function (i_response) {

				var o_result = Ext.decode(i_response.responseText, true) || {
					success: false,
					rows: [{}]
				};

				if (!o_result.rows) {
					o_result.rows = [{}];
				}

				var o_data = o_result.rows[0];

				var i_created = i_model.create(o_data);

				var o_values = Ext.decode(i_created.get("MNUPROP", true));

				if (o_values) {
					o_values.force = b_force;
					Portfolio.util.Handler.addTab(o_values);
				}
			},
			failure: function() {}
		});
	},

	initKeyEvents: function(o_settings) {

		var i_self = this;

		var i_tree = i_self.getTree();
		var i_root = i_tree.getRootNode();

		var o_binding = o_settings.binding || {};

		if (o_binding.keyCode) {

			var i_keyMap = Ext.create("Ext.util.KeyMap", {
				target: Ext.getDoc().el,
				binding: [
					{
						alt: o_binding.alt,
						ctrl: o_binding.ctrl,
						shift: o_binding.shift,
						key: o_binding.keyCode,
						handler: function(n_key, i_event) {

							i_event.stopEvent();

							var i_store = i_tree.getStore();

							if (!i_store.isLoaded()) {

								i_store.on({
									load: {
										fn: function(i_store, a_records) {

											var i_select = i_root.findChildBy(function(i_record) {
												return !i_record.isRoot();
											}, i_tree, true);

											if (i_select) {
												i_tree.view.select(i_select, false, true);
												i_tree.view.focusNode(i_select, 10);
											}
										},
										singel: true
									}
								});
							}
							else {
								var i_select = i_root.findChildBy(function(i_record) {
									return !i_record.isRoot();
								}, i_tree, true);

								if (i_select) {
									i_tree.view.select(i_select, false, true);
									i_tree.view.focusNode(i_select, 10);
								}
							}
						}
					}
				]
			});
		}
	}
});
Ext.define("Portfolio.menu.view.Main", {

	xtype: "portfolio-menu",

	extend: "Ext.panel.Panel",

	layout: {
		type: "vbox",
		align: "stretch"
	},

	border: false,
	bodyBorder: false,

	config: {
		systemArea: null,
		favoriteArea: null
	},

	requires: [
		"Portfolio.menu.view.System",
		"Portfolio.menu.view.Favorite"
	],

	listeners: {
		systemActivate: {
			fn: function(s_itemId) {

				var i_self = this;
				var i_system = i_self.down("#" + s_itemId);
				var i_systemArea = i_self.getSystemArea();

				if(i_system) {
					i_systemArea.setActiveItem(i_system);
				}
			}
		},
		aftershortcut: {
			fn: function(s_itemId) {

				var i_self = this;
				var i_system = i_self.down("#" + s_itemId);
				var i_systemArea = i_self.getSystemArea();

				if (i_system) {
					i_systemArea.setActiveItem(i_system);
					i_system.fireEvent("shortcut");
				}
			}
		}
	},

	ui: "menu-navigation",

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		i_self.add([
			i_self.createFavoriteArea(),
			i_self.createSystemArea()
		]);

		i_self.loadSystems();

		i_self.enableBubble([
			"startapplication",
			"systemAdded",
			"systemShortcut"
		]);

		return i_self;
	},

	createSystemArea: function() {

		var i_self = this;

		var i_panel = Ext.widget("panel", {
			layout: "card",
			flex: 3,
			border: false
		});

		i_self.setSystemArea(i_panel);

		return i_panel;
	},

	createFavoriteArea: function() {

		var i_self = this;

		var i_favorites = Ext.widget("portfolio-menu-favorite", {
			flex: 1,
			collapsible: true,
			collapsed: false,
			border: false,
			bodyBorder: false,
			split: true
		});

		i_self.setFavoriteArea(i_favorites);

		return i_favorites;
	},

	loadSystems: function() {

		var i_self = this;
		var i_user = Portfolio.util.Handler.getUser();
		var a_items = [];

		var i_systemArea = i_self.getSystemArea();

		var s_token = i_user.get(i_user.idProperty);
		var s_url = "/ip2-services/ip2transaction.aspx";

		Ext.Ajax.request({
			url: s_url,
			jsonData: {
				language: i_user.get("USRLNG") || "en",
				usertoken: s_token,
				action: "ip2NavProxy.listMenuNodes",
				node: "root"
			},
			actionMethods: {
				read: "POST"
			},
			success: function (o_result) {

				var a_systems = Ext.decode(o_result.responseText, true) || [];

				var a_bindings = [];
				var a_tabs = [];

				Ext.Array.each(a_systems, function(o_config, n_index) {

					var i_system;

					var s_title;

					var title = o_config.text || o_config.title;

					var o_properties = o_config.properties || {};

					var o_binding = o_properties.binding;

					if (Ext.isObject(title)) {
						s_title = ip2.i18n(title);
					}
					else {
						s_title = title;
					}

					try {
						if (!/\.(js|widget)/.test(o_config.url)) {

							i_system = Ext.widget("portfolio-menu-system", {
								title: s_title,
								layout: "fit",
								system: o_config,
								border: false,
								bodyBorder: false,
								itemId: "system-" + n_index,
							});
						}
						else {

							i_system = Portfolio.util.Handler.callWidget(o_config);
						}

						if (i_system) {

							i_system.setTitle(s_title);

							i_system.enableBubble("startapplication");

							a_tabs.push({
								title: s_title,
								itemId: "system-" + n_index,
								first: n_index === 0,
								binding: o_binding
							});

							a_items.push(i_system);
						}

						if (o_binding && o_binding.keyCode) {

							o_binding.panel = i_system;

							a_bindings.push(o_binding);
						}
					}
					catch (o_error) {

						// TEST FOR LEGACY
						if (!/(ip2Base\/)/.test(o_config.url)) {

							s_title = ip2.i18n({
								da: s_title + " kunne ikke indlæses",
								en: s_title + " could not be loaded"
							});

							Portfolio.util.Message.Add(s_title, {
								message: o_error.message,
								params: o_config
							}, "js");
						}
						else {

							if (!/\.(js|widget)/.test(o_config.url)) {

								s_title = ip2.i18n({
									da: s_title + " kunne ikke indlæses",
									en: s_title + " could not be loaded"
								});

								Portfolio.util.Message.Add(s_title, {
									message: o_error.message,
									params: o_config
								}, "js");
							}
						}
					}
				});

				i_systemArea.add(a_items);

				i_self.initKeys(a_bindings);

				i_self.fireEvent("systemAdded", a_tabs);
			}
		});
	},

	initKeys: function(a_bindings) {

		var i_self = this;

		var a_result = [];

		Ext.Array.each(a_bindings, function(o_config) {

			var i_panel = o_config.panel;

			var o_binding = {
				alt: o_config.alt,
				ctrl: o_config.ctrl,
				key: o_config.keyCode,
				handler: function(n_key, i_event) {

					i_event.stopEvent();
					i_self.fireEvent("systemShortcut", i_panel.itemId);
				}
			};

			a_result.push(o_binding);
		});

		var i_keyMap = Ext.create("Ext.util.KeyMap", {
			target: Ext.getDoc().el,
			binding: a_result
		});
	}
});
Ext.define("Portfolio.menu.form.Link", {

    xtype: "portfolio-menu-form-link",

    extend: "Ext.form.Panel",

    layout: "fit",

    config: {
        tabPanel: null,
        content: null,
        rolePanel: null
    },

    trackResetOnLoad: true,

    requires: [
        "Portfolio.ux.navigation.controller.UserRole",
        "Portfolio.ux.navigation.view.UserRolePanel",
        "Portfolio.ux.form.field.BindingField"
    ],

    initComponent: function() {

        var i_self = this;
        
        i_self.callParent(arguments);

        i_self.add(i_self.createLayout());

        i_self.loadRecord(i_self.record);
    },

    createLayout: function() {

        var i_self = this;

        var i_tabpanel = Ext.widget("tabpanel", {
            layout: "fit",
            defaults: {
				iconAlign: "right"
			},
            items: [
                i_self.createContent(),
                i_self.createRoles()
            ]
        });

        i_self.setTabPanel(i_tabpanel);

        return i_tabpanel;
    },

    createContent: function() {

        var i_self = this;

        var i_panel = Ext.widget("panel", {
            title: ip2.i18n({
                da: "Indhold",
                en: "Content"
            }),
            layout: "anchor",
            autoScroll: true,
            bodyPadding: 10,
            defaults: {
                anchor: "100%",
                maxWidth: 800
            }
        });

        var a_items = [
            {
                xtype: "i18ntextfield",
                name: "title",
                allowBlank: false,
                fieldLabel: ip2.i18n({
                    da: "Titel",
                    en: "Titel"
                })
            },
            {
                xtype: "textfield",
                name: "url",
                regex: new RegExp("(https?|ftps?:\\/\\/)|^\\/\\w+.(?:\\w+|[\\/-])*(?:[-a-zA-Z0-9@:%_\\+.~#?&\/=]|\\/)*$"),
                fieldLabel: ip2.i18n({
                    da: "Url",
                    en: "Url"
                })
            },
            {
                xtype: "ux.form.field.iconpicker",
                name: "icon",
                fieldLabel: ip2.i18n({
                    da: "Ikon",
                    en: "Icon"
                })
            },
            {
                xtype: "checkbox",
                name: "searchable",
                fieldLabel: ip2.i18n({
                    da: "Søgebar",
                    en: "Searchable"
                })
            }
        ];

        var i_fieldSet = Ext.widget("fieldset", {
            title: "Info",
            items: a_items,
            layout: "anchor",
            collapsible: true,
            collapsed: false,
            defaults: {
                anchor: "100%",
                maxWidth: 800
            }
        });

        i_panel.add([
            i_fieldSet,
            {
                xtype: "portfolio-bindigfield",
                name: "binding",
                fieldLabel:  ip2.i18n({
                    da: "Genvejstast",
                    en: "Shortcut"
                })
            }
        ]);

        i_self.setContent(i_panel);

        return i_panel;
    },

    createRoles: function() {

        var i_self = this;

        var i_userpanel = Ext.widget("userrolepanel", {
            title: ip2.i18n({
                da: "Roller",
                en: "Roles"
            }),
            record: i_self.record,
            entity: "NAVMNUET00"
        });

        i_self.setRolePanel(i_userpanel);

        return i_userpanel;
    },

    isDirty: function() {

        var i_self = this;
        var b_dirty = i_self.callOverridden(arguments);

        if (!b_dirty) {

            var i_tabpanel = i_self.getTabPanel();
            var a_tabs = i_tabpanel.items.getRange();

            Ext.Array.each(a_tabs, function(i_panel) {

                var f_isDirty = i_panel.isDirty || Ext.emptyFn;

                if (i_panel.rendered && f_isDirty != Ext.emptyFn) {
                    b_dirty = f_isDirty();

                    if (b_dirty) {
                        return false;
                    }
                }
            });
        }

        return b_dirty;
    },

    doSave: function() {

        var i_self = this;

        var i_promise = new Ext.Promise(function(resolve, reject) {

            var i_tabpanel = i_self.getTabPanel();
            var a_items = i_tabpanel.items.getRange();
            var n_count = 0;

            var i_content = i_self.getContent();

            var o_values = {};

            var a_fields = i_self.getForm().getFields().getRange();

            Ext.Array.each(a_fields, function(i_field) {

                if (i_content.contains(i_field, true)) {
                    o_values[i_field.name] = i_field.getValue();
                }
            });
            
            Ext.Array.each(a_items, function(i_panel) {
                
                var i_controller = i_panel.getController();
                if (i_controller) {
                    if (i_controller.doSave) {
                        n_count++;
                        i_controller.doSave(function() {
                            n_count--;
                            if (n_count === 0) {
                                resolve(o_values);
                            }
                        });
                    }
                }
                else {
                    if (i_panel.doSave) {
                        n_count++;
                        i_panel.doSave(function() {
                            n_count--;
                            if (n_count === 0) {
                                resolve(o_values);
                            }
                        });
                    }
                }
            });

        });

        return i_promise;

    },

    updateNewRecord: function(i_record) {

        var i_self = this;

        var i_userpanel = i_self.getRolePanel();
        i_userpanel.record = i_record;

    }
    
});Ext.define("Portfolio.menu.form.App", {

    xtype: "portfolio-menu-form-app",

    extend: "Ext.form.Panel",

    layout: "fit",

    config: {
        tabPanel: null,
        content: null,
        rolePanel: null
    },

    trackResetOnLoad: true,

    requires: [
        "Portfolio.ux.navigation.controller.UserRole",
        "Portfolio.ux.navigation.view.UserRolePanel",
        "Portfolio.ux.form.field.BindingField"
    ],

    initComponent: function() {

        var i_self = this;
        
        i_self.callParent(arguments);

        i_self.add(i_self.createLayout());

        i_self.loadRecord(i_self.record);

    },

    createLayout: function() {

        var i_self = this;

        var i_tabpanel = Ext.widget("tabpanel", {
            layout: "fit",
            defaults: {
				iconAlign: "right"
			},
            items: [
                i_self.createContent(),
                i_self.createRoles()
            ]
        });

        i_self.setTabPanel(i_tabpanel);

        return i_tabpanel;
    },

    createContent: function() {

        var i_self = this;

        var i_panel = Ext.widget("panel", {
            title: ip2.i18n({
                da: "Indhold",
                en: "Content"
            }),
            layout: "anchor",
            autoScroll: true,
            bodyPadding: 10,
            defaults: {
                anchor: "100%",
                maxWidth: 800
            }
        });

        var a_items = [
            {
                xtype: "i18ntextfield",
                name: "title",
                allowBlank: false,
                fieldLabel: ip2.i18n({
                    da: "Titel",
                    en: "Titel"
                })
            },
            {
                xtype: "ux.form.field.iconpicker",
                name: "icon",
                fieldLabel: ip2.i18n({
                    da: "Ikon",
                    en: "Icon"
                })
            },
            {
                xtype: "textfield",
                name: "appName",
                allowBlank: false,
                regex: new RegExp("^\\w+(?:\\.\\w+)*$"),
                fieldLabel: ip2.i18n({
                    da: "App navn",
                    en: "App name"
                })
            },
            {
                xtype: "textfield",
                name: "appFolder",
                regex: new RegExp("^\\/\\w+.(?:\\w+|[\\/-])*(?:\\w+|\\/)$"),
                allowBlank: false,
                fieldLabel: ip2.i18n({
                    da: "App folder",
                    en: "App folder"
                })
            },
            {
                xtype: "textfield",
                name: "main",
                allowBlank: false,
                regex: new RegExp("^\\w+(?:\\.\\w+)*$"),
                fieldLabel: ip2.i18n({
                    da: "App Main",
                    en: "App Main"
                })
            },
            {
                xtype: "checkbox",
                name: "advance",
                fieldLabel: ip2.i18n({
                    da: "Advanceret",
                    en: "Advanced"
                }),
                listeners: {
                    change: {
                        fn: function(i_field, b_checked) {

                            var i_packages = i_self.getForm().findField("packages");
                            var i_requires = i_self.getForm().findField("requires");
                            var i_requiredScripts = i_self.getForm().findField("requiredScripts");
                            var i_appConfig = i_self.getForm().findField("appConfig");

                            if (i_packages) {
                                i_packages[b_checked ? "show": "hide"]();
                            }

                            if (i_requires) {
                                i_requires[b_checked ? "show": "hide"]();
                            }

                            if (i_requiredScripts) {
                                i_requiredScripts[b_checked ? "show": "hide"]();
                            }

                            if (i_appConfig) {
                                i_appConfig[b_checked ? "show": "hide"]();
                            }
                        }
                    }
                }
            },
            {
                xtype: "acetextareafield",
                name: "requires",
                asArray: true,
                hidden: true,
                fieldLabel: ip2.i18n({
                    da: "Nødvendige filer",
                    en: "Required files"
                })
            },
            {
                xtype: "acetextareafield",
                name: "requiredScripts",
                asArray: true,
                hidden: true,
                fieldLabel: ip2.i18n({
                    da: "Nødvendige scripts",
                    en: "Required scripts"
                })
            },
            {
                xtype: "acetextareafield",
                name: "packages",
                hidden: true,
                mode: "json",
                asJson: true,
                value: {},
                fieldLabel: ip2.i18n({
                    da: "Pakker",
                    en: "Packages"
                })
            },
            {
                xtype: "acetextareafield",
                name: "appConfig",
                hidden: true,
                mode: "json",
                asJson: true,
                value: {},
                fieldLabel: ip2.i18n({
                    da: "Config",
                    en: "Config"
                })
            }
        ];

        var i_fieldSet = Ext.widget("fieldset", {
            title: "Info",
            items: a_items,
            layout: "anchor",
            collapsible: true,
            collapsed: false,
            defaults: {
                anchor: "100%",
                maxWidth: 800
            }
        });

        i_panel.add([
            i_fieldSet,
            {
                xtype: "portfolio-bindigfield",
                name: "binding",
                fieldLabel:  ip2.i18n({
                    da: "Genvejstast",
                    en: "Shortcut"
                })
            }
        ]);

        i_self.setContent(i_panel);

        return i_panel;
    },

    createRoles: function() {

        var i_self = this;

        var i_userpanel = Ext.widget("userrolepanel", {
            title: ip2.i18n({
                da: "Roller",
                en: "Roles"
            }),
            record: i_self.record,
            entity: "NAVMNUET00"
        });

        i_self.setRolePanel(i_userpanel);

        return i_userpanel;
    },

    isDirty: function() {

        var i_self = this;
        var b_dirty = i_self.callOverridden(arguments);

        if (!b_dirty) {

            var i_tabpanel = i_self.getTabPanel();
            var a_tabs = i_tabpanel.items.getRange();

            Ext.Array.each(a_tabs, function(i_panel) {

                var f_isDirty = i_panel.isDirty || Ext.emptyFn;

                if (i_panel.rendered && f_isDirty != Ext.emptyFn) {
                    b_dirty = f_isDirty();

                    if (b_dirty) {
                        return false;
                    }
                }
            });
        }
        
        return b_dirty;
    },

    doSave: function() {

        var i_self = this;

        var i_promise = new Ext.Promise(function(resolve, reject) {

            var i_tabpanel = i_self.getTabPanel();
            var a_items = i_tabpanel.items.getRange();
            var n_count = 0;

            var i_content = i_self.getContent();

            var o_values = {};

            var a_fields = i_self.getForm().getFields().getRange();

            Ext.Array.each(a_fields, function(i_field) {

                if (i_content.contains(i_field, true)) {
                    o_values[i_field.name] = i_field.getValue();
                }
            });
            
            Ext.Array.each(a_items, function(i_panel) {
                
                var i_controller = i_panel.getController();
                if (i_controller) {
                    if (i_controller.doSave) {
                        n_count++;
                        i_controller.doSave(function() {
                            n_count--;
                            if (n_count === 0) {
                                resolve(o_values);
                            }
                        });
                    }
                }
                else {
                    if (i_panel.doSave) {
                        n_count++;
                        i_panel.doSave(function() {
                            n_count--;
                            if (n_count === 0) {
                                resolve(o_values);
                            }
                        });
                    }
                }
            });

        });

        return i_promise;

    },

    updateNewRecord: function(i_record) {

        var i_self = this;

        var i_userpanel = i_self.getRolePanel();
        i_userpanel.record = i_record;

    }
    
});Ext.define("Portfolio.menu.view.Editor", {

	xtype: "portfolio-menu-editor",

	extend: "Portfolio.entity.view.Tree",
	
	alias: [
		"widget.portfolio-menu-editor"
	],

	dmd: "dmd/portfolio.dmd",
	entity: "NAVMNUET00",
	viewName: "portfolio",
	context: "grid",
	parentID: "MNUPNTTKN",
	childID: "MNUMNUTKN",
	searchCombo: false,
	allowLink: false,
	allowExport: false,
	allowFilter: true,
	allowSearch: true,
	autoLoad: false,
	sequence: true,

	requires: [
		"Portfolio.menu.form.Link",
		"Portfolio.menu.form.App"
	],

	config: {
		recordStore: null
	},

	initComponent: function() {

		var i_self = this;

		var i_model = i_self.createModel();

		var i_root = i_model.create({
			MNUMNUTKN: 1,
			MNUPNTTKN: 0,
			MNUPROP_NAME: "...",
			MNUPROP_SEQ: 0,
			PROPERTIES: "{title: \"...\"}"
		});

		i_self.root = i_root;
		
		i_self.callParent(arguments);

		i_self.createRecordStore();

		var i_store = i_self.getStore();
		var i_proxy = i_store.getProxy();

		i_proxy.setUrl("/wsh-services/wshProxy.aspx");

		i_store.on({
			beforeload: {
				fn: function(i_store, i_operation) {

					var i_proxy = i_store.getProxy();
					var o_extraParams = i_proxy.getExtraParams();
					var i_node = i_operation.node;
					delete i_operation.node;

					Ext.apply(o_extraParams, {
						action: "treeStore",
						orderBy: "jsonGetNum(MNUPROP, 'seq')",
						parentidField: "MNUPNTTKN",
						propertiesField: "MNUPROP",
						entity: "NAVMNUET00",
						idField: "MNUMNUTKN",
						xpd: "navigation.xpd",
						dmd: "dmd/portfolio.dmd",
						displayCheckbox: false,
						node: i_node.get("ID")
					});

					delete o_extraParams.where;
				}
			},
			load: {
				fn: function(i_store, a_records) {

					var i_root = i_self.getRootNode();
					var n_count = 0;

					Ext.Array.each(a_records, function(i_record) {
						if (i_record.get("iconCls") == "webshop-parent-node") {
							i_record.set("iconCls", "pf-folder");
							i_record.commit();
						}
						if (i_record.get("iconCls") == "webshop-child-node") {
							i_record.set("iconCls", "pf-document_empty");
							i_record.commit();
						}
					});

					i_root.cascadeBy(function(i_node) {
						n_count++;
					});

					var i_options = i_self.getColumnManager().getHeaderByDataIndex("options");
					i_options.setText(n_count);
				}
			}
		});

		var a_columns = i_self.createColumns();

		i_self.reconfigure(null, a_columns);

		var i_rootNode = i_self.getRootNode();
		
		i_rootNode.set({
			allowDrag: false,
			allowDrop: true
		});

		i_rootNode.expand();

		i_self.events.itemcontextmenu.clearListeners();

		i_self.on({
			beforeitemdblclick: {
				fn: function(i_view, i_node, i_element, n_index, i_event) {
					i_self.editType(i_node);
					return false;
				}
			},
			itemcontextmenu: {
				fn: function(i_view, i_node, i_item, n_index, i_event) {

					i_event.preventDefault();

					var a_coords = i_event.getXY();
					var a_items = i_self.getMenuItems(i_node);

					var i_menu = Ext.widget("menu", {
						plain: true,
						items: a_items
					});

					i_menu.showAt(a_coords[0], a_coords[1]);
				}
			}
		});

	},

	createColumns: function() {

		var i_self = this;

		var a_columns = [
			{
				xtype: "treecolumn",
				header: "Folder",
				dataIndex: "TITLE",
				flex: 1,
				sortable: false,
				groupable: false,
				filterable: false,
				menuDisabled: true,
				renderer: function(value, i_node, i_record) {
		
					var o_properties = Ext.decode(i_record.get("PROPERTIES"), true) || {};
		
					if (Ext.isString(o_properties.title)) {
						if (o_properties.title.startsWith("{") && o_properties.title.endsWith("}")) {
							o_properties.title = Ext.decode(o_properties.title, true) || o_properties.title;
						}
					}
				
					return Ext.isObject(o_properties.title) ? ip2.i18n(o_properties.title) : o_properties.title;
				}
			},
			{
				header: "Url",
				dataIndex: "url",
				flex: 1,
				menuDisabled: true,
				sortable: false,
				filterable: false,
				renderer: function(value, i_node, i_record) {
	
					var o_properties = Ext.decode(i_record.get("PROPERTIES"), true) || {};
		
					return o_properties.url || o_properties.appFolder || "";
				}
			},
			{
				header: "Type",
				dataIndex: "text",
				flex: 1,
				align: "center",
				menuDisabled: true,
				sortable: false,
				filterable: false,
				renderer: function(value, i_node, i_record) {
		
					var s_text = value;
					var o_properties = Ext.decode(i_record.get("PROPERTIES"), true) || {};
		
					switch(o_properties.__cid__) {
						case 1:
							break;
						case 2:
							s_text = ip2.i18n({
								da: "Gruppe",
								en: "Group"
							});
							break;
						case 3:
							s_text = ip2.i18n({
								da: "Link",
								en: "Link"
							});
							break;
						case 4:
							s_text = ip2.i18n({
								da: "App",
								en: "App"
							});
							break;
					}
		
					return s_text;
				}
			},
			{
				xtype: "actioncolumn",
				align: "center",
				dataIndex: "options",
				menuDisabled: true,
				hideable: false,
				sortable: false,
				groupable: false,
				filterable: false,
				text: "0",
				items: [
					{
						xtype: "button",
						iconCls: "pf-options",
						width: 20,
						ui: "function-action",
						handler: function (i_tree, n_row, n_column, i_item, i_event, i_record, i_row) {
		
							var o_events = i_self.events || {
								itemcontextmenu: {}
							};
		
							var a_listeners = Ext.Array.from(o_events.itemcontextmenu.listeners);
		
							if (!Ext.isEmpty(a_listeners)) {
		
								var i_view = i_self.view;
								i_view.select(i_record);
		
								Ext.Array.each(a_listeners, function(i_listener) {
									i_listener.fn.call(i_self, i_view, i_record, i_row, n_row, i_event);
								});
							}
						}
					}
				]
			}
		];

		return a_columns;
	},

	createRecordStore: function() {

		var i_self = this;

		var s_view = i_self.getViewName();

		var i_model = i_self.createModel();

		var i_store = Ext.create("Ext.data.Store", {
			model: i_model,
			proxy: Portfolio.util.Handler.getProxyByEntity({
				dmd: i_self.getDmd(),
				entityName: i_self.getEntity(),
				uiName: i_self.getViewName(),
				context: "form"
			}),
			autoLoad: false,
			listeners: {
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();
						
						var i_selected = i_self.getSelectionModel().getSelection()[0];

						var o_keys = {};
						
						o_keys[i_model.idProperty] = i_selected.get("ID");

						Ext.apply(o_extraParams, {
							action: "getRow",
							context: "form",
							dmdFile: i_self.getDmd(),
							uiName: s_view,
							key: Ext.encode(o_keys)
						});
					}
				}
			}
		});
		
		i_self.setRecordStore(i_store);
	},

	getMenuItems: function(i_node) {

		var i_self = this;
		var i_store = i_self.getStore();

		var o_properties = Ext.decode(i_node.get("PROPERTIES"), true) || {};

		var a_items = [];

		if (o_properties.__cid__ == 2 || i_node.isRoot()) {

			var i_addItem = Ext.widget("menuitem", {
				text: ip2.i18n({
					da: "Tilføj",
					en: "Add"
				}),
				menu: {
					plain: true,
					items: [
						{
							xtype: "menuitem",
							text: ip2.i18n({
								da: "Gruppe",
								en: "Group"
							}),
							handler: function() {
								i_self.createType(i_node, 2);
							}
						},
						{
							xtype: "menuitem",
							text: ip2.i18n({
								da: "Link",
								en: "Link"
							}),
							handler: function() {
								i_self.createType(i_node, 3);
							}
						},
						{
							xtype: "menuitem",
							text: ip2.i18n({
								da: "App",
								en: "App"
							}),
							handler: function() {
								i_self.createType(i_node, 4);
							}
						}
					]
				}
			});

			a_items.push(i_addItem);
		}

		if (!i_node.isRoot()) {

			var i_editItem = Ext.widget("menuitem", {
				text: ip2.i18n({
					da: "Redigér",
					en: "Edit"
				}),
				handler: function() {
					
					i_self.editType(i_node);
				}
			});

			a_items.push(i_editItem);

			if (i_node.isLeaf()) {
				
				var i_copyItem = Ext.widget("menuitem", {
					text: ip2.i18n({
						da: "Kopier",
						en: "Copy"
					}),
					handler: function() {
						
						i_self.copyType(i_node);
					}
				});
	
				a_items.push(i_copyItem);
			}

			var i_deleteItem = Ext.widget("menuitem", {
				text: ip2.i18n({
					da: "Slet",
					en: "Delete"
				}),
				handler: function() {

					Portfolio.util.Handler.messageBox({
						icon: Ext.Msg.WARNING,
						message: Portfolio.util.Handler.i18n({
							da: "Vil du slette " + i_node.get("TITLE"),
							en: "Do you want to delete "+  i_node.get("TITLE") 
						}),
						yesText: Portfolio.util.Handler.i18n({
							da: "Ja",
							en: "Yes"
						}),
						yesFn: function () {
			
							var i_model = i_self.createModel();

							var i_created = i_model.create({});

							i_created.set(i_model.idProperty, i_node.get("ID"));
							
							var o_keys = {};

							i_self.setLoading(ip2.i18n({
								da: "Sletter...",
								en: "Deleting..."
							}));

							o_keys[i_created.idProperty] = i_created.get(i_created.idProperty);

							var o_batch = Ext.apply({}, {
								type: "delete",
								dmd: i_self.getDmd(),
								entity: i_self.getEntity(),
								key: o_keys
							});

							Ext.Ajax.request({
								url: "/ip2-services/ip2dmdProxy.aspx",
								jsonData: {
									batch: [
										o_batch
									]
								},
								success: function (i_response) {

									i_self.setLoading(false);
									
									var i_store = i_self.getStore();

									var i_parent = i_node.isRoot() ? i_node : i_node.parentNode;

									i_parent.collapse();
									i_parent.removeAll(false);
			
									i_store.read({
										node: i_parent,
										callback: function() {
											i_parent.expand();
										}
									});
								},
								failure: function() {
									i_self.setLoading(false);
								}
							});
						},
						noText: Portfolio.util.Handler.i18n({
							da: "Nej",
							en: "No"
						})
					});
				}
			});

			a_items.push(i_deleteItem);
		}

		if (o_properties.__cid__ == 2 || i_node.isRoot()) {

			var i_refresh = Ext.widget("menuitem", {
				text: ip2.i18n({
					da: "Genindlæs",
					en: "Refresh"
				}),
				handler: function() {
	
					var i_selected = i_self.getSelection()[0];
	
					i_selected.collapse();
					i_selected.removeAll(false);
	
					i_store.read({
						node: i_selected,
						callback: function(i_store) {
							i_selected.expand();
						}
					});
				}
			});

			a_items.push(i_refresh);
		}

		return a_items;
	   
	},

	createType: function(i_parent, n_type) {

		var i_self = this;

		n_type = n_type || 1;

		var s_main = "";

		var s_title = ip2.i18n({
			da: "Opret",
			en: "Create"
		});

		var a_title = [
			s_title
		];

		switch(n_type) {
			case 2:
				s_main = "portfolio-menu-form-link";
				a_title.push(ip2.i18n({
					da: "gruppe",
					en: "group"
				}));
				break;
			case 3:
				s_main = "portfolio-menu-form-link";
				a_title.push(ip2.i18n({
					da: "link",
					en: "link"
				}));
				break;
			case 4:
				s_main = "portfolio-menu-form-app";
				a_title.push(ip2.i18n({
					da: "app",
					en: "app"
				}));
				break;
		}

		var i_window = Portfolio.util.Handler.getWindow({
			title: a_title.join(" - "),
			layout: "fit",
			modal: true
		});

		var i_model = i_self.createModel();

		var i_created = i_model.create({});

		var i_panel = Ext.widget(s_main, {
			record: i_created
		});

		var i_toolbar = Ext.widget("toolbar", {
			dock: "bottom",
			ui: "footer",
			items: [
				"->",
				{
					xtype: "button",
					text: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					}),
					tabIndex: 1,
					focusable: true,
					itemId: "close",
					handler: function () {
						i_window.close();
					}
				},
				{
					xtype: "button",
					text: ip2.i18n({
						da: "Gem",
						en: "Save"
					}),
					itemId: "saveclose",
					ui: "primary-button",
					hidden: true,
					focusable: true,
					tabIndex: 1,
					handler: function (i_button) {
						i_window.fireEvent("save", i_panel);
					}
				}
			]
		});

		i_panel.on({
			dirtychange: {
				fn: function(i_form, b_dirty) {

					var b_valid = i_panel.isValid();
					var i_content = i_panel.getContent();

					if (b_valid) {

						var i_saveclose = i_toolbar.items.get("saveclose");

						i_saveclose[b_dirty ? "show" : "hide"]();

						i_content.setIconCls(b_dirty ? "x-dot" : "");

					}
				}
			},
			validitychange: {
				fn: function(i_form, b_valid){

					var i_content = i_panel.getContent();

					var i_saveclose = i_toolbar.items.get("saveclose");

					i_content.tab.removeCls("x-tab-error");

					if (!b_valid) {
						i_content.tab.addCls("x-tab-error");
						i_saveclose.hide();
					}
					else {
						var b_dirty = i_panel.isDirty();
						i_panel.fireEvent("dirtychange", i_panel, b_dirty);
					}
				}
			}
		});

		i_window.on({
			save: {
				fn: function(i_panel) {

					i_window.setLoading(ip2.i18n({
						da: "Gemmer..",
						en: "Saving..."
					}));

					i_created.set("MNUPNTTKN", i_parent.get("ID"));

					var i_promise = new Ext.Promise(function(f_resolve) {

						var o_keys = {};

						o_keys[i_created.idProperty] = null;

						var o_batch = Ext.apply({}, {
							type: "upsert",
							dmd: i_self.getDmd(),
							entity: i_self.getEntity(),
							transactiontype: i_self.getEntity(),
							key: o_keys,
							row: i_created.getData()
						});

						Ext.Ajax.request({
							url: "/ip2-services/ip2dmdProxy.aspx",
							jsonData: {
								batch: [
									o_batch
								]
							},
							success: function (i_response) {

								var o_result = Ext.decode(i_response.responseText, true) || {
									batch: [{
										rows: [{}]
									}]
								};

								var o_batch = o_result.batch[0];
								var o_row = o_batch.row || {};

								i_created.set(o_row);
								i_panel.updateNewRecord(i_created);
								f_resolve();
								
							}
						});
					}).then(function(){
						return i_panel.doSave();
					}).then(function(o_value) {

						var a_children = Ext.Array.from(i_parent.childNodes);

						var o_last = Ext.decode(i_parent.get("PROPERTIES"), true) || {};

						if (a_children.length > 0) {
							var i_last = a_children[a_children.length -1];
							o_last = Ext.decode(i_last.get("PROPERTIES"), true) || {};
						}

						var o_properties = Ext.apply({
							__cid__: n_type,
							seq: parseFloat(o_last.seq) + 1
						}, o_value);

						i_created.set("MNUPROP", Ext.encode(o_properties));

						var o_keys = {};

						o_keys[i_created.idProperty] = i_created.get(i_created.idProperty);

						var o_batch = Ext.apply({}, {
							type: "upsert",
							dmd: i_self.getDmd(),
							entity: i_self.getEntity(),
							transactiontype: i_self.getEntity(),
							key: o_keys,
							row: i_created.getData()
						});

						Ext.Ajax.request({
							url: "/ip2-services/ip2dmdProxy.aspx",
							jsonData: {
								batch: [
									o_batch
								]
							},
							success: function (i_response) {
								var i_store = i_self.getStore();

								i_parent.collapse();
								i_parent.removeAll(false);
		
								i_store.read({
									node: i_parent,
									callback: function() {
										i_parent.expand();
										i_window.setLoading(false);
										i_window.close();
									}
								});
							},
							faliure: function(o_error) {
								i_window.setLoading(false);
							}
						});
					});
				}
			}
		});

		i_window.addDocked(i_toolbar);

		i_window.add(i_panel);
				
		i_window.show();
	},

	editType: function(i_node) {

		var i_self = this;

		var o_properties = Ext.decode(i_node.get("PROPERTIES"), true) || {};

		var i_model = i_self.createModel();

		var i_recordStore = i_self.getRecordStore();

		i_recordStore.load({
			callback: function(a_records, i_store) {

				var i_record = a_records[0];

				var o_values =  Ext.decode(i_record.get("MNUPROP"), null) || {};

				var i_created = i_model.create(o_values);
		
				i_created.set(i_record.idProperty, i_record.get(i_record.idProperty));
		
				var n_type = o_properties.__cid__;
		
				var s_title = ip2.i18n({
					da: "Redigér",
					en: "Edit"
				});
		
				var a_title = [
					s_title,
					i_node.get("TITLE")
				];
		
				var s_main = "";
		
				switch(n_type) {
					case 2:
					case 3:
						s_main = "portfolio-menu-form-link";
						break;
					case 4:
						s_main = "portfolio-menu-form-app";
						break;
				}
		
				var i_window = Portfolio.util.Handler.getWindow({
					title: a_title.join(" - "),
					layout: "fit",
					modal: true
				});
		
				var i_panel = Ext.widget(s_main, {
					record: i_created
				});
		
				var i_toolbar = Ext.widget("toolbar", {
					dock: "bottom",
					ui: "footer",
					items: [
						"->",
						{
							xtype: "button",
							text: ip2.i18n({
								da: "Annuller",
								en: "Cancel"
							}),
							tabIndex: 1,
							focusable: true,
							itemId: "close",
							handler: function () {
								i_window.close();
							}
						},
						{
							xtype: "button",
							text: ip2.i18n({
								da: "Gem",
								en: "Save"
							}),
							itemId: "saveclose",
							ui: "primary-button",
							hidden: true,
							focusable: true,
							tabIndex: 1,
							handler: function (i_button) {
								i_window.fireEvent("save", i_panel);
							}
						}
					]
				});
		
				i_panel.on({
					dirtychange: {
						fn: function(i_form, b_dirty) {
		
							var b_valid = i_panel.isValid();
							var i_content = i_panel.getContent();
		
							if (b_valid) {
		
								var i_saveclose = i_toolbar.items.get("saveclose");
		
								i_saveclose[b_dirty ? "show" : "hide"]();
		
								i_content.setIconCls(b_dirty ? "x-dot" : "");
		
							}
						}
					},
					validitychange: {
						fn: function(i_form, b_valid){
		
							var i_content = i_panel.getContent();
		
							var i_saveclose = i_toolbar.items.get("saveclose");
		
							i_content.tab.removeCls("x-tab-error");
		
							if (!b_valid) {
								i_content.tab.addCls("x-tab-error");
								i_saveclose.hide();
							}
							else {
		
								var b_dirty = i_panel.isDirty();
		
								if (b_dirty) {
									i_panel.fireEvent("dirtychange", i_panel, b_dirty);
								}
							}
						}
					}
				});
		
				i_window.on({
					save: {
						fn: function(i_panel) {
		
							i_window.setLoading(ip2.i18n({
								da: "Gemmer..",
								en: "Saving..."
							}));
		
							i_panel.doSave().then(function(o_values) {
		
								Ext.apply(o_properties, o_values);
		
								i_record.set("MNUPROP", Ext.encode(o_properties));
		
								var o_keys = {};
		
								o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);
		
								var o_batch = Ext.apply({}, {
									type: "upsert",
									dmd: i_self.getDmd(),
									entity: i_self.getEntity(),
									transactiontype: i_self.getEntity(),
									key: o_keys,
									row: i_record.getData()
								});
		
								Ext.Ajax.request({
									url: "/ip2-services/ip2dmdProxy.aspx",
									jsonData: {
										batch: [
											o_batch
										]
									},
									success: function (i_response) {
										i_node.set("PROPERTIES", Ext.encode(o_properties));
										i_window.setLoading(false);
										i_window.close();
										i_node.commit(true);
									},
									faliure: function(o_error) {
										i_window.setLoading(false);
									}
								});
							});
						}
					}
				});
		
				i_window.addDocked(i_toolbar);
		
				i_window.add(i_panel);
						
				i_window.show();

			}
		});

	},

	copyType: function(i_node) {

		var i_self = this;

		var o_properties = Ext.decode(i_node.get("PROPERTIES"), true) || {};

		var i_model = i_self.createModel();

		var i_recordStore = i_self.getRecordStore();

		var i_parent = i_node.parentNode;

		i_recordStore.load({
			callback: function(a_records, i_store) {

				var i_record = a_records[0];

				var o_values =  Ext.decode(i_record.get("MNUPROP"), null) || {};

				var i_temp = i_model.create(o_values);
		
				var n_type = o_properties.__cid__;
		
				var s_title = ip2.i18n({
					da: "Kopier",
					en: "Copy"
				});
		
				var a_title = [
					s_title,
					i_node.get("TITLE")
				];
		
				var s_main = "";
		
				switch(n_type) {
					case 2:
					case 3:
						s_main = "portfolio-menu-form-link";
						break;
					case 4:
						s_main = "portfolio-menu-form-app";
						break;
				}
		
				var i_window = Portfolio.util.Handler.getWindow({
					title: a_title.join(" - "),
					layout: "fit",
					modal: true
				});
		
				var i_panel = Ext.widget(s_main, {
					record: i_temp
				});
		
				var i_toolbar = Ext.widget("toolbar", {
					dock: "bottom",
					ui: "footer",
					items: [
						"->",
						{
							xtype: "button",
							text: ip2.i18n({
								da: "Annuller",
								en: "Cancel"
							}),
							tabIndex: 1,
							focusable: true,
							itemId: "close",
							handler: function () {
								i_window.close();
							}
						},
						{
							xtype: "button",
							text: ip2.i18n({
								da: "Gem",
								en: "Save"
							}),
							itemId: "saveclose",
							ui: "primary-button",
							hidden: true,
							focusable: true,
							tabIndex: 1,
							handler: function (i_button) {
								i_window.fireEvent("save", i_panel);
							}
						}
					]
				});
		
				i_panel.on({
					dirtychange: {
						fn: function(i_form, b_dirty) {
		
							var b_valid = i_panel.isValid();
							var i_content = i_panel.getContent();
		
							if (b_valid) {
		
								var i_saveclose = i_toolbar.items.get("saveclose");
		
								i_saveclose[b_dirty ? "show" : "hide"]();
		
								i_content.setIconCls(b_dirty ? "x-dot" : "");
		
							}
						}
					},
					validitychange: {
						fn: function(i_form, b_valid){
		
							var i_content = i_panel.getContent();
		
							var i_saveclose = i_toolbar.items.get("saveclose");
		
							i_content.tab.removeCls("x-tab-error");
		
							if (!b_valid) {
								i_content.tab.addCls("x-tab-error");
								i_saveclose.hide();
							}
							else {
		
								var b_dirty = i_panel.isDirty();
		
								if (b_dirty) {
									i_panel.fireEvent("dirtychange", i_panel, b_dirty);
								}
							}
						}
					}
				});
		
				i_window.on({
					save: {
						fn: function(i_panel) {

							var i_created = i_model.create({});

							i_window.setLoading(ip2.i18n({
								da: "Gemmer..",
								en: "Saving..."
							}));

							i_created.set("MNUPNTTKN", i_parent.get("ID"));
		
							var i_promise = new Ext.Promise(function(f_resolve) {

								var o_keys = {};
		
								o_keys[i_created.idProperty] = null;
		
								var o_batch = Ext.apply({}, {
									type: "upsert",
									dmd: i_self.getDmd(),
									entity: i_self.getEntity(),
									transactiontype: i_self.getEntity(),
									key: o_keys,
									row: i_created.getData()
								});
		
								Ext.Ajax.request({
									url: "/ip2-services/ip2dmdProxy.aspx",
									jsonData: {
										batch: [
											o_batch
										]
									},
									success: function (i_response) {
		
										var o_result = Ext.decode(i_response.responseText, true) || {
											batch: [{
												rows: [{}]
											}]
										};
		
										var o_batch = o_result.batch[0];
										var o_row = o_batch.row || {};
		
										i_created.set(o_row);
										i_panel.updateNewRecord(i_created);
										f_resolve();
										
									}
								});
							}).then(function(){
								return i_panel.doSave();
							}).then(function(o_values) {
								
								var a_children = Ext.Array.from(i_parent.childNodes);

								var o_last = Ext.decode(i_parent.get("PROPERTIES"), true) || {};

								if (a_children.length > 0) {
									var i_last = a_children[a_children.length -1];
									o_last = Ext.decode(i_last.get("PROPERTIES"), true) || {};
								}

								var o_properties = Ext.apply({
									__cid__: n_type,
									seq: parseFloat(o_last.seq) + 1
								}, o_values);

								i_created.set("MNUPROP", Ext.encode(o_properties));

								var o_keys = {};

								o_keys[i_created.idProperty] = i_created.get(i_created.idProperty);

								var o_batch = Ext.apply({}, {
									type: "upsert",
									dmd: i_self.getDmd(),
									entity: i_self.getEntity(),
									transactiontype: i_self.getEntity(),
									key: o_keys,
									row: i_created.getData()
								});

								Ext.Ajax.request({
									url: "/ip2-services/ip2dmdProxy.aspx",
									jsonData: {
										batch: [
											o_batch
										]
									},
									success: function (i_response) {
										var i_store = i_self.getStore();

										i_parent.collapse();
										i_parent.removeAll(false);
				
										i_store.read({
											node: i_parent,
											callback: function() {
												i_parent.expand();
												i_window.setLoading(false);
												i_window.close();
											}
										});
									},
									faliure: function(o_error) {
										i_window.setLoading(false);
									}
								});
							});
						}
					}
				});
		
				i_window.addDocked(i_toolbar);
		
				i_window.add(i_panel);
						
				i_window.show();

			}
		});
	},

	createViewConfig: function() {

		var i_self = this;

		var i_model = i_self.createModel();

		var o_config = Ext.apply({}, {
			plugins: {
				ptype: "treeviewdragdrop",
				dropGroup: "entitytree",
				dragGroup: "entitytree",
				appendOnly: false,
				dropZone: {
					isValidDropPoint: function(i_node, s_position, i_dragZone, i_event, o_data) {

						var i_dropzone = this;
						var i_view = i_dropzone.view;
						var i_overRecord = i_view.getRecord(i_node);
						var a_records = Ext.Array.from(o_data.records);

						var i_record = a_records[0];

						var b_valid = false;

						if (i_overRecord != i_record) {
							if (!i_overRecord.isRoot()) {
								b_valid = s_position != "append";
							}
						}

						return b_valid;
					}
				}
			},
			listeners: {
				beforedrop: {
					fn: function(i_node, o_data, i_overModel, s_dropPosition, i_dropHandler, e) {

						var i_record = o_data.records[0];

						var i_before = i_overModel.previousSibling;
						var i_after = i_overModel.nextSibling;
						
						var o_properties = Ext.decode(i_overModel.get("PROPERTIES"), true) || {};
						var o_recordProperties = Ext.decode(i_record.get("PROPERTIES"), true) || {};

						var n_over = parseFloat(o_properties.seq);
						var n_extra = 0;
						var n_sequnce;


						if (isNaN(n_over)) {
							n_over = 1;
						}

						if (s_dropPosition === "before") {
							if (i_before) {
								var o_before = Ext.decode(i_before.get("PROPERTIES"), true) || {};
								n_extra = parseFloat(o_before.seq);

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

							n_sequnce = ((n_extra + n_over) / 2);
						}
						if (s_dropPosition === "after") {
							if (i_after) {
								var o_after = Ext.decode(i_after.get("PROPERTIES"), true) || {};
								n_extra = parseFloat(o_after.seq);

								if (isNaN(n_extra)) {
									n_extra = 0;
								}
							}
							else {
								n_extra = n_over + 1;
							}
							n_sequnce = ((n_over + n_extra) / 2);
						}
						
						o_recordProperties.seq = n_sequnce;

						i_record.set("PROPERTIES", Ext.encode(o_recordProperties));

						i_dropHandler.wait = true;

						var o_keys = {};

						o_keys[i_model.idProperty] = i_record.get("ID");

						Ext.Ajax.request({
							url: "/ip2-services/ip2dmdProxy.aspx",
							params: {
								action: "getRow",
								context: "form",
								dmdFile: i_self.getDmd(),
								uiName: i_self.getViewName(),
								model: i_self.getEntity(),
								key: Ext.encode(o_keys)
							},
							success: function (o_response) {
				
								var o_result = Ext.decode(o_response.responseText, true) || {
									success: false,
									rows: [{}]
								};
				
								if (!o_result.rows) {
									o_result.rows = [{}];
								}
				
								var o_data = o_result.rows[0];
				
								var i_loaded = i_model.create(o_data);

								var i_parent = i_overModel.parentNode;

								var n_tkn = i_parent.isRoot() ? i_parent.get("MNUMNUTKN") : i_parent.get("ID");
				
								i_loaded.set({
									MNUPROP: Ext.encode(o_recordProperties),
									MNUPNTTKN: n_tkn
								});

								i_self.upsertRecord(i_loaded);
								i_dropHandler.processDrop();
							},
							failure: function() {
				
								i_dropHandler.cancelDrop();
							}
						});
						
						return false;
					}
				}
			}
		});

		return o_config;
	}
});Ext.define("Portfolio.top.controller.Settings", {
	extend: "Ext.app.ViewController",

	alias: "controller.portfolio-settings",

	onAfterRender: function(i_window) {

		var i_controller = this;
		var i_view = i_controller.getView();
		var i_form = i_view.getForm();

		i_view.setLoading(ip2.i18n({
			da: "Indlæser bruger...",
			en: "Loading user..."
		}));

		i_controller.getUser(function(i_record) {

			var s_prop = i_record.get("USRPROP");

			var o_prop = Ext.decode(s_prop, true);

			if (o_prop && o_prop.hasOwnProperty("USRLNG")) {
				i_record.set("USRLNG", o_prop.USRLNG);
			}

			i_form.loadRecord(i_record);
			i_view.setLoading(false);
		});
	},

	getUser: function(f_callback) {

		var i_controller = this;
		var i_view = i_controller.getView();

		var i_model = ip2.model({
			dmd: "dmd/portfolio.dmd",
			entity: "NAVUSRET00",
			context: "form",
			view: "portfolio"
		});

		var i_user = Portfolio.util.Handler.getUser();

		var i_record = i_model.create(i_user.getData());

		f_callback.call(i_view, i_record);
	},

	onValidityChange: function(i_form, b_valid) {

		var i_controller = this;
		var i_view = i_controller.getView();
		var i_footer = i_view.getFooter();

		var i_buttonSave = i_footer.getComponent("button-save");

		i_buttonSave[b_valid ? "show" : "hide"]();

		if (b_valid) {
			i_buttonSave[i_form.isDirty() ? "show" : "hide"]();
		}
	},

	onDirtyChange: function(i_form, b_dirty) {

		var i_controller = this;
		var i_view = i_controller.getView();
		var i_footer = i_view.getFooter();

		var b_valid = i_form.isValid();

		var i_buttonSave = i_footer.getComponent("button-save");

		if (b_valid) {
			i_buttonSave[b_dirty ? "show" : "hide"]();
		}
		else {
			i_buttonSave.hide();
		}
	},

	onSave: function() {

		var i_controller = this;
		var i_view = i_controller.getView();
		var i_form = i_view.getForm();

		i_view.setLoading(ip2.i18n({
			da: "´Gemmer bruger...",
			en: "Saving user..."
		}));

		var i_record = i_form.getRecord();

		var o_values = i_form.getValues();

		i_record.set(o_values);

		var o_keys = {};

		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		var o_batch = Ext.apply({}, {
			type: "upsert",
			dmd: "dmd/portfolio.dmd",
			entity: "NAVUSRET00",
			key: o_keys,
			row: i_record.getData()
		});

		Ext.Ajax.request({
			url: "/ip2-services/ip2dmdProxy.aspx",
			jsonData: {
				batch: [
					o_batch
				]
			},
			success: function (i_response, i_request) {

				i_view.setLoading(false);

				var o_result = Ext.decode(i_response.responseText, true) || {
					success: false,
					batch: [{
						rows: []
					}]
				};

				Ext.applyIf(o_result, {
					success: false,
					batch: [{
						row: {}
					}]
				});

				if (!o_result.success) {

					Portfolio.util.Handler.messageBox({
						icon: Ext.MessageBox.ERROR,
						title: ip2.i18n({
							da: "Fejl",
							en: "Error"
						}),
						closable: true,
						message: o_result.message,
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						})
					});
				}
				else {
					i_form.loadRecord(i_record);
					i_view.close();
				}
			}
		});
	},

	onDestroy: function() {

		var i_controller = this;
		var i_view = i_controller.getView();
		var i_form = i_view.getForm();
		var i_record = i_form.getRecord();

		var i_user = Portfolio.util.Handler.getUser();

		if (i_record.get("USRLNG") != i_user.get("USRLNG")) {

			Portfolio.util.Handler.messageBox({
				icon: Ext.MessageBox.IFNO,
				title: ip2.i18n({
					da: "Sprog ændring",
					en: "Language changed"
				}),
				message: ip2.i18n({
					da: "Siden genindlæses og åbne tapper vil blive tabt",
					en: "The site will be reloaded, and open tabs will the lost"
				}),
				closable: true,
				yesFn: function() {
					Ext.GlobalEvents.fireEvent("reload");
				},
				yesText: ip2.i18n({
					da: "OK",
					en: "OK"
				})
			});
		}
	}
});
Ext.define("Portfolio.top.view.Settings", {

	extend: "Ext.window.Window",

	xtype: "portfolio-settings",

	layout: "fit",

	modal: true,

	config: {
		footer: null,
		form: null
	},

	requires: [
		"Portfolio.top.controller.Settings"
	],

	listeners: {
		afterrender: {
			fn: "onAfterRender"
		},
		beforedestroy: {
			fn: "onDestroy"
		}
	},

	ui: "message",

	controller: "portfolio-settings",

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		i_self.add(i_self.createForm());
	},

	createFields: function() {

		var i_user = ip2.getUser();

		var i_languageField = Ext.create("Ext.ux.form.field.LanguageComboBox", {
			fieldLabel: ip2.i18n({
				da: "Sprog",
				en: "Language"
			}),
			name: "USRLNG",
			value: i_user.get("USRLNG"),
			allowBlank: false,
			pageSize: 0,
		});

		var a_fields = [
			{
				xtype: "textfield",
				fieldLabel: ip2.i18n({
					da: "Bruger ID",
					en: "User ID"
				}),
				name: "USRID",
				readOnly: true,
				allowBlank: false
			},
			{
				xtype: "textfield",
				vtype: "email",
				fieldLabel: ip2.i18n({
					da: "Email",
					en: "Email"
				}),
				name: "USREML",
				allowBlank: false
			},
			i_languageField,
			{
				fieldLabel: ip2.i18n({
					da: "Profil billede",
					en: "Profile image"
				}),
				xtype: "uploadpicker",
				name: "USRIMG",
				path: "/images/profile",
				value: i_user.get("USRIMG"),
				extensions: Ext.ux.file.util.Handler.imageExtension,
				pageSize: 10
			}
		];

		return a_fields;
	},

	createForm: function() {

		var i_self = this;

		var i_panel = Ext.widget("form", {
			trackResetOnLoad: true,
			layout: "anchor",
			defaults: {
				labelAlign: "top",
				anchor: "100%"
			},
			items: i_self.createFields(),
			listeners: {
				validitychange: {
					fn: "onValidityChange"
				},
				dirtychange: {
					fn: "onDirtyChange"
				}
			}
		});

		i_panel.addDocked(i_self.createFooter());

		i_self.setForm(i_panel);

		return i_panel;
	},

	createFooter: function() {

		var i_self = this;

		var i_footer = Ext.widget("toolbar", {
			dock: "bottom",
			ui: "footer",
			defaults: {
				minWidth: 75
			},
			items: [
				"->",
				{
					xtype: "button",
					itemId: "button-close",
					text: ip2.i18n({
						da: "Annuller",
						en: "Cancel"
					}),
					handler: function () {

						i_self.close();
					}
				},
				{
					xtype: "button",
					itemId: "button-save",
					text: ip2.i18n({
						da: "Gem",
						en: "Save"
					}),
					hidden: true,
					handler: "onSave"
				}
			]
		});

		i_self.setFooter(i_footer);

		return i_footer;
	}
});
Ext.define("Portfolio.top.view.Main", {

	xtype: "portfolio-top",

	extend: "Ext.panel.Panel",

	height: 60,

	bodyCls: "x-ux-admin-top-background",

	layout: {
		type: "hbox",
		align: "center"
	},

	cls: "x-ux-admin-top-container",

	requires: [
		"Portfolio.top.view.Settings"
	],

	config: {
		logo: null,
		profileTitle: null,
		profileInfo: null,
		profileImage: null,
		currentUser: null,
		settingsMenu: null,
		systemMenu: null,
		systemArea: null
	},

	defaults: {
		margin: "0 0 0 10"
	},

	listeners: {
		afterrender: {
			fn: function(i_panel) {

				i_panel.body.addCls("x-portfolio-top");

				var o_settings = Portfolio.login.util.Handler.getSettings();
				var o_header = o_settings.header || {};

				var s_backgroundColor = o_header.backgroundColor;

				var i_element = i_panel.getTargetEl();

				if (i_element && s_backgroundColor) {
					i_element.setStyle("backgroundColor", s_backgroundColor);
				}

				i_panel.updateProfile();
			}
		},
		click: {
			element: "el",
			fn: function(i_event, i_element) {

				var i_self = this.component;

				var i_profileimage = i_self.getProfileImage();
				var i_settingsMenu = i_self.getSettingsMenu();

				if (!i_event.within(i_profileimage.getEl(), true)) {
					i_settingsMenu.hide();
				}
			}
		},
		systemAdded: {
			fn: function(a_systems) {

				var i_self = this;

				var i_systemArea = i_self.getSystemArea();

				Ext.Array.each(a_systems, function (o_config) {
					i_self.createSystemButton(o_config.title, o_config.itemId, o_config.first, o_config.binding);
				});

				var a_range = i_systemArea.items.getRange();

				if (a_range.length > 0) {
					i_systemArea.setActiveTab(i_systemArea.items.getAt(0));
				}

			}
		},
		systemShortcut: {
			fn: function (s_itemId) {

				var i_self = this;

				var i_systemArea = i_self.getSystemArea();

				var i_tab = i_systemArea.getComponent(s_itemId);

				if (i_tab) {
					i_systemArea.setActiveTab(i_tab);
					i_self.fireEvent("aftershortcut", s_itemId);
				}
			}
		},
		minimizeWindow: {
			fn: function(i_window) {

				var i_self = this;

				var s_title = i_window.getTitle();
				var i_systemArea = i_self.getSystemArea();

				i_systemArea.add(0, {
					text: s_title,
					closable: false,
					style: {
						"text-transform": "initial !important"
					},
					listeners: {
						click: {
							element: "el",
							fn: function(i_event) {

								var i_element = Ext.get(i_event.currentTarget);
								var i_tab = i_element.component;

								i_event.stopEvent();

								i_tab.hide();
								i_systemArea.remove(i_tab, true);
								i_window.show();

							}
						}
					}
				});

				i_window.hide();
			}
		},
		desktopAdded: {
			fn: function(i_desktop) {

				var i_self = this;
				var i_systemMenu = i_self.getComponent("system-menu");

				if (i_systemMenu) {
					var n_index = i_self.items.indexOf(i_systemMenu);

					i_self.add(n_index, i_desktop.getButton());
				}
			}
		}
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);
		i_self.add(i_self.createItems());
		i_self.createMenu();

		i_self.mon(Portfolio.app, "updateinfotemplate", function(s_template) {

			var i_infoComponent = i_self.getProfileInfo();
			i_infoComponent.update(s_template);
		});

		i_self.mon(Portfolio.app, "minimizeWindow", function (i_window) {
			i_self.fireEvent("minimizeWindow", i_window);
		});

		i_self.mon(Portfolio.app, "desktopadded", function (i_desktop) {
			i_self.fireEvent("desktopadded", i_desktop);
		});

		i_self.enableBubble([
			"systemActivate",
			"aftershortcut"
		]);
	},

	createItems: function() {

		var i_self = this;

		var o_settings = Portfolio.login.util.Handler.getSettings();

		var o_header = o_settings.header || {};

		if (!o_header.hasOwnProperty("profile")) {
			Ext.apply(o_header, {
				profile: {
					showIcon: true,
					showTip: true
				}
			});
		}

		var s_adminLogo = o_header.logo;

		var a_items = [];

		var o_iconStyle = {};

		if (s_adminLogo) {

			Ext.apply(o_iconStyle, {
				"background-image": "url(\"" + s_adminLogo + "\")",
				"background-position": "center center",
				"background-repeat": "no-repeat"
			});
		}

		var o_icon = {
			autoEl: {
				tag: "span"
			}
		};

		if (o_header.iconStyle) {
			Ext.Object.merge(o_iconStyle, o_header.iconStyle);
		}

		if (s_adminLogo) {

			Ext.apply(o_icon, {
				width: o_header.logoWidth || 30,
				height: o_header.logoHeight || 50,
				margin: "0 0 0 20",
				style: o_iconStyle
			});
		}
		else {
			Ext.apply(o_icon, {
				cls: "x-site-icon pf-sitemule",
				margin: "0 35 0 30"
			});
		}

		var i_logo = Ext.widget("component", o_icon);

		if (!o_header.profile.hasOwnProperty("showTip")) {
			Ext.apply(o_header.profile, {
				showTip: true
			});
		}

		var i_profileTitle = Ext.widget("component", {
			html: "",
			itemId: "profile-title",
			style: {
				"color": "white",
				"font-weight": "bold",
				"cursor": "default"
			},
			listeners: {
				afterrender: {
					fn: function(i_component) {

						var o_settings = Portfolio.login.util.Handler.getSettings();
						var o_header = o_settings.header || {};

						if (o_header.hideTitle) {
							return false;
						}

						if (ip2.preset.text) {
							ip2.navigator.system.server.description = ip2.preset.text;
						}

						var a_items = [];

						var o_banner = ip2.navigator.banner;

						if (o_banner) {
							a_items.push(o_banner.text || ip2.baseconfig.session.preset.text);
						}
						else {
							a_items.push(ip2.baseconfig.session.preset.text);
						}

						var s_title = a_items.join("");
						i_component.setHtml(s_title);
					}
				}
			}
		});

		var i_infoComponent = Ext.widget("component", {
			html: ""
		});

		var i_profileImage = Ext.widget("component", {
			autoEl: {
				tag: "span"
			},
			itemId: "profile-image",
			cls: o_header.profile.showIcon ? "x-site-user-icon" : "x-site-user-icon-none",
			margin: o_header.profile.showIcon ? "0 35 0 30" : "0 20 0 30",
			showIcon: o_header.profile.showIcon,
			listeners: {
				afterrender: {
					fn: function(i_component) {

						if(o_header.profile.showTip) {

							var i_element = i_component.getEl();

							Ext.create("Ext.tip.ToolTip", {
								target: i_element,
								html: "",
								anchor: true,
								anchorSize: 27,
								defaultAlign: "t50-b40",
								style: {
									margin: "0 10 0 0"
								},
								mouseOffset: [0, 0],
								listeners: {
									beforeshow: {
										fn: function (i_tip) {

											var i_user = ip2.getUser();

											var a_list = [];

											if (i_user.get("USRPRF")) {
												a_list.push(i_user.get("USRPRF"));
											}

											if (i_user.get("USRNAM")) {
												a_list.push(i_user.get("USRNAM"));
											}

											var s_value = a_list.join(" - ");

											if (s_value) {
												i_tip.update(s_value);
											}
											else {
												return false;
											}
										}
									}
								}
							});
						}
					}
				},
				click: {
					element: "el",
					fn: function(i_event, i_element) {

						var i_settingsMenu = i_self.getSettingsMenu();
						var i_container = this;

						i_event.stopEvent();

						if (i_settingsMenu.isVisible()) {
							i_settingsMenu.hide();
						}
						else {
							i_settingsMenu.showBy(i_container.el, "tr-br", [10, 0]);
						}
					}
				}
			}
		});

		var i_systemArea = Ext.widget("tabbar", {
			overflowHandler: "menu",
			plain: false,
			ui: "system-list",
			height: 60,
			layout: {
				type: "hbox",
				align: "stretch"
			},
			tabConfig: {
				ui:"default"
			},
			defaults: {
				xtype: "tab",
				ui:"system-item"
			},
			listeners: {
				change: {
					fn: function(i_tabbar, i_tab, i_card) {
						i_self.fireEvent("systemActivate", i_tab.itemId);
					}
				}
			}
		});

		var i_systemMenu = Ext.widget("component", {
			autoEl: {
				tag: "span"
			},
			itemId: "system-menu",
			cls: "x-site-user-icon pf-windows_arrange",
			listeners: {
				click: {
					element: "el",
					fn: function(i_event, i_element) {

						var i_menu = Ext.widget("menu", {
							listeners: {
								beforeshow: {
									fn: function(i_menu) {

										var b_hasTabs = Portfolio.app.fireEvent("hasTabs");

										var a_windows = Ext.WindowManager.zIndexStack.getRange();

										var i_organize = i_menu.child("#pf-organize");
										var i_fit = i_menu.child("#pf-fit");
										var i_windows = i_menu.child("#pf-windows");
										var i_tabs = i_menu.child("#pf-tabs");
										var i_desktop = i_menu.child("#pf-desktop");

										if (i_organize) {
											i_organize[a_windows.length ? "enable": "disable"]();
										}

										if (i_fit) {
											i_fit[a_windows.length ? "enable" : "disable"]();
										}

										if (i_windows) {
											i_windows[b_hasTabs ? "enable" : "disable"]();
										}

										if (i_tabs) {
											i_tabs[a_windows.length ? "enable" : "disable"]();
										}

										if (i_desktop) {
											i_desktop[a_windows.length ? "enable" : "disable"]();
										}

									}
								}
							},
							items: [
								{
									xtype: "menuitem",
									itemId: "pf-organize",
									text: ip2.i18n({
										da: "Organiser",
										en: "Organize"
									}),
									iconCls: "pf-elements3",
									handler: function () {

										Portfolio.app.fireEvent("organizewindows");
									}
								},
								{
									xtype: "menuitem",
									itemId: "pf-fit",
									text: ip2.i18n({
										da: "Tilpas",
										en: "Fit"
									}),
									iconCls: "pf-elements4",
									handler: function () {

										Portfolio.app.fireEvent("resizewindows");
									}
								},
								{
									xtype: "menuitem",
									itemId: "pf-windows",
									text: ip2.i18n({
										da: "Vinduer",
										en: "Windows"
									}),
									iconCls: "pf-elements",
									handler: function () {

										Portfolio.app.fireEvent("tabstowindow");
									}
								},
								{
									xtype: "menuitem",
									itemId: "pf-tabs",
									text: ip2.i18n({
										da: "Faner",
										en: "Tabs"
									}),
									iconCls: "pf-minus",
									handler: function () {

										Portfolio.app.fireEvent("windowstotab");
									}
								},
								{
									xtype: "menuitem",
									itemId: "pf-desktop",
									text: ip2.i18n({
										da: "Desktop",
										en: "Desktop"
									}),
									iconCls: "pf-element",
									handler: function () {

										Portfolio.app.fireEvent("createdesktop");
									}
								}
							]
						});

						var i_container = this;

						i_event.stopEvent();

						if (i_menu.isVisible()) {
							i_menu.hide();
						}
						else {
							i_menu.showBy(i_container.el, "tr-br", [10, 0]);
						}
					}
				}
			}
		});

		a_items.push(i_logo);
		a_items.push(i_profileTitle);
		a_items.push({
			xtype: "tbfill"
		});
		a_items.push(i_infoComponent);
		a_items.push({
			xtype: "tbfill"
		});
		a_items.push(i_systemArea);
		a_items.push(i_systemMenu);
		a_items.push(i_profileImage);

		i_self.setLogo(i_logo);
		i_self.setProfileTitle(i_profileTitle);
		i_self.setProfileInfo(i_infoComponent);
		i_self.setSystemArea(i_systemArea);
		i_self.setProfileImage(i_profileImage);

		return a_items;
	},

	updateProfile: function(s_username, s_profileImage) {

		var i_self = this;

		var i_user = Portfolio.util.Handler.getUser();

		var i_profileImage = i_self.getProfileImage();

		if (i_profileImage.showIcon) {
			var fn_updateImage = function(s_profileImage) {

				var o_style = {};
				var s_html = "";

				s_profileImage = s_profileImage || i_user.get("USRIMG") || i_user.get("URL");

				if (s_profileImage) {

					s_profileImage = Ext.apply(o_style, {
						"background-image": "url(\"" + s_profileImage + "\")",
					});

					i_profileImage.addCls("header-user-image");
				}
				else{
					i_profileImage.addCls("pf-profile2");
				}

				i_profileImage.setStyle(o_style);
				i_profileImage.setHtml(s_html);
			};

			if (i_profileImage.rendered) {
				fn_updateImage(s_profileImage);
			}
			else {
				i_profileImage.on({
					afterrender: {
						fn: function() {
							fn_updateImage(s_profileImage);
						},
						single: true
					}
				});
			}
		}
		else {
			i_profileImage.setHtml(i_user.get("USRPRF") || i_user.get("USRID"));
		}

	},

	createMenu: function() {

		var i_self = this;

		var i_settingsMenu = Ext.widget("menu", {
			showSeparator: false,
			over: false,
			bodyPadding: 10,
			items: [
				{
					xtype: "menuitem",
					text: ip2.i18n({
						da: "Indstillinger",
						en: "Settings"
					}),
					iconCls: "pf-gearwheel",
					handler: function() {

						var i_settingsWindow = Ext.widget("portfolio-settings", {
							title: ip2.i18n({
								da: "Redigere bruger",
								en: "Edit user"
							}),
							width: 400
						});

						i_settingsWindow.show();
					}
				},
				{
					xtype: "menuitem",
					iconCls: "pf-lock",
					text: ip2.i18n({
						da: "Log ud",
						en: "Logout"
					}),
					handler: function() {
						Ext.GlobalEvents.fireEvent("logout");
					}
				}
			],
			listeners: {
				mouseout: {
					element: "el",
					fn: function(i_event, i_element) {

						var i_settingsMenu = i_self.getSettingsMenu();

						if (!i_event.within(this, true)) {
							if (i_settingsMenu) {
								i_settingsMenu.hide();
							}
						}
					},
					buffer: 500
				}
			}
		});

		i_self.setSettingsMenu(i_settingsMenu);
	},

	createSystemButton: function(s_title, s_itemId, b_first, o_binding) {

		var i_self = this;

		o_binding = o_binding || {};

		var i_systemArea = i_self.getSystemArea();

		var i_tab = i_systemArea.add({
			text: s_title,
			closable: false,
			pressed: b_first,
			itemId: s_itemId
		});

		if (o_binding.keyCode) {

			var o_shortcut = {
				ctrl: o_binding.ctrl,
				alt: o_binding.alt,
				keyCode: o_binding.keyCode,
				shift: o_binding.shift
			};

			Ext.create("Ext.tip.ToolTip", {
				target: i_tab.getEl(),
				html: "",
				anchor: true,
				defaultAlign: "t50-b50",
				listeners: {
					beforeshow: {
						fn: function (i_tip) {

							var a_list = [];

							if (o_shortcut.ctrl) {
								a_list.push("Ctrl");
							}

							if (o_shortcut.alt) {
								a_list.push("Alt");
							}

							if (o_shortcut.shift) {
								a_list.push("shift");
							}

							if (o_shortcut.keyCode) {
								a_list.push(Ext.event.Event.getKeyId(o_shortcut.keyCode));
							}

							var s_value = a_list.join(" + ");

							if (s_value) {
								i_tip.update(s_value);
							}
							else {
								return false;
							}
						}
					},
					show: {
						fn: function(i_tip) {

							i_tip.realignToTarget();
						},
						buffer: 10
					}
				}
			});
		}

	}

});
Ext.define("Portfolio.view.Main", {

	xtype: "portfolio-viewport",

	extend: "Ext.panel.Panel",

	layout: "border",

	border: false,

	config: {

		navigation: null,
		centerTabs: null,
		northArea: null,
		helpArea: null,
		centerStateFul: true,
		showHelp: true,
		hash: "",
		desktops: []
	},

	listeners: {
		afterrender: {
			fn: function() {

				var i_self = this;
				var s_hash = i_self.getHash();

				if (s_hash) {
					Portfolio.Router.instance.redirectTo(s_hash, {
						force: true,
						replace: true
					});
				}
			},
			buffer: 10
		},
		startapplication: {
			fn: function(i_system, i_record) {

				var i_self = this;

				var i_centerTabs = i_self.getCenterTabs();
				i_centerTabs.fireEvent("startapplication", i_record);
			}
		},
		systemAdded: {
			fn: function (a_systems) {

				var i_self = this;
				var i_topArea = i_self.getNorthArea();

				i_topArea.fireEvent("systemAdded", a_systems);
			}
		},
		systemShortcut: {
			fn: function (s_itemId) {

				var i_self = this;
				var i_topArea = i_self.getNorthArea();

				i_topArea.fireEvent("systemShortcut", s_itemId);
			}
		},
		systemActivate: {
			fn: function (s_itemId) {

				var i_self = this;
				var i_navigation = i_self.getNavigation();

				i_navigation.fireEvent("systemActivate", s_itemId);
			}
		},
		aftershortcut: {
			fn: function (s_itemId) {

				var i_self = this;
				var i_navigation = i_self.getNavigation();

				i_navigation.fireEvent("aftershortcut", s_itemId);
			}
		},
		toggleNavigation: {
			fn: function(b_collapse) {

				var i_self = this;
				var i_navigation = i_self.getNavigation();

				if (!i_navigation.getPlaceholder().isVisible() && b_collapse) {
					i_navigation.collapse();
				}

			}
		},
		organizewindows: {
			fn: function () {

				var i_self = this;
				i_self.doOrganizeWindows();
			}
		},
		resizewindows: {
			fn: function (b_comparing) {
				var i_self = this;
				i_self.resizeAndOrganize(b_comparing);
			}
		},
		tabsToWindow: {
			fn: function() {
				var i_self = this;
				i_self.tabsToWindow();
			}
		},
		windowsToTab: {
			fn: function () {
				var i_self = this;
				i_self.windowsToTab();
			}
		},
		createdesktop: {
			fn: function () {
				var i_self = this;
				i_self.createDesktop();
			}
		},
		beforeDetached: {
			fn: function (o_config) {

				var i_self = this;
				i_self.addConstrain(o_config);
			}
		},
		applicationDetached: {
			fn: function (i_window, s_managerId) {

				var i_self = this;
				i_self.addToDesktop(i_window, s_managerId);
			}
		},
		hasTabs: {
			fn: function() {

				var i_self = this;
				var i_centerTabs = i_self.getCenterTabs();
				return i_centerTabs.items.getRange().length > 0;
			}
		}
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent(arguments);

		i_self.add(i_self.createLayout());

		var s_hash = Ext.History.getHash();

		if (s_hash) {
			i_self.setHash(s_hash);
		}

		i_self.enableBubble("login");

		i_self.mon(Portfolio.app, "toggleNavigation", function (b_collapse) {
			i_self.fireEvent("toggleNavigation", b_collapse);
		});

		i_self.mon(Portfolio.app, "organizewindows", function () {
			i_self.fireEvent("organizewindows");
		});

		i_self.mon(Portfolio.app, "resizewindows", function (b_comparing) {
			i_self.fireEvent("resizewindows", b_comparing);
		});

		i_self.mon(Portfolio.app, "createdesktop", function () {
			i_self.fireEvent("createdesktop");
		});

		i_self.mon(Portfolio.app, "tabstowindow", function () {
			i_self.fireEvent("tabstowindow");
		});

		i_self.mon(Portfolio.app, "windowsToTab", function () {
			i_self.fireEvent("windowsToTab");
		});

		i_self.mon(Portfolio.app, "beforedetached", function (o_config) {
			i_self.fireEvent("beforedetached", o_config);
		});

		i_self.mon(Portfolio.app, "applicationdetached", function (i_window, s_managerId) {
			i_self.fireEvent("applicationdetached", i_window, s_managerId);
		});

		i_self.mon(Portfolio.app, "hasTabs", function () {
			return i_self.fireEvent("hasTabs");
		});

		return i_self;
	},

	createLayout: function() {

		var i_self = this;

		var a_items = [];

		var o_params = Ext.Object.fromQueryString(window.location.search);

		var n_layout = parseInt(o_params.layout, 10) || o_params.hide || 0;

		var b_header = true;
		var b_navigation = true;
		var b_help = i_self.getShowHelp();
		var b_centertabs = true;
		var b_message = true;

		if (o_params.layout == "fullscreen" || o_params.layout == "terminal") {
			n_layout = 0xff;
		}

		if (o_params.layout == "frontend") {
			n_layout = 2;
		}

		// DOES HIDE CONTAIN BIT VALUE FOR 1 ('00001')
		if (n_layout & 1) {
			b_header = false;
		}

		// DOES HIDE CONTAIN BIT VALUE FOR 2 ('00010')
		if (n_layout & 2) {
			b_navigation = false;
		}

		// DOES HIDE CONTAIN BIT VALUE FOR 4 ('00100')
		if (n_layout & 4) {
			b_help = false;
		}

		// DOES HIDE CONTAIN BIT VALUE FOR 8 ('01000')
		if (n_layout & 8) {
			b_centertabs = false;
		}

		// DOES HIDE CONTAIN BIT VALUE FOR 16 ('10000')
		if (n_layout & 16) {
			b_message = false;
		}

		a_items.push(i_self.createTop(b_header));
		a_items.push(i_self.createWest(b_navigation));
		a_items.push(i_self.createCenter(b_centertabs));
		a_items.push(i_self.createEast(b_help));
		a_items.push(i_self.createBottom(b_message));

		return a_items;
	},

	createTop: function(b_show) {

		var i_self = this;

		var i_toppanel = Ext.widget("portfolio-top", {
			region: "north",
			hidden: !b_show
		});

		i_self.setNorthArea(i_toppanel);

		return i_toppanel;
	},

	createWest: function(b_show) {

		var i_self = this;

		var i_menu = Ext.widget("portfolio-menu", {
			title: ip2.i18n({
				da: "Navigation",
				en: "Navigation"
			}),
			width: 300,
			minwidth: 100,
			collapsible: true,
			split: {
				width: 1,
				size: 1
			},
			border: false,
			bodyBorder: false,
			region: "west",
			hidden: !b_show,
			header: {
				style: {
					"border-top": "0 !important;"
				}
			},
			listeners: {
				afterrender: {
					fn: function (i_panel) {
						var i_placeHolder = i_panel.getPlaceholder();
						if (i_placeHolder) {
							i_placeHolder.on({
								mouseenter: {
									fn: function () {
										i_panel.floatCollapsedPanel();
									},
									element: "el",
									scope: this
								}
							});
						}
					},
				}
			}
		});

		i_self.setNavigation(i_menu);

		return i_menu;
	},

	createCenter: function(b_show) {

		var i_self = this;

		var i_user = Portfolio.util.Handler.getUser();

		var n_token = i_user.get("USRUSRTKN") || 0;

		var i_tabpanel = Ext.widget("portfolio-centertabs", {
			flex: 1,
			region: "center",
			split: true,
			stateful: b_show && n_token > 0 ? i_self.getCenterStateFul() : false,
			stateId: n_token > 0 ? "portfolio-center-main-" + i_user.get("USRUSRTKN") : ""
		});

		if (!b_show) {
			i_tabpanel.tabBar.hide();
		}

		i_self.setCenterTabs(i_tabpanel);

		return i_tabpanel;
	},

	createEast: function(b_show) {

		var i_self = this;

		var i_panel = Ext.widget("panel", {
			title: ip2.i18n({
				da: "Hjælp",
				en: "Help"
			}),
			width: 300,
			collapsible: true,
			collapsed: true,
			split: true,
			region: "east",
			hidden: !b_show,
			ui: "menu-navigation"
		});

		i_self.setHelpArea(i_panel);

		return i_panel;
	},

	createBottom: function(b_show) {

		var i_panel = Portfolio.util.Message.initGrid({
			title: ip2.i18n({
				da: "Log & beskeder",
				en: "Log & Messages"
			}),
			region: "south",
			height: 400,
			collapsible: true,
			collapsed: true,
			hidden: !b_show,
		});

		return i_panel;
	},

	doOrganizeWindows: function () {

		var i_self = this;
		var i_northArea = i_self.getNorthArea();
		var i_northRegion = i_northArea.getRegion(false, true);

		var i_region = i_self.getRegion();

		var n_x = 10;
		var n_y = i_northRegion.bottom + 10;
		var n_count = 1;
		var o_rows = {};
		var n_index = 0;
		var n_heigthes = 0;
		var n_padding = 10;

		var a_windows = Ext.WindowManager.zIndexStack.getRange();

		var a_filtered = Ext.Array.filter(a_windows, function(i_window) {
			return !i_window.hidden && i_window.$className == "Ext.window.Window";
		});

		Ext.Array.each(a_filtered, function (i_window) {

			if (!i_window.hidden) {
				var o_windowSize = i_window.getSize();

				var o_box = Ext.Object.merge({}, {
					x: n_x,
					y: n_y
				}, o_windowSize);

				var a_rows = o_rows[n_count] || [];

				if ((n_x + o_box.width) > i_region.width) {
					n_heigthes = 0;
					n_index = 0;
					n_x = n_count % 2 ? 40 : 10;
					n_count++;

					a_rows = [];
				}

				a_rows.push({
					box: o_box,
					el: i_window.getEl()
				});

				o_rows[n_count] = a_rows;

				if (n_count > 1) {

					var a_saved = o_rows[n_count - 1];

					if (n_index < a_saved.length) {

						var o_index = a_saved[n_index];
						var b_intersected = false;
						var o_intersected;

						var o_saved = o_index.box;

						n_y = o_saved.y + o_saved.height + n_padding;
						o_box.y = n_y;
						o_box.x = n_x;

						Ext.Array.each(a_saved, function (o_entry) {

							var o_value = o_entry.box;

							// THIS WILL BE FALSE IF WE INTERSECT

							var n_maxX = Math.max(o_box.x, o_value.x);
							var n_maxY = Math.max(o_box.y, o_value.y);

							var n_minWidth = Math.min(o_box.x + o_box.width, o_value.x + o_value.width);
							var n_minHeight = Math.min(o_box.y + o_box.height, o_value.y + o_value.height);

							if (n_minWidth >= n_maxX && n_minHeight >= n_maxY) {
								b_intersected = true;
								o_intersected = o_value;
							}
						});

						if (b_intersected) {
							n_y = o_intersected.y + o_intersected.height + n_padding;
							o_box.y = n_y;
						}
					}
				}

				n_index++;

				i_window.setPosition(n_x, n_y, true);

				n_x += o_windowSize.width + n_padding;
			}
		});
	},

	resizeAndOrganize: function (b_comparing) {

		var i_self = this;

		var i_northArea = i_self.getNorthArea();
		var i_northRegion = i_northArea.getRegion(false, true);

		var i_region = i_self.getRegion();

		var n_top = i_northRegion.bottom;
		var n_regionHeight = i_region.height - i_northRegion.height;

		var a_windows = Ext.WindowManager.zIndexStack.getRange();

		var a_filtered = [];

		if (b_comparing) {
			a_filtered = Ext.Array.filter(a_windows, function(i_window) {
				return i_window.comparing;
			});
		}
		else {
			a_filtered = Ext.Array.filter(a_windows, function (i_window) {
				return !i_window.hidden && i_window.$className == "Ext.window.Window";
			});
		}

		var n_windows = a_filtered.length;

		if (n_windows > 0) {

			var n_padding = 10;

			var n_rows = n_windows > 2 ? 2 : 1;
			var n_cols = n_windows > 2 ? Math.ceil(n_windows / 2) : n_windows;

			var n_calcWidth = (i_region.width - n_padding) - (n_padding * n_cols);
			var n_calcHeight = (n_regionHeight - n_padding) - (n_padding * n_rows);

			var n_count = 0;

			var o_size = {
				width: Math.ceil(n_calcWidth / n_cols),
				height: Math.ceil(n_calcHeight / n_rows)
			};

			var n_x = i_region.left + n_padding;
			var n_y = n_top + n_padding;

			Ext.suspendLayouts();

			Ext.Array.each(a_filtered, function (i_window) {
				i_window.setSize(o_size.width, o_size.height);
			});

			Ext.resumeLayouts(true);

			Ext.Array.each(a_filtered, function (i_window) {

				if (n_windows <= 2) {
					i_window.setPosition(n_x, n_y, true);

					n_x += o_size.width + n_padding;
				}
				else {
					if (n_count < n_cols) {

						i_window.setPosition(n_x, n_y, true);

						n_x += o_size.width + n_padding;
						n_count++;
					}
					else {

						n_count = 0;

						n_x = i_region.left + n_padding;
						n_y += o_size.height + n_padding;

						i_window.setPosition(n_x, n_y, true);

						n_x += o_size.width + n_padding;

					}
				}
			});
		}
	},

	createDesktop: function() {

		var i_self = this;

		var a_desktops = i_self.getDesktops();

		var a_windows = Ext.WindowManager.zIndexStack.getRange();

		var n_count = a_desktops.length;


		var i_desktop = Ext.create("Portfolio.util.Desktop", {
			count: n_count,
			items: a_windows,
			listeners: {
				activate: {
					fn: function (i_desktop, b_pressed) {

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

							if (!i_current.getIsActive()) {
								i_current.fireEvent("deactivate");
							}
							else {
								i_current.fireEvent("preview");
							}
						});

						i_desktop.setIsActive(b_pressed);
						i_desktop.fireEvent(b_pressed ? "preview" : "depreview");
					}
				},
				preshift: {
					fn: function (i_desktop) {

						Ext.WindowManager.hideAll();

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

							if (i_current == i_desktop) {
								i_current.fireEvent("preview");
							}
							else {
								i_current.fireEvent("depreview");
							}
						});
					}
				},
				deshift: {
					fn: function(i_desktop) {

						var b_active = false;

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

							if (!i_current.getIsActive()) {
								i_current.fireEvent("deactivate");
							}
							else {
								i_current.fireEvent("preview");
								b_active = true;
							}
						});

						if (!b_active) {

							var a_windows = Ext.WindowManager.zIndexStack.getRange();

							Ext.Array.each(a_windows, function (i_window) {
								i_window.show();
							});
						}
					}
				},
				destroy: {
					fn: function(i_desktop) {
						Ext.Array.remove(a_desktops, i_desktop);
						i_self.setDesktops(a_desktops);
					}
				}
			}
		});

		a_desktops.push(i_desktop);
		i_self.setDesktops(a_desktops);

		Portfolio.app.fireEvent("desktopadded", i_desktop);
	},

	tabsToWindow: function() {

		var i_self = this;
		var i_centerTabs = i_self.getCenterTabs();

		var a_tabs = i_centerTabs.items.getRange();

		Portfolio.app.fireEvent("toWindow", a_tabs);
	},

	windowsToTab: function () {

		var a_windows = Ext.WindowManager.zIndexStack.getRange();

		Ext.Array.each(a_windows, function(i_window) {

			var o_stateData = i_window.stateData;

			if (o_stateData) {

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

				if (i_panel) {
					i_panel.setTitle(i_window.getTitle());

					Portfolio.app.fireEvent("toTab", i_panel, o_stateData);
					i_window.close();
				}
			}
		});
	},

	addToDesktop: function(i_window, s_managerId) {

		var i_self = this;

		var a_desktops = i_self.getDesktops();

		Ext.Array.each(a_desktops, function(i_desktop) {

			var i_manager = i_desktop.getManager();

			if (i_manager.id == s_managerId) {

				var a_items = i_desktop.getItems();

				a_items.push(i_window);

				i_desktop.addItems(i_window, true);

				i_desktop.setItems(a_items);
			}
		});
	},

	addConstrain: function(o_config) {

		var i_self = this;

		var n_padding = 10;

		var i_northArea = i_self.getNorthArea();
		var i_northRegion = i_northArea.getRegion(false, true);

		var i_region = i_self.getRegion();

		var n_top = i_northRegion.bottom;
		var n_regionHeight = i_region.height - (i_northRegion.height + n_padding * 2);

		var i_constrain = Ext.util.Region.create({});

		Ext.apply(i_constrain, {
			x: i_region.left + n_padding,
			y: n_top + n_padding,
			left: i_region.left + n_padding,
			right: i_region.right - n_padding,
			top: n_top + n_padding,
			bottom: i_region.bottom - n_padding,
			height: n_regionHeight,
			width: i_region.width - (n_padding * 2)
		});

		Ext.apply(o_config, {
			constrainTo: i_constrain,
			maxHeight: n_regionHeight - n_padding
		});

		return o_config;
	}
});
Ext.define("Ext.ux.GMapPanel", {
	extend: "Ext.panel.Panel",

	alias: "widget.gmappanel",

	config: {
		center: null,
		mapOption: {},
		scaleControl: true,
		geoCoder: null,
		map: null,
		markers: [],
		zoom: 7,
		stored: null,
		added: [],
		api: "//maps.googleapis.com/maps/api/js",
		gestureHandling: "greedy"
	},

	border: false,

	listeners: {
		afterrender: {
			fn: function(i_panel) {

				var i_self = this;

				var o_google = window.google || {};

				if (o_google.maps) {
					i_self.initMap();
				}
				else {
					var i_entry = Ext.Boot.getEntry(i_self.getApi(), {
						crossDomain: true,
						listeners: [
							function(i_entry) {
								o_google = window.google || {};
								if (o_google.maps) {
									i_self.initMap();
								}
								else {
									Ext.raise("Error loading google maps api at :" + i_self.getApi());
								}
							}
						]
					});
					i_entry.load(false);
				}
			},
			buffer: 10
		},
		beforedestroy: {
			fn: function(i_panel) {

				var i_self = this;
				var a_markers = i_self.getAdded();

				Ext.Array.each(a_markers, function(i_marker) {
					i_marker.setMap(null);
				});

				i_self.setAdded(null);
				i_self.setMap(null);
				i_self.setStored(null);
				i_self.setCenter(null);
				i_self.setGeoCoder(null);
			}
		}
	},

	initComponent: function() {

		var i_self = this;
		i_self.callParent();
	},

	initMap: function() {

		var i_self = this;

		var o_center = i_self.getCenter() || {
			lat: 55.846330,
			lng: 10.593858
		};

		var o_stored = i_self.getStored() || "";

		if (o_stored) {
			if (o_stored.lat && o_stored.lng) {
				o_center = o_stored;
			}
		}

		if (o_center) {
			if (o_center.geoCodeAddr) {
				i_self.lookupCode(o_center.geoCodeAddr, o_center.marker);
			}
			else {
				i_self.createMap(o_center);
			}
		}
		else {
			Ext.raise("center is required");
		}
	},

	createMap: function(o_center, o_marker) {

		var i_self = this;
		var a_markers = i_self.getMarkers();
		var google = window.google;

		var o_options = Ext.apply({}, i_self.mapOptions);

		o_options = Ext.applyIf(o_options, {
			zoom: i_self.getZoom(),
			center: o_center,
			mapTypeId: google.maps.MapTypeId.MAP,
			scaleControl: i_self.getScaleControl(),
			gestureHandling: i_self.getGestureHandling()
		});

		var i_map = new google.maps.Map(i_self.body.dom, o_options);

		i_self.setMap(i_map);

		if (o_marker) {
			i_self.addMarker(Ext.applyIf(o_marker, {
				position: o_center
			}));
		}

		Ext.Array.each(a_markers, i_self.addMarker, i_self);

		i_self.setCenter(o_center);

		i_self.fireEvent("mapready", i_self, i_map);
	},

	addMarker: function(o_config) {

		var i_self = this;
		var google = window.google;

		o_config = Ext.apply({
			map: i_self.getMap()
		}, o_config);

		if (!o_config.position) {
			o_config.position = new google.maps.LatLng(o_config.lat, o_config.lng);
		}
		var i_marker = new google.maps.Marker(o_config);

		Ext.Object.each(i_marker.listeners, function(s_name, f_handler) {
			google.maps.event.addListener(i_marker, s_name, f_handler);
		});

		var a_added = i_self.getAdded();
		a_added.push(i_marker);

		return i_marker;
	},

	removeMarker: function(i_marker) {

		var i_self = this;
		var a_added = i_self.getAdded();

		Ext.Array.remove(a_added, i_marker);

		i_marker.setMap(null);
	},

	lookupCode: function(addr, marker) {

		var i_self = this;
		var i_geocoder = i_self.getGeoCoder();
		var google = window.google;

		if (!i_geocoder) {
			i_geocoder = new google.maps.Geocoder();
			i_self.setGeoCoder(i_geocoder);
		}

		i_geocoder.geocode({
			address: addr
		}, Ext.Function.bind(i_self.onLookupComplete, i_self, [marker], true));
	},

	lookupAddr: function(addr, f_callback) {

		var i_self = this;

		f_callback = f_callback || function(o_data) {
			var i_element = i_self.getEl();
			if (i_element && i_element.dom) {
				if (i_self.getMap()) {
					var i_map = i_self.getMap();
					if (o_data[0]) {
						i_map.setCenter(o_data[0].geometry.location);

						var a_markers = i_self.getAdded();

						Ext.Array.each(a_markers, function(i_marker) {
							i_marker.setMap(null);
						});

						i_self.setAdded([]);

						i_self.addMarker({
							position: o_data[0].geometry.location
						});
					}
				}
				else {
					if (o_data[0]) {
						i_self.setStored(o_data[0].geometry.location);
					}
				}
			}
			else {
				if (o_data[0]) {
					i_self.setStored(o_data[0].geometry.location);
				}
			}
		};

		var i_geocoder = i_self.getGeoCoder();
		var google = window.google;

		if (!i_geocoder) {
			i_geocoder = new google.maps.Geocoder();
			i_self.setGeoCoder(i_geocoder);
		}

		i_geocoder.geocode({
			address: addr
		}, Ext.Function.bind(f_callback, i_self, [{}], true));
	},

	onLookupComplete: function(o_data, response, marker) {

		var i_self = this;

		if (response != "OK") {
			Ext.MessageBox.alert("Error", "An error occured: \"" + response + "\"");
			return;
		}
		var i_element = i_self.getEl();
		if (i_element.dom) {
			i_self.createMap(o_data[0].geometry.location, marker);
		}
		else {
			i_self.setStored(o_data[0].geometry.location);
		}
	},

	afterComponentLayout: function(w, h) {

		var i_self = this;

		i_self.callParent(arguments);
		i_self.redraw();
	},

	redraw: function() {

		var i_self = this;
		var google = window.google;
		var i_map = i_self.getMap();

		if (i_map) {
			google.maps.event.trigger(i_map, "resize");
		}
	}

});
