//class Option
function Option(name, value)
{
    this.name = name;
    this.value = value;
}

//class Select
function Select(
    pnlContainerId,
    txtInputId,
    hfdSelectedIndexId,
    hfdSelectedValueId,
    onchangeHandler,
    cssClass_Input,
    cssClass_Container,
    cssClass_Element,
    cssClass_Element_Selected,
    cssClass_Element_MouseOver,
    cssClass_Element_MouseOver_Selected,
    emptyOptionName)
{
    this.pnlContainer = document.getElementById(pnlContainerId);
    this.txtInput = document.getElementById(txtInputId);
    this.hfdSelectedIndex = document.getElementById(hfdSelectedIndexId);
    this.hfdSelectedValue = document.getElementById(hfdSelectedValueId);
    this.onchange = onchangeHandler;
    this.cssClass_Element = cssClass_Element;
    this.cssClass_Element_Selected = cssClass_Element_Selected;
    this.cssClass_Element_MouseOver = cssClass_Element_MouseOver;
    this.cssClass_Element_MouseOver_Selected = cssClass_Element_MouseOver_Selected;
    this.emptyOptionName = emptyOptionName;
    
    var currentThis = this;
    this.txtInput.className = cssClass_Input;
    this.txtInput.onblur = function() { staticInputBlur(currentThis); };
    this.txtInput.onclick = function() { staticInputClick(currentThis); };
    this.pnlContainer.className = cssClass_Container;
        
    this.selectedIndex = -1;
    this.selectedValue = "";
    this.selectedOption = null;
    this.options = new Array(0);
    this.length = 0;
    
    this.elementClick = elementClick;
    this.elementMouseover = elementMouseover;
    this.elementMouseout = elementMouseout;
    this.addOption = addOption;
    this.addEmptyOption = addEmptyOption;
    this.getSelectedValueAsInt = getSelectedValueAsInt;
    this.getValueAsIntByIndex = getValueAsIntByIndex;
    this.getSelectedElement = getSelectedElement;
    this.getElementByIndex = getElementByIndex;
    this.getSelectedName = getSelectedName;
    this.getSelectedValue = getSelectedValue;
    this.getOptionByIndex = getOptionByIndex;
    this.getOptionByValue = getOptionByValue;
    this.getOptionByName = getOptionByName;
    this.removeOptionByIndex = removeOptionByIndex;
    this.removeOptionByValue = removeOptionByValue;
    this.removeOptionByName = removeOptionByName;
    this.changeSelectedOptionByValue = changeSelectedOptionByValue;
    this.changeSelectedOptionByName = changeSelectedOptionByName;
    this.changeSelectedOptionByIndex = changeSelectedOptionByIndex;
    this.showContainer = showContainer;
    this.hideContainer = hideContainer;
    this.inputBlur = inputBlur;
    this.inputClick = inputClick;
    this.clearOptions = clearOptions;
    this.saveOptions = saveOptions;
    this.bindOptions = bindOptions;
    this.bindOptionsAndSelectOptionByIndex = bindOptionsAndSelectOptionByIndex;
    this.bindOptionsAndSelectOptionByValue = bindOptionsAndSelectOptionByValue;
}

//return void
function addEmptyOption()
{
    this.addOption(this.emptyOptionName, '');
}

//return void
//name: string
//value: string
//add new option
function addOption(name, value)
{
    var pnlElement = document.createElement('DIV');
    var lblName = document.createElement('SPAN');
    var hfdValue = document.createElement('INPUT');
    
    pnlElement.id = this.pnlContainer.id + '_pnlElement_' + this.length;
    lblName.id = this.pnlContainer.id + '_pnlElement_lblName_' + this.length;
    hfdValue.id = this.pnlContainer.id + '_pnlElement_hfdValue_' + this.length;
   
    lblName.innerHTML = name;
    
    hfdValue.type = 'hidden';
    hfdValue.value = value;
    
    var currentThis = this;
    var onchangeHandler = this.onchange;
    pnlElement.className = this.cssClass_Element;
    pnlElement.onclick = function(){ staticElementClick(currentThis, pnlElement.id, onchangeHandler); };
    pnlElement.onmouseover = function(){ staticElementMouseover(currentThis, pnlElement.id); };
    pnlElement.onmouseout = function(){ staticElementMouseout(currentThis, pnlElement.id); };
    pnlElement.appendChild(lblName);
    pnlElement.appendChild(hfdValue);
    
    this.pnlContainer.appendChild(pnlElement);
    this.options.push(new Option(name, value));

    if (this.length == 0)
    {
        this.selectedIndex = 0;
        this.selectedValue = value;
        this.selectedOption = this.options[0];
        
        this.txtInput.value = name;
        this.hfdSelectedIndex.value = this.selectedIndex;
        this.hfdSelectedValue.value = this.selectedValue;
    }
    
    this.length++;
}

