
Ext.define("Portfolio.designer.view.Main", {

	xtype: "portfolio-designer-panel",

	extend: "Ext.panel.Panel",

	layout: {
		type: "border"
	},

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

	requires: [
		"Portfolio.designer.model.ip2DomainModelHistory",
		"Portfolio.designer.ui.domainModelEntity",
		"Portfolio.designer.ui.wizard.view.Window",
		"Portfolio.designer.import.view.Main",
		"Portfolio.designer.ui.save.view.Main",
		"Portfolio.pd.util.Handler",
		"Portfolio.pd.util.Cache",
		"Ext.ux.file.view.Explorer"
	],

	requiredScripts: [
		"/system/shared/jquery/jquery-1.9.0.js",
		"/system/shared/raphael/raphael.2.1.0.min.js",
		"/system/shared/jquery/jquery.utilities.js",
		"/portfolio/app/designer/SvgConnecter.js",
		"/portfolio/app/designer/Designer.css"
	],

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

				var o_result = ip2.getEvaled("/portfolio/app/designer/designer.json");

				i_self.setNormal(o_result);

				if (i_self.getDmdFile()) {
					if (i_self.getDmdFile() == "*new") {
						i_self.newDomainModel();
					}
					else {
						i_self.loadDomainModel(i_self.getDmdFile());
					}
				}
			},
			buffer: 100
		},
		statechange: {
			fn: function(i_self) {

				var o_menu = i_self.getMenu();

				o_menu.file.fireEvent("setState");
				o_menu.tool.fireEvent("setState");

				i_self.setChanged();
			}
		},
		complete: {
			fn: function(i_self) {

				var o_menu = i_self.getMenu();

				o_menu.file.fireEvent("setState");
				o_menu.tool.fireEvent("setState");
				i_self.setDesignerTitle();
			}
		},
		beforeclose: {
			fn: function(i_self) {

				var b_dirty = i_self.checkChange();

				if (b_dirty) {
					i_self.promptSaveChanges(function() {
						i_self.close();
					});
				}

				return !b_dirty;
			}
		},
		removeEntity: {
			fn: function(i_panel, o_entity) {

				var i_self = this;

				var i_modelpanel = i_self.getModelPanel();
				var o_model = i_self.getModel();

				var o_remove = 0;

				Ext.Array.each(o_model.entities, function(o_value) {
					if (o_value.name == o_entity.name) {
						o_remove = o_value;
					}
				});

				if (o_remove) {
					Ext.Array.remove(o_model.entities, o_remove);
				}


				Ext.Array.each(o_model.required, function(o_value, n_idx) {
					if (o_value.name == o_entity.name) {
						o_remove = o_value;
					}
				});

				if (o_remove) {
					Ext.Array.remove(o_model.required, o_remove);
				}

				i_modelpanel.remove(i_panel);
			}
		}
	},

	settings: {
		entities: {
			lastX: 0,
			lastY: 0,
			size: [200,150]
		}
	},

	current: {
		extend: {}
	},

	changed: false,

	config: {
		model: {},
		normal: {},
		state: "new",
		baseDatatypeChanged: false,
		modelPanel: null,
		menu: null,
		dmdFile: "",
		serviceProxy: "/ip2-services/ip2dmdProxy.aspx",
		biosProxy: "/ip2-services/webBios.aspx",
		actionBar: null,
		relations: [],
		entityPanels: [],
		svg: null,
		entities: [],
		originalModel: {},
		requiredPanel: null
	},

	initComponent: function() {

		var i_self = this;

		i_self.callParent();

		var o_menu = {};

		var i_fileMenu = i_self.createFileMenu();

		var i_toolMenu = i_self.createToolMenu();

		var i_toolbar = Ext.widget("toolbar", {
			dock: "top",
			items: [
				{
					text: "File",
					menu: i_fileMenu
				},
				{
					text: "Tools",
					menu: i_toolMenu
				}
			]
		});

		i_self.addDocked(i_toolbar);

		i_self.add(i_self.createLayout());

		Ext.apply(o_menu, {
			file: i_fileMenu,
			tool: i_toolMenu
		});

		i_self.setMenu(o_menu);
		i_self.setActionBar(i_toolbar);

		i_self.resetDirty();
	},

	createFileMenu: function() {

		var i_self = this;

		var i_resentStore = Ext.create("Ext.data.Store", {
			autoLoad: false,
			model: "Portfolio.designer.model.ip2DomainModelHistory",
		});

		var i_resentFiles = Ext.create("Ext.menu.Menu", {
			items: [],
			store: i_resentStore,
			listeners: {
				beforeshow: {
					fn: function(i_menuitem) {

						i_menuitem.removeAll(true);
						i_resentStore.load();
					}
				}
			}
		});

		i_resentStore.on({
			load: {
				fn: function (i_store) {

					var a_records = i_store.getRange();

					var a_files = [];

					Ext.Array.each(a_records, function (i_record) {

						var i_menuitem = Ext.widget("menuitem", {
							text: i_record.get("HISVAL"),
							handler: function () {
								if (i_self.checkChange()) {
									i_self.promptSaveChanges(function () {
										i_self.cleanUp();
										i_self.loadDomainModel(i_record.get("HISVAL"));
									});
								}
								else {
									i_self.cleanUp();
									i_self.loadDomainModel(i_record.get("HISVAL"));
								}
							}
						});

						a_files.push(i_menuitem);
					});

					i_resentFiles.add(a_files);
				}
			}
		});

		var i_fileMenu = Ext.create("Ext.menu.Menu", {
			defaults: {
				xtype: "menuitem"
			},
			items: [
				{
					text: ip2.i18n("newDomainModel"),
					itemId: "newDomainModel",
					iconCls: "pf-document_empty",
					handler: function() {
						i_self.newDomainModel();
					}
				},
				{
					text: ip2.i18n("openDomainModel"),
					itemId: "openDomainModel",
					iconCls: "pf-cabinet",
					handler: function() {
						i_self.openDomainModel();
					}
				},
				{
					text: ip2.i18n("saveDomainModel"),
					itemId: "saveDomainModel",
					iconCls: "pf-floppy_disk",
					handler: function() {
						i_self.saveDomainModel();
					}
				},
				{
					text: ip2.i18n("saveAsDomainModel"),
					itemId: "saveAsDomainModel",
					iconCls: "pf-floppy_disks",
					handler: function() {
						i_self.saveAsDomainModel();
					}
				},
				{
					text: ip2.i18n("closeDomainModel"),
					itemId: "closeDomainModel",
					iconCls: "pf-close",
					handler: function() {
						i_self.closeDomainModel();
					}
				},
				{
					xtype: "menuseparator"
				},
				{
					text: ip2.i18n("properties"),
					itemId: "properties",
					iconCls: "pf-gearwheel",
					handler: function() {
						i_self.domainModelProperties("existing");
					}
				},
				{
					xtype: "menuseparator"
				},
				{
					text: ip2.i18n("newEntity"),
					itemId: "newEntity",
					iconCls: "pf-documents_empty",
					handler: function() {
						i_self.newEntity();
					}
				},
				{
					xtype: "menuseparator"
				},
				{
					text: ip2.i18n("recentFiles"),
					itemId: "recentFiles",
					iconCls: "pf-history2",
					menu: i_resentFiles
				},
				{
					xtype: "menuseparator"
				}
			],
			listeners: {
				render: {
					fn: function(i_menu) {
						i_menu.fireEvent("setState");
					}
				},
				setState: {
					fn: function() {

						var i_menu = this;
						var s_file = i_self.getDmdFile();

						if (i_self.state == "new") {
							i_menu.items.get("saveDomainModel").disable();
							i_menu.items.get("saveAsDomainModel").enable();
							i_menu.items.get("closeDomainModel").disable();
							i_menu.items.get("properties").enable();
							i_menu.items.get("newEntity").enable();
						}
						else {

							if (!s_file) {
								i_menu.items.get("saveDomainModel").disable();
								i_menu.items.get("saveAsDomainModel").disable();
								i_menu.items.get("closeDomainModel").disable();
								i_menu.items.get("properties").disable();
								i_menu.items.get("newEntity").disable();
							}
							else {
								i_menu.items.get("saveDomainModel").enable();
								i_menu.items.get("saveAsDomainModel").enable();
								i_menu.items.get("closeDomainModel").enable();
								i_menu.items.get("properties").enable();
								i_menu.items.get("newEntity").enable();
							}
						}
					}
				}
			}
		});

		return i_fileMenu;
	},

	createToolMenu: function() {

		var i_self = this;

		var i_menuTools = Ext.create("Ext.menu.Menu", {
			items: [
				{
					text: ip2.i18n("importLibrary"),
					itemId: "importLibrary",
					iconCls: "pf-server_client_exchange",
					handler: function() {
						i_self.importEntities("library");
					}
				},
				{
					text: ip2.i18n("importTable"),
					itemId: "importTable",
					iconCls: "pf-server_client_exchange",
					handler: function() {
						i_self.importEntities("table");
					}
				},
				{
					xtype: "menuitem",
					text: ip2.i18n({
						da: "Byg model",
						en: "Build model"
					}),
					itemId: "buildmodel",
					iconCls: "pf-wrench",
					disabled: !i_self.getDmdFile() ? true : false,
					handler: function() {
						i_self.doBuildModel();
					}
				},
				{
					xtype: "menuitem",
					text: ip2.i18n({
						da: "Organiserer",
						en: "Organize"
					}),
					itemId: "organizemodel",
					disabled: !i_self.getDmdFile() ? true : false,
					menu: {
						items: [
							{
								xtype: "menuitem",
								iconCls: "pf-find_text",
								text: ip2.i18n({
									da: "Navn",
									en: "Name"
								}),
								handler: function() {
									i_self.doOrganizeModel(0);
								}
							},
							{
								xtype: "menuitem",
								iconCls: "pf-calendar_clock",
								text: ip2.i18n({
									da: "Sidste ændring",
									en: "Last modified"
								}),
								handler: function() {
									i_self.doOrganizeModel(1);
								}
							}
						]
					}

				}
			],
			listeners: {
				render: {
					fn: function(i_menu) {
						i_menu.fireEvent("setState");
					}
				},
				setState: {
					fn: function() {

						var i_menu = this;
						var o_model = i_self.getModel();

						if (!o_model.name) {
							i_menu.items.get("importLibrary").disable();
							i_menu.items.get("importTable").disable();
						}
						else {
							i_menu.items.get("importLibrary").enable();
							i_menu.items.get("importTable").enable();
						}
					}
				}
			}
		});

		return i_menuTools;
	},

	doOrganizeModel: function(n_type) {

		var i_self = this;
		var i_modelpanel = i_self.getModelPanel();

		var o_size = i_modelpanel.getSize();

		var a_panels = i_modelpanel.query("ip2DomainModelEntity");

		var n_x = 10;
		var n_y = 10;
		var n_count = 1;
		var o_rows = {};
		var n_index = 0;
		var n_heigthes = 0;
		var n_padding = 10;

		var a_sorted = [];

		switch (n_type) {
			case 0:
				a_sorted = Ext.Array.sort(a_panels, function(a, b) {
					return Ext.Array.lexicalCompare(a.entity.name, b.entity.name);
				});
				break;
			case 1:
				a_sorted = Ext.Array.sort(a_panels, function(a, b) {
					var n_lastA = a.getLastModified() || 0;
					var n_lastB = b.getLastModified() || 0;

					return n_lastB - n_lastA;
				});
				break;
			default:
				a_sorted = Ext.Array.sort(a_panels, function(a, b) {
					return Ext.Array.lexicalCompare(a.entity.name, b.entity.name);
				});
				break;
		};

		Ext.Array.each(a_sorted, function(i_panel) {

			var o_panelSize = i_panel.getSize();

			var o_box = Ext.Object.merge({}, {
				x: n_x,
				y: n_y
			}, o_panelSize);

			var a_rows = o_rows[n_count] || [];

			if ((n_x + o_box.width) > (o_size.width - 25)) {
				n_heigthes = 0;
				n_index = 0;
				n_x = n_count % 2 ? 40 : 10;
				n_count++;

				a_rows = [];
			}

			a_rows.push({
				box: o_box,
				el: i_panel.getEl()
			});

			o_rows[n_count] = a_rows;

			if (n_count > 1) {

				var a_saved = o_rows[n_count - 1];

				if (n_index < a_saved.length) {

					var o_index = a_saved[n_index];
					var b_intersected = false;
					var o_intersected;

					var o_saved = o_index.box;

					n_y = o_saved.y + o_saved.height + n_padding;
					o_box.y = n_y;
					o_box.x = n_x;

					Ext.Array.each(a_saved, function(o_entry) {

						var o_value = o_entry.box;

						// THIS WILL BE FALSE IF WE INTERSECT

						var n_maxX = Math.max(o_box.x, o_value.x);
						var n_maxY = Math.max(o_box.y, o_value.y);

						var n_minWidth = Math.min(o_box.x + o_box.width, o_value.x + o_value.width);
						var n_minHeight = Math.min(o_box.y + o_box.height, o_value.y + o_value.height);

						if (n_minWidth >= n_maxX && n_minHeight >= n_maxY) {
							b_intersected = true;
							o_intersected = o_value;
						}
					});

					if (b_intersected) {
						n_y = o_intersected.y + o_intersected.height + n_padding;
						o_box.y = n_y;
					}
				}
			}

			n_index++;

			i_panel.setPosition(n_x, n_y, true);

			n_x += o_panelSize.width + n_padding;
		});
	},

	createLayout: function() {

		var i_self = this;

		var a_items = [];

		var i_panel = Ext.widget("panel", {
			flex: 5,
			layout: "absolute",
			autoScroll: true,
			region: "center",
			listeners: {
				afterrender: {
					fn: function(i_panel) {

						var i_owner = i_panel.ownerCt;

						Ext.create("Ext.dd.DropTarget", i_panel.body.el, {
							ddGroup: "model",
							panelId: i_panel.id,
							notifyEnter: function() {
								var i_self = Ext.getCmp(this.panelId);
								var i_body = i_self.body;
								i_body.setStyle("background-color", "#d4e7f7");
							},
							notifyOut: function() {
								var i_self = Ext.getCmp(this.panelId);
								var i_body = i_self.body;
								i_body.setStyle("background-color", "white");
							},
							notifyDrop: function(source, e, data) {

								var i_self = Ext.getCmp(this.panelId);
								var i_body = i_self.body;
								var i_new = i_self.add(data.panel);

								i_new.dd.removeFromGroup("model");
								i_new.dd.addToGroup(i_new.ddGroup);

								i_body.setStyle("background-color", "white");
								Ext.defer(i_new.updateLayout, 1, i_new);
							}
						});

						i_panel.body.on({
							scroll: {
								fn: function(i_element) {

									if (i_owner.svg) {

										var a_connections = i_owner.svg.connections;

										Ext.Array.each(a_connections, function(o_connection) {

											var a_slaves = o_connection.slaves;
											var b_found = false;

											Ext.Array.each(a_slaves, function(o_slave) {
												if (o_slave.path.id) {
													b_found = true;
													return false;
												}
											});

											if (b_found) {

												o_connection.hide();
												o_connection.show();
											}
										});
									}
								},
								scope: "this"
							}
						});
					}
				}
			}
		});

		a_items.push(i_panel);

		i_self.setModelPanel(i_panel);

		return a_items;
	},

	setChanged: function() {

		var i_self = this;
		i_self.setDesignerTitle();
	},

	setDesignerTitle: function() {

		var i_self = this;
		var o_model = i_self.getModel();
		var s_title = ip2.i18n(o_model.title);

		var a_titel = [];

		a_titel.push("Domain Model");
		a_titel.push(s_title);
		a_titel.push("( " + i_self.getDmdFile() + ")");

		a_titel = Ext.Array.filter(a_titel, function(s_value) {
			return s_value;
		});

		s_title = a_titel.join(" - ");

		i_self.setTitle(s_title);
	},

	newDomainModel: function() {

		var i_self = this;

		if (i_self.checkChange()) {
			i_self.promptSaveChanges(function() {
				i_self.cleanUp();
				i_self.domainModelProperties("new");
			});
		}
		else {
			i_self.cleanUp();
			i_self.domainModelProperties("new");
		}
	},

	openDomainModel: function() {

		var i_self = this;

		var i_window = Ext.widget("file.explorer", {
			fileExtension: [
				{
					ext: "dmd",
					desc: "Domain Model (*.dmd)"
				}
			],
			path: ip2.baseconfig.session.preset.root || "/",
			modal: true,
			listeners: {
				fileopen: {
					fn: function(i_explorer, s_file) {

						i_self.cleanUp();
						i_self.loadDomainModel(s_file);
					}
				}
			}
		});

		i_window.show();
	},

	checkChange: function() {

		// var i_self = this;

		// var o_copy = Ext.clone(i_self.getModel());

		// var a_entities = Ext.Object.getValues(o_copy.entities);

		// Ext.Array.each(a_entities, function(o_entity) {

		// 	i_self.convertEntityObject2Array(o_entity);

		// 	delete o_entity.menuEntryPoint;

		// 	Ext.Array.each(o_entity.columns, function(o_column) {
		// 		i_self.sanitizeObject(o_column);
		// 	});
		// });

		// var a_entityPanels = i_self.query("ip2DomainModelEntity");

		// Ext.Array.each(a_entityPanels, function(i_panel) {

		// 	Ext.Array.each(a_entities, function(o_entity) {

		// 		if (i_panel.entity.name == o_entity.name) {

		// 			var o_panelEntity = i_panel.getEntity();

		// 			var i_element = i_panel.getEl();
		// 			var a_xy = i_element.getLocalXY();

		// 			Ext.Object.merge(o_entity, o_panelEntity);

		// 			o_entity.designer.x = a_xy[0];
		// 			o_entity.designer.y = a_xy[1];

		// 			return false;
		// 		}
		// 	});
		// });

		// if (!o_copy.designer) {
		// 	o_copy.designer = {};
		// }

		// o_copy = i_self.setDomainModelDefaults(o_copy);

		// // insert unique token for entities and relations
		// var cid = 65;

		// Ext.Array.each(a_entities, function(o_value) {
		// 	o_value.cid = String.fromCharCode(cid);
		// 	cid++;
		// });

		// var r_cid = 65;

		// Ext.Array.each(o_copy.relations, function(o_value) {
		// 	o_value.cid = String.fromCharCode(r_cid);
		// 	r_cid++;
		// });

		// var o_originalModel = i_self.getOriginalModel();

		// var s_model = Ext.encode(o_copy);
		// var s_originalValue = Ext.encode(o_originalModel);

		return false;
	},

	resetDirty: function() {

		var i_self = this;

		// var o_result = Ext.clone(i_self.getModel());

		// var a_entities = Ext.Object.getValues(o_result.entities);

		// Ext.Array.each(a_entities, function(o_entity) {

		// 	i_self.convertEntityObject2Array(o_entity);

		// 	delete o_entity.menuEntryPoint;

		// 	Ext.Array.each(o_entity.columns, function(o_column) {

		// 		i_self.sanitizeObject(o_column);
		// 	});
		// });

		// var a_entityPanels = i_self.query("ip2DomainModelEntity");

		// Ext.Array.each(a_entityPanels, function(i_panel) {

		// 	Ext.Array.each(a_entities, function(o_entity) {

		// 		if (i_panel.entity.name == o_entity.name) {

		// 			var o_panelEntity = i_panel.getEntity();
		// 			var i_element = i_panel.getEl();
		// 			var a_xy = i_element.getLocalXY();

		// 			Ext.apply(o_entity, o_panelEntity);

		// 			o_entity.designer.x = a_xy[0];
		// 			o_entity.designer.y = a_xy[1];

		// 			return false;
		// 		}
		// 	});
		// });

		// if (!o_result.designer) {
		// 	o_result.designer = {};
		// }

		// o_result = i_self.setDomainModelDefaults(o_result);

		// // insert unique token for entities and relations
		// var cid = 65;

		// Ext.Array.each(a_entities, function(o_value) {
		// 	o_value.cid = String.fromCharCode(cid);
		// 	cid++;
		// });

		// var r_cid = 65;

		// Ext.Array.each(o_result.relations, function(o_value) {
		// 	o_value.cid = String.fromCharCode(r_cid);
		// 	r_cid++;
		// });

		// i_self.setOriginalModel(Ext.clone(o_result));
		// i_self.setModel(o_result);
	},

	loadDomainModel: function(s_file) {

		var i_self = this;

		i_self.setDmdFile(s_file);

		i_self.setLoading(true);

		Ext.Ajax.request({
			method: "GET",
			url: "/ip2-services/webBios.aspx",
			params: {
				func: "readstmf",
				file: s_file
			},
			success: function(i_response, i_operation) {

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

				if (!o_result) {

					ip2.messageBox({
						title: ip2.i18n({
							da: "Fejl",
							en: "Error"
						}),
						closable: false,
						message: ip2.i18n({
							da: "DMD er ikke velformet",
							en: "DMD is not wellformed"
						}),
						yesText: "Ok",
						icon: Ext.MessageBox.ERROR
					});
				}
				else {

					var a_models = [];
					var a_requires = [];
					var a_required = [];
					var o_model = o_result.model;

					i_self.addNameToConfig(o_model.entities);

					o_model.entities = Ext.Object.getValues(o_model.entities);

					Ext.Array.each(o_model.entities, function(o_entity) {
						i_self.convertEntityObject2Array(o_entity);
					});

					a_models.push(o_model);
					o_model.required = a_required;

					var a_require = o_model.require || [];
					var n_require = a_require.length;

					if (n_require) {
						Ext.Array.each(a_require, function(s_file) {

							Ext.Ajax.request({
								method: "GET",
								url: "/ip2-services/webBios.aspx",
								params: {
									func: "readstmf",
									file: s_file
								},
								success: function(i_response, i_operation) {

									var o_gotten = Ext.decode(i_response.responseText, true) || false;

									if (Ext.isObject(o_gotten)) {

										var s_model = s_file.split("/").pop().split(".").shift();
										o_gotten.model.id = s_model;
										a_models.push(o_gotten.model);
										a_requires.push(o_gotten.model);

										var o_requiredModel = o_gotten.model;

										i_self.addNameToConfig(o_requiredModel.entities);

										var a_entities = Ext.Object.getValues(o_requiredModel.entities);

										Ext.Array.each(a_entities, function(o_entity) {

											o_entity.modelId = s_model;
											o_entity.model = o_requiredModel;
											o_entity = i_self.convertEntityObject2Array(o_entity);
											a_required.push(o_entity);
										});
									}
									n_require--;
									if (n_require === 0) {
										i_self.completeLoad(o_result, o_model, a_models, a_requires, a_required);
										i_self.setLoading(false);
									}
								},
								failure: function(o_err) {
									i_self.setLoading(false);
								}
							});
						});
					}
					else {
						i_self.completeLoad(o_result, o_model, a_models, a_requires, a_required);
						i_self.setLoading(false);
					}
				}
			}
		});
	},

	addNameToConfig: function(o_values) {

		if (Ext.isObject(o_values)) {

			Ext.Object.each(o_values, function(s_key, o_value) {
				o_value.name = s_key;
				//o_value.name = s_key.toUpperCase();
			});
		}
		else {
			Ext.Array.each(o_values, function(o_value) {
				var s_key = o_value.name;
				//o_value.name = s_key.toUpperCase();
			});
		}
	},

	completeLoad: function(o_result, o_model, a_models, a_requires, a_required) {

		var i_self = this;

		var o_settings = i_self.settings;
		var i_modelpanel = i_self.getModelPanel();
		var o_menu = i_self.getMenu();

		Ext.Ajax.request({
			method: "GET",
			url: "/ip2-services/ip2navigator.aspx",
			params: {
				func: "database",
				dbName: "navhis",
				action: "create",
				histyp: "dmd",
				hisval: i_self.getDmdFile()
			}
		});

		// insert missing object, if needed
		o_model = i_self.setDomainModelDefaults(o_model);

		var a_entities = Ext.Object.getValues(o_model.entities);

		Ext.apply(i_self, o_result);

		Ext.apply(i_self, {
			state: "old"
		});

		var a_entityPanels = [];

		Ext.Array.each(a_entities, function(o_entity) {

			i_self.convertEntityObject2Array(o_entity);

			var o_designer = o_entity.designer || {};

			var n_width = o_settings.entities.size[0];
			var n_height = o_settings.entities.size[1];
			var n_modified = o_designer.lastmodified || null;

			if (o_designer) {
				n_width = o_designer.width || n_width;
				n_height = o_designer.height || n_height;
			}

			var i_entityPanel = Ext.widget("ip2DomainModelEntity", {
				designer: i_self,
				entity: o_entity,
				entityName: o_entity.name,
				width: n_width,
				height: n_height,
				lastModified: n_modified,
				listeners: {
					afterrender: {
						fn: function(i_panel) {

							var i_header = i_panel.getHeader();
							var i_current = i_panel;

							if (o_model.header) {
								i_header.setStyle("background-color", o_model.header);
								i_header.titleCmp.setStyle("color", o_model.text);
							}

							if (i_current.getEl()) {
								var i_el = i_current.getEl();
								i_el.on({
									click: {
										fn: function(i_element) {
											var a_panels = i_modelpanel.query("ip2DomainModelEntity");

											Ext.Array.each(a_panels, function(i_panel) {
												i_panel.setZIndex(1);
											});

											i_current.setZIndex(2);
										}
									}
								});
							}

							var a_buttons = i_header.query("button[itemId=menubutton]");
							var a_tools = i_header.query("tool");

							Ext.Array.each(a_buttons, function(i_component) {
								i_component.on({
									afterrender: {
										fn: function(i_button) {
											var s_color = window.getComputedStyle(i_header.el.dom, null).getPropertyValue("background-color");
											i_button.el.dom.style.setProperty("background-color", s_color, "important");
										}
									}
								});
							});
						}
					},
					edit: {
						fn: function(i_panel) {

							i_self.setLoading(true);
							i_panel.onEdit();
							i_self.setLoading(false);
						}
					}
				}
			});

			a_entityPanels.push(i_entityPanel);

			if (o_designer) {
				if (o_designer.x > o_settings.entities.lastX) {
					o_settings.entities.lastX = o_designer.x;
					o_settings.entities.lastY = o_designer.y;
				}
				else if (o_designer.y > o_settings.entities.lastY) {
					o_settings.entities.lastY = o_designer.y;
				}
			}
		});

		var a_temp = [];

		Ext.Array.each(o_model.required, function(o_entity) {

			var o_entityModel = o_entity.model;

			var o_designer = o_entity.designer || {};

			o_entityModel.required = o_model.required;

			delete o_entity.model;

			var n_width = o_settings.entities.size[0];
			var n_height = o_settings.entities.size[1];
			var n_modified = o_designer.lastmodified || null;

			if (o_designer) {
				n_width = o_designer.width || n_width;
				n_height = o_designer.height || n_height;
			}

			var i_entityPanel = Ext.widget("ip2DomainModelEntity", {
				designer: i_self,
				entity: Ext.apply({}, o_entity),
				entityName: o_entity.name,
				modelId: o_entity.modelId,
				model: o_entityModel,
				ddGroup: o_entity.modelId,
				width: o_settings.entities.size[0],
				height: o_settings.entities.size[1],
				lastModified: n_modified,
				required: true,
				border: true,
				listeners: {
					afterrender: {
						fn: function(panel) {

							var i_header = panel.getHeader();

							if (panel.model.header) {
								i_header.setStyle("background-color", panel.model.header);
								i_header.titleCmp.setStyle("color", panel.model.text);
							}

							var a_buttons = i_header.query("button[itemId=menubutton]");

							Ext.Array.each(a_buttons, function(i_component) {
								i_component.on({
									afterrender: {
										fn: function(i_button) {
											var s_color = window.getComputedStyle(i_header.el.dom, null).getPropertyValue("background-color");
											i_button.el.dom.style.setProperty("background-color", s_color, "important");
										}
									}
								});
							});
						}
					},
					boxready: {
						fn: function(i_panel) {
							i_panel.dd.addToGroup("model");
						}
					},
					edit: {
						fn: function(i_panel) {

							i_self.setLoading(true);
							i_panel.onEdit();
							i_self.setLoading(false);
						}
					}
				}
			});

			a_temp.push(i_entityPanel);

			if (o_designer) {
				if (o_designer.x > o_settings.entities.lastX) {
					o_settings.entities.lastX = o_designer.x;
					o_settings.entities.lastY = o_designer.y;
				}
				else if (o_designer.y > o_settings.entities.lastY) {
					o_settings.entities.lastY = o_designer.y;
				}
			}
			delete o_entity.model;
			delete o_entity.modelId;
		});

		Ext.suspendLayouts();

		i_modelpanel.add(a_entityPanels);

		i_self.setDesignerTitle();

		o_model.required = a_required;

		var a_relations = [];

		Ext.Array.each(a_models, function(o_model) {

			var a_modelRelation = Ext.Object.getValues(o_model.relations);
			a_relations = a_relations.concat(a_modelRelation);
		});

		if (a_requires.length > 0 && a_temp.length > 0) {
			i_self.addRequire(a_requires, a_temp);
			a_entityPanels = a_entityPanels.concat(a_temp);
		}

		i_self.setRelations(a_relations);
		i_self.setEntityPanels(a_entityPanels);

		Ext.resumeLayouts(true);

		var a_connections = a_entities.concat(a_required);

		o_model.required = a_connections;

		var i_svg = i_self.doSvgConnections(a_relations, a_connections, a_entityPanels);

		var i_menuitem = o_menu.tool.child("#buildmodel");

		if (i_menuitem) {
			i_menuitem.enable();
		}

		i_menuitem = o_menu.tool.child("#organizemodel");

		if (i_menuitem) {
			i_menuitem.enable();
		}

		Ext.Array.each(i_svg.connections, function(i_connection) {
			i_connection.hide();
		});

		i_self.setSvg(i_svg);

		i_self.resetDirty();

		var i_panelRequired = i_self.getRequiredPanel();

		if (i_panelRequired) {
			i_panelRequired.collapse();
		}

		i_self.fireEvent("complete", i_self);
	},

	doSaveApplication: function(s_entity) {

		var i_self = this;
		var o_model = i_self.getModel();

		var o_entity = Ext.Array.findBy(o_model.required, function(o_value) {
			return o_value.name == s_entity;
		});

		var i_window = Ext.widget("designer.ui.save.view.main", {
			title: ip2.i18n({
				en: "Save application:",
				da: "Gem applikation:"
			}),
			width: 900,
			height: 500,
			entity: s_entity,
			dmd: "dmd/" + ip2.cleanPath(i_self.getDmdFile()).split("/").pop(),
			entityTitle: o_entity.title
		});

		i_window.show();
	},

	doSaveAndBuild: function(s_entity) {

		var i_self = this;
		var o_model = i_self.getModel();
		var a_required = o_model.required;

		o_model = i_self.prepareSave(o_model);

		if (!o_model.name) {
			Portfolio.util.Handler.messageBox({
				icon: Ext.Msg.WARNING,
				closable: false,
				message: ip2.i18n({
					da: "Database mangler",
					en: "Batabase missing"
				}),
				yesText: ip2.i18n({
					da: "OK",
					en: "OK"
				})
			});
			return;
		}

		delete o_model.required;

		ip2.mask(ip2.i18n({
			da: "Gemmer og bygger entitet....",
			en: "Saving and building entity..."
		}));

		var o_values = {
			dmdFile: i_self.getDmdFile(),
			entity: s_entity,
			database: o_model.name
		};

		var o_json = Ext.apply({}, {
			model: o_model
		});

		var s_params = Ext.urlEncode(o_values);

		var s_file = i_self.getDmdFile();

		Ext.Ajax.request({
			url: i_self.getServiceProxy(),
			params: {
				action: "updateModel",
				dmdFile: s_file,
				entity: s_entity,
				database: o_model.name
			},
			jsonData: o_json,
			success: function (o_response) {

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

				ip2.unmask();

				if (o_result.success) {
					Portfolio.util.Handler.messageBox({
						icon: Ext.Msg.INFO,
						closable: false,
						title: "Status",
						message: ip2.i18n({
							da: "Bygging af entity komplet",
							en: "Building entity complete"
						}),
						yesText: ip2.i18n({
							da: "Ok",
							en: "OK"
						}),
						noText: ip2.i18n({
							da: "Vis joblog",
							en: "Show joblog"
						}),
						yesFn: function() {

							i_self.cleanUp();
							i_self.loadDomainModel(s_file);
						},
						noFn: function() {

							var o_size = ip2.getWindowSize();

							i_self.getJoblog(function(s_result) {

								var i_stackTrace = Ext.widget("acetextarea", {
									hideLabel: true,
									mode: "javascript",
									useWorker: false,
									margin: "0 0 0 0",
									listeners: {
										editorready: {
											fn: function() {

												var i_field = this;

												i_field.setValue(s_result);
											},
											buffer: 100
										}
									}
								});

								var i_window = Ext.widget("window", {
									title: ip2.i18n({
										da: "Job log",
										en: "Job log"
									}),
									layout: "fit",
									width: o_size.width * 0.9,
									height: o_size.height * 0.9,
									items: [
										i_stackTrace
									]
								});
								i_window.show();
							});

							i_self.cleanUp();
							i_self.loadDomainModel(s_file);
						}
					});
				}
				else {

					o_model.required = a_required;

					Portfolio.util.Handler.messageBox({
						icon: Ext.Msg.WARNING,
						closable: false,
						title: "Status",
						message: ip2.i18n({
							da: "Der skete en fejl under bygging af <strong>" + o_values.entity + "</strong>",
							en: "An error occured while building <strong>" + o_values.entity + "</strong>"
						}),
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						}),
						noText: ip2.i18n({
							da: "Vis joblog",
							en: "Show joblog"
						}),
						noFn: function() {

							var o_size = ip2.getWindowSize();

							var i_window = Ext.widget("window", {
								title: ip2.i18n({
									da: "Job log",
									en: "Job log"
								}),
								layout: "fit",
								width: o_size.width * 0.9,
								height: o_size.height * 0.9,
								items: [
									{
										xtype: "containeriframe",
										src: o_result.url,
										layout: "fit"
									}
								]
							});
							i_window.show();
						}
					});
				}
			},
			failure: function(o_err) {

				var o_error = {
					params: o_err
				};

				Portfolio.util.Message.Add("Build error", o_err, "js");

				ip2.unmask();
				i_self.cleanUp();
				i_self.loadDomainModel(s_file);
			}
		});
	},

	doBuildModel: function() {

		var i_self = this;
		var o_model = i_self.getModel();
		var a_required = o_model.required || [];

		o_model = i_self.prepareSave(o_model);

		if (!o_model.name) {
			Portfolio.util.Handler.messageBox({
				icon: Ext.Msg.WARNING,
				closable: false,
				message: ip2.i18n({
					da: "Database mangler",
					en: "Batabase missing"
				}),
				yesText: ip2.i18n({
					da: "OK",
					en: "OK"
				})
			});
			return;
		}

		delete o_model.required;

		Ext.getBody().mask(ip2.i18n({
			da: "Bygger model....",
			en: "Building model..."
		}));

		var o_values = {
			dmdFile: i_self.getDmdFile(),
			database: o_model.name
		};

		var o_json = Ext.apply({}, {
			model: o_model
		});

		var s_params = Ext.urlEncode(o_values);

		Ext.Ajax.request({
			url: i_self.getServiceProxy(),
			params: {
				action: "updateModel",
				dmdFile: i_self.getDmdFile(),
				database: o_model.name
			},
			jsonData: o_json,
			success: function (o_response) {

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

				Ext.getBody().unmask();

				if (o_result.success) {

					Portfolio.util.Handler.messageBox({
						icon: Ext.Msg.INFO,
						closable: false,
						title: "Status",
						message: ip2.i18n({
							da: "Bygging af entity komplet",
							en: "Building entity complete"
						}),
						yesText: ip2.i18n({
							da: "Luk",
							en: "Close"
						}),
						noText: ip2.i18n({
							da: "Vis joblog",
							en: "Show joblog"
						}),
						yesFn: function() {

							var s_file = i_self.getDmdFile();
							var s_path = "dmd/" + s_file.split("/").pop();
							ip2.resource.reload(s_path);
							i_self.cleanUp();
							i_self.loadDomainModel(s_file);
						},
						noFn: function() {

							var o_size = ip2.getWindowSize();

							i_self.getJoblog(function(s_result) {

								var i_stackTrace = Ext.widget("acetextarea", {
									hideLabel: true,
									mode: "javascript",
									useWorker: false,
									margin: "0 0 0 0",
									listeners: {
										editorready: {
											fn: function() {

												var i_field = this;

												i_field.setValue(s_result);
											},
											buffer: 100
										}
									}
								});

								var i_window = Ext.widget("window", {
									title: ip2.i18n({
										da: "Job log",
										en: "Job log"
									}),
									layout: "fit",
									width: o_size.width * 0.9,
									height: o_size.height * 0.9,
									items: [
										i_stackTrace
									]
								});
								i_window.show();
							});
						}
					});
				}
				else {

					o_model.required = a_required;

					Portfolio.util.Handler.messageBox({
						icon: Ext.Msg.WARNING,
						closable: false,
						title: "Status",
						message: ip2.i18n({
							da: "Der skete en fejl under bygging af model",
							en: "An error occured while building model"
						}),
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						}),
						noText: ip2.i18n({
							da: "Vis joblog",
							en: "Show joblog"
						}),
						noFn: function() {

							var o_size = ip2.getWindowSize();

							i_self.getJoblog(function(s_result) {

								var i_stackTrace = Ext.widget("acetextarea", {
									hideLabel: true,
									mode: "javascript",
									useWorker: false,
									margin: "0 0 0 0",
									listeners: {
										editorready: {
											fn: function() {

												var i_field = this;

												i_field.setValue(s_result);
											},
											buffer: 100
										}
									}
								});

								var i_window = Ext.widget("window", {
									title: ip2.i18n({
										da: "Job log",
										en: "Job log"
									}),
									layout: "fit",
									width: o_size.width * 0.9,
									height: o_size.height * 0.9,
									items: [
										i_stackTrace
									]
								});
								i_window.show();
							});
						}
					});
				}
			},
			failure: function() {

				Ext.getBody().unmask();

				o_model.required = a_required;

				Portfolio.util.Handler.messageBox({
					icon: Ext.Msg.WARNING,
					closable: false,
					title: "Status",
					message: ip2.i18n({
						da: "Der skete en fejl under bygging af model",
						en: "An error occured while building model"
					}),
					yesText: ip2.i18n({
						da: "Vis joblog",
						en: "Show joblog"
					}),
					yesFn: function() {

						var o_size = ip2.getWindowSize();

						i_self.getJoblog(function(s_result) {

							var i_stackTrace = Ext.widget("acetextarea", {
								hideLabel: true,
								mode: "javascript",
								useWorker: false,
								margin: "0 0 0 0",
								listeners: {
									editorready: {
										fn: function() {

											var i_field = this;

											i_field.setValue(s_result);
										},
										buffer: 100
									}
								}
							});

							var i_window = Ext.widget("window", {
								title: ip2.i18n({
									da: "Job log",
									en: "Job log"
								}),
								layout: "fit",
								width: o_size.width * 0.9,
								height: o_size.height * 0.9,
								items: [
									i_stackTrace
								]
							});
							i_window.show();
						});
					}
				});
			}
		});
	},

	getJoblog: function(f_callback) {

		f_callback = f_callback || Ext.emptyFn;

		Ext.Ajax.request({
			url: "/ip2-services/webBios.aspx",
			params: {
				func: "readstmf",
				file: "/www/ip2sqlTrace.txt"
			},
			success: function (o_response) {

				var s_result = o_response.responseText;

				f_callback(s_result);
			}
		});
	},

	addRequire: function(a_requires, a_temp) {

		var i_self = this;

		var i_pnlRequirements = Ext.widget("panel", {
			title: ip2.i18n({
				da: "Required filer",
				en: "Required files"
			}),
			flex: 2,
			itemId: "panel-require",
			layout: {
				type: "vbox",
				align: "stretch"
			},
			region: "east",
			split: true,
			collapsible: true,
			collapseDirection: "right",
			border: false
		});

		var a_items = [];

		Ext.Array.each(a_requires, function(o_model) {

			var i_panel = Ext.widget("panel", {
				title: "Model - " + o_model.id,
				layout: "absolute",
				itemId: "model-" + o_model.id,
				ddGroup: o_model.id,
				flex: 1,
				split: true,
				autoScroll: true,
				collapsible: true,
				collapsed: false,
				listeners: {
					afterrender: {
						fn: function(i_panel) {

							var i_droptarget = new Ext.dd.DropTarget(i_panel.body.el, {
								ddGroup: i_panel.ddGroup,
								panelId: i_panel.id,
								notifyEnter: function(source, e, data) {
									var i_self = Ext.getCmp(this.panelId);
									i_self.body.setStyle("background-color", "#d4e7f7");
								},
								notifyOut: function() {
									var i_self = Ext.getCmp(this.panelId);
									i_self.body.setStyle("background-color", "white");
								},
								notifyDrop: function(source, e, data) {
									var i_self = Ext.getCmp(this.panelId);
									var i_new = i_self.add(data.panel);
									i_new.dd.removeFromGroup(i_panel.ddGroup);
									i_new.dd.addToGroup("model");
									i_self.body.setStyle("background-color", "white");
									Ext.defer(i_new.updateLayout, 1, i_new);
								}
							});

							i_panel.body.on({
								scroll: {
									fn: function(i_element) {

										var i_svg = i_self.getSvg();

										if (i_svg) {
											var a_connections = i_svg.connections;
											Ext.Array.each(a_connections, function(o_connection) {

												var a_slaves = o_connection.slaves;
												var b_found = false;

												Ext.Array.each(a_slaves, function(o_slave) {
													if (o_slave.path.id) {
														b_found = true;
														return false;
													}
												});

												if (b_found) {

													o_connection.hide();
													o_connection.show();
												}
											});
										}
									},
									scope: "this"
								}
							});
						}
					}
				}
			});
			delete o_model.id;

			var a_subs = [];

			Ext.Array.each(a_temp, function(i_temp) {
				if (i_panel.itemId == "model-" + i_temp.modelId) {
					a_subs.push(i_temp);
				}
			});

			i_panel.add(a_subs);

			a_items.push(i_panel);
		});

		i_pnlRequirements.add(a_items);

		i_self.add(i_pnlRequirements);

		i_self.setRequiredPanel(i_pnlRequirements);
	},

	sanitizeObject: function(o_value) {

		var i_self = this;

		for (var s_key in o_value) {
			var value = o_value[s_key];
			if (Ext.isPrimitive(value)) {
				if (Ext.isEmpty(value)) {
					delete o_value[s_key];
				}
			}
			else {
				i_self.sanitizeObject(o_value[s_key]);
			}
		}
	},

	saveDomainModel: function() {

		Ext.getBody().mask(ip2.i18n({
			da: "Gemmer",
			en: "Saving"
		}));

		var i_self = this;
		var o_model = i_self.getModel();

		o_model = i_self.prepareSave(o_model);

		var doServerSideSave = function() {

			delete o_model.required;

			var o_params = {
				model: o_model
			};

			Ext.Ajax.request({
				url: i_self.getServiceProxy(),
				params: {
					action: "saveModel",
					dmdFile: i_self.getDmdFile()
				},
				jsonData: o_params,
				success: function () {

					Ext.getBody().unmask();

					var s_file = i_self.getDmdFile();
					var s_path = "dmd/" + s_file.split("/").pop();

					ip2.resource.reload(s_path);

					i_self.cleanUp();
					i_self.loadDomainModel(s_file);
				},
				failure: function(o_err) {

					Ext.getBody().unmask();

					Portfolio.util.Handler.messageBox({
						icon: Ext.Msg.WARNING,
						closable: false,
						message: o_err.message,
						yesText: ip2.i18n({
							da: "OK",
							en: "OK"
						})
					});
				}
			});
		};

		if (i_self.state == "new" && i_self.action != "saveAs") {

			var i_window = Ext.widget("file.explorer", {
				fileExtension: [
					{
						ext: "dmd",
						desc: "Domain Model (*.dmd)"
					}
				],
				path: ip2.baseconfig.session.preset.root || "/",
				modal: true,
				closable: false,
				saveAction: true,
				listeners: {
					filesave: {
						fn: function(i_explorer, s_file) {

							i_self.setDmdFile(s_file);
							doServerSideSave();
						}
					}
				}
			});

			i_window.show();
		}
		else {
			delete i_self.action;
			doServerSideSave();
		}
	},

	saveAsDomainModel: function() {

		var i_self = this;

		i_self.action = "saveAs";

		var o_model = i_self.getModel();

		var i_window = Ext.widget("file.explorer", {
			fileExtension: [
				{
					ext: "dmd",
					desc: "Domain Model (*.dmd)"
				}
			],
			path: ip2.baseconfig.session.preset.root || "/",
			modal: true,
			closable: false,
			saveAction: true,
			listeners: {
				filesave: {
					fn: function(i_explorer, s_file) {

						i_self.setDmdFile(s_file);

						if (o_model && o_model.navigator) {
							delete o_model.navigator.rrn;
							delete o_model.navigator.applicationGroup;
						}

						i_self.saveDomainModel();
					}
				}
			}
		});

		i_window.show();
	},

	closeDomainModel: function() {

		var i_self = this;

		if (i_self.checkChange()) {
			i_self.promptSaveChanges(function() {
				i_self.cleanUp();
			});
		}
		else {
			i_self.cleanUp();
		}
	},

	prepareSave: function(o_model) {

		var i_self = this;

		var a_entities = Ext.Object.getValues(o_model.entities);

		o_model.entities = a_entities;
		var o_generate = o_model.generate || {};

		Ext.applyIf(o_generate, {
			tables: false,
			views: true,
			constraints: true,
			primaryKey: true
		});

		o_model.generate = o_generate;

		Ext.Object.each(a_entities, function(o_entity) {

			i_self.convertEntityObject2Array(o_entity);

			delete o_entity.menuEntryPoint;
		});

		var a_entityPanels = i_self.query("ip2DomainModelEntity");

		Ext.Array.each(a_entityPanels, function(i_panel) {

			Ext.Array.each(a_entities, function(o_entity) {

				if (i_panel.entity.name == o_entity.name) {

					var o_panelEntity = i_panel.getEntity();
					var i_element = i_panel.getEl();
					var a_xy = i_element.getLocalXY();
					var o_size = i_panel.getSize();
					Ext.Object.merge(o_entity, o_panelEntity);

					Ext.apply(o_entity.designer, {
						width: o_size.width,
						height: o_size.height,
						x: a_xy[0],
						y: a_xy[1]
					});

					i_self.sanitizeObject(o_entity);

					return false;
				}
			});
		});

		if (!o_model.designer) {
			o_model.designer = {};
		}

		o_model = i_self.setDomainModelDefaults(o_model);

		// insert unique token for entities and relations
		var cid = 65;

		Ext.Object.each(a_entities, function(s_key, o_value) {
			o_value.cid = String.fromCharCode(cid++);
		});

		var r_cid = 65;

		Ext.Array.each(o_model.relations, function(o_value) {
			o_value.cid = String.fromCharCode(r_cid++);
		});

		var n_rrn = o_model.navigator.rrn || 0;
		var s_action = n_rrn === 0 ? "create" : "update";
		var n_sequence = s_action === "create" ? -1 : -2;

		if (!o_model.generate.version) {

			var o_entities = i_self.arrayToObject(a_entities);

			Ext.Object.each(o_entities, function(s_key, o_entity) {

				var o_ui = o_entity.ui || {};

				Ext.applyIf(o_ui, {
					grids: [],
					forms: []
				});

				var o_grids = i_self.arrayToObject(o_ui.grids);
				var o_forms = i_self.arrayToObject(o_ui.forms);

				o_ui.grids = o_grids;
				o_ui.forms = o_forms;

				o_entity = o_ui;
			});

			o_model.entities = o_entities;
		}
		else {

			Ext.Array.each(a_entities, function(o_entity) {

				var o_ui = o_entity.ui || {};

				Ext.applyIf(o_ui, {
					grids: {},
					forms: {}
				});

				var a_grids = i_self.objectToArray(o_ui.grids);
				var a_forms = i_self.objectToArray(o_ui.forms);

				o_ui.grids = a_grids;
				o_ui.forms = a_forms;

				o_entity = o_ui;
			});
		}

		var a_filtered = [];

		var a_relations = o_model.relations || [];

		Ext.Array.each(a_relations, function(o_config) {

			var s_between = o_config.between.entity;
			var s_and = o_config.and.entity;

			var o_found = Ext.Array.findBy(a_filtered, function(o_stored) {

				return (s_between == o_stored.between.entity || s_between == o_stored.and.entity) &&
						(s_and == o_stored.and.entity || s_and == o_stored.between.entity);
			});

			if (!o_found) {
				a_filtered.push(o_config);
			}
		});

		o_model.relations = a_filtered;

		return o_model;
	},

	objectToArray: function(o_values) {

		var a_result = [];

		if (Ext.isObject(o_values)) {

			Ext.Object.each(o_values, function(s_key, o_value) {
				o_value.name = s_key;
				a_result.push(o_value);
			});
		}
		else {
			a_result = o_values;
		}

		return a_result;
	},

	arrayToObject: function(a_values) {

		var o_result = {};

		if (Ext.isArray(a_values)) {
			Ext.Array.each(a_values, function(o_value) {
				o_result[o_value.name] = o_value;
			});
		}
		else {
			o_result = a_values;
		}

		return o_result;
	},

	promptSaveChanges: function(f_callback) {

		var i_self = this;

		f_callback = f_callback || Ext.emptyFn;

		ip2.messageBox({
			icon: Ext.MessageBox.QUESTION,
			closable: false,
			title: ip2.i18n({
				da: "Ikke gemte ændringer",
				en: "Unsaved changes"
			}),
			message: ip2.i18n({
				da: "Vil du gemme ændringerne",
				en: "Do you want to save the changes"
			}),
			yesText: ip2.i18n({
				da: "Ja",
				en: "Yes"
			}),
			noText: ip2.i18n({
				da: "Nej",
				en: "no"
			}),
			yesFn: function() {
				i_self.saveDomainModel();
				f_callback();
			},
			noFn: function() {
				i_self.resetDirty();
				f_callback();
			}
		});
	},

	domainModelProperties: function(s_mode) {

		var i_self = this;
		var o_model = i_self.getModel();

		if (s_mode == "new") {
			i_self.state = "new";
			i_self.setDmdFile("dmd/new.dmd");

			o_model = i_self.setDomainModelDefaults(o_model);
			i_self.setModel(o_model);
		}

		var i_window = Ext.create("Portfolio.designer.ui.domainModelProperties", {
			designer: i_self
		});

		i_window.show();
	},

	importEntities: function(importType) {

		var i_self = this;

		var i_form = Ext.widget("designer.import.view.main", {
			border: false,
			bodyPadding: 10,
			layout: "anchor",
			defaults: {
				xtype: " textfield",
				labelAlign: "left",
				labelWidth: 150,
				anchor: "100%"
			},
			importType: importType
		});

		var i_window = Ext.widget("window", {
			title: "Import",
			width: 500,
			layout: "fit",
			resizable: true,
			modal: true,
			items: [
				i_form
			],
			listeners: {
				import: {
					fn: function(i_form, o_result) {

						var i_window = this;
						i_window.close();

						var i_modelpanel = i_self.getModelPanel();

						var o_model = i_self.getModel();

						var a_imported = [];

						var o_gotten = o_result.model;

						var a_new = [];

						if (o_gotten) {

							i_self.addNameToConfig(o_gotten.entities);

							var a_entities = Ext.Object.getValues(o_gotten.entities);

							Ext.Array.each(a_entities, function(o_entity) {

								i_self.convertEntityObject2Array(o_entity);

								delete o_entity.primaryKey;

								a_imported.push(o_entity);

								var i_entityPanel = Ext.widget("ip2DomainModelEntity", {
									designer: i_self,
									entity: o_entity,
									entityName: o_entity.name,
									listeners: {
										afterrender: {
											fn: function(i_panel) {

												var i_header = i_panel.getHeader();
												var i_current = i_panel;

												if (o_model.header) {
													i_header.setStyle("background-color", o_model.header);
													i_header.titleCmp.setStyle("color", o_model.text);
												}

												if (i_current.getEl()) {

													var i_el = i_current.getEl();

													i_el.on({
														click: {
															fn: function(i_element) {
																var a_panels = i_modelpanel.query("ip2DomainModelEntity");

																Ext.Array.each(a_panels, function(i_panel) {
																	i_panel.setZIndex(1);
																});

																i_current.setZIndex(2);
															}
														}
													});
												}

												var a_buttons = i_header.query("button[itemId=menubutton]");
												var a_tools = i_header.query("tool");

												Ext.Array.each(a_buttons, function(i_component) {
													i_component.on({
														afterrender: {
															fn: function(i_button) {
																var s_color = window.getComputedStyle(i_header.el.dom, null).getPropertyValue("background-color");
																i_button.el.dom.style.setProperty("background-color", s_color, "important");
															},
															buffer: 10
														}
													});
												});

												Ext.Array.each(a_tools, function(i_component) {
													i_component.stopEvent = false;
												});
											}
										},
										edit: {
											fn: function(i_panel) {

												i_self.setLoading(true);
												i_panel.onEdit();
												i_self.setLoading(false);
											}
										}
									}
								});

								a_new.push(i_entityPanel);
							});
						}

						o_model.entities = o_model.entities.concat(a_imported);
						o_model.required = o_model.required.concat(a_imported);

						i_self.setModel(o_model);

						i_modelpanel.add(a_new);
					}
				},
				cancel: {
					fn: function(i_form) {

						var i_window = this;
						i_window.close();
					}
				}
			}
		});

		i_window.show();
	},

	newEntity: function() {

		var i_self = this;

		var i_window = Ext.widget("designer.ui.wizard.view.window", {
			width: 800,
			height: 600,
			designer: i_self,
			entity: {},
			modal: true
		});

		i_window.show();
	},

	cleanUp: function() {

		var i_self = this;
		var i_modelpanel = i_self.getModelPanel();
		var o_settings = i_self.settings;
		var o_menu = i_self.getMenu();
		var i_panelRequired = i_self.getRequiredPanel();

		var o_default = {};

		i_self.setDomainModelDefaults(o_default);

		i_self.setModel(o_default);
		i_self.changed = false;
		i_self.state = "new";
		i_self.setDmdFile("");

		i_modelpanel.removeAll(true);

		if (i_panelRequired) {
			i_self.remove(i_panelRequired, true);
		}

		o_settings.entities.lastX = 0;
		o_settings.entities.lastY = 0;

		var i_menuitem = o_menu.tool.child("#buildmodel");

		if (i_menuitem) {
			i_menuitem.disable();
		}

		i_menuitem = o_menu.tool.child("#organizemodel");

		if (i_menuitem) {
			i_menuitem.disable();
		}

		if (i_self.getSvg()) {
			i_self.removeSvg();
		}

		i_self.resetDirty();

		i_self.fireEvent("complete", i_self);
	},

	removeSvg: function() {

		var i_self = this;
		if (i_self.getSvg()) {
			var i_svg = document.querySelector("svg");
			i_svg.parentElement.removeChild(i_svg);
			i_self.setSvg(null);
		}
	},

	createSettings: function() {

		var i_self = this;
		var i_modelpanel = i_self.getModelPanel();
		var o_settings = i_self.settings || {};
		var a_panels = i_modelpanel.query("ip2DomainModelEntity");

		var o_result = {};

		var n_x = 0;
		var n_y = 0;

		Ext.Array.each(a_panels, function(i_panel) {

			var o_box = i_panel.getBox(false, true);

			if (o_box.right > n_x) {
				n_x = o_box.right;
			}

			if (o_box.y > n_y) {
				n_y = o_box.y;
			}
		});

		o_result.x = n_x + 10;
		o_result.y = n_y;

		o_settings.entities.lastY = n_y;
		o_settings.entities.lastX = n_x;

		o_result.width = 200;
		o_result.height = 150;

		i_self.settings = o_settings;

		return o_result;
	},

	convertEntityObject2Array: function(o_entity) {

		var i_self = this;

		i_self.addNameToConfig(o_entity.columns);

		var a_columns = Ext.Object.getValues(o_entity.columns);
		var a_keys = Ext.Object.getValues(o_entity.keys);

		var o_ui = o_entity.ui || {};

		o_ui.grids = o_ui.grids || {};
		o_ui.forms = o_ui.forms || {};

		var o_tempGrid = {};
		var o_tempForms = {};

		if (Ext.isArray(o_ui.grids)) {

			Ext.Array.each(o_ui.grids, function(o_config) {
				o_tempGrid[o_config.name] = o_config;
			});

			o_ui.grids = o_tempGrid;
		}


		if (o_ui.grids.hasOwnProperty("common")) {
			o_ui.grids.portfolio = Ext.Object.merge({}, o_ui.grids.common, o_ui.grids.portfolio);
			delete o_ui.grids.common;
		}

		if (o_ui.grids.hasOwnProperty("commonAll")) {
			o_ui.grids.portfolio = Ext.Object.merge({}, o_ui.grids.commonAll, o_ui.grids.portfolio);
			delete o_ui.grids.commonAll;
		}

		if (Ext.isArray(o_ui.forms)) {

			Ext.Array.each(o_ui.forms, function(o_config) {
				o_tempForms[o_config.name] = o_config;
			});

			o_ui.forms = o_tempForms;
		}

		if (o_ui.forms.hasOwnProperty("common")) {
			o_ui.forms.portfolio = Ext.Object.merge({}, o_ui.forms.common, o_ui.forms.portfolio);
			delete o_ui.forms.common;
		}

		if (o_ui.forms.hasOwnProperty("commonAll")) {
			o_ui.forms.portfolio = Ext.Object.merge({}, o_ui.forms.commonAll, o_ui.forms.portfolio);
			delete o_ui.forms.commonAll;
		}

		Ext.Object.each(o_ui.forms, function(s_key, o_form) {

			if (Ext.isObject(o_form.items)) {

				var o_items = o_form.items;
				var a_columns = [];

				if (o_items.portlet1) {
					a_columns = Ext.Array.from(o_items.portlet1.columns);
				}
				else {
					a_columns = Ext.Array.from(o_items.columns);
				}

				o_form.items = a_columns;
			}
		});

		o_entity.affiliations = o_entity.affiliations || o_entity.affilations || [];

		if (Ext.isObject(o_entity.affiliations)) {

			Ext.Object.each(o_entity.affiliations, function (s_key, o_affilation) {
				o_affilation.name = s_key;
			});

			o_entity.affiliations = Ext.Object.getValues(o_entity.affiliations);
		}


		o_entity.columns = a_columns;
		o_entity.keys = a_keys;

		return o_entity;
	},

	setDomainModelDefaults: function(o_model) {

		var i_self = this;

		o_model = o_model || {};

		Ext.applyIf(o_model, {
			API: {
				eventHandler: ""
			},
			proxy: {
				url: i_self.getServiceProxy()
			},
			entities: [],
			required: [],
			types: {},
			relations: [],
			languages: {
				da: {
					text: {}
				},
				en: {
					text: {}
				}
			},
			navigator: {},
			menu: {},
			generate: {
				tables: false,
				views: true,
				constraints: true,
				primaryKey: true
			}
		});

		Ext.Array.each(o_model.entities, function(o_entity) {

			var o_permission = o_entity.permission = o_entity.permission || {};
			var o_result = Ext.apply({
				add: {
					form: true,
					grid: true
				},
				edit: {
					form: true,
					grid: true
				},
				remove: {
					grid: true,
					form: true
				}
			}, o_permission);
			o_entity.permission = o_result;
		});

		return o_model;
	},

	doSvgConnections: function(a_relations, a_required, a_entityPanels) {

		var i_self = this;
		var i_body = i_self.body;

		// render cardinalities after render of all entities

		var connections = SvgConnecterIP2({
			body: $(i_body.dom),
			offset: {
				y: 53
			},
			defaults: {
				width: 2,
				color: "#990000",
				gradient: {
					master: {
						"color": "#990000"
					},
					slave: {
						"color": "#00CC00"
					}
				},
				point: "center"
			}
		});

		var o_masters = {};

		Ext.Array.each(a_required, function(o_entity) {

			Ext.Array.each(a_relations, function(o_relation) {

				var n_index = 0;
				var and_index = 0;
				var b_master = false;
				var b_slave = false;

				Ext.Array.each(a_entityPanels, function(i_panel) {
					if (i_panel.entity.name == o_relation.between.entity) {
						b_master = true;
						return false;
					}
					n_index++;
				});

				Ext.Array.each(a_entityPanels, function(i_panel) {
					if (i_panel.entity.name == o_relation.and.entity) {
						b_slave = true;
						return false;
					}
					and_index++;
				});

				var masterEl;
				var slaveEl;
				var occurrence;

				if (o_relation.between.entity == o_entity.name) {
					if (b_master && b_slave) {
						masterEl = a_entityPanels[n_index].header.getComponent("btn-relation");
						slaveEl = a_entityPanels[and_index].header.getComponent("btn-relation");
						occurrence = o_relation.between.occurrence + "2" + o_relation.and.occurrence;
					}
				}
				else if (o_relation.and.entity == o_entity.name) {
					if (b_master && b_slave) {
						masterEl = a_entityPanels[and_index].header.getComponent("btn-relation");
						slaveEl = a_entityPanels[n_index].header.getComponent("btn-relation");
						occurrence = o_relation.and.occurrence + "2" + o_relation.between.occurrence;
					}
				}

				if (!Ext.isEmpty(masterEl)) {
					if (!o_masters.hasOwnProperty(o_entity.name)) {
						o_masters[o_entity.name] = {
							el: masterEl,
							slaves: [],
							occurrence: [],
							parent: a_entityPanels[and_index]
						};
					}
					o_masters[o_entity.name].slaves.push(slaveEl);
					o_masters[o_entity.name].occurrence.push(occurrence);
				}
			});
		});

		Ext.Object.each(o_masters, function(s_master, o_master) {

			connections.addConnection({
				master: o_master.el,
				slaves: o_master.slaves,
				parent: o_master.parent,
				occurrence: o_master.occurrence
			});
		});

		connections.canvas[0].style.setProperty("pointer-events", "none", "important");

		return connections;
	}
});
