(function() {

	SL.ui.TreeTable = Class.create(SL.Component, {
		init : function() {

			this.config.setDefault('selectable', false);
			this.config.setDefault('keyboard_editing', false);
			this.config.setDefault('no_double_select', false);

			this.rows = this.config.get('rows');
			this.componentID = this.config.get('component_id');

			if (this.config.get('selectable') && this.rows) {
				this.selected = false;

				this.config.get('rows').each(function(row) {
					var e = $(row.id);
					e.observe('click', this.onRowClicked.bind(this, e));
				}.bind(this));

				var id = this.config.get('selected');

				if (!this.componentID) {
					if (id) {
						SL.storage.ensureHash('tree_selection').set(this.id, id);
					} else {
						id = SL.storage.ensureHash('tree_selection').get(this.id);
					}
				}

				if (id) {
					this.selected = $(id);
					if (this.selected) {
						this.selected.addClassName('selected');
						if (this.componentID) {
							SL.byID(this.componentID).updateArgs({
								'tree.selection' : id
							});
						}
					}
				} else if (this.config.get('select_first')) {
					console.log(this.rows[0].id);
					this.onRowClicked.bind(this, $(this.rows[0].id)).defer();
				}

				this.dndActionURL = this.config.get('dnd_action_url');
				this.dndActionComponent = this.config.get('dnd_action_component');
				if (this.dndActionURL) {
					this.dnd = new SL.dnd.SortableTable(this.e.down('table'), {
						cb : {
							dragStart : this.onDragStart.bind(this),
							dragStop : this.onDragStop.bind(this)
						},
						grip_class : this.config.get('grip_class')
					});
				}

				if (this.config.get('keyboard_editing')) {
					this.keyObserver = SL.events.pushKeyboardObserver({
						keydown : this.onKey.bind(this)
					});
				}
			}
			this.ignoreSelect = 0;
		},

		ignoreNextSelect : function() {
			this.ignoreSelect++;
			setTimeout(function() {
				this.ignoreSelect--;
			}.bind(this), 100);
		},

		onDragStart : function(dnd, e) {

			this.rows.each(function(row) {
				if (!row.last) {
					return;
				}

				var e = $(row.id);
				var br = SL.elements.createBlindRow(e);
				br.setStyle({
					backgroundColor : '#cccccc',
					height : '10px'
				});
				br.addClassName('sljs__tree_table_dnd_marker');
				br.id = row.id + '__last_child';
				e.insert({
					after : br
				});

			}.bind(this));
		},

		onDragStop : function(dnd, e, index) {

			/* get this before removing the markers */
			var next = e.next();
			var prev = e.previous();

			this.e.select('.sljs__tree_table_dnd_marker').each(function(e) {
				e.remove();
			});

			if (this.dndActionURL) {
				var target;
				var above;
				if (next) {
					target = next.id;
					if (target.endsWith('__last_child')) {
						target = target.substring(0, target.length - 12);
						above = false;
					} else {
						above = true;
					}
				} else if (prev) {
					target = prev.id;
					above = false;
				} else {
					console.log("No target found");
					return;
				}

				var url = this.dndActionURL + '&args.dnd_action_source_id=' + e.id + '&args.dnd_action_target_id=' + target + '&args.dnd_action_above=' + above;

				var c = SL.byID(this.dndActionComponent);
				c.loadBackground(url);
			}
		},

		onKey : function(state) {

			if (!this.selected || this.disabled) {
				return;
			}

			if (state.shift) {
				var a = $H(this.getActions(this.selected.id));
				var action = undefined;

				switch (state.code) {
				case Event.KEY_DOWN:
					action = a.get('down');
					break;
				case Event.KEY_UP:
					action = a.get('up');
					break;
				case Event.KEY_LEFT:
					action = a.get('left');
					break;
				case Event.KEY_RIGHT:
					action = a.get('right');
					break;
				default:
					if (state.key == 'n') {
						action = a.get('add');
					} else if (state.key == 'e') {
						action = a.get('edit');
					} else if (state.key == 'm') {
						action = a.get('move');
					}
				}

				if (action) {
					this._disableTemp();
					action();
				}

				return true;
			}

			if (state.code == Event.KEY_DOWN) {
				var e = this.selected.next();
				if (e) {
					this.onRowClicked(e);
				}
				return true;
			}

			if (state.code == Event.KEY_UP) {
				var e = this.selected.previous();
				if (e) {
					this.onRowClicked(e);
				}
				return true;
			}

			if (state.code == Event.KEY_ESC) {
				this.onRowClicked(null);
				return true;
			}

			if (state.code == Event.KEY_LEFT || state.code == Event.KEY_RIGHT) {
				var a = $H(this.getActions(this.selected.id)).get('toggle');
				if (a) {
					this._disableTemp();
					a();
				}
				return true;
			}
		},

		toggle : function(id) {
			var row = $(id);
			if (!row)
				return;

			var el = row.down('.gtvlm');
			if (!el)
				el = row.down('.gtvtm');
			if (!el)
				el = row.down('.gtvlp');
			if (!el)
				el = row.down('.gtvtp');
			if (!el)
				el = row.down('.gtvtn');
			if (!el)
				el = row.down('.gtvln');
			if (!el) {
				return;
			}

			el.update(this._getLoadingContent());

		},

		onRowClicked : function(e, event) {

			if (event) {
				var eventElement = event.findElement();
				if (eventElement && eventElement.hasClassName('_tree_cell_')) {
					return;
				}
			}

			if (!e) {
				if (this.selected) {
					this.selected.removeClassName('selected');
					this.setSelected();
					this.selected = undefined;
				}
				return;
			}
			if (this.selected) {
				if (this.selected == e && this.config.get('no_double_select')) {
					return;
				}
				this.selected.removeClassName('selected');
			}
			e.addClassName('selected');
			this.selected = e;

			if (this.ignoreSelect > 0) {
				console.log("Ignoring select");
				return;
			}

			this.setSelected(e.id);
		},

		setSelected : function(id) {

			if (this.componentID) {
				SL.byID(this.componentID).updateArgs({
					'tree.selection' : id
				});
			} else {
				var selections = SL.storage.ensureHash('tree_selection');
				selections.set(this.id, id);
			}

			if (this.selectionNotifyHandler) {
				if (id) {
					this.selectionNotifyHandler($(id), this.getActions(id));
				} else {
					this.selectionNotifyHandler(null, {});
				}
			}

			var action = $H(this.getActions(this.selected.id)).get('select');
			if (action) {
				action();
			}
		},

		getActions : function(id) {
			for ( var i = 0; i < this.rows.length; i++) {
				var o = this.rows[i];
				if (o && o.id == id) {
					return o.actions;
				}
			}

			console.log('TreeTable: No actions for id ' + id);
			return $H();
		},

		connectSelectionNotify : function(handler, emitNow) {
			this.selectionNotifyHandler = handler;
			if (emitNow && this.selected) {
				this.selectionNotifyHandler($(this.selected), this.getActions(this.selected.id));
			}
		},

		cleanup : function() {
			if (this.keyObserver) {
				SL.events.removeKeyboardObserver(this.keyObserver);
			}
		},

		_disableTemp : function() {
			if (!this.disabled) {
				this.disabled = true;
				setTimeout(function() {
					this.disabled = false;
				}.bind(this), 5000);
			}
		},

		onSuccess : function() {
			this.disabled = undefined;
		}
	});

	SL.ui.TreeTableActions = Class.create(SL.Component, {
		init : function() {

			this.tree = SL.byID(this.config.get('tree_id'));
			this.actions = $H(this.config.get('actions'));

			this.actions.each(function(p) {
				var a = p.value;
				var e = $(a.image);
				if (e) {
					e.observe('click', this._clicked.bind(this, p.key));
				}
			}.bind(this));

			this.tree.connectSelectionNotify(this.onChanged.bind(this), this.config.get('emit_on_load'));
		},

		_clicked : function(action) {

			var a = this.actions.get(action);

			if (action.startsWith("_entries_")) {
				a.fallback();
				return;
			}

			var a = this.actions.get(action);

			if (!this.currentActions) {
				if (a.fallback) {
					a.fallback();
				}
				return;
			}

			var f = this.currentActions.get(action);
			if (f) {
				f();
			} else if (a.fallback) {
				a.fallback();
			}
		},

		setActions : function(actions) {
			this.currentActions = actions;

			this.actions.each(function(as, p) {
				var action = p.key;
				var a = p.value;
				var e = $(a.image);

				if (!e) {
					return;
				}

				var img;
				if (e.tagName.toLowerCase() == 'img') {
					img = e;
				} else {
					img = e.down('img');
				}

				if (as.get(action) || a.fallback) {
					if (img && img.src.endsWith("_i.png")) {
						img.src = img.src.substring(0, img.src.length - 6) + ".png";
					}
					e.setStyle({
						cursor : 'pointer'
					});
				} else {
					if (img && !img.src.endsWith("_i.png")) {
						img.src = img.src.substring(0, img.src.length - 4) + "_i.png";
					}
					e.setStyle({
						pointer : 'default'
					});
				}
			}.curry(actions));
		},

		onChanged : function(e, actions) {
			this.setActions($H(actions));
		}
	});

	SL.ui.Tree = Class.create(SL.Component, {

		init : function() {
			this.active = this.e.down('li.selected');
			this.topUL = this.e.down('ul');
			this.initDefered.bind(this).defer();
		},

		initDefered : function() {
			this.e.select('li').each(function(e) {
				var a = e.down('>div.item>a');
				if (a) {
					a.observe('click', this._update.bind(this, e));
				}
			}.bind(this));
		},

		_deselect : function(e) {
			if (this.active) {
				if (e && this.active == e) {
					return;
				}
				this.active.removeClassName('selected');

				var ul = this.active.up('ul');
				while (ul && ul != this.topUL) {
					var li = ul.up('li');
					if (!li) {
						break;
					}
					li.removeClassName('active');
					ul = li.up('ul');
				}
			}
		},

		_deselectAll : function(className) {
			$$('.' + className).each(function(e) {
				var c = SL.getC(e);
				if (c) {
					try {
						c._deselect();
					} catch (e) {
						console.error(e);
					}
				}
			});
		},

		_update : function(e, event) {

			if (event.isRightClick()) {
				return;
			}

			this._deselect(e);
			if (this.e.hasClassName('gui_html_tree')) {
				this._deselectAll('gui_html_tree');
			} else {
				this._deselectAll('html_tree');
			}

			this.active = e;
			e.addClassName('selected');

			var ul = this.active.up('ul');
			while (ul && ul != this.topUL) {
				var li = ul.up('li');
				if (!li) {
					break;
				}
				li.addClassName('active');
				ul = li.up('ul');
			}
		}
	});

})();