//return int
function getSelectedValueAsInt()
{
    return parseInt(this.selectedValue);
}

//return int
//index: int
function getValueAsIntByIndex(index)
{
    return parseInt(this.getOptionByIndex(index).value);
}

//return DIV
function getSelectedElement()
{
    if (this.selectedIndex == -1)
    {
        return null;
    }
    
    return this.pnlContainer.childNodes[this.selectedIndex];
}

//return DIV
//index: int
function getElementByIndex(index)
{
    if (index < 0 || index >= this.length)
    {
        return null;
    }
    
    return this.pnlContainer.childNodes[index];
}

//return SPAN
function getSelectedName()
{
    if (this.selectedIndex == -1)
    {
        return null;
    }
    
    return this.pnlContainer.childNodes[this.selectedIndex].firstChild;
}

//return INPUT type="hidden"
function getSelectedValue()
{
    if (this.selectedIndex == -1)
    {
        return null;
    }
    
    return this.pnlContainer.childNodes[this.selectedIndex].lastChild;
}

//return Option
//index: int
function getOptionByIndex(index)
{
    if (index < 0 || index >= this.length)
    {
        return null;
    }
    
    return this.options[index];
}

//return Option
//value: string
function getOptionByValue(value)
{
    for (var i = 0; i < this.length; ++i)
    {
        if (this.options[i] && this.options[i].value == value)
        {
            return this.options[i];
        }
    }
    return null;
}

//return Option
//value: string
function getOptionByName(name)
{
    for (var i = 0; i < this.length; ++i)
    {
        if (this.options[i] && this.options[i].name == name)
        {
            return this.options[i];
        }
    }
    return null;
}

//return bool
//index: int
//remove option by index
function removeOptionByIndex(index)
{
    if (index < 0 || index >= this.length)
    {
        return false;
    }
        
    var pnlElement = this.pnlContainer.childNodes[index];
    this.pnlContainer.removeChild(pnlElement);
    this.options.splice(index, index);
    this.length--;
    
    if (this.length == 0)
    {
        this.selectedIndex = -1;
        this.selectedValue = '';
        this.selectedOption = null;
        
        this.txtInput.value = '';
        this.hfdSelectedIndex.value = this.selectedIndex;
        this.hfdSelectedValue.value = this.selectedValue;
    }
    else
    {
        if (index < this.selectedIndex)
        {
            this.selectedIndex--;
        }
        else if (index == this.selectedIndex)
        {
            if (index == this.length)
            {
                this.selectedIndex--;
                index--;
            }
            
            this.selectedValue = this.options[index].value;
            this.selectedOption = this.options[index];
            
            this.txtInput.value = this.options[index].name;
            this.hfdSelectedIndex.value = this.selectedIndex;
            this.hfdSelectedValue.value = this.selectedValue;
            
            this.pnlContainer.childNodes[index].className = this.cssClass_Element_Selected;
        }
    }
    
    return true;
}

//return bool
//value: string
function removeOptionByValue(value)
{
    for (var i = 0; i < this.length; ++i)
    {
        if (this.options[i] && this.options[i].value == value)
        {
            return this.removeOptionByIndex(i);
        }
    }
    
    return false;
}

//return bool
//name: string
function removeOptionByName(name)
{
    for (var i = 0; i < this.length; ++i)
    {
        if (this.options[i] && this.options[i].name == name)
        {
            return this.removeOptionByIndex(i);
        }
    }
    
    return false;
}

//return bool
//value: string
function changeSelectedOptionByValue(value)
{
    for (var i = 0; i < this.length; ++i)
    {
        if (this.options[i] && this.options[i].value == value)
        {
            return changeSelectedOptionByIndex(i);
        }
    }
    
    return false;
}

//return bool
//value: string
function changeSelectedOptionByName(name)
{
    for (var i = 0; i < this.length; ++i)
    {
        if (this.options[i] && this.options[i].name == name)
        {
            return changeSelectedOptionByIndex(i);
        }
    }
    
    return false;
}

//return bool
//index: int
function changeSelectedOptionByIndex(index)
{
    if (index < 0 || index >= this.length)
    {
        return false;
    }
    
    if (this.selectedIndex != -1)
    {
        this.pnlContainer.childNodes[this.selectedIndex].className = this.cssClass_Element;
    }
    
    this.selectedIndex = index;
    this.selectedValue = this.options[index].value;
    this.selectedOption = this.options[index];
    
    this.txtInput.value = this.options[index].name;
    this.hfdSelectedIndex.value = this.selectedIndex;
    this.hfdSelectedValue.value = this.selectedValue;
    
    this.pnlContainer.childNodes[index].className = this.cssClass_Element_Selected;
    
    return true;
}

