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

	singleton: true,

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

	getFields: function(o_xpd, s_cid) {
		var i_self = this;
		var a_xpdFields = [];
		var o_collection = Ext.clone(o_xpd.collections[s_cid]);
		var o_default = o_xpd.layout.editor.__default__;
		var n_extend = s_cid;

		i_self.getExtended(o_collection, o_xpd, n_extend);

		i_self.getRecursive(o_default, o_collection, null, o_collection.properties);

		var o_uiCollection = i_self.createUiCollection({
			collection: o_collection,
			xpd: o_xpd,
			rulesXpd: ip2.uirules.flatten,
			rulesJs: ip2.loadUiTypeRules(),
			context: "form",
			values: {},
			environment: i_self.environment || "editor",
			defaults: {
				labelWidth: 140
			}
		});

		Ext.Object.each(o_uiCollection, function(s_key, i_field) {
			a_xpdFields.push(i_field);
		});

		return a_xpdFields;
	},

	getRecursive: function(o_default, o_collection, s_name, o_value) {

		var i_self = this;
		var a_keys = Ext.Object.getKeys(o_value);
		var a_fields = [];
		Ext.Array.each(a_keys, function(s_prop) {

			var o_property = o_value[s_prop];
			if (o_property.hasOwnProperty("properties")) {
				var s_newProp = s_prop;
				if (s_name) {
					var a_temp = [s_name, s_prop];
					s_newProp = a_temp.join("-");
				}

				i_self.getRecursive(o_default, o_collection, s_newProp, o_property.properties);
				delete o_collection.properties[s_prop];
			}
			else {
				if (s_name) {
					var o_new = Ext.apply(o_property, o_default);
					o_new.extended = true;
					o_collection.properties[s_name + "-" + s_prop] = o_new;
				}
			}
		});
	},

	getExtended: function(o_original, o_collection, o_xpd, n_extend) {

		var i_self = this;
		var a_keys = Ext.Object.getKeys(o_xpd.collections);
		if (o_collection.extend) {
			var o_extended = Ext.clone(o_xpd.collections[o_collection.extend]);
			while (o_extended.extend) {
				n_extend = o_extended.extend;
				o_extended = Ext.clone(o_xpd.collections[o_extended.extend]);
			}
			var o_originalExtend = o_xpd.collections[n_extend];
			i_self.getExtended(o_originalExtend, o_extended, o_xpd, n_extend);
			Ext.Object.merge(o_collection.properties, o_extended.properties);
		}
		else {
			Ext.Array.each(a_keys, function(s_collection) {
				var o_object = Ext.clone(o_xpd.collections[s_collection]);
				var o_originalExtend = o_xpd.collections[s_collection];
				if (o_object.extend && o_object.extend == n_extend) {
					n_extend = o_object.id;
					o_original.extended = n_extend;
					Ext.Object.merge(o_collection.properties, o_object.properties);
					i_self.getExtended(o_originalExtend, o_collection, o_xpd, n_extend);
					return false;
				}
			});
		}
	},

	getFieldsWithValues: function(o_xpd, s_cid, o_value) {

		var i_self = this;
		var a_xpdFields = [];
		var o_original = o_xpd.collections[s_cid];
		var o_collection = Ext.clone(o_xpd.collections[s_cid]);
		var o_default = o_xpd.layout.editor.__default__;
		var n_extend = s_cid;

		i_self.getExtended(o_original, o_collection, o_xpd, n_extend);

		i_self.getRecursive(o_default, o_collection, null, o_collection.properties);

		var o_uiCollection = i_self.createUiCollection({
			collection: o_collection,
			xpd: o_xpd,
			rulesXpd: ip2.uirules.flatten,
			rulesJs: ip2.loadUiTypeRules(),
			context: "form",
			values: o_value,
			environment: i_self.environment || "editor",
			defaults: {
				labelWidth: 140
			}
		});

		Ext.Object.each(o_uiCollection, function(s_key, i_field) {
			a_xpdFields.push(i_field);
		});

		return a_xpdFields;
	},

	getValueFromProperties: function(o_xpd, o_data) {

		var i_self = this;
		var o_value = {};
		var o_collection = o_xpd.collections[o_data[o_xpd.idProperty]];
		var a_removeProps = [];

		o_value[o_xpd.idProperty] = o_data[o_xpd.idProperty];

		// Find all depricated values and remove them:
		if (o_collection) {
			Ext.Object.each(o_collection.properties, function(s_key, o_prop) {

				var a_asimilate = Ext.Array.from(o_prop.assimilate);

				Ext.Array.each(a_asimilate, function(o_config) {
					a_removeProps.push(o_config.field);
				});
				o_value[s_key] = o_data[s_key];
			});
		}

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

		return o_value;
	},

	convertData: function(o_xpd, o_data) {

		if (o_xpd.hasOwnProperty("convert")) {

			var o_convert = o_xpd.convert || {};

			Ext.Object.each(o_convert, function(s_property, o_value) {
				o_data[s_property] = o_value.to;
			});
		}

		return o_data;
	},

	getCollectionFromData: function(o_xpd, o_data) {
		var i_self = this;
		var o_collection = "";
		if (o_data[o_xpd.idProperty]) {
			o_collection = o_xpd.collections[o_data[o_xpd.idProperty]];
		}
		return o_collection;
	},

	getValues: function(o_xpd, a_fields, o_collection, o_data, b_usefields) {

		var i_self = this;
		var o_value = {};
		var a_removeProps = [];
		var a_extended = [];

		if (!o_collection.extend && !o_collection.extended) {
			var a_keys = Ext.Object.getKeys(o_xpd.collections);
			var o_root = o_collection;
			Ext.Array.each(a_keys, function(s_collection) {
				if (s_collection != "all") {
					var o_temp = o_xpd.collections[s_collection];
					if (o_temp.extend == o_collection.id) {
						a_extended.push(o_temp);
						o_root = o_temp;
					}
				}
			});
		}

		if (o_collection.extended && o_collection.extend) {
			var o_extend = o_xpd.collections[o_collection.extend];
			var o_extended = o_xpd.collections[o_collection.extended];
			a_extended.push(o_extend);
			a_extended.push(o_extended);
			while (o_extend.extend) {
				o_extend = o_xpd.collections[o_extend.extend];
				if (o_extend) {
					var b_found = false;
					Ext.Array.each(a_extended, function(o_sub) {
						if (o_sub.id == o_extend.id) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_extended.push(o_extend);
					}
				}
			}
			while (o_extended.extend) {
				o_extended = o_xpd.collections[o_extended.extend];
				if (o_extended) {
					var b_found = false;
					Ext.Array.each(a_extended, function(o_sub) {
						if (o_sub.id == o_extended.id) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_extended.push(o_extended);
					}
				}
			}
		}
		else if (o_collection.extended && !o_collection.extend) {
			a_extended.push(o_collection);
			var o_extended = o_xpd.collections[o_collection.extended];
			var b_found = false;
			Ext.Array.each(a_extended, function(o_sub) {
				if (o_sub.id == o_extended.id) {
					b_found = true;
					return false;
				}
			});
			if (!b_found) {
				a_extended.push(o_extended);
			}
			while (o_extended.extended) {
				o_extended = o_xpd.collections[o_extended.extended];
				if (o_extended) {
					var b_found = false;
					Ext.Array.each(a_extended, function(o_sub) {
						if (o_sub.id == o_extended.id) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_extended.push(o_extended);
					}
				}
			}
		}
		else if (!o_collection.extended && o_collection.extend) {
			a_extended.push(o_collection);
			var o_extended = o_xpd.collections[o_collection.extend];
			var b_found = false;
			Ext.Array.each(a_extended, function(o_sub) {
				if (o_sub.id == o_extended.id) {
					b_found = true;
					return false;
				}
			});
			if (!b_found) {
				a_extended.push(o_extended);
			}
			while (o_extended.extend) {
				o_extended = o_xpd.collections[o_extended.extend];
				if (o_extended) {
					var b_found = false;
					Ext.Array.each(a_extended, function(o_sub) {
						if (o_sub.id == o_extended.id) {
							b_found = true;
							return false;
						}
					});
					if (!b_found) {
						a_extended.push(o_extended);
					}
				}
			}
		}

		if (!o_data[o_xpd.idProperty]) {
			o_value[o_xpd.idProperty] = o_collection.id;
		}
		else {
			o_value[o_xpd.idProperty] = o_data[o_xpd.idProperty];
		}
		var a_collectionKeys = Ext.Object.getKeys(o_collection.properties);
		var a_cid = [];

		if (o_collection.extended) {
			a_cid.push(o_collection.id);
		}

		Ext.Array.each(a_fields, function (i_field, n_index) {

			Ext.Object.each(o_collection.properties, function(s_key) {

				if (i_field) {
					var s_name = i_field.name;

					if (i_field._xpdConfig && !i_field._xpdConfig.extended) {

						if (i_field.name == s_key) {

							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())) {

								a_removeProps.push(i_field.name);
							}
							if (b_usefields) {
								o_value[i_field.name] = i_field.getValue();
							}
							else {
								if (o_data[i_field.name] != undefined) {
									o_value[i_field.name] = o_data[i_field.name];
								}
								if (i_field._xpdConfig.borrow && Ext.isString(i_field._xpdConfig.borrow)) {
									o_value[i_field._xpdConfig.borrow] = o_data[i_field._xpdConfig.borrow];
								}
							}
						}
					}
					else {
						if (i_field.from || (i_field.isDisabled && i_field.isDisabled())) {

							a_removeProps.push(i_field.name);
						}
						else {

							var a_split = s_name.split("-");
							var o_root = o_value;
							var n_count = 1;

							Ext.Array.each(a_split, function(s_key) {

								if (n_count < a_split.length) {
									if (!o_root[s_key]) {
										o_root[s_key] = {};
										o_root = o_root[s_key];
									}
									else {
										o_root = o_root[s_key];
									}
								}
								else {

									var value = i_field.getValue();
									var o_prop;
									var o_col;

									Ext.Array.each(a_extended, function(o_extended) {

										var s_join = a_split.join(".properties.");

										if (!o_prop) {
											try {
												eval("o_prop = o_extended.properties." + s_join);
											}
											catch (err) {}
										}
										if (o_prop) {
											o_col = o_extended;
											return false;
										}
									});

									if (o_prop && value) {

										if (a_cid.indexOf(o_col.id) == -1) {

											a_cid.push(o_col.id);
										}
									}
									o_root[s_key] = value;
								}
								n_count++;
							});
						}
					}
				}
			});
		});

		if (a_cid.length > 0) {

			var n_cid;

			Ext.Array.each(a_cid, function(n_id) {

				var o_collection = o_xpd.collections[n_id];

				if (o_collection.extended) {

					if (a_cid.indexOf(o_collection.extended) == -1) {
						n_cid = o_collection.id;
					}
				}
				else {
					n_cid = o_collection.id;
				}
			});
			if (n_cid) {

				o_value[o_xpd.idProperty] = n_cid;

				if (o_xpd.cidMap) {

					var a_keys = Ext.Object.getKeys(o_xpd.cidMap);

					Ext.Object.each(o_xpd.cidMap, function(s_key) {

						var o_prop = o_value[s_key];

						var o_map = o_xpd.cidMap[s_key];

						if (o_prop) {

							i_self.applyCidMap(o_xpd, o_prop, o_map, n_cid);
						}
					});
				}
			}
		}
		else {
			if (a_extended.length > 0) {

				var o_base;

				Ext.Array.each(a_extended, function(o_extended) {

					if (!o_extended.extend) {

						o_base = o_extended;

						return false;
					}
				});
				if (o_base) {

					o_value[o_xpd.idProperty] = o_base.id;

					if (o_xpd.cidMap) {

						var a_keys = Ext.Object.getKeys(o_xpd.cidMap);

						Ext.Object.each(o_xpd.cidMap, function(s_key) {

							var o_prop = o_value[s_key];
							var o_map = o_xpd.cidMap[s_key];

							if (o_prop) {

								i_self.applyCidMap(o_xpd, o_prop, o_map, o_base.id);
							}
						});
					}
				}
			}
		}

		// Find all depricated values and remove them:
		Ext.Object.each(o_collection.properties, function(s_key, o_prop) {

			var a_asimilate = Ext.Array.from(o_prop.assimilate);

			Ext.Array.each(a_asimilate, function(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) {
			delete o_value[s_key];
		});

		return o_value;
	},

	applyCidMap: function(o_xpd, o_value, o_map, n_cid) {

		var i_self = this;
		o_value[o_xpd.idProperty] = o_map[n_cid];

		var a_keys = Ext.Object.getKeys(o_map);

		Ext.Array.each(a_keys, function(s_key) {
			if (Ext.isObject(o_value[s_key])) {
				var o_prop = o_value[s_key];
				var o_tmpMap = o_map[s_key];
				i_self.applyCidMap(o_xpd, o_prop, o_tmpMap, n_cid);
			}
		});
	},

	getProperties: function(o_xpd, o_values) {

		var i_self = this;
		var o_collection = o_xpd.collections[o_values[o_xpd.idProperty]];
		var o_value = {};
		var a_removeProps = [];

		if (o_collection) {
			// Find all depricated values and remove them:
			Ext.Object.each(o_collection.properties, function(s_key, o_prop) {
				o_value[s_key] = "";
			});

			// Find all depricated values and remove them:
			Ext.Object.each(o_collection.properties, function(s_key, o_prop) {

				var a_asimilate = Ext.Array.from(o_prop.assimilate);

				Ext.Array.each(a_asimilate, function(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) {
				delete o_value[s_key];
			});

			Ext.apply(o_value, o_values);
		}

		return o_value;
	},

	createGroups: function(a_xpdFields, o_xpd, o_collection, i_dataParent) {

		var a_groups = [];
		var a_nogroup = [];
		var i_user = ip2.getUser();

		var s_language = i_user.get("USRLNG") || "en";

		var n_length = Ext.Object.getKeys(o_xpd.groups).length;

		if (n_length > 0) {
			Ext.Object.each(o_xpd.groups, function(s_key, o_group) {
				var found = false;
				if (o_group.renderIn.editor) {
					Ext.Array.each(a_groups, function(i_group) {
						if (i_group.name == s_key) {
							found = true;
							return false;
						}
					});
					if (!found) {
						var a_fields = [];
						Ext.Array.each(a_xpdFields, function(i_field) {
							var a_groups = i_field._xpdConfig.groups || [];
							if (a_groups.length > 0) {
								Ext.Array.each(a_groups, function(s_group) {
									if (s_group === s_key) {
										if (i_field.prefix) {
											i_field.name = i_field.prefix + "-" + i_field.name;
										}
										a_fields.push(i_field);
										return false;
									}
								});
							}
							else {
								var b_found = false;
								Ext.Object.each(o_collection.properties, function(s_property, o_prop) {
									if (o_prop.groups) {
										if (o_prop.name == i_field.name && o_prop.groups.indexOf(s_key) != -1 && a_fields.indexOf(i_field) == -1) {
											if (i_field.prefix) {
												i_field.name = i_field.prefix + "-" + i_field.name;
											}
											a_fields.push(i_field);
											b_found = true;
										}
									}
								});
								if (!b_found) {
									b_found = false;
									Ext.Array.each(a_nogroup, function(i_leftover) {
										if (i_leftover.name == i_field.name) {
											b_found = true;
											return false;
										}
									});
									if (!b_found) {
										a_nogroup.push(i_field);
									}
								}
							}
						});
						if (a_fields.length > 0) {

							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);

								return n_a - n_b;
							});
							
							var b_collapsed = false;
							var b_collapsible = true;
							var n_sequence = 99999;
							var b_protected = false;
							var b_hidden = false;
							var s_type = "fieldset";
							if (o_group.renderIn.editor.layout) {
								b_collapsed = Ext.isBoolean(o_group.renderIn.editor.layout.collapsed) ? o_group.renderIn.editor.layout.collapsed : false;
								b_collapsible = Ext.isBoolean(o_group.renderIn.editor.layout.collapsible) ? o_group.renderIn.editor.layout.collapsible : true;
								n_sequence = o_group.renderIn.editor.layout.sequence || 99999;
								b_protected = Ext.isBoolean(o_group.renderIn.editor.layout["protected"]) ? o_group.renderIn.editor.layout["protected"] : false;
								s_type = o_group.renderIn.editor.layout.type || "fieldset";
								b_hidden = o_group.renderIn.editor.layout.hidden || false;
							}
							else {
								if (o_group.renderIn.editor) {
									b_collapsed = Ext.isBoolean(o_group.renderIn.editor.collapsed) ? o_group.renderIn.editor.collapsed : false;
									b_collapsible = Ext.isBoolean(o_group.renderIn.editor.collapsible) ? o_group.renderIn.editor.collapsible : true;
									n_sequence = o_group.renderIn.editor.sequence || 99999;
									b_protected = Ext.isBoolean(o_group.renderIn.editor["protected"]) ? o_group.renderIn.editor["protected"] : false;
									s_type = o_group.renderIn.editor.type || "fieldset";
									b_hidden = o_group.renderIn.editor.hidden || false;
								}
							}
							if (b_protected) {
								a_fields.unshift({
									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_button) {

												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_button.up(s_type).setProtected(false);
													},
													noText: ip2.i18n({
														da: "Fortryd",
														en: "Cancel"
													})
												});
											},
											iconCls: "pf-edit"
										}
									]
								});
							}

							var o_groupConfig = {
								name: s_key,
								collapsible: b_collapsible,
								collapsed: b_collapsed,
								hidden: b_hidden,
								sequence: n_sequence,
								dataParent: i_dataParent,
								layout: "anchor",
								defaults: {
									anchor: "100%"
								},
								title: ip2.xpd.translate(o_xpd, o_group.title, s_language),
								_protected: b_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_cmp = this;

									var a_items = i_cmp.items.getRange();

									Ext.Array.each(a_items, function (i_item) {
										if (i_item._protectionToggler) {
											i_item[b_protect ? "show" : "hide"]();
										}
										else {
											i_item[b_protect ? "hide" : "show"]();
										}
									});
								},
								items: a_fields,
								listeners: {
									afterrender: {
										fn: function (i_group) {
											if (i_group._protected) {
												i_group.toggleProtect(this.getProtected());
											}
										},
										single: true
									}
								}
							};

							Ext.applyIf(o_groupConfig, o_group);

							var i_group = Ext.widget(s_type, o_groupConfig);

							if (i_group.dependsOn) {
								Ext.Array.each(i_group.dependsOn, function(o_depends) {
									Ext.Array.each(a_xpdFields, function(i_field) {
										if (i_field.name == 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_group.mon(i_field, "change", check);
											i_group.mon(i_field, "disable", check);
											i_group.mon(i_field, "enable", check);

											i_group.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_group.show();
												}
												else {
													i_group.hide();
												}
											}
										}
									});
								});
							}
							a_groups.push(i_group);
						}
					}
				}
			});
		}
		else {
			Ext.Object.each(o_collection.properties, function(s_key, value) {

				var i_field;

				Ext.Array.each(a_xpdFields, function(i_xpdField) {
					if (i_xpdField.name == s_key) {
						i_field = i_xpdField;
						return false;
					}
				});

				if (i_field) {
					a_nogroup.push(i_field);
				}
			});
		}

		a_groups.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 {
			groups: a_groups,
			nogroup: a_nogroup
		};
	}
});
