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

	extend: 'Ext.tree.Panel',

	alias: [
		'widget.ip2TreeSelector',
		'widget.ip2treeSelector',
		'widget.ip2treeselector'
	],

	useArrows: true,

	rootVisible: false,

	singleExpand: false,

	autoScroll: true,

	border: true,

	initComponent: function () {

		var me = this;

		me.title = ip2.i18n(me.title);

		me.initialize();

		me.clearSelection();

		// initialize tree column
		me.columns = [{
			xtype: 'treecolumn',
			dataIndex: 'TITLE',
			flex: 1,
			text: ip2.i18n({
				da: 'Beskrivelse',
				en: 'Description'
			}),
			renderer: function (value, meta, record, rowIndex, colIndex, store, view) {
				if (value && value.length > 0) {
					return ip2.i18n(value);
				}
				else {
					var props = {};
					if (ip2.isStringedObject(record.data.PROPERTIES)) {
						props = Ext.decode(record.data.PROPERTIES);
					}
					else {
						var o_props = {};
						var a_split = record.data.PROPERTIES.split(",");
						ip2.each(a_split, function(s_props) {
							var a_propsplit = s_props.split(":");
							if (a_propsplit.length == 2) {
								o_props[a_propsplit[0].trim()] = a_propsplit[1].trim();
							}
						});
						props = o_props;
						record.data.PROPERTIES = JSON.stringify(o_props);
					}
					var cid = props.__cid__;
					var collection = me.getXpdCollection(cid);
					var title = '';

					if (collection && collection.properties) {
						for (var name in collection.properties) {
							if (collection.properties[name].isTitle) {
								title = me.concatTitle(title, props[name]);
							}
						}
						title = ip2.i18n(title);
					}
					if (title.length == 0) {
						if (me.environment && record.data[me.environment]) {
							props = Ext.decode(record.data[me.environment]);
							if (props && props.properties && props.properties.title) {
								title = ip2.i18n(props.properties.title);
							}
						}
					}
					if (title.length == 0) {
						if (record.data.rowProps || record.data.extraProps) {
							props = Ext.decode(record.data.rowProps || record.data.extraProps);
							if (props && props.properties && props.properties.title) {
								title = ip2.i18n(props.properties.title);
							}
							if (title.length == 0) {
								if (props && props.properties && props.properties.name) {
									title = ip2.i18n(props.properties.name);
								}
							}
						}
					}
					return title;
				}
			}
		}];

		if (me.xpd) {
			me.columns = Ext.ux.folderorganizer.Util.addCollectionColumns(me, me.columns);
		}

		me.hideHeaders = true;
		if (me.columns.length > 1) {
			me.hideHeaders = false;
		}

		var extraParams = {
			action: 'treeStore',
			entity: me.entity,
			cid: me.cid.root,
			childCid: me.cid.child,
			xpd: me.xpdPath,
			dmd: me.dmdPath,
			menus: '',
			displayRootNode: me.displayRootNode,
			displayCheckbox: true,
			language: ip2.session.getLanguage(),
			idField: me.propertyNameMapping.ID,
			parentidField: me.propertyNameMapping.PARENTID,
			propertiesField: me.propertyNameMapping.PROPERTIES
		};

		if (me.omitCid) {
			extraParams.omitCid = me.cid.child;
		}
		if (me.environment) {
			extraParams.environment = me.environment;
		}
		if (me.extraProps) {
			extraParams.extraProps = me.extraProps;
		}
		if (me.filter) {
			extraParams.filter = me.filter;
		}

		var fields = [
			{
				name: 'TITLE',
				type: 'string',
				title: 'Folder'
			},
			{
				name: 'ID',
				type: 'int'
			},
			{
				name: 'PARENTID',
				type: 'int'
			},
			{
				name: 'PROPERTIES',
				type: 'string'
			}
		];

		// extra data model fields
		if (me.environment) {
			fields.push({
				name: 'extraProps',
				type: 'string'
			});
		}
		if (me.extraProps) {
			fields.push({
				name: 'rowProps',
				type: 'string'
			});
		}

		// Insert extra columns
		if (me.extraColumns && me.extraColumns.length > 0) {

			for (var i = 0; i < me.extraColumns.length; i++) {

				var column = Ext.apply({}, me.extraColumns[i]);

				if (Ext.isObject(column.text)) {
					column.text = ip2.i18n(column.text);
				}

				// ui type and renderer
				if (column.uitype && ip2.uitypes[column.uitype]) {
					var uitype = ip2.uitypes[column.uitype];

					// uitype require ?
					if (uitype.require) {
						Ext.require(uitype.require);
					}
					column.subRenderer = uitype.editor.renderer;

					//column.renderer = uitype.editor.renderer;
					column.renderer = function(value, meta, record, rowIndex, colIndex, store, view) {
						if (me.environment && record.data[me.environment]) {

							var header = view.getGridColumns()[colIndex];
							var props = Ext.decode(record.data[me.environment]);

							if (props && props.properties) {
								var value = props.properties[header.dataIndex];
								return header.subRenderer.call(header, value);
							}
						}
					};
				}
				me.hideHeaders = false;
				me.columns.push(column);
			}
		}

		var s_model = ip2.unique('FolderOrganizerModel-');

		Ext.define(s_model, {
			extend: 'Ext.data.Model',
			fields: fields,
			proxy: {
				type: 'ajax',
				url: me.proxy,
				extraParams: extraParams
			}
		});

		me.store = Ext.create('Ext.data.TreeStore', {
			model: s_model,
			clearOnLoad: false,
			autoLoad: true,
			listeners: {
				beforeload: {
					fn: function(store, operation) {
						var i_node = operation.node;
						var i_proxy = operation.getProxy();
						var o_extraParams = i_proxy.getExtraParams();
						o_extraParams.node = i_node.get("ID");
						delete operation.node;
					}
				},
				'load': {
					fn: function (i_store, a_records, b_success, i_node) {
						if (me.expandRootNode && i_node.getId() == 'root') {
							ip2.each(a_records, function(i_record) {
								i_record.expand();
							});
						}
					}
				}
			}
		});

		me.rowMenu = Ext.create('Ext.menu.Menu', {
			items: [{
				text: ip2.i18n({ da: 'Sæt flueben på alle underliggende rækker', en: 'Check all rows below' }),
				iconCls: 'ip2-icon-checks',
				handler: function() {
					me.checkAllNodesBelow(me.node);
				}
			},{
				text: ip2.i18n({ da: 'Fjern flueben på alle underliggende rækker', en: 'Uncheck all rows below' }),
				iconCls: 'ip2-icon-undo',
				handler: function() {
					me.uncheckAllNodesBelow(me.node);
				}
			}]
		});

		me.listeners = me.listeners || {};

		Ext.apply(me.listeners, {
			itemcontextmenu: function(view, node, item, index, e) {
				e.stopEvent();
				me.getSelectionModel().select(node);
				me.node = node;
				var coords = e.getXY();
				me.rowMenu.showAt([coords[0], coords[1]]);
			},
			checkchange: function(node, checked) {
				if (checked && !node.isLeaf() && me.multiChoice) {
					// new checked and multi choice active
					var showWarning = true;

					var cid = Ext.ux.folderorganizer.Util.getXpdCollectionId(me, node);
					var collection = Ext.ux.folderorganizer.Util.getXpdCollection(me, cid);
					if (collection && collection.allowedchilds && collection.allowedchilds[0] && collection.allowedchilds[0] == me.cid.child) {
						showWarning = false;
					}

					if (showWarning) {
						me.multiChoice.node = node;
						me.multiChoice.show();
					}
				}
				else {
					me.checkChangeSingleNode(node, checked);
				}
			},
			select: function(view, node, index, e) {
				Ext.ux.folderorganizer.Util.setCollectionColumnHeader(me, node);
			}
		});

		me.callParent(arguments);

		var parent = (Ext.isFunction(me.wrapper.getRecord)) ? me.wrapper : (Ext.isFunction(me.wrapper.getDataParent)) ? me.wrapper.getDataParent() : null;

		if (parent instanceof Ext.ux.container.Ip2Widget) {
			var i_form = parent.up("entityform");
			if (i_form) {
				parent = i_form;
			}
		};

		if (parent && Ext.isFunction(parent.getRecord)) {

			me.record = parent.getRecord(me);

			if (me.record) {
				me.onParentLoad();
			}

			// wait for data parent store loaded
			else {

				var store = me.wrapper.getDataParent().getStore();

				store.on('load', function (store, records) {

					if (Ext.isArray(records)) {
						me.record = records[0];
						me.onParentLoad();
					}
				});
			}
		}
		me.enableBubble("dirtychange");
	},

	/**
	 * @method on parent load
	 *
	 */
	onParentLoad: function () {

		var me = this;

		me.clearSelection();

		me.getData(me.setExisting);
	},

	isDirty: function () {

		var i_cmp = this;
		var i_store = i_cmp.store;
		var a_nodes = i_store.getData().items;
		var b_dirty = false;

		ip2.each(a_nodes, function(i_node) {
			if (i_node.dirty) {
				b_dirty = true;
			}
		});

		return b_dirty;
	},

	resetDirty: function() {

		var i_self = this;
		var i_store = i_self.getStore();
		var a_nodes = i_store.getData().items;
		ip2.each(a_nodes, function(i_node) {
			i_node.oldChecked = i_node.get("checked");
			i_node.dirty = false;
		});
		i_self.fireEvent("dirtychange", i_self, false);
	},

	/**
	 * @method Set Existing: set checkbox as checked for already existing relation
	 *
	 */
	setExisting: function (a_records) {

		var i_cmp = this;

		i_cmp.existing = {
			ID: []
		};

		if (!a_records) {
			return;
		}

		// create unique array with parents
		var a_parentTokens = [];

		// Build the parentToken array
		Ext.Array.each(a_records, function (i_record) {

			var s_parents = i_record.get('parents');
			var a_parents = s_parents.split(',');

			Ext.Array.each(a_parents, function (n_parent) {
				// Only push if not already in parentToken array
				if (Ext.Array.indexOf(a_parentTokens, n_parent) == -1) {
					a_parentTokens.push(n_parent);
				}
			});
		});

		// expand all parents and set check mark when expanding is finished
		i_cmp.expandParent({
			index: 0,
			parents: a_parentTokens,
			records: a_records,
			success: function (a_records) {

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

					var s_parents = i_base.get('parents');
					var a_parents = s_parents.split(',');
					var s_token = a_parents.pop();

					i_cmp.setCheck(s_token, true);
					i_cmp.existing.ID.push(s_token);

					// Make sure the relevant record checked is not flagged
					// as dirty due to check change
					var i_record = i_cmp.store.findRecord("ID", s_token, 0, true, false, false);
					if (i_record) {
						var b_clean = false;
						if (Ext.Object.getSize(i_record.modified) == 1) {
							b_clean = true;
						}
						i_record.raw.checked = true;
						if (b_clean) {
							i_record.dirty = false;
						}
					}
				});
				i_cmp.getView().refresh();
			}
		});
	},

	/**
	 * @method expand parent
	 *
	 */
	expandParent: function (args) {

		var me = this;

		if (args.index >= args.parents.length) {

			var task = new Ext.util.DelayedTask(function () {
				Ext.callback(args.success, me, [args.records]);
			});

			task.delay(300);

			return false;
		}

		var node = me.store.findNode("ID", args.parents[args.index], true, 0, false, false);

		if (node && !node.isExpanded()) {

			node.expand(false, function () {

				args.index = args.index + 1;

				var task = new Ext.util.DelayedTask(function () {
					me.expandParent(args);
				});

				task.delay((args.index >= args.parents.length) ? 0 : 300);
			}, me);
		}
		else {

			args.index = args.index + 1;

			me.expandParent(args);
		}
	},

	/**
	 * @method check all nodes below
	 *
	 */
	checkAllNodesBelow: function (node) {
		var me = this;

		var setCheck = function(node) {
			node.set('checked', true);
			me.checkChangeSingleNode(node, true);
			if (node.hasChildNodes()) {
				for (var i = 0; i < node.childNodes.length; i++) {
					setCheck(node.childNodes[i]);
				}
			}
		};

		node.expand(true, function() {
			setCheck(node);
		});
	},

	/**
	 * @method uncheck all nodes below
	 *
	 */
	uncheckAllNodesBelow: function (node) {
		var me = this;

		var setUncheck = function(node) {
			node.set('checked', false);
			me.checkChangeSingleNode(node, false);
			if (node.hasChildNodes()) {
				for (var i = 0; i < node.childNodes.length; i++) {
					setUncheck(node.childNodes[i]);
				}
			}
		};

		node.expand(true, function() {
			setUncheck(node);
		});
	},

	/**
	 * @method set uncheck for already check (single selection)
	 *
	 */
	singleSelection: function () {
		var me = this;

		for (var i = 0; i < me.existing.ID.length; i++) {
			me.setCheck(me.existing.ID[i], false);
		}
		me.existing.ID = [];

		for (var i = 0; i < me.checkedItems.ID.length; i++) {
			me.setCheck(me.checkedItems.ID[i], false);
		}
		me.checkedItems.ID = [];
	},

	/**
	 * @method set check or uncheck
	 *
	 */
	setCheck: function (s_token, b_checked) {

		var i_cmp = this;
		var i_store = i_cmp.store;
		var i_node = i_store.findNode("ID", s_token, 0, true, false, false);

		if (i_node) {
			i_node.set('checked', b_checked);
		}
	},

	/**
	 * @method set check or uncheck for single node and update array
	 *
	 */
	checkChangeSingleNode: function (node, checked) {

		var me = this;

		var token = node.data.ID;

		if (me.checkedItems.ID.indexOf(token) > -1) {
			var pos = me.checkedItems.ID.indexOf(token);
			me.checkedItems.ID.splice(pos, 1);
		}
		if (me.uncheckedItems.ID.indexOf(token) > -1) {
			var pos = me.uncheckedItems.ID.indexOf(token);
			me.uncheckedItems.ID.splice(pos, 1);
		}
		if (checked) {
			// new checked
			if (!me.multiSelect) {
				me.singleSelection();
			}
			me.checkedItems.ID.push(token);
			me.setCheck(token, true);
		}
		else {
			// existing unchecked
			me.uncheckedItems.ID.push(token);
		}

		me.fireEvent('change', me, me.checkedItems.ID);
	},

	/**
	 * @method getvalue
	 *
	 */
	getValue: function () {

		return this.checkedItems;
	},

	/**
	 * @method doSave
	 *
	 */
	doSave: function () {
		var me = this;

		// checked
		for (var i = 0; i < me.checkedItems.ID.length; i++) {
			var node = me.getNode(me.checkedItems.ID[i]);
			var token = node.data.ID;
			me.doUpdate('update', token);
		}

		// unchecked
		if (me.multiSelect || me.checkedItems.ID.length == 0) {

			for (var i = 0; i < me.uncheckedItems.ID.length; i++) {

				var node = me.getNode(me.uncheckedItems.ID[i]);
				var token = node.data.ID;
				me.doUpdate('remove', token);
			}
		}

		me.existing.ID = me.checkedItems.ID;
		me.clearSelection();
		me.resetDirty();

		me.fireEvent('savecomplete', me, true);
	},

	/**
	 * @method doUpdate
	 *
	 */
	doUpdate: function (action, token) {

		var me = this;

		Ext.Ajax.request({
			url: me.proxy,
			params: {
				action: (action == 'update') ? 'addItemToParent' : 'removeItemFromParent',
				token: token,
				item: me.getKeyValue(),
				cid: me.cid.child
			}
		});
	},

	/**
	 * @method doDelete (empty function). Make you own function :-)
	 *
	 */
	doDelete: function () {

		var me = this;

		var key = {
			product: me.getKeyValue()
		};

		// existing
		for (var i = 0; i < me.existing.ID.length; i++) {
			var node = me.getNode(me.existing.ID[i]);
			var token = node.data.ID;
			me.setCheck(token, false);
			me.doUpdate('remove', token);
		}

		// checked
		for (var i = 0; i < me.checkedItems.ID.length; i++) {
			var node = me.getNode(me.checkedItems.ID[i]);
			var token = node.data.ID;
			me.setCheck(token, false);
			me.doUpdate('remove', token);
		}
	},

	/**
	 * @method get data for this product
	 *
	 */
	getData: function (f_callback) {

		var i_cmp = this;
		var i_store = i_cmp._dataStore;

		if (!i_store) {

			var s_entity = i_cmp.entity;
			var s_proxy = i_cmp.proxy;
			var n_token = i_cmp.getKeyValue();
			var n_cid = i_cmp.cid.child;
			var s_action;

			// Find correct action to use for service
			switch (s_entity) {
				case 'WSHSTCET00':
					s_action = 'getParentByOrganizedPage';
				break;
				default:
					s_action = 'getParentByOrganizedItem';
				break;
			}

			i_store = i_cmp._dataStore = Ext.create('Ext.data.Store', {
				autoLoad: false,
				fields: [
					{ name: 'ID', type: 'string' },
					{ name: 'parents', type: 'string' }
				],
				idProperty: 'ID',
				proxy: {
					type: 'ajax',
					url: s_proxy,
					extraParams: {
						action: s_action,
						token: n_token,
						entity: s_entity,
						cid: n_cid
					},
					reader: {
						type: 'json',
						rootProperty: 'rows'
					}
				}
			});
		}

		i_store.on({
			'load': {
				fn: function (i_self, a_records) {
					f_callback.call(i_cmp, a_records);
				},
				scope: i_cmp,
				single: true
			}
		});

		i_store.load();
	},

	/**
	 * @method getKeyValue
	 *
	 */
	getKeyValue: function () {
		var me = this;

		if (me.record) {
			switch (me.entity) {
				case 'WSHSTCET00':
					return (me.record.data.link && me.record.data.link.token) ? me.record.data.link.token : 0;
				break;
				default:
					return me.record.data.ITMITMTKN || me.record.id;
				break;
			}
		}
		else {
			return '';
		}
	},

	/**
	 * @method get node data
	 *
	 */
	getNode: function (id) {

		var i_self = this;
		var i_store = i_self.getStore();
		return i_store.findNode("ID", id, id, id, true);
	},

	/**
	 * @method clean up selection
	 *
	 */
	clearSelection: function () {

		this.checkedItems = {
			ID: []
		};
		this.uncheckedItems = {
			ID: []
		};
	},

	/**
	 * @method: Get XPD collection by cid
	 *
	 */
	getXpdCollection: function (n_cid) {

		var i_cmp = this;
		var o_xpd = i_cmp.xpd;
		var o_return = null;

		if (o_xpd && o_xpd.flatten.collections[n_cid]) {
			o_return = o_xpd.flatten.collections[n_cid];
		}

		return o_return;
	},

	/**
	 * @method: Concat nice title
	 *
	 */
	concatTitle: function (title, value) {

		var v = value || '';

		return (title) ? title + ' ' + v : v;
	},

	initialize: function () {

		var me = this;

		me.cid = me.cid || {
			root: 0,
			child: 0
		};
		me.displayRootNode = Ext.isBoolean(me.displayRootNode) ? me.displayRootNode : true;
		me.expandRootNode = Ext.isBoolean(me.expandRootNode) ? me.expandRootNode : true;
		me.multiSelect = Ext.isBoolean(me.multiSelect) ? me.multiSelect : true;
		me.omitChild = Ext.isBoolean(me.omitChild) ? me.omitChild : true;

		if (!me.propertyNameMapping) {

			if (me.entity && me.entity == 'WSHNAMET00') {
				me.propertyNameMapping = {
					ID: 'NAMNAMTKN',
					PARENTID: 'NAMPNTTKN',
					PROPERTIES: 'NAMPROP'
				};
			}
			else if (me.entity && me.entity == 'WSHSTCET00') {
				me.propertyNameMapping = {
					ID: 'STCSTCTKN',
					PARENTID: 'STCPNTTKN',
					PROPERTIES: 'STCPROP'
				};
			}
			else {
				me.propertyNameMapping = {
					ID: 'FLDFLDTKN',
					PARENTID: 'FLDPNTTKN',
					PROPERTIES: 'FLDPROP'
				};
			}
		}
		me.propertyNameMappingReverse = {};
		for (var key in me.propertyNameMapping) {
			me.propertyNameMappingReverse[me.propertyNameMapping[key]] = key.toString();
		}

		// initialize dmd -& xpd path and object
		me.dmdName = me.dmd;
		me.dmdPath = me.dmdName;
		me.xpdName = me.xpd;
		me.xpdPath = me.xpdName;
		me.xpd = ip2.resource.get(me.xpdName);

		if (me.xpd) {
			me.xpd.flatten = ip2.xpd.flatten(me.xpd);
		}

		// prepare multi choice dialog box
		if (me.addToAllChildren && me.addToAllChildren.allow && me.addToAllChildren.warning && me.addToAllChildren.multiChoiceDialog) {
			var mcd = me.addToAllChildren.multiChoiceDialog;
			var questions = [];
			for (var i = 0; i < mcd.questions.length; i++) {
				questions.push({
					answer: i,
					question: ip2.i18n(mcd.questions[i])
				});

				switch (i) {
					case 0:
						questions[i].icon = '/system/images/icons/16x16/check2.png';
					break;
					case 1:
						questions[i].icon = '/system/images/icons/16x16/checks.png';
					break;
					case 2:
						questions[i].icon = '/system/images/icons/16x16/undo.png';
					break;
				}
			}
			me.multiChoice = Ext.create('Ext.ux.folderorganizer.MultiChoice', {
				title: ip2.i18n(mcd.title),
				questions: questions,
				guideLine: ip2.i18n(mcd.guideLine),
				modal: true,
				handler: function(answer) {
					switch (answer) {
						case 0:

							// do nothing
						break;
						case 1:

							// mark all below
							me.checkAllNodesBelow(this.node);
						break;
						case 2:
							this.node.set('checked', false);
						break;
					}
				}
			});
		}
	}

});
