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

var __CFWEIGHT_ERROR_EDITOR_ID = "invalid CFWeightEditor id";
var __CFWEIGHT_ERROR_VALUE = "invalid weight value";

var __CFWEIGHT_GRAMS_IN_KILOGRAM = 1000.0;
var __CFWEIGHT_GRAMS_IN_POUND = 453.59237;
var __CFWEIGHT_MAXIMUM_VALUE = 100000;
var __CFWEIGHT_OUNCES_IN_POUND = 16.0;

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

var __cfWeightEditorMap = {};

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

// CFWeightEditor

function CFWeightEditor(id, systemCheckBoxId, systemLabelId, largeUnitSpinnerId,
                        smallUnitSpinnerId, smallUnitSpinnerWrapperId, hiddenId,
                        gramsDescriptionId, kilogramsDescriptionId,
                        ouncesDescriptionId, poundsDescriptionId, value)
{
    CFWidget.call(this, id);
    var hiddenInput = cfElementGet(hiddenId);
    var largeUnitSpinner = cfSpinnerGet(largeUnitSpinnerId);
    var ouncesDescription = cfElementGet(ouncesDescriptionId);
    var smallUnitSpinner = cfSpinnerGet(smallUnitSpinnerId);
    var systemCheckBox = cfElementGet(systemCheckBoxId);
    this.__gramsDescription = cfElementGet(gramsDescriptionId);
    this.__hiddenInput = hiddenInput;
    this.__kilogramsDescription = cfElementGet(kilogramsDescriptionId);
    this.__largeUnitSpinner = largeUnitSpinner;
    this.__ouncesDescription = ouncesDescription;
    this.__poundsDescription = cfElementGet(poundsDescriptionId);
    this.__smallUnitSpinner = smallUnitSpinner;
    this.__systemCheckBox = systemCheckBox;
    this.__usingMetricSystem = false;
    this.setValue(value);
    cfElementRemoveClass(cfElementGet(systemLabelId), CFELEMENT_HIDDEN_CLASS);
    cfElementRemoveClass(cfElementGet(smallUnitSpinnerWrapperId),
                         CFELEMENT_HIDDEN_CLASS);
    cfElementRemoveClass(ouncesDescription, CFELEMENT_HIDDEN_CLASS);
    cfElementRemoveClass(systemCheckBox, CFELEMENT_HIDDEN_CLASS);
    var name = hiddenInput.name;
    hiddenInput.name = largeUnitSpinner.getName();
    largeUnitSpinner.setName(name);
    __cfWeightEditorMap[id] = this;
    var f = cfEventHandlerCreate(this.__handleSystemCheckBoxUpdate.bind(this));
    cfCheckBoxSetChangeCallback(systemCheckBox, f);
    var f = cfEventHandlerCreate(this.__handleValueUpdate.bind(this));
    largeUnitSpinner.addEventHandler(CFWIDGET_EVENT_USER_UPDATE, f);
    smallUnitSpinner.addEventHandler(CFWIDGET_EVENT_USER_UPDATE, f);
}

CFWeightEditor.extendClasses(CFWidget);

CFWeightEditor.prototype.__handleSystemCheckBoxUpdate = function()
{
    var checked = this.__systemCheckBox.checked;
    if (checked != this.__usingMetricSystem) {
        gramsDescription = this.__gramsDescription;
        kilogramsDescription = this.__kilogramsDescription;
        ouncesDescription = this.__ouncesDescription;
        poundsDescription = this.__poundsDescription;
        if (checked) {
            cfElementAddClass(ouncesDescription, CFELEMENT_HIDDEN_CLASS);
            cfElementAddClass(poundsDescription, CFELEMENT_HIDDEN_CLASS);
            cfElementRemoveClass(gramsDescription, CFELEMENT_HIDDEN_CLASS);
            cfElementRemoveClass(kilogramsDescription, CFELEMENT_HIDDEN_CLASS);
        } else {
            cfElementAddClass(gramsDescription, CFELEMENT_HIDDEN_CLASS);
            cfElementAddClass(kilogramsDescription, CFELEMENT_HIDDEN_CLASS);
            cfElementRemoveClass(ouncesDescription, CFELEMENT_HIDDEN_CLASS);
            cfElementRemoveClass(poundsDescription, CFELEMENT_HIDDEN_CLASS);
        }
        this.__usingMetricSystem = checked;
        this.refresh();
        this.__triggerEvent(CFWIDGET_EVENT_USER_UPDATE);
    }
}

CFWeightEditor.prototype.__handleValueUpdate = function()
{
    var largeValue = this.__largeUnitSpinner.getValue();
    var smallValue = this.__smallUnitSpinner.getValue();
    var value;
    if (this.__usingMetricSystem) {
        value = ((largeValue * __CFWEIGHT_GRAMS_IN_KILOGRAM) + smallValue) /
                __CFWEIGHT_GRAMS_IN_POUND;
    } else {
        value = largeValue + (smallValue / __CFWEIGHT_OUNCES_IN_POUND);
    }
    if (value > __CFWEIGHT_MAXIMUM_VALUE) {
        value = __CFWEIGHT_MAXIMUM_VALUE;
    } else if (value < 0) {
        value = 0;
    }
    this.__setValue(value);
    this.__triggerEvent(CFWIDGET_EVENT_USER_UPDATE);
}

CFWeightEditor.prototype.__setValue = function(value)
{
    var n = new Number(value);
    if (isNaN(n) || (n < 0) || (n > __CFWEIGHT_MAXIMUM_VALUE)) {
        return cfErrorTrigger("CFWeightEditor::setValue: '" + value + "': " +
                              __CFWEIGHT_ERROR_VALUE);
    }
    this.__value = n;
    this.__hiddenInput.value = n.toString();
}

CFWeightEditor.prototype.getValue = function()
{
    return this.__value;
}

CFWeightEditor.prototype.refresh = function()
{
    CFWidget.prototype.refresh.call(this);
    var largeUnitSpinner = this.__largeUnitSpinner;
    var smallUnitSpinner = this.__smallUnitSpinner;
    var value = this.__value;
    if (this.__usingMetricSystem) {
        var grams = value * __CFWEIGHT_GRAMS_IN_POUND;
        var kilograms = grams / __CFWEIGHT_GRAMS_IN_KILOGRAM;
        largeUnitSpinner.setValue(kilograms.getBase());
        smallUnitSpinner.setValue(kilograms.getFraction() *
                                  __CFWEIGHT_GRAMS_IN_KILOGRAM);
    } else {
        largeUnitSpinner.setValue(value.getBase());
        smallUnitSpinner.setValue(value.getFraction() *
                                  __CFWEIGHT_OUNCES_IN_POUND);
    }
}

CFWeightEditor.prototype.setValue = function(value)
{
    this.__setValue(value);
    this.refresh();
}

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

function cfWeightEditorCreate(arg)
{
    return new CFWeightEditor(arg.id, arg.systemCheckBoxId, arg.systemLabelId,
                              arg.largeUnitSpinnerId, arg.smallUnitSpinnerId,
                              arg.smallUnitSpinnerWrapperId, arg.hiddenId,
                              arg.gramsDescriptionId,
                              arg.kilogramsDescriptionId,
                              arg.ouncesDescriptionId, arg.poundsDescriptionId,
                              arg.value);
}

function cfWeightEditorGet(id)
{
    var editor = __cfWeightEditorMap[id];
    if (! editor) {
        return cfErrorTrigger("cfWeightEditorGet: '" + id + "': " +
                              __CFWEIGHT_ERROR_EDITOR_ID);
    }
    return editor;
}
