Ext.define("Ext.ux.stackorganizer.Panel", {

	extend: "Ext.panel.Panel",

	alias: "widget.stackpanel",

	mixins: {
		componentController: "Ext.ux.util.ComponentController"
	},

	refs: [
		{
			ref: "westRegion",
			selector: "#west"
		},
		{
			ref: "centerRegion",
			selector: "#center"
		},
		{
			ref: "stackTree",
			selector: "stacktree"
		},
		{
			ref: "accordion",
			selector: "stackcontentaccordion"
		}
	],

	config: {
		dataTokenKey: "",
		tokenKey: "__cid__",
		xpd: null,
		supportXpd: null,
		dataParent: null,
		cid: null,
		collectionId: null,
		defaultLanguage: "da",
		languages: null,
		fields: null,
	},

	originalValue: null,

	initComponent: function () {

		var i_self = this;
		var o_initial = Ext.apply({}, i_self.initialConfig);

		i_self.initComponentController();

		Ext.apply(i_self, {
			layout: "border",
			languages: o_initial.languages || wsh.getLanguages(),
			items: [
				{
					xtype: "panel",
					itemId: "west",
					region: "west",
					flex: 1,
					minWidth: 300,
					border: false,
					layout: "fit",
					cls: "x-ux-stack",
					split: true
				},
				{
					xtype: "panel",
					itemId: "center",
					region: "center",
					border: false,
					cls: "x-ux-stack",
					layout: "fit",
					flex: 1
				}
			]
		});

		i_self.callParent(arguments);

		// Sanitize the xpd values
		var xpd = i_self.xpd;
		i_self.xpd = i_self.sanitizeXpdValue(xpd);

		// Sanitize the support xpds
		var support = i_self.supportXpd;
		i_self.supportXpd = i_self.sanitizeXpdValue(support);

		i_self.fields = ["stacktoken", "token", i_self.tokenKey, "toplink", "title", "ptype", "layout", "properties", "stackId"];

		// Initilize the value - and if no value, do a fetch to get it and load
		// the components and add controls
		i_self.initValue();

		return i_self;
	},

	_initValue: function (o_stack) {

		var i_self = this;

		i_self.value = o_stack;

		return i_self;
	},

	initValue: function () {

		var i_self = this;
		var o_value = i_self.value;

		// No value supplied - we must fetch one
		if (!o_value) {
			// We have been supplied a cid - fetch the stack
			if (i_self.cid) {
				i_self.fetchStack(i_self.cid, function (o_value) {
					i_self._initValue(o_value);
					i_self.initChildren(o_value);
				});
			}

			// No cid supplied - we really need one!
			else {
				i_self.fireEvent("needcid", i_self, i_self);
				i_self.fetchStack(i_self.cid, function (o_value) {
					i_self._initValue(o_value);
					i_self.initChildren(o_value);
				});
			}
		}
		else {
			i_self._initValue(o_value);
			i_self.initChildren(o_value);
		}

		return i_self;
	},

	// Initialize the children components - the stacktree and content grids
	initChildren: function (o_stack) {

		var i_self = this;
		var o_xpd = ip2.xpd.flatten(i_self.supportXpd);
		var n_cid = i_self.cid;
		var n_id;

		o_stack = o_stack || i_self.getValue();

		// Find and set the collection id - used by to determine
		// allowedparents and allowedchildren
		n_id = o_xpd.collections[n_cid].stack;
		i_self.collectionId = n_id;

		// Now we have data we add the components
		i_self.addComponents(o_stack);

		// And the controls
		i_self.addControls();

		return i_self;
	},

	addControls: function () {

		var i_self = this;

		// The controls for beforedrop and drop in the stacktree are bound on the
		// components view in the method "addComponents"

		i_self.control({
			"stackTree": {
				"itemcontextmenu": i_self.onStackContext,
				"itemdblclick": i_self.onStackEditPage,
				"checkchange": i_self.onCheckBoxChange,
				"onDeleteKey": i_self.stackRemove,
				"onRightKey": i_self.swapToGrid,
				"scope": i_self
			},
			"accordion": {
				"stackadd": i_self.onStackAdd,
				"onLeftKey": i_self.swapToTree,
				"scope": i_self
			}
		});

		i_self.on({
			"tree_delete": {
				fn: function (tree, record) {
					i_self.onStackRemove(record);
					i_self.fireEvent("change", i_self);
				}
			}
		});

		i_self.getStackTree().getView().getStore().on({
			"add": {
				fn: function () {
					i_self.fireEvent("change", i_self);
				}
			}
		});

		return i_self;
	},

	swapToGrid: function () {

		var i_self = this;
		var i_tab = i_self.getAccordion();

		i_tab.setActiveFocus();

		return i_self;
	},

	swapToTree: function () {

		var i_self = this;
		var i_tree = i_self.getStackTree();

		i_tree.setActiveFocus();

		return i_self;
	},

	addComponents: function (o_stack) {

		var i_self = this;
		var o_xpd = i_self.xpd;
		var s_key = i_self.tokenKey;
		var i_west = i_self.getWestRegion();
		var i_center = i_self.getCenterRegion();

		// Add and create the list component with store

		var a_children = o_stack.children || [];

		Ext.Array.each(a_children, function(o_child) {
			o_child.iconCls = "x-tree-no-icon";
			o_child.leaf = true;
		});

		var i_stacktree = Ext.widget("stacktree", {
			layout: "fit",
			border: 0,
			supportXpd: i_self.supportXpd,
			viewConfig: {
				border: 1
			},
			store: Ext.create("Ext.ux.stackorganizer.store.Tree", {
				fields: i_self.fields,
				root: o_stack
			}),
			rootVisible: false,
			lines: false
		});

		var i_toolbar = Ext.widget("toolbar", {
			dock: "top",
			items: [
				{
					xtype: "splitbutton",
					text: ip2.i18n({
						da: "Tilføj",
						en: "Add"
					}),
					iconCls: "pf-add",
					menu: i_self.getCreateMenu()
				}
			]
		});

		var i_store = i_stacktree.getStore();
		i_store.on({
			datachanged: {
				fn: function(store, a_nodes) {

					var a_items = store.data.items;
					Ext.Array.each(a_items, function(i_node) {
						i_node.set("leaf", true);
						i_node.set("iconCls", "x-tree-no-icon");
					});
				}
			}
		});

		i_stacktree.addDocked(i_toolbar);

		i_west.add(i_stacktree);

		// Add and create the content component
		i_center.add({
			xtype: "stackcontentaccordion",
			border: 0,
			xpd: i_self.xpd,
			supportXpd: i_self.supportXpd,
			tokenKey: i_self.tokenKey,
			collectionId: i_self.collectionId,
			stack: o_stack,
			fields: i_self.fields/*,
			dragConfig: {
				dragGroup: "stackDD",
				enableDrag: true,
				enableDrop: false
			}*/
		});

		// Create the context menu for the stack tree
		i_self.stackContextMenu = Ext.create("Ext.menu.Menu", {
			renderTo: Ext.getBody(),
			itemId: "stackcontextmenu",
			items: [
				{
					xtype: "menuitem",
					iconCls: "pf-navigate_cross",
					text: ip2.i18n({
						da: "Fjern",
						en: "Remove"
					}),
					itemId: "remove"
				},
				{
					xtype: "menuitem",
					iconCls: "pf-edit",
					text: ip2.i18n({
						da: "Rediger toplink",
						en: "Edit Toplink"
					}),
					itemId: "edit"
				},
				{
					xtype: "menuitem",
					iconCls: "pf-edit",
					text: ip2.i18n({
						da: "Rediger siden",
						en: "Edit Page"
					}),
					itemId: "editpage"
				}
			]
		});
		i_self.getStackContextMenu = function () {
			return this.stackContextMenu;
		};

		// Set the original value of this component now
		var o_value = i_self.getValue();
		i_self.originalValue = o_value;

		return i_self;
	},

	getCreateMenu: function() {

		var i_self = this;
		var o_xpd = i_self.xpd;
		var o_supportXpd = i_self.supportXpd;
		var o_collections = o_xpd.collections;
		var a_items = [];

		ip2.each(o_collections, function(o_collection, s_key) {

			var b_allow = (function () {

				var b_allow = false;
				var parents = o_collection.allowedparents;
				var n_id = i_self.collectionId;

				// Parents is an array
				// If array is empty or collectionId is in the allowedparent array
				// it is allowed
				if (Ext.isArray(parents)) {

					if (!parents.length) {
						b_allow = true;
					}
					else {
						b_allow = (Ext.Array.indexOf(parents, n_id) >= 0);
					}
				}

				return b_allow;
			})();

			if (b_allow) {
				var o_supportXpd = i_self.sanitizeXpdValue(o_collection.xpd);
				var i_menuitem = Ext.widget("menuitem", {
					text: ip2.xpd.translate(o_xpd, o_collection.title, ip2.session.getLanguage()),
					itemId: "collection-" + o_collection.id,
					stackId: o_collection.id,
					collection: o_collection,
					supportXpd: o_supportXpd,
					handler: function(item) {

						var i_grid = i_self.getAccordion().getStackById(item.stackId);
						var i_model = i_grid.getStore().getModel();

						var i_record = i_model.create({
							__cid__: item.supportXpd.collections[item.collection.ptype].id
						});

						var s_event = "entityupdate:" + item.collection.entity;
						var o_event = {};
						o_event[s_event] = {
							fn: function(i_record, s_action) {
								i_grid.refreshData(i_record);
							},
							single: true
						};

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

						var i_window = Ext.widget("window", {
							modal: false,
							closable: true,
							collapsible: true,
							resizable: true,
							width: o_size.width * 0.9,
							height: o_size.height * 0.9,
							layout: "fit"
						});

						ip2.addChild(i_window, i_record, "create", item.collection);

						i_self.mon(ip2.App, o_event);

						i_window.show();
					}
				});
				a_items.push(i_menuitem);
			}
		});

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

	fetchStack: function(n_cid, f_callback) {

		if (!n_cid) {
			throw new Error("Ext.ux.stackorganizer.Panel: I really need a cid! (Listen to my needcid event and call my setCid to help me)");
		}

		var i_self = this;

		// Load the stack data and add the initialize the components
		Ext.Ajax.request({
			url: "/wsh-services/wshproxy.aspx",
			params: {
				xpd: i_self.supportXpd._path,
				stackxpd: i_self.xpd._path,
				token: i_self.getToken(),
				action: "getpage",
				environment: "treestore",

				// TODO: Get this from pages.xpd (pageLang.widget)
				cid: n_cid
			},
			success: function (o_response) {

				var o_xpd = i_self.xpd;
				var n_id;
				var o_stack = {};

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

				o_stack.children || (o_stack.children = []);

				i_self.sanitizeStackValue(o_stack, true);

				f_callback && f_callback(o_stack);
			}
		});

		return i_self;
	},

	stackRemove: function () {

		var i_self = this;
		var i_tree = i_self.getStackTree();
		var i_store = i_tree.getView().getStore();
		var a_selected = i_tree.getSelectionModel().getSelection();

		i_store.remove(a_selected);

		return i_self;
	},

	onCheckBoxChange: function (i_node, b_checked) {

		var i_self = this;
		var o_properties = i_node.get("properties");

		i_node.set({
			"toplink": b_checked,
			"checked": b_checked
		});

		if (o_properties) {
			o_properties.toplink = b_checked;
			i_node.set("properties", o_properties);
		}
		i_self.fireEvent("change", i_self);

		return i_self;
	},

	onStackAdd: function (i_grid, i_record, b_create) {

		var i_self = this;
		var i_tree = i_self.getStackTree();
		var i_store = i_tree.getStore();
		var i_root = i_store.getRootNode();
		var i_selected = i_tree.getLastSelectedNode();
		var o_stack;

		i_tree.cleanIndexes();

		if (b_create) {
			var i_node = i_root.createNode(i_record.data);
			var o_prop = i_record.get("properties");

			// Insert after last selected node in stacktree
			// unless last selected node is last node in stacktree
			if (i_selected) {

				var n_index = i_selected.get("index");

				i_root.insertChild(n_index + 1, i_node);
			}

			// No node selected, or last selected node is also last node in tree
			else {
				i_root.appendChild(i_node);
			}

			i_tree.cleanIndexes().getView().refresh();
			i_tree.setNodeFocus(i_node);
		}
		else {
			var a_removed = i_store.getRemovedRecords();
			ip2.each(a_removed, function(i_removed) {
				if (i_removed.get("token") == i_record.get("token")) {
					i_record.set(i_removed.data);
				}
			});
		}

		if (!i_record.get("title")) {
			var o_prop = i_record.get("properties");
			var title = o_prop.title || o_prop.header || o_prop.name;

			if (Ext.isString(title)) {
				if (ip2.isStringedObject(title)) {
					title = JSON.parse(title);
				}
				else {
					title = {
						da: title,
						en: "",
						fr: "",
						de: ""
					};
				}
			}

			i_record.set("title", title);
		}

		o_stack = i_self.getValue();

		// Set the new stack value on the grid so filter will update and the
		// grid will refresh itself
		i_grid.setStack(o_stack);

		i_self.fireEvent("change", i_self);

		return i_self;
	},

	onStackEdit: function (i_self, i_record) {

		var i_self = this;
		var o_title = i_self.getStackTitle(i_record);
		var b_checked = i_record.get("checked");
		var s_language = ip2.session.getLanguage();
		var i_window;

		i_window = Ext.widget("window", {
			renderTo: Ext.getBody(),
			closable: true,
			width: 600,
			layout: "fit",
			title: ip2.i18n(o_title),
			items: [
				{
					xtype: "form",
					itemId: "stackform",
					layout: "anchor",
					bodyPadding: 20,
					defaults: {
						anchor: "100%",
						labelWidth: 100
					},
					items: [
						{
							xtype: "i18ntextfield",
							name: "title",
							itemId: "title",
							preventI18nTrigger: true,
							defaultLanguage: s_language,
							languages: i_self.languages,
							fieldLabel: ip2.i18n({
								da: "Titel",
								en: "Title"
							}),
							value: o_title
						},
						{
							xtype: "checkbox",
							name: "checked",
							itemId: "checked",
							inputValue: "true",
							fieldLabel: ip2.i18n({
								da: "Toplink",
								en: "Toplink"
							}),
							checked: b_checked
						}
					],
					listeners: {
						dirtychange: {
							fn: function(i_form, b_dirty) {
								var i_owner = i_form.owner;
								var i_save = i_owner.down("#button-save");
								if (i_save) {
									if (b_dirty) {
										i_save.enable();
									}
									else {
										i_save.disable();
									}
								}
							}
						}
					},
					buttons: [
						{
							text: ip2.i18n("save"),
							action: "save",
							itemId: "button-save",
							disabled: true,
							handler: function () {

								var i_form = i_window.down("#stackform");
								var o_title = i_form.down("#title").getValue();
								var b_checked = i_form.down("#checked").getValue();

								i_record.set({
									title: o_title,
									checked: b_checked ? true : false,
									toplink: b_checked ? true : false
								});

								i_window.close();

								i_self.fireEvent("change", i_self);
							}
						},
						{
							text: ip2.i18n("cancel"),
							action: "cancel",
							handler: function () {
								i_window.close();
							}
						}
					]
				}
			]
		}).show();

		return i_self;
	},

	onStackRemove: function (i_record) {

		var i_self = this;
		var i_tree = i_self.getStackTree();
		var i_accordion = i_self.getAccordion();
		var i_grid = i_accordion.getStackById(i_record.get("stackId"));
		var o_stack = i_self.getValue();

		if (!i_grid) {
			i_accordion.refreshStackData(o_stack); // THIS WILL CAUSE A TOTAL REFRESH
		}
		else {
			i_grid.stack = o_stack;
			i_grid.refreshData();
		}

		return i_self;
	},

	onStackEditPage: function (i_tree, i_node, i_item, n_index, e, o_events) {

		var i_self = this;
		var o_xpd = ip2.xpd.flatten(i_self.xpd);
		var o_collections = o_xpd.collections;
		var o_collection = o_collections[i_node.get("stackId")];

		var i_el = Ext.get(i_item.id);

		var o_keys = {};
		var o_size = Portfolio.util.Handler.getWindowSize();
		var i_user = Portfolio.util.Handler.getUser();

		var s_entity = o_collection.xpd == "pages.xpd" ? "WSHPAGET00" : o_collection.entity;

		var o_config = {
			dmd: "dmd/webshop.dmd",
			entityName: s_entity,
			uiName: "portfolio",
			context: "form"
		};

		var i_model = ip2.model(o_config);

		var i_record = i_model.create();
		var s_key = i_record.idProperty;
		var n_token = i_node.get("token");

		i_record.set(s_key, n_token);
		o_keys[i_record.idProperty] = i_record.get(i_record.idProperty);

		var i_window = Ext.widget("window", {
			modal: false,
			closable: true,
			collapsible: true,
			resizable: true,
			width: o_size.width * 0.9,
			height: o_size.height * 0.9,
			layout: "fit"
		});

		i_window.show();
		i_window.setLoading();

		var i_entitypanel = Ext.widget("portfolio-entity-form", {
			keys: o_keys,
			action: "update",
			dmd: o_config.dmd,
			entity: o_config.entityName,
			view: o_config.uiName,
			context: "form",
			language: i_user.get("USRLNG") || "en",
			languages: wsh.getLanguages(),
			closable: false,
			listeners: {
				contentReady: {
					fn: function(i_contentPanel, i_entitypanel) {

						var i_header = i_entitypanel.getHeader();
						i_header.hide();
					}
				}
			}
		});

		i_window.add(i_entitypanel);

		i_window.setLoading(false);
	},

	onStackContext: function (i_stack, i_node, i_item, n_index, e, o_events) {

		var i_self = this;
		var i_menu = i_self.getStackContextMenu();

		e.preventDefault();
		var a_xy = e.getXY();
		i_menu.showAt(a_xy[0], a_xy[1]);

		i_menu.down("#remove").handler = function () {
			i_node.remove(false);
			i_self.onStackRemove(i_node);
			i_self.fireEvent("change", i_self);
		};

		i_menu.down("#edit").handler = function () {
			i_self.onStackEdit(i_self, i_node);
		};

		i_menu.down("#editpage").handler = function () {
			i_self.onStackEditPage(i_self, i_node, i_item, n_index, e, o_events);
		};

		return i_self;
	},

	getStackTitle: function (i_record) {

		var s_title = "";
		var o_title = i_record.get("title") || {};
		var o_properties = i_record.get("properties") || {};
		var s_language = ip2.session.getLanguage();

		if (!Ext.isObject(o_title) && ip2.isStringedObject(o_title)) {
			o_title = Ext.decode(o_title);
		}

		if (!o_title || (o_title && !o_title[s_language])) {

			if (!Ext.isObject(o_title)) {
				o_title = {};
			}

			o_title[s_language] = o_properties.title || o_properties.header || "";
		}

		return o_title;
	},

	getToken: function () {

		var i_self = this;
		var i_parent = i_self.dataParent;
		var s_key = i_self.dataTokenKey;
		var o_keys = i_parent.getKeys();

		return o_keys[s_key];
	},

	getValue: function () {

		var i_self = this;
		var i_stackTree = i_self.getStackTree();
		var value = {};

		if (i_stackTree) {
			var i_root = i_stackTree.getStore().getRootNode();
			value = i_self.serializeNode(i_root, true);
		}

		return value;
	},

	setValue: function (o_value) {

		var i_self = this;
		var i_stackTree = i_self.getStackTree();
		var i_root;

		if (i_stackTree) {
			i_root = i_stackTree.getStore().getRootNode();
			i_root.set(o_value);
		}

		i_self.value = o_value;

		return i_self;
	},

	getOriginalValue: function () {

		return this.originalValue;
	},

	resetOriginalValue: function () {

		var i_self = this;

		i_self.originalValue = i_self.value = i_self.getValue();

		return i_self;
	},

	isDirty: function () {

		var i_self = this;
		var o_original = i_self.getOriginalValue() || {};
		var o_value = i_self.getValue() || {};

		if (o_original === null || o_value === null) {
			return false;
		}

		var s_original = JSON.stringify(o_original);
		var s_value = JSON.stringify(o_value);

		return s_original != s_value;
	},

	serializeNode: function (i_node, b_root) {

		var i_self = this;
		var a_fields = i_self.fields;
		var o_data = i_node.data;
		var o_node = {};

		Ext.Array.each(a_fields, function (s_field) {

			var value = o_data[s_field];

			if (value != null && value != undefined) {

				// Normalize toplink to boolean
				if (s_field == "toplink") {

					if (value == "false" || value === "") {
						value = false;
					}
				}

				o_node[s_field] = value;
			}
		});

		if (b_root) {
			o_node.children = [];
		}

		if (i_node.childNodes && i_node.childNodes.length) {

			o_node.children = [];

			Ext.Array.each(i_node.childNodes, function (i_child) {
				o_node.children.push(i_self.serializeNode(i_child));
			});
		}

		return o_node;
	},

	sanitizeStackValue: function (o_stack, b_root) {

		var i_self = this;

		Ext.Object.each(o_stack, function (s_key, value) {

			if (s_key == "children") {
				Ext.Array.each(value, function (o_child) {
					i_self.sanitizeStackValue(o_child);
				});
			}
			else if (s_key == "checked") {
				o_stack.toplink = value;
				if (o_stack.properties) {
					o_stack.properties.toplink = value;
				}
			}
			else if (s_key == "leaf" && b_root) {
				o_stack.leaf = false;
			}
		});
	},

	sanitizeXpdValue: function (xpd) {

		if (Ext.isString(xpd)) {
			xpd = ip2.resource.get(xpd, true);
		}

		return xpd;
	}
});
