/**
 * SuggestBox - category search with tree-expanding suggestions
 * @extends component
 * @constructor
 * @param {String} options.func - name of function to be fired on selection (relative to SuggestBox)
 */
var SuggestBox = Class.create(Component);

SuggestBox.prototype.init = function()
{
	this.contents.removeChildren();
	this.textBox = new Element('input');
	this.textBox.type = 'text';
	this.textBox.className = 'suggest_box_text';
	this.textBox.tabindex = 0;
	this.textBox.onkeyup = this.loadNames.bindAsEventListener(this);
	Event.observe(this.textBox, 'blur', (function() {
		if(!this.mouseDown) this.list.hide();
	}).bind(this));
	Event.observe(this.textBox, 'focus', this.loadNames.bind(this, null));
	Event.observe(this.textBox, 'mousedown', (function() {
		this.mouseDown = true;
	}).bind(this));
	new OverrideSubmit(this.textBox);
	this.textBox.autocomplete = 'off';
	this.textBox.value = this.initText || '';
	this.contents.appendChild(this.textBox);

	this.valueBox = new Element('input');
	this.valueBox.type = 'hidden';
	this.valueBox.value = this.initValue || '';
	this.valueBox.name = this.contents.id;
	this.contents.appendChild(this.valueBox);

	if(this.initValue && this.keepResult)
		this.textBox.addClassName('selected');

	this.list = new SuggestList(this, null);
	this.contents.appendChild(this.list.getContainer());
	this.activeList = this.list;
	this.submitted = false;
	this.mouseDown = false;

	Event.observe(document, 'mouseup', (function() {
		if(!this.mouseDown)
			this.list.hide();
		this.mouseDown = false;
	}).bind(this));
	if(this.takeFocus)
		this.textBox.focus();

	if(this.createNew)
	{
		this.chooseParent = this.contents.appendChild(new Element('div'));
		this.chooseParent.className = 'choose_parent';
		var parentSuggest = new SuggestBox(
			this.chooseParent.appendChild(new Element('span')),
			{
				func: (function(parentCat, parentName) {
					var catName = this.textBox.value;
					if(confirm(language('subcat-confirm', [catName, parentName])))
					{
						this.chooseParent.hide()
						this.setEnabled(true);
						this.layout.addCat(parentCat, parentName, catName);
					}
				}).bind(this),
				title: language('newcat-parent')
			}
		);
		parentSuggest.layout = this.layout;
		parentSuggest.init();
		this.chooseParent.hide()
		this.chooseParent.appendChild(new TextButton((function() {
			this.chooseParent.hide()
			this.setEnabled(true);
		}).bind(this), language('cancel')));
	}

	if(this.initData)
		this.list.updateList(this.initData);
}

SuggestBox.prototype.setEnabled = function(enabled)
{
	this.textBox.disabled = !enabled;
	enabled ? this.textBox.removeClassName('disabled') : this.textBox.addClassName('disabled');
}

/**
 * SuggestList - container for SuggestBox results
 * @constructor
 * @param {SuggestBox} suggestBox - owner SuggestBox
 * @param {SuggestList} parentList - parent SuggestList if launched from a list
 */
var SuggestList = Class.create();
SuggestList.prototype.initialize = function(suggestBox, parentList)
{
	this.parentList = parentList;
	this.suggestBox = suggestBox;
	this.suggestionsContainer = new Element('div');
	this.suggestionsContainer.className = 'suggest_box_container';
	this.suggestions = this.suggestionsContainer.appendChild(new Element('div'));
	this.suggestions.className = 'suggest_box' + (parentList ? ' rel' : '');
	this.suggestions.hide();
	this.results = [];
	this.hoverIndex = -1;
	this.loaded = false;
	if(this.suggestBox.createNew && !this.parentList)
	{
		this.createButton = new Element('a');
		this.createButton.className = 'create_new';
		this.createButton.clickHandler = (function() {
			var catName = this.suggestBox.textBox.value;
			if(catName)
			{
				this.suggestBox.chooseParent.show();
				this.suggestBox.setEnabled(false);
				this.hide();
			}
			else
			{
				alert(language('newcat-alert'));
			}
		}).bind(this);
		Event.observe(this.createButton, 'mousedown', (function(){ this.suggestBox.mouseDown = true; }).bind(this));
	}
}
/**
 * SuggestList.getConatiner - get container HTMLObject
 * @method
 */
