/**
 * @class Ext.ux.ip2.component.groupSelector.Selector
 *
 * @extend Ext.container.Container
 *
 */

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

	alias: ['widget.ip2GroupSelector'],

	extend: 'Ext.ux.form.JsonForm',

	plugins: [
		{
			ptype: 'datatracker'
		}
	],

	config: {

		fieldsetConfig: {

			padding: 15
		},

		cid: null,

		valueKey: null,

		fieldsetTitle: 'Fieldset',

		proxy: null,

		defaultHive: 'admin',

		dmd: null,

		entity: null,

		xpd: null,

		trackerParent: null,

		batchName: null,

		propertyNameMapping: {
			ID: 'ID',
			PARENTID: 'PARENTID',
			PROPERTIES: 'PROPERTIES'
		}

	},

	collections: null,

	border: false,

	keyField: null,

	_store: null,

	initComponent: function() {

		var selector = this,
			fieldsetConfig;

		selector.initConfig(selector.initialConfig);

		if (selector.proxy && selector.proxy.length > 0) {
			selector.serviceUrl = selector.proxy;
		}
		else {
			selector.serviceUrl = ip2.getWepshopProxyUrl(selector.wrapper);
		}

		selector.callParent();

		selector.collections = [];

		// Prepare the fieldset config to add to selector
		fieldsetConfig = selector.getFieldsetConfig();

		// Setup property name
		selector.propertyNameMapping = selector.getPropertyNameMapping();
		selector.propertyNameMappingReverse = {};
		for (var key in selector.propertyNameMapping) {
			selector.propertyNameMappingReverse[selector.propertyNameMapping[key]] = key.toString();
		}

		Ext.Object.merge(fieldsetConfig, {
			xtype: 'fieldset',
			items: [
				{
					xtype: 'checkboxgroup',
					vertical: true,
					columns: 2,
					border: false,
					listeners: {
						'added': {
							fn: function(self) {

								selector._checkboxgroup = self;
							}
						}
					}
				}
			]
		});

		// Add fieldset to selector and set private variable
		selector._fieldset = selector.add(fieldsetConfig);

		// Prepare the store for selector
		selector.dmdName = selector.getDmd();
		selector.dmdPath = selector.dmdName,

		selector.setStore({
			dmdName: selector.dmdName,
			entityName: selector.getEntity(),
			dataLibrary: selector.dataLibrary || ''
		});

		// Load and add the XPD to the selector
		selector.addXpd();

		if (selector.cid) {

			selector.doAfterInit();
		}
		else if (selector.whoami) {

			selector.doWhoami(selector.whoami);
		}

		return selector;
	},

	addXpd: function() {

		var selector = this;
		var servicePath = "/ip2-services/";

		selector.xpdName = selector.getXpd();
		selector.xpdPath = selector.xpdName;

		// Get the flattened XPD in a synchronized request and add to selector
		selector.xpd = ip2.resource.get(selector.xpdName, true);

		return selector;
	},

	doAfterInit: function() {

		this.cid.child = Ext.isArray(this.cid.child) ? this.cid.child : [this.cid.child];
		this.cid.parent = Ext.isArray(this.cid.parent) ? this.cid.parent : [this.cid.parent];

		var selector = this;

		// Prepare an collections array to store found collections in
		selector.collections = [];

		// Iterate each found cid child to find collections to push to selector
		Ext.Array.each(selector.cid.child, function(cid) {

			// Get the collection from the xpd via the iterated cid
			var collection = selector.xpd.collections[cid];

			// and push it..
			selector.collections.push(collection);

			// Iterate each of the found collections properties to look for
			// database bound key to set as selectors keyField
			Ext.Object.each(collection.properties, function(key) {

				if (collection.properties[key].isKey) {

					selector.keyField = collection.properties[key].databasebind;

					return false;
				}
			});
		});

		// Get the datatracker parent to get a record to use
		if (Ext.isFunction(selector.getDataParent)) {

			selector.doDataTracker();
		}
		else {

			selector.on({
				'datatrackerinit': {
					fn: function() {

						selector.doDataTracker();
					}
				}
			});
		}
	},

	doDataTracker: function() {

		var selector = this,
			dataParent = selector.getDataParent(),
			record = dataParent.getRecord();

		// Data parent record is already loaded and found
		if (record) {

			selector.record = record;

			// Everything is honky dory - lets actually load
			selector.onParentLoad();
		}

		// No record yet - wait for data parent store loaded
		else {

			var store = selector.getDataParent().getStore();

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

				if (Ext.isArray(records)) {

					record = records[0];

					selector.record = record;

					selector.onParentLoad();
				}
			});
		}
	},

	/**
	 * @method getChildComponent
	 *
	 */
	onParentLoad: function() {

		var selector = this;

		selector.clearSelection();

		selector.getData(function (fetched) {

			Ext.define('Ext.ux.folderorganizer.model.GroupSelector', {
				extend: 'Ext.data.Model',
				fields: [
					{ name: 'ID', type: 'int' },
					{ name: 'TITLE', type: 'string' },
					{ name: 'CID', type: 'int' }
				],
				idProperty: 'ID',
				proxy: {
					type: 'ajax',

					// TODO: To join with comma on selector.cid.parent
					url: selector.serviceUrl + '?action=getProductGroups&cid=' + selector.cid.parent + '&skipGrandParent=true&delimiter=/',
					extraParams: {
						action: 'getProductGroups',
						dataLibrary: selector.dataLibrary || '',
						cid: selector.cid.parent,
						skipGrandParent: true,
						delimiter: '/',
						xpd: selector.xpdPath,
						orderBy: selector.orderBy || ''
					}
				}
			});

			selector.breadCrumbStore = Ext.create('Ext.data.Store', {
				model: 'Ext.ux.folderorganizer.model.GroupSelector',
				autoLoad: true,
				listeners: {
					load: function(store, records) {

						store.records = records;

						selector.addFields(fetched);
					}
				}
			});
		});
	},

	/**
	 * @method addFields
	 *
	 */
	addFields: function(fetched) {

		fetched = fetched || [];

		var selector = this,
			checkboxGroup = selector.getCheckboxgroup(),
			alreadyID = [],

			store = selector.breadCrumbStore,
			records = store.records || [],
			checkboxes = [];

		//columnWidth = selector.getColumnWidth(records),
		//containerWidth = fieldset.getWidth(),
		//columns = Math.floor(containerWidth / columnWidth);

		Ext.Array.each(fetched, function(selected) {

			var record,
				parentId,
				checkbox;

			parentId = selected.data.PARENTID;

			record = store.getById(parentId);

			if (record) {

				checkbox = selector.createCheckbox(record.data, selected.data.ID);

				checkboxes.push(checkbox);

				alreadyID.push(record.data.ID);
			}
		});

		// Iterate all records and add checkboxes to the group
		Ext.Array.each(records, function(record) {

			var checkbox;

			// Filter away those whos ID is in the alreadyID array
			// They will already have been added to checkboxes array
			if (Ext.Array.indexOf(alreadyID, record.data.ID) == -1) {

				checkbox = selector.createCheckbox(record.data, 0);

				checkboxes.push(checkbox);
			}
		});

		checkboxGroup.removeAll();

		checkboxGroup.add(checkboxes);

		return selector;
	},

	/**
	 * @method createCheckbox
	 *
	 */
	createCheckbox: function(data, recordID) {

		var selector = this;

		return {
			xtype: 'checkbox',
			name: 'selector_' + data.ID,
			parentId: +(data.ID),
			boxLabel: data.TITLE,
			checked: (recordID > 0) ? true : false,
			recordID: recordID,
			cid: data.CID,
			listeners: {
				change: function(box, newValue) {

					var pos;

					//if ( selector.checkedItems.PARENTID.indexOf(box.name) > -1 ) {
					if (Ext.Array.indexOf(selector.checkedItems.PARENTID, box.parentId) > -1) {

						pos = selector.checkedItems.PARENTID.indexOf(box.parentId);

						selector.checkedItems.PARENTID.splice(pos, 1);

						selector.checkedItems.ID.splice(pos, 1);
					}

					//if ( selector.uncheckedItems.PARENTID.indexOf(box.name) > -1 ) {
					if (Ext.Array.indexOf(selector.uncheckedItems.PARENTID, box.parentId) > -1) {

						pos = selector.uncheckedItems.PARENTID.indexOf(box.parentId);

						selector.uncheckedItems.PARENTID.splice(pos, 1);

						selector.uncheckedItems.ID.splice(pos, 1);
					}

					if (newValue) {

						// new checked
						if (!box.originalValue) {

							selector.checkedItems.PARENTID.push(box.parentId);

							selector.checkedItems.ID.push(box.recordID);
						}
					}

					// existing unchecked
					else if (box.originalValue) {

						selector.uncheckedItems.PARENTID.push(box.parentId);

						selector.uncheckedItems.ID.push(box.recordID);
					}
				}
			}
		};
	},

	doWhoami: function(whoami) {

		var selector = this,
			flatten = selector.xpd,
			children = [],
			parents = [],
			fixXpdbind;

		fixXpdbind = function(s) {

			var o = {};

			s.replace(/([a-z]+)\(([0-9,\s]+)\),?/gi, function(_, name, values) {
				o[name] = values.replace(/\s/g, '').split(',');
			});

			return o;
		};

		ip2.each(flatten.collections, function(coll, key) {

			if (key != 'all') {
				key = +key;

				var almostTrue = false;

				if (coll.dmdpath && coll.entity) {
					almostTrue = coll.entity == whoami.entity && coll.dmdpath.toLowerCase() == whoami.dmdPath.toLowerCase();
				}

				if (almostTrue) {

					if (coll.xpdbind) {

						var o = fixXpdbind(coll.xpdbind);

						ip2.each(o, function(cids, prop) {

							var index = -1;

							ip2.each(cids, function(cid, i) {
								if (cid == whoami.data[prop].__cid__) index = i;
							});

							if (index > -1) {
								children.push(key);
							}
						});
					}
					else {
						children.push(key);
					}
				}
			}
		});

		var inserted = 0;

		ip2.each(children.slice(), function(childId, index) {
			index += inserted;
			var allowedparents = flatten.collections[childId].allowedparents;

			parents = parents.concat(allowedparents);

			var insert = allowedparents.length - 1;
			inserted += insert;

			ip2.each(Array.apply(null, new Array(insert)), function() {
				children.splice(index, 0, childId);
			});
		});

		// TODO: Convert back to real array - we grab first right now for testing purposes
		selector.cid = {
			child: children,
			parent: parents
		};

		if (whoami.valueKey)
			selector.valueKey = whoami.valueKey;

		selector.doAfterInit();
	},

	getCheckboxgroup: function() {

		return this._checkboxgroup;
	},
	getFieldset: function() {

		return this._fieldset;
	},

	getStore: function() {

		var selector = this;

		return selector._store;
	},
	setStore: function(settings) {

		var selector = this,
			batchName = selector.getBatchName();

		selector._store = ip2._store({
			type: 'batch',
			model: ip2.model({
				dmd: settings.dmdName,
				entityName: settings.entityName,
				dataLibrary: settings.dataLibrary
			}),
			autoSync: false,
			batchName: batchName
		});

		selector._store.proxy.extraParams = {
			storeId: ip2.storeId(),
			uiName: 'common',
			context: 'form'
		};

		return selector;
	},

	/**
	 * @method getColumnWidth
	 *
	 */
	getColumnWidth: function(records) {

		var i = 0,
			maxLen = 0;

		for (; i < records.length; i++) {

			if (records[i].data.TITLE.length > maxLen)
				maxLen = records[i].data.TITLE.length;
		}

		return Math.floor((maxLen * 5.8) + 24); // title length + checkbox width;
	},

	/**
	 * @method getData
	 *
	 */
	getData: function(callback) {

		var selector = this,
			key = selector.getValueKey(),
			value = selector.getKeyValue();

		// get existing item data and load the records into writer store
		Ext.define('data', {
			extend: 'Ext.data.Model',
			fields: [
				{ name: 'ID', type: 'int' },
				{ name: 'PARENTID', type: 'int' },
				{ name: 'PROPERTIES', type: 'string' }
			],
			idProperty: 'ID',
			proxy: {
				type: 'ajax',
				url: selector.serviceUrl + '?action=getproperties&key=' + key + '&value=' + value,
				reader: {
					type: 'json',
					root: 'rows'
				},
				extraParams: {
					entity: 'WSHFLDET00',
					dataLibrary: selector.dataLibrary || ''
				}
			}
		});

		Ext.create('Ext.data.Store', {
			model: 'data',
			autoLoad: true,
			listeners: {
				load: function(store, records) {

					// Return the records as an array in the callback
					// Becomes "alreadySelected"

					Ext.callback(callback, selector, [records]);
				}
			}
		});
	},

	/**
	 * @method getKeyValue
	 *
	 */
	getKeyValue: function() {

		var selector = this;

		return (selector.record) ? selector.record.data[selector.keyField] : '';
	},

	/**
	 * @method doSave
	 *
	 */
	doSave: function(reload) {

		var selector = this;

		reload = reload || false;

		var neededToSync = 0;

		var checkLength = function(cancelWrite) {

			if (neededToSync === 0) {

				selector._store.fireEvent(cancelWrite ? 'cancelwrite' : 'write');
			}
		};

		Ext.Array.each(selector.collections, function(collection) {

			var saveLength = selector.checkedItems.ID.length,
				deleteLength = selector.uncheckedItems.ID.length;

			neededToSync += saveLength + deleteLength;

			// Checked items
			Ext.Array.each(selector.checkedItems.ID, function(id, index) {

				var record = selector.createRecord({
					action: 'updateRow',
					id: id,
					parentId: selector.checkedItems.PARENTID[index],
					properties: collection.properties
				});

				record.save({
					success: function(rec) {

						record.checkbox.recordID = rec.data.ID;
						record.checkbox.resetOriginalValue();

						neededToSync--;

						checkLength();
					}
				});
			});

			// Unchecked items
			Ext.Array.each(selector.uncheckedItems.ID, function(id, index) {

				var record = selector.createRecord({
					action: 'deleteRow',
					id: id,
					parentId: selector.uncheckedItems.PARENTID[index],
					properties: collection.properties
				});

				record.checkbox.resetOriginalValue();
				record.destroy({
					success: function() {

						neededToSync--;

						checkLength();
					}
				});
			});
		});

		selector.clearSelection();

		if (reload)	selector.onParentLoad();

		checkLength(true);

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

	createRecord: function(settings) {

		var selector = this,
			model,
			properties,
			record,
			checkbox,
			cid,
			store = selector.getStore();

		// Get the model to use on record
		model = store.proxy.getModel();

		// Set the action
		store.proxy.extraParams.dmdPath = selector.dmdPath;
		store.proxy.extraParams.action = settings.action;

		// Get the checkbox - has values for us to use!
		checkbox = selector.down('[name=selector_' + settings.parentId + ']');

		// Get the CID from checkbox
		cid = checkbox.cid;

		// Create the properties object we will be saving
		properties = {
			// Set the properties cid matched up against index position of child on properties object
			__cid__: selector.cid.child[ Ext.Array.indexOf(selector.cid.parent, cid) ]
		};

		var propertyHandler = function(val, k, parent) {

			if (val === null) {
				val = parent[k];
			}
			try {
				var o = JSON.parse(val);
				parent[k] = o;
				return o;
			}
			catch (e) {
				return val;
			}
		};

		// Add to the properties object that we save!
		Ext.Object.each(settings.properties, function(key, object) {

			var bound = object.databasebind,
				data = selector.record.data;

			if (bound) {

				if (Ext.isArray(bound)) {

					// TODO: This is to make backwards compatible with old XPD definition:
					// (['title', 'header', 'name'] is really eq: ['properties.title', 'properties.header', 'properties.name'])
					bound = Ext.Array.map(bound, function(v) {
						return 'properties.' + v;
					});
				}
				else {

					bound = ip2.xpd.fixDatabasebind(bound);
				}

				Ext.Array.some(bound, function(o) {

					var value = ip2.getProperty(o, data, propertyHandler);

					if (value) {

						properties[key] = value;

						return true;
					}
				});
			}
		});

		// Create the record!
		var data = {};
		data[selector.propertyNameMapping.ID] = settings.id,
		data[selector.propertyNameMapping.PARENTID] = settings.parentId;
		data[selector.propertyNameMapping.PROPERTIES] = Ext.encode(properties);
		record = Ext.create(model.modelName, data);

		record.checkbox = checkbox;

		return record;
	},

	/**
	 * @method doDelete
	 *
	 */
	doDelete: function() {

		var selector = this;

		return selector;
	},

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

		var selector = this;

		selector.checkedItems = {
			PARENTID: [],
			ID: []
		};

		selector.uncheckedItems = {
			PARENTID: [],
			ID: []
		};
	}
});
