var glob_sel          = document.createElement('select');
var glob_div          = document.createElement('div');
var glob_errdiv       = document.createElement('div');
var glob_cur_field    = null;  // Поле, в которое происходит выбор
var glob_cur_id_field = null;  // Поле, в которое заносится идентификатор
var glob_ElementName  = "";    // Назание массива, с которым работает селект
var glob_SecondFocus  = false; // Если попадаем в поле из селекта, то true;
var glob_ExternalFunction = null; // Ссылка на внешнюю функцию в которую передаем выбранный id


cssDiv = "border: 1px solid blue; position: absolute; margin: 0px; padding: 0px; background-color: white; visibility: hidden;z-index: 10;";
cssErr = "border: 1px solid blue; position: absolute; margin: 0px; padding: 3px; background-color: white; visibility: hidden;z-index: 10;";
cssSel = "margin: 0px; padding: 0px; background-color: white; border: none;z-index: 10;";

SetCss(glob_sel, cssSel);
SetCss(glob_div, cssDiv);
SetCss(glob_errdiv, cssErr);

glob_sel.setAttribute('multiple', false);
glob_sel.setAttribute("size", 2); // Нужно ставить больше 1 сразу, иначе опера потом не увеличивает

glob_div.appendChild(glob_sel);


// Скрывает див с ошибкой
glob_errdiv.hide_me = function ()
{
	this.style.visibility = 'hidden';
}

// Добавляем обработчики событий селекта
glob_sel.onblur = function (evt)
{
	// Удаляем ссылки на объект
	//alert ("im_blur");
	//glob_cur_field = null;
	//glob_cur_id_field = null;
	//glob_ElementName = "";
	glob_SecondFocus = true;

	glob_div.style.visibility = "hidden";
}

glob_sel.onkeyup = function(evt)
{
	if (!evt)
	{
		evt = window.event;
	}
	// Если нажали Enter то возвращаемся в поле ввода
	if (evt.keyCode == 13)
	{
		glob_cur_field.focus();
		return false; // Чтобы опера не инициализировала submit
	}
	else if (evt.keyCode == 9 || evt.keyCode == 40)
	{
		return false;
	}

}

// То, что делаем при выборе записи; в отдельной функции, потому что используется в двух событиях
function SelEl(evt)
{
	if (glob_cur_field && glob_cur_id_field)
	{
		var sel_ind = this.options[this.selectedIndex].value;
		if (sel_ind >= 0)
		{
			glob_cur_field.value    = eval(glob_ElementName)[sel_ind].ElementName;
			glob_cur_id_field.value = eval(glob_ElementName)[sel_ind].ElementId;

			if (glob_ExternalFunction)
				eval(glob_ExternalFunction)(glob_cur_id_field.value);
		}
	}
	else
	{
		//alert ("glob_cur_field "    + glob_cur_field);
		//alert ("glob_cur_id_field " + glob_cur_id_field);

		//alert ("Ошибка при определении объектов. Обратитесь к разработчикам.");
		return false;
	}
}
glob_sel.onchange = SelEl;
glob_sel.onclick = function (evt)
{
	if (!evt)
	{
		evt = window.event;
	}
	this.onchange(evt);
	if (glob_cur_field)
	{glob_cur_field.focus();}
}

document.body.appendChild(glob_div);
document.body.appendChild(glob_errdiv);

glob_errdiv.innerHTML = "Такого значения в списке нет";

// Вызывается по событию onfocus на поле, которое инициирует выбор контекста,
// задает внешнюю функцию in_ExtFunct которая вызывается после выбора id
function AddContextWithFunction(in_obj, in_ElementName, in_id_Field, in_ExtFunc, evt)
{
	glob_ExternalFunction = in_ExtFunc;
	AddContext(in_obj, in_ElementName, in_id_Field, evt);
}

