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);
	}
});
