////////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////////

var __CFEXPANDEDSELECT_ERROR_ID = "invalid CFExpandedSelect id";
var __CFEXPANDEDSELECT_ERROR_VALUE = "invalid CFExpandedSelect value";

////////////////////////////////////////////////////////////////////////////////
// Static Variables
////////////////////////////////////////////////////////////////////////////////

var __cfExpandedSelectMap = {};

////////////////////////////////////////////////////////////////////////////////
// Classes
////////////////////////////////////////////////////////////////////////////////

// CFExpandedSelect

function CFExpandedSelect(id, selectBoxId, textBoxId, textBoxLabelId, hiddenId,
                          selectValue, textValue)
{
    CFWidget.call(this, id);
    var hiddenInput = cfElementGet(hiddenId);
    var selectBox = cfElementGet(selectBoxId);
    var selectOptions = selectBox.options;
    var selectTextValues = new Array();
    var textBox = cfElementGet(textBoxId);
    var textBoxLabel = textBoxLabelId.length ? cfElementGet(textBoxLabelId) :
                       undefined;
    for (var i = 0; i < selectOptions.length; i++) {
        var option = selectOptions[i];
        if (option.disabled) {
            selectTextValues.push(option.value);
            option.disabled = false;
        }
    }
    this.__hiddenInput = hiddenInput;
    this.__selectBox = selectBox;
    this.__selectTextValues = selectTextValues;
    this.__textBox = textBox;
    this.__textBoxLabel = textBoxLabel;
    this.__textBoxVisible = true;
    this.setValue(selectValue, textValue);
    cfElementRemoveClass(textBox, CFELEMENT_HIDDEN_CLASS);
    if (textBoxLabel) {
        cfElementRemoveClass(textBoxLabel, CFELEMENT_HIDDEN_CLASS);
    }
    var name = hiddenInput.name;
    hiddenInput.name = selectBox.name;
    selectBox.name = name;
    __cfExpandedSelectMap[id] = this;
    var f = cfEventHandlerCreate(this.__handleSelectBoxUpdate.bind(this));
    cfSelectSetChangeCallback(selectBox, f);
    f = cfEventHandlerCreate(this.__handleTextBoxBlur.bind(this));
    textBox.onblur = f;
}

CFExpandedSelect.extendClasses(CFWidget);

CFExpandedSelect.prototype.__handleSelectBoxUpdate = function()
{
    var selectValue = cfSelectGetValue(this.__selectBox);
    var textValue = this.__selectTextValues.contains(selectValue) ?
                    this.__textBox.value : undefined;
    this.setValue(selectValue, textValue);
    this.__triggerEvent(CFWIDGET_EVENT_USER_UPDATE);
}

CFExpandedSelect.prototype.__handleTextBoxBlur = function()
{
    this.setValue(cfSelectGetValue(this.__selectBox), this.__textBox.value);
    this.__triggerEvent(CFWIDGET_EVENT_USER_UPDATE);
}

CFExpandedSelect.prototype.getValue = function()
{
    return {
        selectValue: this.__selectValue,
        textValue: this.__textValue
    };
}

CFExpandedSelect.prototype.setValue = function(selectValue, textValue)
{
    var hiddenInput = this.__hiddenInput;
    var selectBox = this.__selectBox;
    var textBox = this.__textBox;
    var textBoxLabel = this.__textBoxLabel;
    var textBoxVisible = this.__textBoxVisible;
    if (this.__selectTextValues.contains(selectValue)) {
        cfSelectSetValue(selectBox, selectValue);
        textBox.value = textValue || '';
        if (! textBoxVisible) {
            cfElementRemoveClass(textBox, CFELEMENT_HIDDEN_CLASS);
            if (textBoxLabel) {
                cfElementRemoveClass(textBoxLabel, CFELEMENT_HIDDEN_CLASS);
            }
            this.__textBoxVisible = true;
        }
        hiddenInput.value = selectValue + ' ' + textValue;
    } else {
        if (textValue) {
            return cfErrorTrigger("CFExpandedSelect::setValue: ('" +
                                  selectValue + "', '" + textValue + "'): " +
                                  __CFEXPANDEDSELECT_ERROR_VALUE);
        }
        cfSelectSetValue(selectBox, selectValue);
        if (textBoxVisible) {
            cfElementAddClass(textBox, CFELEMENT_HIDDEN_CLASS);
            if (textBoxLabel) {
                cfElementAddClass(textBoxLabel, CFELEMENT_HIDDEN_CLASS);
            }
            this.__textBoxVisible = false;
        }
        hiddenInput.value = selectValue;
    }
    this.__selectValue = selectValue;
    this.__textValue = textValue;
}

////////////////////////////////////////////////////////////////////////////////
// Public API
////////////////////////////////////////////////////////////////////////////////

function cfExpandedSelectCreate(arg)
{
    return new CFExpandedSelect(arg.id, arg.selectBoxId, arg.textBoxId,
                                arg.textBoxLabelId, arg.hiddenId,
                                arg.selectValue, arg.textValue);
}

function cfExpandedSelectGet(id)
{
    var select = __cfExpandedSelectMap[id];
    if (! select) {
        return cfErrorTrigger("cfExpandedSelectGet: '" + id + "': " +
                              __CFEXPANDEDSELECT_ERROR_ID);
    }
    return select;
}
