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

var __CFSELECT_ERROR_INDEX = "invalid select box index";
var __CFSELECT_ERROR_VALUE = "invalid select box value";
var __CFSELECT_ERROR_VALUES = "invalid select box values";

////////////////////////////////////////////////////////////////////////////////
// Private functions
////////////////////////////////////////////////////////////////////////////////

function __cfSelectVerifyIndex(box, index, declineNegativeOne)
{
    if (((index < -1) || (index > box.options.length)) ||
        ((index == -1) && declineNegativeOne)) {
        return cfErrorTrigger("__cfSelectVerifyIndex: " + index + ": " +
                              __CFSELECT_ERROR_INDEX);
    }
}

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

function cfSelectClearOptions(box)
{
    var options = box.options;
    while (options.length) {
        box.remove(0);
    }
}

function cfSelectGetAvailableValues(box)
{
    var options = box.options;
    var values = new Array();
    for (var i = 0; i < options.length; i++) {
        values.push(options[i].value);
    }
    return values;
}

function cfSelectGetDeselectedValues(box)
{
    var options = box.options;
    var values = new Array();
    for (var i = 0; i < options.length; i++) {
        var option = options[i];
        if (! option.selected) {
            values.push(option.value);
        }
    }
    return values;
}

function cfSelectGetSelectedIndices(box)
{
    var indices = new Array();
    var options = box.options;
    for (var i = 0; i < options.length; i++) {
        if (options[i].selected) {
            indices.push(i);
        }
    }
    return indices;
}

function cfSelectGetValue(box)
{
    var index = box.selectedIndex;
    return (index == -1) ? undefined : box.options[index].value;
}

function cfSelectGetValues(box)
{
    var options = box.options;
    var values = new Array();
    for (var i = 0; i < options.length; i++) {
        var option = options[i];
        if (option.selected) {
            values.push(option.value);
        }
    }
    return values;
}

function cfSelectSetAllValues(box)
{
    var args = new Array();
    for (var i = 0; i < box.options.length; i++) {
        args.push(i);
    }
    cfSelectSetSelectedIndices(box, args);
}

function cfSelectSetChangeCallback(box, f)
{
    box.onchange = f;
    box.onkeyup = f;
}

function cfSelectSetOptions(box, options)
{
    cfSelectClearOptions(box);
    for (var i = 0; i < options.length; i++) {
        box.add(options[i], undefined);
    }
}

function cfSelectSetSelectedIndex(box, index)
{
    __cfSelectVerifyIndex(box, index);
    box.selectedIndex = index;
}

function cfSelectSetSelectedIndices(box, indices)
{
    for (var i = 0; i < indices.length; i++) {
        __cfSelectVerifyIndex(box, indices[i], true);
    }
    var multiple = (indices.length > 1) || box.multiple;
    var options = box.options;
    if (multiple) {
        box.multiple = true;
    }
    for (var i = 0; i < options.length; i++) {
        options[i].selected = indices.indexOf(i) != -1;
    }
    if (multiple) {
        // Make IE refresh the box to avoid delay of option selections
        box.focus();
        box.blur();
    }
}

function cfSelectSetValue(box, value, selectEmptyIndex)
{
    var index = -1;
    var result = true;
    if (typeof(value) != "undefined") {
        var options = box.options;
        for (var i = 0; i < options.length; i++) {
            if (value == options[i].value) {
                index = i;
                break;
            }
        }
        if (index == -1) {
            if (! selectEmptyIndex) {
                return cfErrorTrigger("cfSelectSetValue: '" + value + "': " +
                                      __CFSELECT_ERROR_VALUE);
            }
            result = false;
        }
    }
    box.selectedIndex = index;
    return result;
}

function cfSelectSetValues(box, values)
{
    var indices = new Array();
    var options = box.options;
    values = values.copy();
    for (var i = 0; i < options.length; i++) {
        var index = values.indexOf(options[i].value);
        if (index != -1) {
            indices.push(i);
            values.splice(index, 1);
        }
    }
    if (values.length) {
        return cfErrorTrigger("cfSelectSetValues: [" + values + "]: " +
                              __CFSELECT_ERROR_VALUES);
    }
    cfSelectSetSelectedIndices(box, indices);
}