// Вызывается по событию onfocus на поле, которое инициирует выбор контекста
function AddContext(in_obj, in_ElementName, in_id_Field, evt)
{
	// Отрабатываем, только если скрыт div с вариантами,
	// иначе ждем, пока в нем что-то выберут

	if (glob_div.style.visibility == 'hidden')
	{
		// Если пришли не после селекта
		if (!glob_SecondFocus)
		{
			// Добавляем событие "отпустили кнопку"
			if (!in_obj.onkeyup)
			{
				in_obj.onkeyup = function (evt)
				{
					if (!evt)
					{
						evt = window.event;
					}
					// Если таб или стрелка "вниз", то ничего не делаем
					if (evt.keyCode == 9 || evt.keyCode == 40)
					{
						return true;
					}
					else
					{
						// Если список построен, выводим его, иначе сообщение
						if (GetElements(this, in_ElementName, in_id_Field))
						{
							var show_div = glob_div;
							glob_errdiv.style.visibility = 'hidden';
						}
						else
						{
							var show_div = glob_errdiv;
							glob_div.style.visibility = 'hidden';
						}
						// Позиционируем див для вывода правильно
						el_pos = OffsetPos(this);

						show_div.style.top  = parseFloat(el_pos.Top) + parseFloat(this.offsetHeight) + "px";
						show_div.style.left = el_pos.Left + "px";

						show_div.style.visibility = 'visible';

						// Если это сообщение об ошибке, то запускаем таймер, чтобы его закрыть
						if (show_div == glob_errdiv)
							setTimeout("glob_errdiv.hide_me()", 3000);

					}
				}
			}
			// Добавляем событие "нажали кнопку"
			if (!in_obj.onkeydown)
			{

				in_obj.onkeydown = function (evt)
				{
				/*	evt = (evt) ? evt : ((window.event) ? event : null);
					if (evt)
					{
						var target = (evt.target) ? evt.target : ((evt.scrElement) ? evt.srcElement : null );
						if (target && target.tagName && target.tagName.toLowerCase() == "input")
						{
				         // обработываем, если ЕСТЬ событие, и элемент, с которого
				         // это событие пришло - <input>
							alert (glob_div.style.visibility);
							if (glob_div.style.visibility == 'visible')
							{
								alert ("test " + glob_div.style.visibility);
							}
							else
							{
								alert(" false ");
							}
						}
					}*/
					if (!evt)
					{
						evt = window.event;
					}

					// Если список раскрыт, то пытаемся переключиьтся на него
					if (glob_div.style.visibility == 'visible')
					{
						// Если таб или стрелка "вниз", то передаем фокус селекту
						if (evt.keyCode == 9 || evt.keyCode == 40)
						{
							glob_sel.focus();
							if (glob_sel.options.length > 0)
							{
								glob_sel.options[0].selected = true;
								glob_sel.onchange();
							}
							evt.cancelBubble = true;
							evt.returnValue  = false;

							return false;
						}
					}
				}
			}

			//Добавляем в селект ссылки на текущий объект
			glob_cur_field = in_obj;

			glob_cur_id_field = document.getElementById(in_id_Field);

			if (glob_cur_id_field)
			{
				if (glob_cur_id_field.id != in_id_Field)
				{
					glob_cur_id_field = null;
				}
			}


			if (!glob_cur_id_field)
			{
				// Если не нашли, то пытаемся создать - если, конечно, форма только одна
				if (document.forms.length == 1)
				{
					// Если имя id-поля - массив, то не проверяем на существование имени
					// иначе не создаем одноименных элементов.
					var create_me = false;
					if (in_id_Field.lastIndexOf('[]') == -1)
					{
						if (typeof(document.forms[0][in_id_Field]) == 'undefined')
						{
							create_me = true;
						}
					}
					else
					{
						create_me = true;
					}

					if (create_me)
					{
						// Если с таким именем нет на форме - то создаем
						var new_hidden = document.createElement('input');
						// Если поле создается как массив, то id должно быть уникальным
						new_hidden.setAttribute('name', in_id_Field);

						if (in_id_Field.lastIndexOf('[]') == -1)
						{
							new_hidden.setAttribute('id', in_id_Field);
						}
						else
						{
							var my_date = new Date;
							var my_plus = my_date.getTime();
							//new_hidden.setAttribute('name', in_id_Field + my_plus);
							new_hidden.setAttribute('id', my_plus);
						}
						new_hidden.setAttribute('type', 'hidden');

						document.forms[0].appendChild(new_hidden);
						glob_cur_id_field = new_hidden;
					}
					else
					{
						// Если это hidden, то присваиваем то, что нашли
						if (document.forms[0][in_id_Field].type == 'hidden')
						{
							glob_cur_id_field = document.forms[0][in_id_Field];
						}
						else
						{
							alert ("Нельзя использовать с таким типом - " + document.forms[0][in_id_Field].type);
						}
					}
				}
				else
				{
					alert ("Поле " + in_id_Field + "не найдено, количество форм " + document.forms.length);
				}

				//alert ("glob_cur_field = " + glob_cur_id_field);
			}
			else
			{
				// alert ("2" + glob_cur_id_field.id);
			}

			glob_ElementName = in_ElementName;

			glob_sel.tabIndex = in_obj.tabIndex + 1;
		}
		else
		{
			glob_SecondFocus = false;
		}
	}
	else
	{
		glob_sel.focus();
	}
}