//return void
function showContainer()
{
    this.pnlContainer.style.display = 'block';
}

//return void
function hideContainer()
{
    this.pnlContainer.style.display = 'none';
}

//return void
function hideContainer(pnlContainer)
{
    pnlContainer.style.display = 'none';
}

//return void
//event handler onblur for input
function inputBlur()
{
    var pnlContainer = this.pnlContainer;
    setTimeout(function() { hideContainer(pnlContainer); }, 250);
}

//return void
//event handler onclick for input
function inputClick()
{
    this.showContainer();
}

//return void
//index: int
//event handler onclick for option
function elementClick(index)
{
    this.changeSelectedOptionByIndex(index);
}

//return void
//index: int
//event handler onmouseover for option
function elementMouseover(index)
{
    var element = this.getElementByIndex(index);
    if (element != null)
    {
        if (index == this.selectedIndex)
        {
            element.className = this.cssClass_Element_MouseOver_Selected;
        }
        else
        {
            element.className = this.cssClass_Element_MouseOver;
        }
    }
}

//return void
//event handler onmouseout for option
function elementMouseout(index)
{
    var element = this.getElementByIndex(index);
    if (element != null)
    {
        if (index == this.selectedIndex)
        {
            element.className = this.cssClass_Element_Selected;
        }
        else
        {
            element.className = this.cssClass_Element;
        }
    }
}

//return void
//remove all options
function clearOptions()
{
    var elementsCount = this.pnlContainer.childNodes.length;
    while (elementsCount > 0)
    {
        this.pnlContainer.removeChild(this.pnlContainer.childNodes[--elementsCount]);
    }
    
    this.selectedIndex = -1;
    this.selectedValue = '';
    this.selectedOption = null;
    this.options.splice(0, this.options.length);
    
    this.txtInput.value = '';
    this.hfdSelectedIndex.value = this.selectedIndex;
    this.hfdSelectedValue.value = this.selectedValue;
    this.length = 0;
}

//return void
//hfdOptionsId: string
//nameValueSeparator: char
//optionsSeparator: char
function saveOptions(hfdOptionsId, nameValueSeparator, optionsSeparator)
{
    var hfdOptions = document.getElementById(hfdOptionsId);
    hfdOptions.value = '';
    
    var i;
    for (i = 0; i < this.options.length - 1; ++i)
    {
        if (this.options[i])
        {
            hfdOptions.value += this.options[i].name + nameValueSeparator + this.options[i].value + optionsSeparator;
        }
    }
    if (this.options[i])
    {
        hfdOptions.value += this.options[i].name + nameValueSeparator + this.options[i].value;
    }
}

//return void
//options: array<Option>
//bind options created on server side
function bindOptions(options)
{
    for (var i = 0; i < options.length; ++i)
    {
        if (options[i])
        {
            this.addOption(options[i].name, options[i].value);
        }
    }
}

//return void
//options: array<Option>
//selectedIndex: int
//bind options created on server side and check selected
function bindOptionsAndSelectOptionByIndex(options, selectedIndex)
{
    this.bindOptions(options);
    this.changeSelectedOptionByIndex(selectedIndex);
}

//return void
//options: array<Option>
//selectedValue: string
//bind options created on server side and check selected
function bindOptionsAndSelectOptionByValue(options, selectedValue)
{
    this.bindOptions(options);
    this.changeSelectedOptionByValue(selectedValue);
}

//return void
//select: Select
//event handler onclick for input
function staticInputClick(select)
{
    select.inputClick();
}

//return void
//select: Select
//event handler onblur for input
function staticInputBlur(select)
{
    select.inputBlur();
}

//return void
//select: Select
//elementId: string
//event handler onmouseout for option
function staticElementMouseout(select, elementId)
{
    var idParts = elementId.split('_');
    var currentIndex = parseInt(idParts[idParts.length - 1]);
    select.elementMouseout(currentIndex);
}

//return void
//select: Select
//elementId: string
//event handler onmouseover for option
function staticElementMouseover(select, elementId)
{
    var idParts = elementId.split('_');
    var currentIndex = parseInt(idParts[idParts.length - 1]);
    select.elementMouseover(currentIndex);
}

//return void
//select: Select
//elementId: string
//callback: function
//event handler onclick for option
function staticElementClick(select, elementId, callback)
{
    var idParts = elementId.split('_');
    var currentIndex = parseInt(idParts[idParts.length - 1]);
    select.elementClick(currentIndex);
    if (callback != null)
    {
        callback();
    }
}

//return void
//select: Select
//event handler __doPostBack
function staticSaveOptions(select, hfdOptionsId)
{
    select.saveOptions(hfdOptionsId, '+', '|');
}
