var inputElement = Class.create();
inputElement.prototype = {
	initialize: function(params) {
		// значения по умолчанию
		this.errorBegin   = '';
		this.labelClass   = 'label';
		this.errorClass   = 'errorMsg';
		this.elErrorClass = 'checkError'; // класс ошибки самого элемента ввода
		this.disableTitle = true;
		Object.extend(this, params);
		this.element = $(this.element);
		var el = this.element;
		if (!el)
			return;
		// проверяем и присваиваем тип компоненту
		var type = (el.type) ? el.type.toLowerCase() : "";
		switch (type)
		{
			case 'text'    : this.type = 'text';
				break;
			case 'password': this.type = 'password';
				break;
			case 'file'    : this.type = 'file';
				break;
			case 'hidden'  : this.type = 'hidden';
				break;
			case 'checkbox': this.type = 'checkbox';
				break;
			default:
				if (el.tagName.toLowerCase() == 'textarea')
					this.type = 'textarea';
				else
					if (el.tagName.toLowerCase() == 'select') {
						this.type = 'select';
						this.selectDefaultIndex = el.selectedIndex;
					}
					else {
						alert('inputElement: unknown element type');
						return;
					}
			break;
		}
		// присваиваем имя компоненту
		this.name = this.element.id;
		// ... и значение
		this.setValue(el.value);
		// создаем элемент, в который будут выводится сообщения об ошибках
		this.errorElement = document.createElement("span");
		this.errorElement = $(this.errorElement);
		var erEl = this.errorElement;
		erEl.hide();
		// если errorClass явно не указан, то назначить имя класса errorMsg
		erEl.addClassName(this.errorClass);
		el.parentNode.appendChild(this.errorElement);
		//el.parentNode.insertBefore(erEl, el.nextSibling)
		// создаем подписи
		this.labelText = (this.labelText || el.title);
		if (((el.type == 'text') || (el.type == 'textarea') || (el.type == 'password')) && (this.labelText)) {
			el.label = new lables2({
				text         : this.labelText,
				labelClass   : this.labelClass,
				element      : this.element,
				disableTitle : this.disableTitle
			});
		}
		this.defaultClass = this.element.className;
		var that = this;
		// обновление значения компонента
		['change', 'focus', 'blur', 'mouseout'].each(function(event){
			Event.observe(el, event, that.refreshValue.bindAsEventListener(that));
		});
		// сброс ошибки
		['change', 'focus', 'click', 'keypress'].each(function(event){
			Event.observe(el, event, that.resetError.bindAsEventListener(that));
		});
	},

	// установить значение в компонент
	setValue: function(value) {
		if (this.type == 'file')
			return;
		if (this.type == 'checkbox') {
			this.value = this.element.checked = parseInt(value); // значения 0 или 1
			return;
		}
		if ((this.element.tagName == 'SELECT') && (value == '')) {
			this.element.selectedIndex = this.selectDefaultIndex;
			return;
		}
		this.value = this.element.value = value.unescapeHTML();
		if (this.element.label)
			this.element.label.set();
	},

	// обновить значение
	refreshValue: function() {
		if (this.element.label && this.element.label.isEmptyValue()) {
			this.value = "";
			return;
		}
		this.value = this.element.value;
		if (this.type == 'checkbox') {
			this.value = this.element.checked; // значения 0 или 1
		}
	},

	// установка ошибки
	setError: function(errorMsg) {
		if (!errorMsg)
			return;
		this.element.removeClassName(this.elErrorClass);
		this.element.addClassName(this.elErrorClass);
		this.errorElement.update(this.errorBegin + errorMsg).show();
	},

	// сброс ошибки элемента формы
	resetError: function() {
		if (!this.errorElement)
			return;
		if (!this.errorElement.visible())
			return;
		this.element.removeClassName(this.elErrorClass);
		this.errorElement.update().hide();
		if (this.onErrorReset) {
			var func = this.onErrorReset;
			func = func.replace(/#\{elementId\}/g, this.element.id);
			eval(func);
		}
	},

	getValue: function() {
		this.refreshValue();
		return this.value;
	}
};

// элемент - метка
var markItem = Class.create();
markItem.prototype = {
	initialize: function(params) {
		var that = this;
		Object.extend(this, params);
		this.id = this.marksObj.items.length;
		this.addElement();
		this.getDelElem();
		if (this.delElem)
			Event.observe(this.delElem, 'click', function(){
				that.marksObj.delMark(that.id);
			});
	},

	addElement: function() {
		var tpl = new Template(this.tplt);
		var html = tpl.evaluate({mark: this.mark});
		var r = new Insertion.Bottom(this.holder, html);
		this.element = $(this.holder.lastChild);
	},

	getDelElem: function() {
		var that = this;
		this.holder.descendants().each(function(dsc) {
			if (dsc.id == 'del')
				that.delElem = dsc;
		});
	}

}
// метки (ключевые слова)
var marks = Class.create();
marks.prototype = {
	initialize: function(params) {
		var that = this;
		Object.extend(this, params);
		window[this.name] = this;
		this.holder = $(this.holder);
		this.items = [];
		this.getElementsByIds(['marks','showAdd','addForm','markInput','addMark','hideAdd','error']);
		// показать форму по клику
		Event.observe(this.showAdd, 'click', function() {that.addForm.show();that.markInput.focus()});
		// скрыть форму
		Event.observe(this.hideAdd, 'click', function() {that.addForm.hide();that.markInput.value = ''});
		Event.observe(document, 'keypress', this.escHide.bindAsEventListener(this));
		// добавить метку
		var f = this.collectMark.bindAsEventListener(this);
		Event.observe(this.markInput, 'keypress', f);
		Event.observe(this.addMark, 'click', f);
	},

	// получить элементы по id, ids - строка или массив строк
	getElementsByIds: function(ids) {
		var that = this;
		this.holder.descendants().each(function(dsc) {
			for (var i = 0; i < ids.length; ++i)
				if (dsc.id == ids[i])
					that[dsc.id] = dsc;
		});
	},

	// закрыть при нажатии клавиши ESC
	escHide: function(e) {
		if (e.keyCode && (e.keyCode == Event.KEY_ESC)) {
			this.addForm.hide();
			this.markInput.value = '';
		}
	},
	
	// обработка метки
	getMark: function(wordsLimit) {
		if (!wordsLimit)
			wordsLimit = 5;
		var mark = this.markInput.value;
		if (!mark || (mark.length < 2))
			return false;
		mark = mark.replace(/[^0-9a-zа-я-ё\. ]+/gi, '');
		mark = mark.replace(/\s+/g, ' ').toLowerCase();
		// trim
		mark = mark.replace(/(^\s+)|(\s+$)/g, '');
		words = mark.split(' ');
		var newWords = [];
		for (var i = 0; ((i < wordsLimit) && (i < words.length)); i++)
			newWords.push(words[i]); 
		return newWords.join(' ');
	},

	collectMark: function(e) {
		var elt = Event.element(e);
		if ((elt.id == 'markInput') && (e.keyCode != Event.KEY_RETURN))
			return;
	 	var mark = this.getMark();
		this.markInput.value = '';
		this.addForm.hide();
		if (!mark) {
			Event.stop(e);
			return;
		}
		// проверить на повторы
		for(var i = 0; i < this.items.length; i++)
			if (this.items[i] && (this.items[i].mark == mark)) {
				Event.stop(e);
				return;
			}
		this.items.push(new markItem({
			marksObj: this,
			holder: this.marks,
			mark: mark,
			tplt: this.markTemplate
		}));
		if (this.backend)
			this.ajax('add', mark);
		Event.stop(e);
	},
	
	delMark: function(itemId) {
		if (!confirm('Удалить метку "'+this.items[itemId].mark+'"?'))
			return;
		this.items[itemId].element.remove();
		if (this.backend)
			this.ajax('del', this.items[itemId].mark);
		delete this.items[itemId];
	},
	
	ajax: function(mode, markText)
	{
		var params = {};
		if (mode == 'add')
			Object.extend(params, this.addParams);
		if (mode == 'del')
			Object.extend(params, this.delParams);
		params['markText'] = markText;
		if (this.onSaveMark)
			eval(this.onSaveMark);
		if (!params)
			return;
		var r = new Ajax.Request(this.backend, {
			method: 'post',
			parameters: params,
			onFailure: function(tr) {
				//alert('Ошибка передачи данных');
			},
			onSuccess: function(tr) {
			}
		});
	},
	
	getValue: function() {
		var res = [];
		this.items.each(function(n){
			if (n)
				res.push(n.mark);
		});
		this.value = res;
		return res;
	},
	
	setValue: function(vals) {
		var that = this;
		this.clearValue();
		that.addForm.hide();
		that.markInput.value = '';
		if (!vals)
			return;
		vals.each(function(v){
			that.items.push(new markItem({
				marksObj: that,
				holder: that.marks,
				mark: v,
				tplt: that.markTemplate
			}));
		});
	},
	
	// обновить значение
	refreshValue: function() {
		this.value = this.getValue();
	},
	
	clearValue: function() {
		var that = this;
		this.items.each(function(n){
			if (n)
				that.items[n.id].element.remove();
		});
		this.items = [];
	},
	
	// установка ошибки
	setError: function(errorMsg) {
		if (!errorMsg || !this.error)
			return;
		this.error.update(this.errorBegin + errorMsg).show();
		this.error.show();
	},
	
	// сброс ошибки
	resetError: function() {
		if (this.error)
			this.error.hide();
		if (this.onErrorReset)
			this.execFunc(this.onErrorReset);
	}
}
