// {{{ Cache

function Cache(limit) {
	this.limit = limit || Infinity;	// лимит на кол-во кэшируемых элементов
	this.keys = [];		// список ключей
	this.cache = {};	// ассоц. массив "ключ -> значение"
}

Cache.prototype.deleteItemByIndex = function(num) {
	if (this.keys[num] === undefined) return false;
	delete this.cache[this.keys.splice(num, 1)];
	return true;
}

// deprecated
Cache.prototype.deleteItemByKey = function(key) {

	if (this.cache[key] === undefined) return false;

	var released = false;
	
	for (var i=0; i < this.keys; i++) {
		if (this.keys[i] == key) {
			released = this.deleteItemByIndex(i);
			break;
		}
	}

	if (!released) {
		throw "Cache.set internal error: data structure corrupted";
	} else {
		return true;
	}
}

Cache.prototype.set = function(key, value){
	if (this.cache[key] !== undefined) {
		this.deleteItemByKey(key);
	}
	
	if (this.keys.length >= this.limit) {
		this.deleteItemByIndex(0);
	}
	
	this.cache[key] = value;
	this.keys.push(key);
}

Cache.prototype.get = function(key){
	return this.cache[key];
}

// }}}
// {{{ Html

function Html() {}

Html.buildSelect = function(options, selectedOption, attributes){
	var strAttr = "";
	attributes = attributes || {};

	for (var i in attributes) { //foreach ($attributes as $k=>$v) {
		//$strAttr .= ' ' . htmlspecialchars($k) . ' = "' . htmlspecialchars($v) . '"';
		strAttr += ' ' + i + ' = "' + attributes[i] + '"';
	}

	var out = '<select' + strAttr + '>';
	for (var i in options) {	//foreach ($options as $k => $v) {
		if (typeof options[i] == "object") {	//if (is_array($v)) {
			out += '<optgroup label="' + i + '">';
			for (var k in options[i]) {
				out += Html._getOption(l, options[i][k], selectedOption);
			}
			out += '</optgroup>';
		} else {
			out += Html._getOption(i, options[i], selectedOption);
		}
	}
	out += '</select>';
	return out;
}

/**
 * Вспомогательный метод для buildSelect
 *
 * @param	string	optionName
 * @param	string	optionValue
 * @param	string	selectedOption	
 * @return	string	HTML-код элемента OPTION
 * @access	protected
 * @static
 */
Html._getOption = function (optionName, optionValue, selectedOption) {
	return '<option value="' + optionName + '"' +
				(optionName == selectedOption ? ' selected="selected"' : '') + '>' +
				optionValue + '</option>';
}

// }}}

// {{{ Selector
function Selector(node){
	if (typeof node !== "object") {
		node = document.getElementById(node);
	}
	this.node = node;
	this.items = [];
	this.init();
	this.selected = 0;
}

Selector.prototype.init = function(){
	if (!this.node) return;
	
	var tmp = this.node.getElementsByTagName("li");
	var _self = this;
	for(var i = 0; i < tmp.length; i++){
		this.items[i] = tmp[i];
		tmp[i].onclick = function(num){
			return function() {
				_self.itemClick(num);
			}
		}(i);
	}
}

Selector.prototype.itemClick = function(num){
	this.select(num);
}

Selector.prototype.setItemState = function(num, isSelected) {
	if (typeof this.items[num] != "undefined") {
		this.items[num].className = isSelected ? "selected" : "";
	}
}

Selector.prototype.select = function(num){
	this.setItemState(this.selected, false);
	this.setItemState(num, true);
    this.selected = num;
}

// }}}
// {{{ SearchTypeSelector

function SearchTypeSelector(clickHandler, node){
	//Selector.apply(this, arguments);	// parent class constructor call
	Selector.apply(this, Array.prototype.slice.apply(arguments, [1]));	// parent class constructor call
	this.clickHandler = clickHandler;
}

// search type constants
SearchTypeSelector.ALL = 0;
SearchTypeSelector.ORG = 1;
SearchTypeSelector.CAT = 2;
SearchTypeSelector.ADR = 3;

SearchTypeSelector.prototype = new Selector(null);
SearchTypeSelector.prototype.consturctor = SearchTypeSelector;
/**
SearchTypeSelector.prototype.itemClick = function(num){
	Selector.prototype.select.apply(this, arguments);
	if (num == 2) alert('Отображение категорий...');
}
/**/
SearchTypeSelector.prototype.itemClick = function(num){
	Selector.prototype.select.apply(this, arguments);
	this.clickHandler(num);
}

// }}}
// {{{ ResultSelector

function ResultSelector(clickHandler, node){
	Selector.apply(this, Array.prototype.slice.apply(arguments, [1]));	// parent class constructor call
	this.clickHandler = clickHandler;
}

ResultSelector.prototype = new Selector(null);
ResultSelector.prototype.consturctor = ResultSelector;

ResultSelector.prototype.itemClick = function(num){
	this.clickHandler(num);
}

// }}}
