Ext.define("Ext.ux.form.field.TreePicker", {

	extend: "Ext.form.field.Picker",

	alias: [
		"widget.ux.form.field.treepicker",
		"widget.treepicker"
	],

	alternateClassName: [
		"Ext.ux.form.TreePicker"
	],

	config: {
		columns: null,
		url: "",
		store: null,
		listConfig: {},
		displayField: "value",
		valueField: "key",
		lastLoaded: null,
		multiSelect: false
	},

	editable: false,

	triggers: {
		clear: {
			cls: Ext.baseCSSPrefix + "form-clear-trigger",
			weight: 1,
			handler: "onClearClick",
			hidden: true,
			scope: "this"
		},
		picker: {
			weight: 3,
			handler: "onTriggerClick",
			scope: "this"
		}
	},

	listeners: {
		afterrender: {
			fn: function(i_field) {

				var i_self = this;
				var i_clearTrigger = i_self.getTrigger("clear");

				if (i_clearTrigger) {
					var value = i_self.getValue();

					var b_show = !Ext.isEmpty(value);

					i_clearTrigger[b_show ? "show" : "hide"]();
				}
			}
		},
		change: {
			fn: function(i_field, value) {

				var i_self = this;
				var i_clearTrigger = i_self.getTrigger("clear");

				if (i_clearTrigger) {

					var b_show = !Ext.isEmpty(value);

					i_clearTrigger[b_show ? "show" : "hide"]();
				}
			}
		}
	},

	initComponent: function() {

		var i_self = this;

		i_self.createStore();

		i_self.callParent(arguments);
	},

	createStore: function() {

		var i_self = this;

		var o_root = {
			expanded: true
		};

		o_root[i_self.getValueField()] = "00000000000000";

		var i_store = Ext.create("Ext.data.TreeStore", {
			proxy: {
				type: "ajax",
				url: i_self.getUrl(),
				paramsAsJson: true,
				reader: {
					type: "json",
					rootProperty: "rows",
					totalProperty: "totalRows"
				},
				actionMethods: {
					read: "POST"
				}
			},
			root: o_root
		});

		i_self.setStore(i_store);
	},

	createPicker: function() {

		var i_self = this;

		var i_picker;

		var o_listConfig = i_self.getListConfig() || {};

		var a_columns = i_self.getColumns() || [
			{
				xtype: "treecolumn",
				dataIndex: i_self.getDisplayField(),
				flex: 1,
				menuDisabled: true,
				listeners: {
					afterrender: {
						fn: function(i_column) {

							i_column.setHeight(0);
						}
					}
				}
			}
		];

		Ext.apply(o_listConfig, {
			columns: a_columns,
			useArrows: true,
			rootVisible: false,
			maxHeight: 300,
			height: 300
		});

		var o_options = Ext.Object.merge({
			selModel: {
				mode: i_self.getMultiSelect() ? "MULTI" : "SINGLE"
			},
			floating: true,
			hidden: true,
			header: false,
			ownerCt: i_self,
			store: i_self.getStore(),
			listeners: {
				itemclick: {
					fn: function(i_tree, i_record) {

						i_tree.fireEvent("select", i_tree, i_record);

						var a_selection = i_tree.getSelection();

						i_self.setValue(a_selection);

						if (!i_self.getMultiSelect()) {
							i_self.collapse();
						}
					}
				},
				select: {
					fn: function(i_tree, i_record) {

						var a_selection = i_tree.getSelection();

						Ext.Array.each(a_selection, function(i_record) {

							var i_temp = i_record;

							var s_value = "";

							var a_values = [];

							while (i_temp && !i_temp.isRoot()) {

								var value = i_temp.get(i_self.getValueField());

								i_temp = i_temp.parentNode;

								a_values.push(value);
							}

							a_values.reverse();

							i_record.set(i_self.getDisplayField(), a_values.join(" - "));
						});
					}
				},
				deselect: {
					fn: function(i_tree, i_record) {
						i_record.set(i_self.getDisplayField(), "");
					}
				},
				beforeload: {
					fn: function(i_store, i_operation) {

						var i_proxy = i_store.getProxy();
						var o_extraParams = i_proxy.getExtraParams();

						var i_node = i_operation.node;

						var n_node = i_node.get(i_self.getValueField()) || "00000000000000";

						Ext.apply(o_extraParams, {
							parent: n_node
						});

						i_self.setLastLoaded(i_node);
					}
				},
				load: {
					fn: function(i_store, a_records) {

						var i_tree = i_store.ownerTree;
						var i_loaded = i_self.getLastLoaded();

						Ext.Array.each(a_records, function(i_record) {
							if (!i_record.get("expandable")) {
								i_record.set("leaf", true);
								i_record.commit();
							}
						});

						if (i_loaded) {
							i_tree.ensureVisible(i_loaded);
						}
					}
				}

			}
		}, i_self.listConfig);

		i_picker = i_self.picker = Ext.widget("treepanel", o_options);

		var i_navigationModel = i_picker.getNavigationModel();

		var o_bindings = Ext.apply({}, {
			enter: {
				scope: i_self,
				fn: function(n_key, i_event) {

					var i_picker = i_self.getPicker();

					var a_selection = i_picker.getSelection();

					i_self.setValue(a_selection);

					i_self.collapse();
				}
			},
			esc: {
				scope: i_self,
				fn: function(n_key, i_event) {

					i_self.collapse();
				}
			}
		});

		i_navigationModel.keyNav.addBindings(o_bindings);

		if (!i_picker.initialConfig.maxHeight) {
			i_picker.on({
				beforeshow: i_self.onBeforePickerShow,
				scope: i_self
			});
		}

		return i_picker;
	},

	setValue: function(value) {

		var i_self = this;

		var i_picker = i_self.getPicker();

		var i_store = i_picker.getStore();

		var a_value = Ext.Array.from(value);

		var s_rawValue = "";

		var a_display = [];

		Ext.Array.each(a_value, function(value) {

			if (value) {
				if (value.isModel) {
					s_rawValue = value.get(i_self.getDisplayField());
				}
				else {
					var i_record = null;

					i_record = i_store.findRecord(i_self.getDisplayField(), value);

					if (!i_record) {
						i_record = i_store.findRecord(i_self.getValueField(), value);
					}

					if (i_record) {
						s_rawValue = i_record.get(i_self.getDisplayField());
						i_picker.getSelectionModel().select(i_record, false, true);
					}
				}

				a_display.push(s_rawValue);
			}
		});

		i_self.setRawValue(a_display.join(", "));

		i_self.fireEvent("change", i_self, i_self.getValue());
	},

	getValue: function() {

		var i_self = this;
		var i_picker = i_self.getPicker();

		var a_selection = i_picker.getSelection();

		var i_selected = a_selection[0];

		var a_value = [];

		Ext.Array.each(a_selection, function(i_record) {
			a_value.push(i_record.get(i_self.getValueField()));
		});

		if (a_value.length === 0) {
			var s_rawValue = i_self.getRawValue();
			a_value = s_rawValue.split(",");
		}

		return a_value.filter(function(value) {
			return !Ext.isEmpty(value);
		});
	},

	getSubmitValue: function() {

		var i_self = this;
		var i_picker = i_self.getPicker();

		var a_selection = i_picker.getSelection();

		var i_selected = a_selection[0];

		var a_value = [];

		Ext.Array.each(a_selection, function(i_record) {
			a_value.push(i_record.get(i_self.getValueField()));
		});

		if (a_value.length === 0) {
			var s_rawValue = i_self.getRawValue();
			a_value = s_rawValue.split(",");
		}

		return a_value;
	},

	setRawValue: function(rawValue) {
		this.callParent([rawValue]);
	},

	onBeforePickerShow: function(picker) {

		var me = this;
		var heightAbove = me.getPosition()[1] - Ext.getBody().getScroll().top;
		var heightBelow = Ext.Element.getViewportHeight() - heightAbove - me.getHeight();

		picker.maxHeight = Math.max(heightAbove, heightBelow) - 5;
	},

	onClearClick: function() {

		var i_self = this;

		var i_tree = i_self.getPicker();

		i_tree.getSelectionModel().deselectAll();

		i_self.setValue([]);
	}
});