SuggestList.prototype.getContainer = function()
{
	return this.suggestionsContainer;
}
/**
 * SuggestBox.loadName - load suggested names given suggestBox value
 * @method
 * @param {int} event - event
 */
SuggestBox.prototype.loadNames = function(event)
{
	var kc = event ? event.keyCode : null;
	if(this.activeList.results.length)
	{
		if(kc == Event.KEY_UP && this.activeList.hoverIndex > 0)
			this.activeList.updateHover(this.activeList.hoverIndex - 1);

		if(kc == Event.KEY_DOWN && this.activeList.hoverIndex < this.activeList.results.length - 1)
			this.activeList.updateHover(this.activeList.hoverIndex + 1);

		if(kc == Event.KEY_RIGHT)
			this.activeList.loadChildren(true);

		if(kc == Event.KEY_LEFT)
		{
			if(this.activeList.parentList)
				this.activeList.parentList.updateHover(this.activeList.parentList.hoverIndex);
		}

		if(kc == Event.KEY_RETURN && !this.submitted)
			this.clickVal(this.activeList.hoverIndex >= 0 ? this.activeList.results[this.activeList.hoverIndex] : this.activeList.results[0]);
	}
	if(!this.controlKeys.member(kc))
	{
		this.submitted = false;
		this.list.hoverIndex = -1;
		this.activeList = this.list;
		if(this.rpc)
			this.rpc.abort();

		if(this.textBox.value !== '')
		{
			this.rpc = new RPC('ajax.loadname.xml.php', {
				parameters: {
					name: this.textBox.value,
					priv: session.priv ? 1 : 0
				},
				onSuccess: (function(transport) {
					this.list.updateList(transport.responseXML);
				}).bind(this)
			});
			this.list.loading();
		}
		else
		{
			this.list.updateList();
		}
		this.valueBox.value = '';
		if(this.keepResult)
			this.textBox.removeClassName('selected');
		this.list.updateCreateButton();
	}
}

/**
 * SuggestBox.clickVal - select the highlighted index and evaluate func
 * @method
 * @param {Object} result - result object
 */
