Ext.define('Ext.ux.xpd.Field', {

	extend: 'Ext.form.FieldContainer',

	alias: [
		'widget.xpdeditorfield',
		'widget.xpdfield'
	],

	mixins: {
		field: 'Ext.form.field.Field'
	},

	requires: [
		"Ext.ux.xpd.Panel"
	],

	/**
	 * @cfg
	 */

	dataParent: null,

	listAs: 'fieldset',

	xpd: '',

	xpdCollection: null,
	idProperty: '',

	name: 'xpdeditorfield',

	language: 'da',
	languages: null,

	environment: 'editor',

	value: '',
	baseValue: '',

	action: 'new',

	xpdComponent: null,

	xpdFields: null,

	layout: 'fit',

	preventMark: true,

	_error: null,

	_initializingValue: true,

	doSaveFields: [],

	initComponent: function() {

		var i_cmp = this;
		i_cmp.doSaveFields = [];
		var o_config = i_cmp.initialConfig;
		var o_xpd = ip2.resource.get(o_config.xpd, true);

		i_cmp.xpdCollection = o_xpd;
		i_cmp.idProperty = i_cmp.xpdCollection.idProperty;

		Ext.apply(i_cmp, {
			languages: o_config.languages || ['en'],
			isFormField: true
		});

		i_cmp.callParent(arguments);

		// Create the xpdpanel or collection picker in case no value was given
		i_cmp.initXpdController();

		i_cmp.initField();

		ip2.each(i_cmp.xpdFields, function(i_field) {
			if (i_field.doSave) {
				i_cmp.doSaveFields.push(i_field);
			}
		});

		return i_cmp;
	},

	initValue: function () {

		var i_cmp = this;
		var s_value = i_cmp.getValue();

		i_cmp.value = s_value;

		i_cmp.mixins.field.initValue.call(i_cmp);

		i_cmp._initializingValue = false;
	},

	initXpdController: function () {

		var i_cmp = this;
		var s_value = i_cmp.value;
		var s_idProperty = i_cmp.xpdCollection.idProperty;
		var o_value;
		var o_baseValue;

		// Value is present - create the XPD component with fields
		if (s_value) {

			o_value = i_cmp.valueToRaw(s_value);
			o_baseValue = {};

			o_baseValue[s_idProperty] = o_value[s_idProperty];
			i_cmp.baseValue = Ext.encode(o_baseValue);

			i_cmp.addXpdComponent(o_value);
		}

		// No value is present - create the picker IF there are more than one collection!
		else {

			var o_collections = i_cmp.xpdCollection.collections;

			var n_collections = 0;

			Ext.Object.each(o_collections, function (s_key, o_collection) {
				n_collections = s_key != 'all' ? n_collections + 1 : n_collections;
			});

			if (n_collections > 1) {
				i_cmp.addXpdPicker();
			}

			else {

				var n_id;
				o_value = {};

				Ext.Object.each(o_collections, function (s_key, o_collection) {
					if (s_key != 'all') {
						n_id = o_collection.id;
					}
				});

				o_value[s_idProperty] = n_id;

				s_value = Ext.encode(o_value);

				i_cmp.value = s_value;
				i_cmp.baseValue = s_value;

				i_cmp.addXpdComponent(o_value);
			}
		}

		return i_cmp;
	},

	getXpdComponent: function () {

		var i_cmp = this;

		return i_cmp.xpdComponent;
	},

	addXpdComponent: function (o_value) {

		var i_cmp = this;
		var i_xpdComponent;

		var i_dataParent = i_cmp.dataParent || null;

		var i_record;

		if (i_dataParent) {
			i_record = i_dataParent.getRecord();
		}
		else {
			i_record = i_cmp.record || i_cmp.parentRecord;
		}

		i_xpdComponent = i_cmp.add({
			xtype: 'xpdeditorpanel',
			border: false,
			value: o_value,
			dataParent: i_cmp.dataParent,
			listAs: i_cmp.listAs,
			xpd: i_cmp.xpd,
			language: i_cmp.language,
			environment: i_cmp.environment,
			record: i_record,
			layout: "anchor",
			autoScroll: true
		});

		Ext.Object.each(i_xpdComponent.xpdFields, function (s_key, i_field) {
			i_field.preventMark = true;
		});

		i_cmp.xpdComponent = i_xpdComponent;
		i_cmp.xpdFields = i_xpdComponent.xpdFields;

		// Route change, dirtychange and validitychange
		ip2.each(i_cmp.xpdFields, function (i_field) {
			i_field.on('change', function () {
				i_cmp.checkChange();
			});
			i_field.on('validitychange', function () {
				i_cmp.checkChange();
			});
		});

		return i_xpdComponent;
	},

	addXpdPicker: function () {

		var i_cmp = this;
		var o_xpd = i_cmp.xpdCollection;
		var o_collections = i_cmp.xpdCollection.collections;
		var s_idProperty = i_cmp.idProperty;

		i_cmp.add({
			xtype: 'container',
			itemId: 'pickercontainer',
			layout: {
				type: 'vbox',
				align: 'center',
				pack: 'center'
			},
			width: '100%',
			height: 140,
			items: [
				{
					xtype: 'fieldset',
					title: ip2.i18n({
						da: 'Vælg type',
						en: 'Choose Type'
					}),
					padding: 20,
					items: [
						{
							xtype: 'quickcombo',
							name: s_idProperty,
							itemId: s_idProperty,
							emptyText: 'Pick a collection',
							forceSelection: true,
							valueField: 'id',
							width: 400,
							margin: '0 0 15 0',
							displayField: 'name',
							fields: ['id', 'name'],
							isFormField: false,
							data: (function () {

								var a_return = [];

								Ext.Object.each(o_collections, function (s_key, o_collection) {
									if (s_key != 'all') {
										a_return.push({
											'id': o_collection.id,
											'name': ip2.xpd.translate(o_xpd, o_collection.title, i_cmp.language)
										});
									}
								});

								return a_return;
							})(),
							listeners: {
								'afterrender': {
									fn: function (i_self) {
										var i_record = i_self.getStore().getAt(0);
										i_self.select(i_record);
									},
									single: true
								}
							}
						},
						{
							xtype: 'container',
							style: 'text-align: right;',
							items: [
								{
									xtype: 'button',
									text: 'OK',
									minWidth: 100,
									handler: function () {

										var i_self = this;
										var i_container = i_self.up('#pickercontainer');
										var i_picker = i_container.down('#' + s_idProperty);
										var n_value = i_picker.getValue();
										var o_value = {};
										var s_value;

										o_value[s_idProperty] = n_value;
										s_value = i_cmp.rawToValue(o_value);

										i_cmp.suspendCheckChange++;

										var i_xpdComponent = i_cmp.addXpdComponent(o_value);
										i_cmp.setValue(s_value);

										if (i_cmp._No_cid_Value) {
											i_cmp._No_cid_Value[s_idProperty] = n_value;
											i_xpdComponent.setValue(i_cmp._No_cid_Value);
											delete i_cmp._No_cid_Value;
										}

										i_cmp.resetOriginalValue();

										i_cmp.suspendCheckChange--;

										i_container.destroy();
									}
								}
							]
						}
					]
				}
			]
		});

		return i_cmp;
	},
	removeXpdPicker: function () {

		var i_cmp = this;
		var i_picker = i_cmp.down('#pickercontainer');

		if (i_picker) {
			i_picker.destroy();
		}

		return i_cmp;
	},

	disable: function () {

		var i_cmp = this;
		var o_fields = i_cmp.xpdFields || {};

		Ext.Object.each(i_cmp.xpdFields, function (s_key, i_field) {
			i_field.disable();
		});

		return i_cmp.callParent(arguments);
	},
	enable: function () {

		var i_cmp = this;
		var o_fields = i_cmp.xpdFields || {};

		Ext.Object.each(i_cmp.xpdFields, function (s_key, i_field) {
			i_field.enable();
		});

		return i_cmp.callParent(arguments);
	},

	focus: function (b_select) {

		var i_cmp = this;
		var o_fields = i_cmp.xpdFields;

		if (!o_fields || o_fields && !Ext.Object.getSize(o_fields)) {
			i_cmp.down('quickcombo').focus(b_select);
		}
		else {

			var n_min;
			var i_first;
			Ext.Object.each(o_fields, function (s_key, i_field) {

				var n_index = i_field.index || i_field.sequence;

				if (!n_min || (n_index < n_min)) {
					if (i_field.isVisible() && !i_field.isHidden() && !i_field.isDisabled() && !i_field.readOnly) {
						i_first = i_field;
						n_min = n_index;
					}
				}
			});

			if (i_first) {
				i_first.focus(b_select);
			}
		}
	},

	errorReport: function (err, s_source) {

		var i_cmp = this;
		var b_diff = (s_source != i_cmp._error);

		if (!i_cmp._error || b_diff) {

			var o_error = {
				urlText: ip2.i18n({
					da: 'Du forsøger at afkode en invalid JSON streng',
					en: 'You are trying to decode an invalid JSON string'
				}),
				url: 'test',
				message: ip2.i18n({
					da: 'Der skete en fejl da JSON validerings programmet fandt en fejl i en tekst streng der skulle parses',
					en: 'An error occured as the JSON validation engine found an error in a string supplied for parsing'
				})
			};

			var s_title = ip2.i18n({
				da: 'JSON validerings fejl',
				en: 'JSON validation error'
			});

			Ext.Error.raise({
				description: s_title,
				message: o_error,
				ignore: true
			});
		}
	},

	valueToRaw: function (s_value) {

		var i_cmp = this;
		var o_value;

		if (s_value) {
			o_value = Ext.decode(s_value);
		}
		else {
			o_value = {};
		}

		return o_value;
	},
	rawToValue: function (o_raw) {

		return Ext.encode(o_raw);
	},
	getRawValue: function () {

		var i_cmp = this;
		var i_xpdComponent = i_cmp.xpdComponent;
		var o_value = {};

		if (i_xpdComponent) {
			o_value = i_xpdComponent.getValue();
		}

		return o_value;
	},
	getValue: function () {

		var i_cmp = this;
		var i_xpdComponent = i_cmp.xpdComponent;
		var s_value = i_cmp.value;

		if (i_xpdComponent) {
			var o_value = i_xpdComponent.getValue();
			s_value = i_cmp.rawToValue(o_value);
		}

		return s_value;
	},
	setValue: function (value) {

		var i_cmp = this;
		var i_xpdComponent = i_cmp.xpdComponent;
		var b_initializing = i_cmp._initializingValue;

		var o_value;
		var s_value = value || i_cmp.baseValue;
		var b_hasId = true;

		if (i_xpdComponent && s_value) {

			o_value = i_cmp.valueToRaw(s_value);

			// Do not bother setting the values on to the
			// XPD component if we are initializing
			if (!b_initializing) {
				i_xpdComponent.setValue(o_value);
			}
		}
		else if (s_value) {
			o_value = i_cmp.valueToRaw(s_value);
			if (o_value[i_cmp.idProperty]) {
				i_xpdComponent = i_cmp.addXpdComponent(o_value);
			}
			else {
				i_cmp._No_cid_Value = o_value;
				b_hasId = false;
			}
		}

		// If we have a value and the picker is still there, remove it!
		if (s_value && b_hasId) {
			i_cmp.removeXpdPicker();
		}

		i_cmp.mixins.field.setValue.call(i_cmp, value);

		return i_cmp;
	},
	resetOriginalValue: function () {

		var i_cmp = this;
		var i_xpdComponent = i_cmp.xpdComponent;
		var s_value = i_cmp.getValue();

		if (i_xpdComponent) {

			var o_value = i_cmp.valueToRaw(s_value);

			i_xpdComponent.setValue(o_value);
			i_xpdComponent.resetOriginalValue();
		}

		i_cmp.mixins.field.resetOriginalValue.call(i_cmp);

		return i_cmp;
	},
	isValid: function () {

		var i_cmp = this;
		var b_valid = true;

		ip2.each(i_cmp.xpdFields, function (i_field) {

			i_field.preventMark = false;

			if (i_field.isValid && !i_field.isValid()) {
				b_valid = false;
			}

			i_field.preventMark = true;
		});

		return b_valid;
	},
	isDirty: function () {

		var i_cmp = this;
		var b_dirty = false;

		// If field is disabled - then no need to check
		if (i_cmp.disabled) {
			return b_dirty;
		}

		// Get the originalvalue as object
		var s_original = i_cmp.originalValue;
		var s_value = i_cmp.getValue();

		if (s_original && s_value) {
			var o_value = JSON.parse(s_value);
			var o_original = JSON.parse(s_original);

			var a_valueKeys = Ext.Object.getKeys(o_value);
			var a_originalKeys = Ext.Object.getKeys(o_original);

			if (a_valueKeys.length > a_originalKeys.length) {
				b_dirty = true;
			}
			else {
				ip2.each(a_originalKeys, function(s_key) {
					var value = o_value[s_key];
					var originalvalue = o_original[s_key];
					if (Ext.isObject(value) && Ext.isObject(originalvalue) || (Ext.isArray && (Ext.isArray(s_value) && Ext.isArray(s_ovalue)))) {
						var s_value = JSON.stringify(value);
						var s_ovalue = JSON.stringify(originalvalue);
						if (!ip2.isEqual(s_value, s_ovalue)) {
							b_dirty = true;
						}
					}
					else {
						if (!ip2.isEqual(value, originalvalue)) {
							b_dirty = true;
						}
					}
				});
			}
		}
		else {
			b_dirty = true;
		}

		return b_dirty;
	},
	clearInvalid: function () {

		var i_cmp = this;
		var o_fields = i_cmp.xpdFields;

		if (o_fields && Ext.Object.getSize(o_fields)) {
			Ext.Object.each(o_fields, function (s_key, i_field) {
				if (i_field.el && i_field.el.dom) {
					i_field.clearInvalid();
				}
				else {
					i_field.on('afterrender', function () {
						i_field.clearInvalid();
					}, i_field, { single: true });
				}
			});
		}

		return i_cmp;
	},
	doSave: function(f_callback) {

		var i_self = this;
		var n_tig = 0;
		var f_check = function() {
			n_tig--;
			if (n_tig == 0) {
				f_callback();
			}
		};

		n_tig = i_self.doSaveFields.length;

		if (n_tig > 0) {
			ip2.each(i_self.doSaveFields, function(i_field) {
				i_field.doSave(function() {
					f_check();
				});
			});
		}
		else {
			f_callback();
		}
	},

	getErrors: function() {

		var i_self = this;
		var a_keys = Ext.Object.getKeys(i_self.xpdFields);
		var a_return = [];
		Ext.Array.each(a_keys, function(s_field) {
			var i_field = i_self.xpdFields[s_field];
			var value = i_field.getRawValue ? i_field.getRawValue() : i_field.getValue();
			if (value === null || value === undefined) {
				value = "";
			}
			var a_errors = i_field.getErrors(value);
			a_return = a_return.concat(a_errors);
		});
		return a_return;
	},

	checkChange: function() {
		var me = this;
		var newVal;
		var oldVal;
		if (!me.suspendCheckChange) {
			newVal = me.getValue();
			oldVal = me.lastValue;
			if (!me.isDestroyed && !ip2.isEqual(newVal, oldVal)) {
				me.lastValue = newVal;
				me.fireEvent('change', me, newVal, oldVal);
				me.onChange(newVal, oldVal);
			}
		}
	}
});