function SetCss(in_obj, cssStr)
{
	// Устанавливает значение css-строки
	if(typeof(in_obj.style.cssText) == 'string' )
	{
		in_obj.style.cssText = cssStr;
	}
	in_obj.setAttribute('style', cssStr);
}


function GetElements(txt_Field, ElementName, id_Field)
{

	// Получает список элементов
	// Получаем первую букву в строке

	var value_len = txt_Field.value.length;

	if (value_len == 0)
	{
		return false;
	}

	var FirstL = txt_Field.value.charAt(0);
	FirstL = FirstL.toUpperCase();


	// Определяем следующий букву в массиве индексов первых букв

	var stop_prop = false;
	for (var myProp in eval("FirstLet_" + ElementName))
	{
		if (stop_prop)
		{
			break;
		}
		if (myProp == FirstL)
		{
			stop_prop = true;
		}
	}
	if (!stop_prop)
	{

			// Значит, такой буквы нет в массиве элементов

		return false;
	}


	// start_ind - индекс выбранной буквы
	// find_ind - индекс следующей буквы
	// Для вывода всех значений, начинающихся на заданную букву,
	// надо использовать диапазон (start_ind, fin_ind - 1), включая граничные элементы

	var start_ind = eval("FirstLet_" + ElementName)[FirstL];
	if (myProp != FirstL)
	{
		var fin_ind = eval("FirstLet_" + ElementName)[myProp];
	}
	else
	{
		 var fin_ind = eval(ElementName).length;
	}

	start_ind = parseInt(start_ind);
	fin_ind = parseInt(fin_ind);


	// Если введено больше одного символа, то ужимаем start_ind и fin_ind
	// до нужных значений

	if (value_len > 1)
	{
		var start_ind_new = 0;
		var fin_ind_new = 0;
		var str_part;

		for (var t = start_ind; t < fin_ind; t++)
		{
			str_part = eval(ElementName)[t].ElementName.substring(0, txt_Field.value.length);
			if (str_part.toUpperCase() == txt_Field.value.toUpperCase())
			{
				if (start_ind_new == 0)
				{
					start_ind_new = t;
				}
				fin_ind_new = t;
			}
			else
			{
				if (start_ind_new > 0)
				{
					break;
				}
			}
		}

		if (start_ind_new > 0)
		{
			start_ind = start_ind_new;
			fin_ind = fin_ind_new + 1;
		}
		else
		{
			return false;
		}
	}

	var str_name;
	// Очищаем select
	var sel_len = glob_sel.options.length;
	for (var j = 0; j<sel_len; j++)
	{
		glob_sel.removeChild(glob_sel.options[0]);
	}
	for (j = start_ind; j < fin_ind; j++)
	{
		str_name = eval(ElementName)[j].ElementName.substring(0, txt_Field.value.length);
		str_name = str_name + eval(ElementName)[j].ElementName.substring(txt_Field.value.length, eval(ElementName)[j].ElementName.length);
		glob_sel.options[glob_sel.options.length] = new Option(str_name, j, false, false);
	}
	// Ставим +1, иначе опера некорректно обрабатывает селект с одним значением (нет событий onclick и onchange)
	glob_sel.size = parseInt(fin_ind - start_ind + 1);

	return true;

}

function OffsetPos(obj)
{
	// Определяет координаты объекта
	var currleft = 0;
	var currtop = 0;
	// parentElement
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			currleft += obj.offsetLeft;
			currtop += obj.offsetTop;
			obj = obj.offsetParent;
		}
	}
	else
	{
		 if (obj.x) currleft += obj.x;
		 if (obj.y) currtop += obj.y;
	}

	return {Left: currleft, Top: currtop};
}