/**
 * @class Ext.ux.xpd.Panel
 *
 * @extends Ext.panel.Panel
 *
 * @alias xpdeditorpanel
 */

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

	mixins: {
		DMDUiType: "Portfolio.entity.util.Handler"
	},

	extend: "Ext.form.Panel",

	alias: [
		"widget.xpdeditorpanel",
		"widget.xpdpanel"
	],

	/**
	 * @config
	 */

	dataParent: null,

	xpd: "",

	language: "da",
	languages: null,

	environment: "editor",

	listAs: "fieldset",

	layout: "anchor",

	/**
	 * @properties
	 */

	value: null,

	xpdObject: null,

	xpdCollection: null,

	xpdFields: null,

	trackResetOnLoad: true,

	defaults: {
		anchor: "100%"
	},

	autoScroll: true,

	initComponent: function() {

		var i_self = this;
		var o_config = i_self.initialConfig;

		Ext.apply(i_self, ip2.pick(o_config, [
			"dataParent",
			"xpd",
			"listAs",
			"language",
			"environment",
			"name"
		]));

		Ext.apply(i_self, {
			languages: o_config.languages || ["en"]
		});

		i_self.callParent();

		i_self.initValue();

		i_self.initXpd();

		i_self.initUi();

		return i_self;
	},

	initValue: function () {

		var i_self = this;

		var o_value = {};

		if (i_self.value) {
			o_value = Ext.apply({}, i_self.value);

			Ext.Object.each(o_value, function(s_key, value) {
				if (Ext.isEmpty(value)) {
					delete o_value[s_key];
				}
			});
		}

		i_self.value = o_value;

		return i_self;
	},

	initXpd: function () {

		var i_self = this;
		var s_xpd = i_self.xpd;
		var o_xpd = i_self.xpdObject;
		var o_value = i_self.value;
		var s_id;
		var o_flat;

		if (!o_xpd) {
			o_xpd = ip2.resource.get(s_xpd);
			i_self.xpdObject = o_xpd;
		}

		s_id = o_value[o_xpd.idProperty];

		o_flat = ip2.xpd.flatten(o_xpd, null, true);
		i_self.xpdCollection = o_flat.collections[s_id];

		if (!i_self.xpdCollection) {
			console.warn("Ext.ux.xpd.Panel:initXpd: cannot find collection for cid \"" + s_id + "\" and value " + Ext.encode(o_value));
		}

		return i_self;
	},

	initUi: function () {

		var i_self = this;
		var o_value = i_self.value || {};

		var n_labelWidth = i_self.xpdObject.labelWidth || 170;

		// Create the UI collection from XPD collection
		// These are instanciated objects
		var o_uiCollection = i_self.createUiCollection({
			collection: i_self.xpdCollection,
			xpd: i_self.xpdObject,
			rulesXpd: ip2.uirules.flatten,
			rulesJs: ip2.loadUiTypeRules(),
			context: "form",
			values: o_value,
			environment: i_self.environment,
			defaults: {
				labelWidth: n_labelWidth
			}
		});

		i_self.xpdFields = o_uiCollection;

		Ext.Object.each(o_uiCollection, function (s_key, i_field) {
			if (i_self.record) {
				i_field.record = i_self.record;
			}
			else {
				if (i_self.dataParent) {
					i_field.record = i_self.dataParent.getRecord();
				}
			}
			i_self.mon(i_field, "added", function() {
				// We need to be on nextTick so that our parent can get a time to be attached to its parent
				setTimeout(function() {
					i_field.enableBubble("xpdfieldadded");
					i_field.fireEvent("xpdfieldadded", i_field);
				}, 5);
			});
		});

		// Create the groups needed (if any) for this uiCollection
		// Will omit group if only 1 group needed
		var a_groups = (function () {

			var a_return = [];

			Ext.Object.each(o_uiCollection, function (s_key, o_item) {

				var o_xpdConfig = o_item._xpdConfig;

				if (o_xpdConfig.groups && o_xpdConfig.groups.length) {

					// Add these groups to the groups array if not alreay present
					Ext.Array.each(o_xpdConfig.groups, function (s_group) {

						if (Ext.Array.indexOf(a_return, s_group) == -1) {

							var b_definition = i_self.xpdObject.groups[s_group];
							var b_renderIn = b_definition && b_definition.renderIn[i_self.environment];

							if (b_renderIn) {
								a_return.push(s_group);
							}
						}
					});
				}
			});

			return a_return.length >= 1 ? a_return : [];
		})();

		// If we have groups - Add them and add fields
		// Use "listAs" property to add
		var a_groupComponents;

		if (a_groups.length) {

			switch (i_self.listAs.toLowerCase()) {

				case "accordion":

					a_groupComponents = i_self.createUiGroups(a_groups, {
						xtype: "panel"
					});

					i_self.add({
						xtype: "panel",
						layout: "accordion",
						height: 500,
						layoutConfig: {
							titleCollapse: true,
							animate: true,
							activeOnTop: true
						},
						items: [a_groupComponents]
					});
					break;

				default:

					a_groupComponents = i_self.createUiGroups(a_groups, {
						xtype: "fieldset",
						collapsible: true,
						layout: "anchor",
						defaults: {
							anchor: "100%"
						}
					});

					i_self.add(a_groupComponents);

					break;
			}
		}

		// Create the container map object to hold groups
		// Groups are an array of fields
		var o_container = {
			nogroup: []
		};

		// Run through all group components and create their array
		// in the container object
		if (a_groupComponents) {
			Ext.Array.each(a_groupComponents, function (i_group) {
				o_container[i_group.itemId] = [];
			});
		}

		// Create the container object with group arrays
		Ext.Object.each(o_uiCollection, function (s_key, i_field) {

			var o_config = i_field._xpdConfig;

			// Set nogroup as default group
			var a_containerGroup = o_container.nogroup;

			// Find the right group to put this field in if any
			if (o_config.groups && o_config.groups.length) {
				Ext.Array.some(o_config.groups, function (s_group) {
					if (o_container[s_group]) {
						// We found a group, set it as the one we push to!
						a_containerGroup = o_container[s_group];
						return false;
					}
				});
			}

			a_containerGroup.push(i_field);
		});

		// Sort and place the container array fields
		Ext.Object.each(o_container, function (s_key, a_fields) {

			if (a_fields.length) {

				// Sort the fields, then place them
				a_fields.sort(function(a, b) {
					var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
					var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

					var n_min = Math.min(n_a, n_b);

					return n_min;
				});

				// Now apply to right container
				var i_container = (s_key == "nogroup") ? i_self : i_self.down("fieldset#" + s_key);

				i_container.add(a_fields);

				if (i_container.dependsOn) {

					Ext.Array.each(i_container.dependsOn, function(o_depends) {
						Ext.Object.each(o_uiCollection, function(s_key, i_field) {
							if (s_key == o_depends.field) {

								if (o_depends.equal) {
									o_depends.equals = [o_depends.equal];
								}

								if (o_depends.notEqual) {
									o_depends.notEquals = [o_depends.notEqual];
								}

								var b_allowed = true;

								i_container.mon(i_field, "change", check);
								i_container.mon(i_field, "disable", check);
								i_container.mon(i_field, "enable", check);

								i_container.hide();

								check();

								function check() {

									b_allowed = false;

									if (!i_field.isDisabled || !i_field.isDisabled()) {
										// (Not) Equal
										if ("equals" in o_depends) {
											b_allowed = Ext.Array.some(o_depends.equals, function(equal) {
												return ip2.isEqual(i_field.getValue(), equal);
											});
										}
										else if ("notEquals" in o_depends) {
											b_allowed = Ext.Array.every(o_depends.notEquals, function(notEqual) {
												return !ip2.isEqual(i_field.getValue(), notEqual);
											});
										}

										// (Not) Empty
										if ("empty" in o_depends) {
											b_allowed = !i_field.getValue();
										}
										else if ("notEmpty" in o_depends) {
											b_allowed = i_field.getValue() ? true : false;
										}
									}

									checkChange();
								}

								function checkChange() {

									if (b_allowed) {
										i_container.show();
									}
									else {
										i_container.hide();
									}
								}
							}
						});
					});
				}
			}
		});
	},

	getWidgetComponents: function () {

		var i_self = this;
		var o_fields = i_self.xpdFields;
		var o_widgets = {};

		Ext.Object.each(o_fields, function (s_key, i_field) {
			if (i_field.isWidget) {
				o_widgets[s_key] = i_field;
			}
		});

		return o_widgets;
	},

	createUiGroups: function (a_groups, o_settings) {

		var i_self = this;
		var o_xpd = i_self.xpdObject;
		var a_config = [];

		Ext.Array.each(a_groups, function (s_group) {

			// Get the definition from the XPD
			var o_definition = o_xpd.groups[s_group];
			var o_environment = o_definition.renderIn[i_self.environment] || {};

			// Backwards compatibility with old setup of group environment
			// Looked like so { "renderIn": { "editor": { "layout": { "..": "..." } } } }
			// Is now also supporting { "renderIn": { "editor": { "..": "..." } } }
			// So we are defaulting the whole renderInd object instead of its "layout" object
			// if no "layout" object can be found
			var o_layout = o_environment.layout;

			if (!o_environment.layout) {
				o_layout = o_environment || {};
			}

			var o_config = ip2.extend({
				xtype: "fieldset",
				itemId: s_group,
				title: i_self.translate(o_definition.title),
				layout: "anchor"
			}, o_settings, o_layout);

			var o_group = i_self.createUiGroup(o_config);

			a_config.push(o_group);
		});

		// Sort the groups array based on index position
		a_config.sort(function(a, b) {

			var n_a = (Ext.isNumber(a.sequence) ? a.sequence : 0);
			var n_b = (Ext.isNumber(b.sequence) ? b.sequence : 0);

			return n_a - n_b;
		});

		return a_config;
	},
	createUiGroup: function (o_settings) {

		var i_self = this;
		var o_uiGroup;

		o_uiGroup = Ext.Object.merge(o_settings, {
			_protected: o_settings["protected"],
			getProtected: function () {

				return this._protected;
			},
			setProtected: function (b_protect) {
				this._protected = b_protect ? true : false;
				this.toggleProtect(this._protected);
				return this;
			},
			toggleProtect: function (b_protect) {

				var i_self = this;

				i_self.items.each(function (i_item) {
					if (i_item._protectionToggler) {
						i_item[b_protect ? "show" : "hide"]();
					}
					else {
						i_item[b_protect ? "hide" : "show"]();
					}
				});
			},
			items: [
				{
					xtype: "container",
					_protectionToggler: true,
					style: "margin:20px;text-align: center;",
					items: [
						{
							xtype: "container",
							style: "margin-bottom: 10px;",
							html: ip2.i18n({
								da: "Disse værdier er beskyttede, tryk på knappen for at kunne redigere",
								en: "These values are protected, please press the button to edit"
							})
						},
						{
							xtype: "button",
							text: ip2.i18n({
								da: "Fjern beskyttelse",
								en: "Remove protection"
							}),
							handler: function (i_self) {

								ip2.messageBox({
									icon: Ext.Msg.WARNING,
									message: ip2.i18n({
										da: "Venligst bemærk at dette kan medføre uønskede ændringer på din hjemmeside",
										en: "Please note that this may have undesired impacts on your website"
									}),
									yesText: ip2.i18n({
										da: "Fjern",
										en: "Remove"
									}),
									yesFn: function () {
										i_self.up(o_settings.xtype).setProtected(false);
									},
									noText: ip2.i18n({
										da: "Fortryd",
										en: "Cancel"
									})
								});
							},
							iconCls: "pf-edit"
						}
					]
				}
			],
			listeners: {
				afterrender: {
					fn: function (i_self) {
						i_self.toggleProtect(this.getProtected());
					},
					single: true
				}
			}
		});

		return o_uiGroup;
	},

	getCheckChangeValue: function () {

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

		var a_removeProps = [];

		// Iterate all fields, but do not collection from fields!
		Ext.Object.each(i_self.xpdFields, function (s_key, i_field) {

			if (!i_field.isDisabled) {
				console.warn("This field seems to be missing the method \"isDisabled\" ->", i_field.id, i_field.name);
			}

			if (!i_field.from && (!i_field.isDisabled || !i_field.isDisabled()) && i_field.getValue) {

				var o_json;
				var value = i_field.getValue();

				// We do not want double stringed values!
				try {
					o_json = JSON.parse(value);
				}
				catch (e) {}

				// Prevent: JSON.parse("123.456") === 123.456 // See String -> Num casting
				// Prevent JSON.parse("100.100") === 100.1 // We are losing the last 00
				o_value[s_key] = o_json && !ip2.isNumber(o_json) ? o_json : value;
			}
			else {
				a_removeProps.push(s_key);
			}
		});

		// Find all depricated values and remove them:
		if (i_self.xpdCollection) {
			Ext.Object.each(i_self.xpdCollection.properties, function(s_key, o_property) {
				if (o_property.assimilate) {
					Ext.Object.each(o_property.assimilate, function(s_key, o_config) {
						a_removeProps.push(o_config.field);
					});
				}
			});
		}

		// remove depricated values and dependsOn values that are not visible:
		Ext.Array.each(a_removeProps, function(s_key) {
			if (o_value.hasProperty(s_key)) {
				delete o_value;
			}
		});

		return o_value;
	},

	getValue: function () {

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

		var a_removeProps = [];

		// Iterate all fields, but do not collection from fields!
		Ext.Object.each(i_self.xpdFields, function (s_key, i_field) {

			if (!i_field.isDisabled) {
				console.warn("This field seems to be missing the method \"isDisabled\" ->", i_field.id, i_field.name);
			}

			if (!i_field.from && !i_field.isWidget && i_field.getValue) {

				var o_json;
				var value = i_field.getValue();

				// We do not want double stringed values!
				try {
					o_json = JSON.parse(value);
				}
				catch (e) {}

				// Prevent: JSON.parse("123.456") === 123.456 // See String -> Num casting
				// Prevent JSON.parse("100.100") === 100.1 // We are losing the last 00
				o_value[s_key] = o_json && !ip2.isNumber(o_json) ? o_json : value;
			}
			else {
				a_removeProps.push(s_key);
			}
		});

		// Find all depricated values and remove them:
		if (i_self.xpdCollection) {
			Ext.Object.each(i_self.xpdCollection.properties, function(s_key, o_property) {
				if (o_property.assimilate) {
					Ext.Object.each(o_property.assimilate, function(s_key, o_config) {
						a_removeProps.push(o_config.field);
					});
				}
			});
		}

		// remove depricated values and dependsOn values that are not visible:
		Ext.Array.each(a_removeProps, function(s_key) {
			if (s_key in o_value) {
				delete o_value[s_key];
			}
		});

		return o_value;
	},

	setValue: function (o_val) {

		var i_self = this;
		var o_value = ip2.defaults({}, o_val);

		Ext.Object.each(i_self.xpdFields, function (s_key, i_field) {

			if (!i_field._xpdConfig.from) {

				var value = o_value[s_key];

				i_field.setValue(value, s_key, o_value);
			}
		});

		i_self.value = o_val;

		return i_self;
	},

	resetOriginalValue: function () {

		var i_self = this;
		var i_form = i_self.getForm();
		var o_values = i_form.getFieldValues();

		i_form.setValues(o_values);

		return i_self;
	},

	translate: function(s_value) {

		var i_self = this;
		var o_xpd = i_self.xpdObject;
		var s_language = ip2.session.getLanguage();

		return ip2.xpd.translate(o_xpd, s_value, s_language);
	}
});
