  Ext.define('Ext.ux.folderorganizer.Organizer', {

	extend: 'Ext.panel.Panel',

	layout: {
		type: 'border'
	},

	border: false,

	initComponent: function() {

		var me = this;
		me.dmdProject = me.dmd.split("/").pop().split(".").shift();
		me.setupI18N();

		Ext.tip.QuickTipManager.init();

		me.listeners = me.listeners || {};
		me.contentEvents = ['foldercreate', 'rowselection', 'propertychange'];
		me.focusNo = 1;

		if (me.folder) {
			me.initFolder();
		}
		else {
			me.initBelongTo();
		}

		me.listeners = Ext.apply(me.listeners, {
			afterrender: function() {
				me.setFocus();
				me.enableFocusManager();
			}
		});

		me.title = null,
		me.preventHeader = true;

		me.callParent(arguments);

		return me;
	},
	/* ---------------------------------------------------------------------------------------------
		  initialize folder method
		 --------------------------------------------------------------------------------------------- */
	initFolder: function() {

		var me = this;

		me.items = [];

		me.folder.cid = me.folder.cid || '';
		me.folder.displayRootNode = (Ext.isBoolean(me.folder.displayRootNode)) ? me.folder.displayRootNode : true;
		me.folder.expandRootNode = (Ext.isBoolean(me.folder.expandRootNode)) ? me.folder.expandRootNode : false;
		me.folder.hasRootCid = (Ext.isBoolean(me.folder.hasRootCid)) ? me.folder.hasRootCid : true;
		me.folder.multiAddChoice = (Ext.isBoolean(me.folder.multiAddChoice)) ? me.folder.multiAddChoice : true;
		me.folder.orderBy = me.folder.orderBy || '';
		me.folder.extraProps = me.folder.extraProps || '';
		me.folder.buttons = Ext.Array.filter(me.folder.buttons, function(s_button) {
			var b_allowed = true;
			switch (s_button) {
				case "add":
					b_allowed = ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".create");
					break;
				case "edit":
					b_allowed = (ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".update") ||
								ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".read"));
					break;
				case "remove":
					b_allowed = ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".delete");
					break;
			}
			return b_allowed;
		});

		me.folder.allowExport = ip2.isAccessible("app." + me.dmdProject + ".data." + me.entity + ".export.definitions");

		if (!me.folder.propertyNameMapping) {
			if (me.folder.entity && me.folder.entity == 'WSHNAMET00') {
				me.folder.propertyNameMapping = {
					ID: 'NAMNAMTKN',
					PARENTID: 'NAMPNTTKN',
					PROPERTIES: 'NAMPROP'
				};
			}
			else if (me.folder.entity && me.folder.entity == 'WSHMNUET00') {
				me.folder.propertyNameMapping = {
					ID: 'MNUMNUTKN',
					PARENTID: 'MNUPNTTKN',
					PROPERTIES: 'MNUPROP'
				};
			}
			else {
				me.folder.propertyNameMapping = {
					ID: 'FLDFLDTKN',
					PARENTID: 'FLDPNTTKN',
					PROPERTIES: 'FLDPROP'
				};
			}
		}
		me.folder.propertyNameMappingReverse = {};
		for (var key in me.folder.propertyNameMapping) {
			me.folder.propertyNameMappingReverse[me.folder.propertyNameMapping[key]] = key.toString();
		}

		me.dmdName = me.folder.dmd;
		me.dmdPath = me.dmdName;
		me.xpdName = me.xpd;
		me.xpdPath = me.xpdName;

		// get xpd definition
		me.xpd = ip2.resource.get(me.xpdName);

		// flatten xpd, if passed
		if (me.xpd) {
			me.xpd.flatten = ip2.xpd.flatten(me.xpd);
			ip2.each(me.xpd.flatten.collections, function(collection) {
				collection.uiName = 'portfolio';
			});
		}
		var model = {};

		if (Ext.ClassManager.isCreated("folder-" + me.entity)) {

			model = Ext.ClassManager.get("folder-" + me.entity);

			var i_proxy = model.getProxy();
			var o_extraParams = i_proxy.getExtraParams();

			Ext.apply(o_extraParams, {
				action: 'treeStore',
				entity: me.folder.entity,
				dataLibrary: me.getDataLibrary(),
				menus: Ext.encode(me.folder.menus),
				displayRootNode: me.folder.displayRootNode,
				hasRootCid: me.folder.hasRootCid,
				orderBy: me.folder.orderBy,
				extraProps: me.folder.extraProps,
				cid: me.folder.cid,
				xpd: me.xpdPath,
				dmd: me.dmdPath,
				language: ip2.session.getLanguage(),
				idField: me.folder.propertyNameMapping.ID,
				parentidField: me.folder.propertyNameMapping.PARENTID,
				propertiesField: me.folder.propertyNameMapping.PROPERTIES
			});
		}
		else {
			var a_fields = [
				{ name: 'TITLE', type: 'string', isTitle: true, title: 'Folder' },
				{ name: 'ID' },
				{ name: 'PARENTID', type: 'int' },
				{ name: 'PROPERTIES', type: 'string' },
				{ name: 'rowProps', type: 'string' },
				{ name: 'hasSubFolders', type: 'bool' },
				{ name: 'allowEdit', type: 'bool' },
				{ name: 'allowRemove', type: 'bool' },
				{ name: 'highlight', type: 'bool' }
			];

			var a_extra = me.getModelFields();
			a_fields = a_fields.concat(a_extra);

			model = Ext.define('folder-' + me.entity, {
				extend: 'Ext.data.Model',
				fields: a_fields,
				idProperty: 'ID',
				proxy: {
					type: 'ajax',
					url: me.folder.proxy,
					extraParams: {
						action: 'treeStore',
						entity: me.folder.entity,
						dataLibrary: me.getDataLibrary(),
						menus: Ext.encode(me.folder.menus),
						displayRootNode: me.folder.displayRootNode,
						hasRootCid: me.folder.hasRootCid,
						orderBy: me.folder.orderBy,
						extraProps: me.folder.extraProps,
						cid: me.folder.cid,
						xpd: me.xpdPath,
						dmd: me.dmdPath,
						language: ip2.session.getLanguage(),
						idField: me.folder.propertyNameMapping.ID,
						parentidField: me.folder.propertyNameMapping.PARENTID,
						propertiesField: me.folder.propertyNameMapping.PROPERTIES
					}
				}
			});
		}

		me.store = Ext.create('Ext.data.TreeStore', {
			model: model,
			clearOnLoad: true,
			root: {
				ID: 0,
				PARENTID: 0,
				PROPERTIES: "",
				rowProps: ""
			}
		});

		// add writer store
		if (me.folder.menus && me.folder.menus.length > 0) {

			var i_writerModel = ip2.model({
				dmd: me.dmdPath,
				entityName: me.folder.entity,
				context: "form"
			});

			var i_writerStore = Ext.create('Ext.data.Store', {
				model: i_writerModel,
				autoSync: false,
				proxy: ip2.getProxyByEntity({
					dmd: me.dmdPath,
					entityName: me.folder.entity,
					dataLibrary: me.getDataLibrary()
				})
			});

			var i_writerProxy = i_writerStore.getProxy();
			var o_writerParams = i_writerProxy.getExtraParams();

			Ext.apply(o_writerParams, {
				storeId: ip2.storeId(),
				uiName: me.dmdProject || "portfolio",
				context: 'form'
			});

			me.writerModel = i_writerModel;
			me.writerStore = i_writerStore;
		}

		// relation between folder and content
		me.many2many = {};

		me.many2many.model = ip2.model({
			dmd: me.dmdPath,
			entityName: me.folder.entity,
			dataLibrary: me.getDataLibrary()
		});

		me.many2many.store = Ext.create('Ext.data.Store', {
			model: me.many2many.model,
			proxy: ip2.getProxyByEntity({
				dmd: me.dmdPath,
				entityName: me.folder.entity,
				dataLibrary: me.getDataLibrary()
			})
		});

		Ext.apply(me.many2many.store.getProxy().getExtraParams(), {
			dmdFile: me.dmdPath,
			uiName: me.folder.uiName || 'organizer',
			context: 'grid',
			action: 'getRows'
		});

		me.many2many.root = 'rows';
		me.many2many.allowDuplicateRecords = true;

		me.belongTo = {};
		me.belongTo.foreignKey = me.folder.propertyNameMapping.ID;
		me.hasMany = {};
		me.hasMany.foreignKey = me.folder.propertyNameMapping.ID;

		var o_layout = {
			type: "vbox",
			align: "stretch"
		};
		if (me.folder.entity == "WSHMNUET00") {
			o_layout = {
				type: "border"
			};
			me.displayFilterField = true;
		}
		var folderPanel = Ext.create('Ext.panel.Panel', {
			flex: 1,
			border: true,
			region: "center",
			layout: o_layout,
			split: true,
			items: []
		});

		// Toolbar
		var tb = Ext.create('Ext.ux.folderorganizer.Toolbar', {
			wrapper: me,
			border: false,
			namePrefix: 'folder',
			propertyNameMapping: me.folder.propertyNameMapping
		});
		delete me.folder.buttons;
		if (tb.items.items && tb.items.items.length > 0) {
			folderPanel.addDocked(tb);
			tb.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved', 'nodestartedit', 'nodeloaded', 'nodemouseup']);
		}

		// Breadcrumb
		if (me.showFolderBreadcrumb) {
			me.productCatalogLocation = Ext.create('Ext.ux.folderorganizer.FolderProductLocation', {
				itemId: 'productCatalogLocation',
				wrapper: me,
				listeners: {
					nodeselection: function(node) {
						// prevent firing twice
						if (node.internalId == me.productCatalogLocation.internalId) {
							return false;
						}
						me.productCatalogLocation.internalId = node.internalId;

						if (me.productCatalogLocation.rendered) {
							var key = me.treegrid.buildProperties(node);
							if (key.keyValue) {
								var keyField = (key.properties.__cid__ == 3) ? 'item' : 'folder';
								me.productCatalogLocation.store.proxy.extraParams[keyField] = key.keyValue;
								me.productCatalogLocation.store.load();
								me.productCatalogLocation.store.on('load', function(store, records) {
									if (records.length > 1) {
										me.productCatalogLocation.show();
									}
								});
								delete me.productCatalogLocation.store.proxy.extraParams[keyField];
							}
						}
					}
				}
			});
			folderPanel.add(me.productCatalogLocation);

			me.productCatalogLocation.relayEvents(
				me, [
					'nodeselection',
					'nodeadded',
					'nodechanged',
					'noderemoved',
					'nodestartedit',
					'nodeloaded',
					'nodemouseup'
				]);
		}

		// Folder Tree
		// TODO: This really should be an applyIf - there is no chance of changing these
		// TODO values at all when you do it like this
		var cfg = Ext.apply(me.folder, {
			flex: 1,
			wrapper: me,
			namePrefix: 'belongTo',
			displayCheckbox: false,
			mode: 'folder',
			xpd: me.xpd,
			xpdName: me.xpdName,
			xpdPath: me.xpdPath,
			store: me.store,
			many2many: me.many2many,
			environment: me.environment || 'folderorganizer',
			showFolderBreadcrumb: me.showFolderBreadcrumb || false,
			displayRootNode: true,
			languageService: me.folder.languageService || ""
		});

		if (cfg.title && Ext.isObject(cfg.title)) {
			cfg.title = ip2.i18n(cfg.title);
		}

		if (me.writerStore) {
			cfg.writerStore = me.writerStore;
		}
		me.treegrid = Ext.create('Ext.ux.folderorganizer.Tree', cfg);
		me.treegrid.flex = 3;
		me.treegrid.relayEvents(me, me.contentEvents);
		if (!me.dataParent) {
			if (me.folder.entity == "WSHMNUET00") {
				me.treegrid.on({
					select: {
						fn: function(i_tree, node) {
							var i_stacktree = me.down("#stacktree");
							if (node.get("PROPERTIES")) {
								i_stacktree.clear();
								var o_properties = Ext.decode(node.get("PROPERTIES"));
								var o_rowprops = node.get("rowProps") ? Ext.decode(node.get("rowProps")) : {};
								if (o_rowprops.__cid__ == 13 || o_rowprops.__cid__ == 14) {
									i_stacktree.reload(node, o_properties, o_rowprops);
								}
								if (o_properties.__cid__ && o_properties.__cid__ != 2) {
									var s_title = o_properties.title || node.get("TITLE") || "";
									s_title = ip2.i18n(s_title);
									i_stacktree.setTitle(ip2.i18n({
										da: "Side elementer: " + s_title,
										en: "Page elements: " + s_title
									}));
								}
							}
							else {
								i_stacktree.clear();
							}
						}
					}
				});
			}
		}
		folderPanel.add(me.treegrid);
		if (!me.dataParent) {
			if (me.folder.entity == "WSHMNUET00") {
				var i_south = Ext.widget("treepanel", {
					layout: "fit",
					iconCls: 'ip2-tree-application-group',
					rootVisible: false,
					animate: false,
					useArrows: true,
					collapsible: true,
					viewConfig: {
						loadMask: false
					},
					split: true,
					itemId: "stacktree",
					region: "south",
					flex: 1,
					title: ip2.i18n({
						da: "Side elementer: ",
						en: "Page elements: "
					}),
					hidden: false,
					clear: function() {
						var i_self = this;
						var i_root = i_self.getRootNode();
						i_root.removeAll(false);
						i_self.setTitle("");
					},
					reload: function(node, o_properties, o_rowprops)	{
						var i_tree = this;
						var i_root = i_tree.getRootNode();
						var i_store = i_tree.getStore();
						var i_model = i_store.model.create(node.data);
						i_root.removeAll(false);
						var s_title = "";
						if (o_properties.title) {
							s_title = ip2.i18n(o_properties.title);
						}
						else {
							s_title = node.get("TITLE");
						}
						i_model.set("text", s_title);
						i_model.set("token", o_rowprops.token);
						var i_node = i_root.appendChild(i_model);
						i_node.commit();
						i_tree.getStackItems(i_node, o_rowprops);
					},
					listeners: {
						itemcontextmenu: function(view, node, item, index, e) {
							var i_self = this;
							var coords = e.getXY();
							var a_items = [];

							e.stopEvent();
							if (ip2.isAccessible("app." + me.dmdProject + ".data.WSHPAGET00.update") ||
								ip2.isAccessible("app." + me.dmdProject + ".data.WSHPAGET00.read")) {
								a_items.push({
									xtype: "menuitem",
									iconCls: 'pf-edit',
									itemId: "edit",
									text: ip2.i18n({
										da: "Rediger side",
										en: "Edit page"
									}),
									handler: function() {

										var s_entity = 'WSHPAGET00';
										var s_tkn = node.get("token");

										var i_model = ip2.model({
											dmd: me.dmd,
											entityName: "WSHPAGET00",
											context: 'grid',
											uiName: "portfolio"
										});
										var o_config = {
											dmd: me.dmd,
											entityName: "WSHPAGET00"
										};
										var i_record = i_model.create();
										i_record.set(i_record.idProperty, s_tkn);

										var o_size = Ext.ux.file.util.Handler.getWindowSize();

										var wnd = Ext.widget("window", {
											modal: false,
											closable: true,
											collapsible: true,
											resizable: true,
											width: o_size.width * 0.9,
											height: o_size.height * 0.9,
											layout: "fit"
										});
										ip2.addChild(wnd, i_record, 'update', o_config);
										wnd.show();
									}
								});

								var menu = Ext.widget("menu", {
									items: a_items
								});

								menu.showAt([coords[0], coords[1]]);
							}
						}
					},
					getStackItems: function(i_node, o_rowprops) {
						var i_tree = this;
						var i_store = i_tree.getStore();
						var o_stack_xpd = ip2.resource.get("stack.xpd", true);
						var o_pages_xpd = ip2.resource.get("pages.xpd", true);
						Ext.Ajax.request({
							url: '/wsh-services/wshproxy.aspx',
							params: {
								xpd: o_pages_xpd.path,
								stackxpd: o_stack_xpd.path,
								token: o_rowprops.token,
								action: 'getpage',
								environment: 'treestore'
							},
							success: function (o_response) {

								var o_stack = {};

								try {
									o_stack = Ext.decode(o_response.responseText);
								}
								catch (err) {
									console.log('TODO: Error handling for stack on loading data');
								}

								o_stack.children || (o_stack.children = []);
								if (o_stack.children.length > 0) {
									var a_nodes = [];
									ip2.each(o_stack.children, function(o_item) {
										var i_model = i_store.model.create();
										var s_title = + o_item.token;
										if (Ext.isObject(o_item.title)) {
											s_title = s_title + " - " + ip2.i18n(o_item.title);
										}
										else {
											if (o_item.title) {
												if (o_item.title.substring(0, 1) == "{") {
													var o_title = Ext.decode(o_item.title);
													s_title = s_title + " - " + ip2.i18n(o_item.title);
												}
												else {
													s_title = s_title + " - " + o_item.title;
												}
											}
										}
										i_model.set("TITLE", s_title);
										i_model.set("text", s_title);
										i_model.set("allowDrag", false);
										i_model.set("allowDrop", false);
										i_model.set("checked", null);
										i_model.set("ptype", "stack");
										i_model.set("leaf", true);
										i_model.set("token", o_item.token);
										i_model.set("__cid__", o_item.__cid__);
										a_nodes.push(i_model);
									});
									i_node.set("leaf", false);
									if (i_node.childNodes == null) {
										i_node.childNodes = [];
									}
									i_node.appendChild(a_nodes);
									i_node.expand();
								}
							}
						});
					}
				});
				folderPanel.add(i_south);
			}
		}

		// Folder Property Grid
		if (me.showFolderProperty) {
			me.familyPropertyGrid = Ext.widget('folderorganizerFolderPropertyGrid', {
				title: ip2.i18n(me.getI18N('productFamilyHeaderTitle')),
				itemId: 'familyPropertyGrid',
				action: 'getProductInFamily',
				wrapper: me,
				hidden: true,
				flex: 1,
				listeners: {
					nodeselection: function(node) {
						// prevent firing twice
						if (node.internalId == me.familyPropertyGrid.internalId) {
							return false;
						}
						me.familyPropertyGrid.internalId = node.internalId;

						me.familyPropertyGrid.selectedFolderToken = node.data.ID;

						node.data.cid = 0;

						var props = Ext.decode(node.data.PROPERTIES);
						if (props.__cid__) {
							node.data.cid = props.__cid__;
						}

						if (me.familyPropertyGrid.rendered) {
							if (node.data.cid == 3) {
								me.familyPropertyGrid.show();
								me.familyPropertyGrid.store.removeAll();
								var key = me.treegrid.buildProperties(node);
								if (key.keyValue) {
									me.familyPropertyGrid.store.proxy.extraParams.item = key.keyValue;
									me.familyPropertyGrid.store.load();
								}
							}
							else {
								me.familyPropertyGrid.hide();
							}
						}
					}
				},
				folderPropertyAdded: function(data) {
					me.fireEvent('nodeadded', data);
				},
				folderPropertyRemoved: function(data) {
					me.fireEvent('noderemoved', data);
				},
				getFamilyStatus: function(record) {
					var dnd = this;

					if (record.data.cid != 3) {
						return;
					}

					if (dnd.dragedRecord == record) {
						return;
					}

					dnd.dragedRecord = record;

					Ext.Ajax.request({
						url: me.proxy,
						params: {
							action: 'getProductFamilyStatus',
							item: record.data.ITMITMTKN
						},
						record: record,
						success: function(response, request) {
							var result = Ext.decode(response.responseText);
							request.record.familyStatus = result.familyStatus;
						}
					});
				}
			});

			me.familyPropertyGrid.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved', 'nodestartedit', 'nodeloaded', 'nodemouseup']);

			me.relatedPropertyGrid = Ext.widget('folderorganizerFolderPropertyGrid', {
				title: ip2.i18n(me.getI18N('productRelationHeaderTitle')),
				itemId: 'relatedPropertyGrid',
				action: 'getProductInRelation',
				wrapper: me,
				hidden: false,
				flex: 1,
				listeners: {
					nodeselection: function(node) {
						// prevent firing twice
						if (node.internalId == me.relatedPropertyGrid.internalId) {
							return false;
						}
						me.relatedPropertyGrid.internalId = node.internalId;

						me.relatedPropertyGrid.selectedFolderToken = node.data.ID;

						node.data.cid = 0;

						var props = Ext.decode(node.data.PROPERTIES);
						if (props.__cid__) {
							node.data.cid = props.__cid__;
						}

						if (me.relatedPropertyGrid.rendered) {
							var key = me.treegrid.buildProperties(node);
							if (key.keyValue) {
								me.relatedPropertyGrid.store.proxy.extraParams.token = key.keyValue;
								me.relatedPropertyGrid.store.proxy.extraParams.type = (node.data.cid == 3) ? 'rel' : 'cat';
								me.relatedPropertyGrid.store.load();
							}
						}
					}
				}
			});

			me.relatedPropertyGrid.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved', 'nodestartedit', 'nodeloaded', 'nodemouseup']);

			me.familyPropertyGrid.dependcy = {
				store: me.relatedPropertyGrid.store
			};
			me.relatedPropertyGrid.dependcy = {
				store: me.familyPropertyGrid.store
			};
			folderPanel.add(me.familyPropertyGrid);
			folderPanel.add(me.relatedPropertyGrid);
		}

		me.items.push(folderPanel);

		// Add Content grid ?
		if (!me.content) {
			return;
		}

		var cfg = Ext.apply(me.content, {
			flex: 1,
			wrapper: me,
			xpd: me.xpd,
			uiName: me.folder.uiName || 'portfolio',
			copyNode: (me.copyNode === true) ? true : false,
			alwaysShowGrid: (me.showFolderProperty === true) ? true : false,
			region: "east",
			split: true
		});
		if (cfg.title && Ext.isObject(cfg.title)) {
			cfg.title = ip2.i18n(cfg.title);
		}

		me.contentCt = Ext.create('Ext.ux.folderorganizer.Content', cfg);
		me.items.push(me.contentCt);

		me.relayEvents(me.contentCt, me.contentEvents);

		// Pass event further to child components (relay events)
		me.contentCt.relayEvents(me, ['nodeselection', 'nodeadded', 'nodechanged', 'noderemoved', 'nodestartedit', 'nodeloaded']);
	},

	getModelFields: function() {

		var i_self = this;
		var a_fields = [];

		var o_dmd = ip2.resource.get(i_self.dmdPath);

		var o_model = o_dmd.model;
		var a_entities = o_model.entities;
		var o_entity = Ext.Array.findBy(a_entities, function(o_value) {
			return o_value.name == i_self.entity;
		});

		if (o_entity) {

			var s_view = i_self.uiName || "portfolio";

			var o_view = o_entity.ui.grids[s_view];

			var a_columns = [];
			var viewColumns = o_view.columns;

			if (Ext.isArray(viewColumns)) {
				a_columns = Ext.Array.slice(viewColumns);
			}
			else if (Ext.isObject(viewColumns)) {

				Ext.Object.each(viewColumns, function(s_key, o_value) {
					o_value.name = s_key;
					a_columns.push(o_value);
				});
			}

			Ext.Array.each(a_columns, function(o_column) {

				if (o_column.isOrganizer) {

					var o_field = {
						type: "auto",
						name: o_column.name,
						title: o_column.title || o_column.name,
						flex: o_column.flex || 1,
						isOrganizer: true
					};

					a_fields.push(o_field);
				}
			});
		}

		return a_fields;
	},

	/* ---------------------------------------------------------------------------------------------
		  initialize 'old' method (belongTo -and hasMany method)
		 --------------------------------------------------------------------------------------------- */
	initBelongTo: function() {
		var me = this;

		if (!me.belongTo || !me.hasMany) {
			Ext.ux.folderorganizer.Alert({
				title: me.getI18N('invalidConfig'),
				msg: me.getI18N('missingConfigOptions')
			});
			return;
		}

		// set defaults
		me.belongTo.title = me.belongTo.title || null;
		me.belongTo.displayCheckbox = Ext.isBoolean(me.belongTo.displayCheckbox) ? me.belongTo.displayCheckbox : true;
		me.belongTo.displayFilterField = Ext.isBoolean(me.belongTo.displayFilterField) ? me.belongTo.displayFilterField : true;
		me.belongTo.displayRootNode = (Ext.isBoolean(me.belongTo.displayRootNode)) ? me.belongTo.displayRootNode : true;
		me.belongTo.expandRootNode = (Ext.isBoolean(me.belongTo.expandRootNode)) ? me.belongTo.expandRootNode : false;
		me.belongTo.menus = me.belongTo.menus || [];

		me.hasMany.title = me.hasMany.title || null;
		me.hasMany.displayColumns = me.hasMany.displayColumns ? me.hasMany.displayColumns : [];
		me.hasMany.displayFilterField = Ext.isBoolean(me.hasMany.displayFilterField) ? me.hasMany.displayFilterField : true;

		me.tabSequence = me.tabSequence || [
			{
				parent: 'belongTo',
				child: 'tree'
			},
			{
				parent: 'belongTo',
				child: 'filterField'
			},
			{
				parent: 'hasMany',
				child: 'filterField'
			},
			{
				parent: 'hasMany',
				child: 'grid'
			}
		];

		// setup "Belong-To" store and panel
		me.belongTo.store = Ext.create('Ext.data.TreeStore', {
			model: me.belongTo.model,
			clearOnLoad: false
		});
		var belongToCfg = Ext.apply(me.belongTo, {
			flex: 1,
			store: me.belongTo.store,
			wrapper: me,
			region: "center",
			split: true,
			namePrefix: 'belongTo'
		});

		// setup "Many to many" store and panel
		if (me.many2many) {
			me.many2many.allowDuplicateRecords = Ext.isBoolean(me.many2many.allowDuplicateRecords) ? me.many2many.allowDuplicateRecords : true;

			me.many2many.store = Ext.create('Ext.data.Store', {
				model: me.many2many.model
			});

			// create association between "belong to" -and "has many"
			me.association = Ext.create('Ext.data.HasManyAssociation', {
				associatedModel: me.many2many.model,
				ownerModel: me.belongTo.model,
				associationKey: me.many2many.root,
				foreignKey: me.belongTo.foreignKey,
				primaryKey: (me.belongTo.store.model.prototype.idProperty) ? me.belongTo.store.model.prototype.idProperty : 'id',
				name: 'getOrganizedItems'
			});

			belongToCfg.many2many = {
				store: me.many2many.store
			};
		}

		belongToCfg.writerStore = Ext.create('Ext.data.Store', {
			model: belongToCfg.writerModel
		});
		belongToCfg.writerStore.model.dmdFile = belongToCfg.writerStore.model.dmdFile;

		me.belongTo.panel = Ext.create('Ext.ux.folderorganizer.Tree', belongToCfg);

		// setup "Has many" store and panel

		if (Ext.isArray(me.hasMany.items)) {
			me.hasMany.panel = Ext.create('Ext.panel.Panel', {
				split: true,
				flex: 1,
				width: (ip2.body.init().getWidth() / 2),
				layout: 'accordion',
				region: "east"
			});
			for (var i = 0; i < me.hasMany.items.length; i++) {
				var item = me.hasMany.items[i];
				item.name = item.name || 'accordion-panel-' + i;
				item.store = Ext.create('Ext.data.Store', {
					model: item.model,
					remoteSort: true,
					autoSync: false,
					name: item.name
				});
				var cfg = Ext.apply(item, {
					flex: 1,
					store: item.store,
					wrapper: me,
					namePrefix: 'hasMany',
					copyNode: (me.copyNode === true) ? true : false
				});
				me.hasMany[item.name] = Ext.create('Ext.ux.folderorganizer.Itemgrid', cfg);
				me.hasMany.panel.add(me.hasMany[item.name]);
			}
		}
		else {
			me.hasMany.store = Ext.create('Ext.data.Store', {
				model: me.hasMany.model,
				remoteSort: true,
				autoSync: false
			});
			var cfg = Ext.apply(me.hasMany, {
				flex: 1,
				split: true,
				store: me.hasMany.store,
				wrapper: me,
				namePrefix: 'hasMany',
				copyNode: (me.copyNode === true) ? true : false,
				region: "center"
			});
			me.hasMany.panel = Ext.create('Ext.ux.folderorganizer.Itemgrid', cfg);
		}

		me.items = [
			me.belongTo.panel,
			me.hasMany.panel
		];

		// Pass event further to child components (relay events)
		me.belongTo.panel.relayEvents(me, me.contentEvents);
		me.hasMany.panel.relayEvents(me, ['nodeselection', 'nodeloaded']);
	},
	getDataLibrary: function() {
		return this.folder.dataLibrary || '';
	},
	enableFocusManager: function() {
		var me = this;

		//Ext.FocusManager.enable({focusFrame: this.focusFrame});

		// Ext.FocusManager.addListener({
		// 	componentfocus: function(fm, cmp, previousCmp, eOpts) {
		// 		var name = (cmp.panel) ? cmp.panel.name : cmp.name;
		// 		me.focusNo = me.getFocusNo(name);
		// 	}
		// });
	},

	setFocus: function(direction) {
	var me = this;

	if (!me.tabSequence) {
		return;
	}

	var component;
	var loop = 0;

	var setParameters = function() {
		if (direction == 'forward') {
			me.focusNo++;
		}
		else if (direction == 'backward') {
			me.focusNo--;
		}
		else {
			direction = 'forward';
		}

		if (me.focusNo >= me.tabSequence.length) {
			me.focusNo = 0;
		}
		else if (me.focusNo < 0) {
			me.focusNo = me.tabSequence.length - 1;
		}

		component = me.tabSequence[me.focusNo];
	};

	setParameters();
	while (!me.setChildComponentFocus(component)) {
		loop++;
		if (loop > 10) {
			break;
		}
		setParameters();
	}
  },
	setChildComponentFocus: function(component) {
		var me = this;

		// stop loop
		if (!me[component.parent] || !me[component.parent].panel || !Ext.isFunction(me[component.parent].panel.setFocus)) {
			return true;
		}

		return me[component.parent].panel.setFocus(component.child);
	},
	getFocusNo: function(field) {
		var me = this;

		if (!field || !me.tabSequence) {
			return 0;
		}

		var parent = field.split('.')[0];
		var child = field.split('.')[1];

		for (var i = 0; i < me.tabSequence.length; i++) {
			if (me.tabSequence[i].parent == parent && me.tabSequence[i].child == child) {
				return i;
			}
		}

		return 0;
	},
	setupI18N: function() {
		var texts = {
			ns: 'IP2',
			lang: ['da', 'en'],
			enums: {},
			text: {
				add: {
					value: { da: 'Tilføj', en: 'Add' }
				},
				addTips: {
					value: { da: 'Tryk ctrl+a for at tilføje ny række', en: 'Presse ctrl+a to add new row' }
				},
				refresh: {
					value: { da: 'Opfrisk', en: 'Refresh' }
				},
				refreshTips: {
					value: { da: 'Press F5 to refresh the list', en: 'Press F5 to refresh the list' }
				},
				create: {
					value: { da: 'Opret ny', en: 'Create new' }
				},
				update: {
					value: { da: 'Rediger', en: 'Edit' }
				},
				updateTips: {
					value: { da: 'Tryk ctrl+e for at editere en eksisterende række', en: 'Presse ctrl+e to exit an existing row' }
				},
				remove: {
					value: { da: 'Fjern', en: 'Remove' }
				},
				removeTips: {
					value: { da: 'Will remove a item from the folder', en: 'Will remove a item from the folder' }
				},
				eksport: {
					value: { da: 'Eksport', en: 'Export' }
				},
				confirmExportTitle: {
					value: { da: 'Bekræft eksport', en: 'Confirm export' }
				},
				confirmExport: {
					value: { da: 'Bekræft venligst eksport af : ', en: 'Please confirm export of : ' }
				},
				information: {
					value: { da: 'Information', en: 'Information' }
				},
				exportInformation: {
					value: { da: '<b>"&title"</b> er eksporteret til folder: <b>"&folder"</b>', en: '<b>"&title"</b> has been exported to folder: <b>"&folder"</b>' }
				},
				deselect: {
					value: { da: 'Fravælg', en: 'Deselect' }
				},
				deselectTips: {
					value: { da: 'Fravælg alle valgte rækker', en: 'Deselect all selected rows' }
				},
				confirmDeleteTitle: {
					value: { da: 'Bekræft sletning', en: 'Confirm deleting' }
				},
				confirmDelete: {
					value: { da: 'Vil du slette denne ?', en: 'Do you  want to delete it ?' }
				},
				save: {
					value: { da: 'Gem', en: 'Save' }
				},
				cancel: {
					value: { da: 'Annuller', en: 'Cancel' }
				},
				expand: {
					value: { da: 'Udvid', en: 'Expand' }
				},
				search: {
					value: { da: 'Søg', en: 'Search' }
				},
				searchText: {
					value: { da: 'Søg (min. 3 karakter)', en: 'Search (min. 3 characters)' }
				},
				min3characters: {
					value: { da: 'Indtast minimum 3 karakter', en: 'Enter minimum 3 characters' }
				},
				addPropertiesTitle: {
					value: { da: 'Opret ny properties', en: 'Add new properties' }
				},
				editPropertiesTitle: {
					value: { da: 'Ændre properties', en: 'Edit properties' }
				},
				noRecords: {
					value: { da: 'Ingen rækker blev fundet', en: 'No rows found' }
				},
				message: {
					value: { da: 'Meddelelse', en: 'Message' }
				},
				hasManySelectionMissing: {
					value: { da: 'Has many selection missing !', en: 'Has many selection missing !' }
				},
				invalidConfig: {
					value: { da: 'Invalid config options', en: 'Invalid config options' }
				},
				missingConfigOptions: {
					value: { da: 'Required config options are missing !', en: 'Required config options are missing !' }
				},
				addToAllChildrenTitle: {
					value: { da: 'Tilføj valgte på alle underliggende rækker ?', en: 'Add selected on all children' }
				},
				addToAllChildren: {
					value: {
						da: 'Klik JA for at oprette på alle underliggende rækker<br /><br />Klik på NEJ for kun at oprette på dette niveau',
						en: 'Click YES to add on all children<br /><br />Click NO to only add at this level'
					}
				},
				productFamilyHeaderTitle: {
					value: { da: 'Produktvarianter', en: 'Product variants' }
				},
				productRelationHeaderTitle: {
					value: { da: 'Relaterede produkter', en: 'Related products' }
				},
				product: {
					value: { da: 'Produkt', en: 'Product' }
				},
				name: {
					value: { da: 'Navn', en: 'Name' }
				},
				title: {
					value: { da: 'Titel', en: 'Title' }
				},
				breadcrumb: {
					value: { da: 'Breadcrumb', en: 'Breadcrumb' }
				},
				productCatalogLocationHeaderTitle: {
					value: { da: 'Produktets placering i kataloget', en: 'The products catalog location' }
				},
				primary: {
					value: { da: 'Primær', en: 'Primary' }
				},
				pleaseWait: {
					value: { da: 'Venligst...', en: 'Please wait...' }
				}
			}
		};

		ip2.namespace('ip2.folderorganizer');
		ip2.folderorganizer = new ip2.DynamicNS(texts);
		ip2.folderorganizer.setLanguage(ip2.session.getLanguage());
	},
	getI18N: function(key) {
		return ip2.folderorganizer.getTextValue(key);
	}
});