SuggestBox.prototype.clickVal = function(result)
{
	this.submitted = true; // Lock out KEY_RETURN event until prompt has been processed.
	this.valueBox.value = result.category;

	var text = result.catName;
	this.textBox.value = this.keepResult ? text : '';
	if(this.keepResult)
		this.textBox.addClassName('selected');

	switch(typeof(this.func))
	{
		case 'string':
			eval('this.' + this.func + '(' + result.category + ',\'' + text.replace(/'/g, "\\'") + '\')');
			break;
		case 'function':
			this.func(result.category, text);
			break;
	}
	this.list.hide();
}

SuggestBox.prototype.controlKeys = [Event.KEY_LEFT, Event.KEY_RIGHT, Event.KEY_UP, Event.KEY_DOWN, Event.KEY_RETURN, Event.KEY_TAB];

/**
 * SuggestList.updateHover - set new item as selected
 * @method
 * @param {int} newHover - result index of selected item
 */
SuggestList.prototype.updateHover = function(newHover)
{
	this.suggestBox.activeList = this;
	if(this.hoverIndex >= 0)
	{
		this.results[this.hoverIndex].className = (this.results[this.hoverIndex].isLeaf ? '' : 'expands');
		if(!this.results[this.hoverIndex].isLeaf)
			this.results[this.hoverIndex].list.hide();
	}

	this.results[newHover].className = (this.results[newHover].isLeaf ? '' : 'expands ') + 'hover';

	//clear highlight from parent list
	if(this.parentList)
	{
		var parentResult = this.parentList.results[this.parentList.hoverIndex];
		parentResult.className = (parentResult.isLeaf ? '' : 'expands ');
	}

	this.hoverIndex = newHover;

	this.loadChildren(false);
}
/**
 * SuggestList.loadChildren - load children of highlighted item
 * @method
 * @param {boolean} goInto - select first item of child list when loaded (for when keystrokes are used)
 */
SuggestList.prototype.loadChildren = function(goInto)
{
	if(!this.results[this.hoverIndex].isLeaf)
	{
		var category = this.results[this.hoverIndex].category;

		var childList = this.results[this.hoverIndex].list;
		if(!childList.loaded)
		{
			childList.rpc = new RPC('ajax.loadchildren.xml.php', {
				parameters: {
					category: category,
					priv: session.priv ? 1 : 0
				},
				onSuccess: function(transport) {
					childList.updateList(transport.responseXML);
				}
			});
			childList.loading();
		}
		else
		{
			if(childList.results.length)
				childList.suggestions.show();
			//clear any highlight from child list as this list active
			for(var i = 0, il = childList.results.length; i < il; i++)
				childList.results[i].className = (childList.results[i].isLeaf ? '' : 'expands');

			//hide any previously loaded exapnsion
			for(var i = 0, il = childList.results.length; i < il; i++)
				childList.results[i].list.hide();

			//highlight top item if using keypresses
			if(goInto && childList.results.length)
				childList.updateHover(0);
		}
	}
}
/**
 * SuggestList.loading - show the loading/updating indicator for the list
 * @method
 */
SuggestList.prototype.loading = function()
{
	if(!this.updateMessage)
	{
		this.suggestions.show();
		var item = this.suggestions.appendChild(new Element('a'));
		item.className = 'loading';
		item.appendChild(new Span((this.results.length == 0) ? language('loading') : language('updating')));
		this.updateMessage = true;
	}
}
/**
 * SuggestList.updateList - update SuggestList with new data
 * @method
 * @param {XMLObject} xml - XML data
 */
SuggestList.prototype.updateList = function(xml)
{
	var categories = xml instanceof Array ? xml : xml ? xml.getElementsByTagName('category') : '';

	this.suggestions.removeChildren();
	this.updateMessage = false;
	this.results = [];
	this.suggestions.show();
	if(categories.length)
	{
		for(var i = 0, il = categories.length; i < il; i++)
		{
			var catName = categories[i].getAttribute('name');
			var parentName = categories[i].getAttribute('parentname');
			var category = parseInt(categories[i].getAttribute('category'));
			var isLeaf = parseInt(categories[i].getAttribute('isleaf')) ? true : false;
			var displayName = catName + (parentName ? ' (' + parentName + ')' : '');
			if(displayName.length > 30)
				displayName = displayName.substring(0, 30) + '...';

			this.results[i] = this.suggestions.appendChild(new Element('a'));
			this.results[i].clickHandler = (function(result){ this.suggestBox.clickVal(result); return false; }).bind(this, this.results[i]);
			this.results[i].onmousedown = (function(){ this.suggestBox.mouseDown = true; }).bind(this);
			this.results[i].href = 'javascript:void(0);';
			this.results[i].appendChild(new Span(displayName));
			this.results[i].catName = catName;
			this.results[i].category = category;
			this.results[i].isLeaf = isLeaf;
			if(!isLeaf)
				this.results[i].className = 'expands';
			this.results[i].onmouseover = this.updateHover.bind(this, i);

			this.results[i].list = new SuggestList(this.suggestBox, this);
			this.suggestions.appendChild(this.results[i].list.getContainer());
		}
	}
	else if(this.parentList)
	{
		var a = this.suggestions.appendChild(new Element('a'));
		a.className = 'no_results';
		a.appendChild(new Span(language('no-public-photos')));
	}
	else if(xml != null)
	{
		var a = this.suggestions.appendChild(new Element('a'));
		a.className = 'no_results';
		a.appendChild(new Span(language('no-search-results')));
	}
	else
	{
		this.suggestions.hide();
	}
	this.updateCreateButton();

	this.loaded = true;
}
/**
 * SuggestList.updateCreateButton - redraw the create category button, if required
 * @method
 */
SuggestList.prototype.updateCreateButton = function()
{
	if(this.createButton)
	{
		this.createButton.removeChildren();
		var val = this.suggestBox.textBox.value;
		if(val)
		{
			if(val.length > 15)
				val = val.substring(0, 15) + '...';
			this.createButton.appendChild(new Span(language('new-cat', val)));
			this.suggestions.appendChild(this.createButton);
		}
	}
}

/**
 * SuggestList.hide - hide the suggest list and kill any pending http request
 * @method
 */
SuggestList.prototype.hide = function()
{
	if(this.rpc)
		this.rpc.abort();

	if(this.suggestions)
		this.suggestions.hide();
}