# Source: ui/base/abstract-number-field.js

    /*global require, exports, document, Error*/
    var AbstractControl = require("./abstract-control").AbstractControl,
        KeyComposer = require("../../composer/key-composer").KeyComposer;

    var CLASS_PREFIX = "montage-NumberField";

    /**
     * @class AbstractNumberField
     * @extends AbstractControl
     */
    var AbstractNumberField = exports.AbstractNumberField = AbstractControl.specialize(
    /** @lends AbstractNumberField# */
    {

        // Life Cycle

        constructor: {
            value: function AbstractNumberField() {
                if (this.constructor === AbstractNumberField) {
                    throw new Error("AbstractNumberField cannot be instantiated.");
                }

                this._propertyNamesUsed = {};
                this.defineBinding( "classList.has('montage--disabled')", { "<-": "!enabled" });
            }
        },

        enterDocument: {
            value: function (firstTime) {
                if (firstTime) {

                    // read initial values from the input type=range
                    var used = this._propertyNamesUsed;
                    if (!used.min) {
                        this.min = this.element.getAttribute('min') || this._min;
                    }
                    if (!used.max) {
                        this.max = this.element.getAttribute('max') || this._max;
                    }
                    if (!used.step) {
                        this.step = this.element.getAttribute('step') || this._step;
                    }
                    if (!used.value) {
                        this.value = this.element.getAttribute('value') || this._value;
                    }
                    delete this._propertyNamesUsed;

                    this._numberFieldTextFieldComponent.addEventListener("action", this, false);
                    this._numberFieldMinusComponent.addEventListener("action", this, false);
                    this._numberFieldPlusComponent.addEventListener("action", this, false);

                    this._numberFieldTextFieldComponent.delegate = this;

                    // needs to be fixed for pointer handling
                    this.element.addEventListener("mousedown", this, false);

                    this.element.tabIndex = "-1";

                    this._upKeyComposer = KeyComposer.createKey(this, "up", "increase");
                    this._downKeyComposer = KeyComposer.createKey(this, "down", "decrease");
                    this._rightKeyComposer = KeyComposer.createKey(this, "right", "increase");
                    this._leftKeyComposer = KeyComposer.createKey(this, "left", "decrease");
                }
            }
        },

        textFieldShouldBeginEditing: {
            value: function () {
                return this.enabled;
            }
        },

        textFieldDidChange: {
            value: function () {
            }
        },

        textFieldDidEndEditing: {
            value: function () {
                this.value = this._numberFieldTextFieldComponent.value;
            }
        },

        textFieldShouldAcceptValue: {
            value: function (textField, value) {
                if (this._activeValueChange === true) {
                    return true;
                }
            }
        },

        prepareForActivationEvents: {
            value: function () {
                this._upKeyComposer.addEventListener("keyPress", this, false);
                this._downKeyComposer.addEventListener("keyPress", this, false);
                this._leftKeyComposer.addEventListener("keyPress", this, false);
                this._rightKeyComposer.addEventListener("keyPress", this, false);
            }
        },

        draw: {
            value: function () {
                this.element.setAttribute("aria-valuemax", this.max);
                this.element.setAttribute("aria-valuemin", this.min);
                this.element.setAttribute("aria-valuenow", this.value);
            }
        },

        // Event Handlers

        acceptsActiveTarget: {
            value: true
        },

        handleMousedown: {
            value: function () {
                this.element.focus();
            }
        },

        /**
         * Handle increment-button action
         * @private
         */
        handlePlusAction: {
            value: function () {
                this._activeValueChange = true;
                var step = this.step * this._stepDecimal;
                var stepBase = (typeof this.min === "number") ? this.min * this._stepDecimal : 0;
                var value = (this.value * this._stepDecimal) - stepBase;
                if (value % step) {
                    if (value < 0) {
                        value -= value % step;
                    } else {
                        value += step - (value % step);
                    }
                } else {
                    value += step;
                }
                this.value = (value + stepBase) / this._stepDecimal;
                this._activeValueChange = false;
            }
        },

        /**
         * Handle decrement-button action
         * @private
         */
        handleMinusAction: {
            value: function () {
                this._activeValueChange = true;
                var step = this.step * this._stepDecimal;
                var stepBase = (typeof this.min === "number") ? this.min * this._stepDecimal : 0;
                var value = (this.value * this._stepDecimal) - stepBase;
                if (value % step) {
                    if (value > 0) {
                        value -= value % step;
                    } else {
                        value -= step + (value % step);
                    }
                } else {
                    value -= step;
                }
                this.value = (value + stepBase) / this._stepDecimal;
                this._activeValueChange = false;
            }
        },

        handleKeyPress: {
            value: function (event) {
                if (!this.enabled) {
                    return;
                }
                if(event.identifier === "increase") {
                    this.handlePlusAction();
                } else if (event.identifier === "decrease") {
                    this.handleMinusAction();
                }
            }
        },

        handleAction: {
            value: function (event) {
                if (event.target === this._numberFieldTextFieldComponent ||
                    event.target === this._numberFieldMinusComponent ||
                    event.target === this._numberFieldPlusComponent) {
                    event.stopPropagation();
                    this.dispatchActionEvent();
                }
            }
        },

        // Properties

        _value: {
            value: 0
        },

        _required: {
            value: false
        },

        _min: {
            value: "any"
        },

        _max: {
            value: "any"
        },

        _step: {
            value: 1
        },

        /**
         * The maximum value allowed in the InputNumber. Can be any number or the string "any".
         * @type {number|string}
         * @default "any"
         */
        min: {
            get: function () {
                return this._min;
            },
            set: function (value) {
                if (value !== "any" && isNaN(value = parseFloat(value))) {
                    return false;
                }
                if (this._min !== value) {
                    if (this._propertyNamesUsed) {
                        this._propertyNamesUsed.min = true;
                    }
                    this._min = value;
                    this.needsDraw = true;
                    if (typeof value === "number" && this.value < value) {
                        this.value = value;
                    }
                }
            }
        },

        /**
         * The maximum value allowed in the InputNumber. Can be any number or the string "any".
         * @type {number|string}
         * @default "any"
         */
        max: {

            get: function () {
                return this._max;
            },
            set: function (value) {
                if (value !== "any" && isNaN(value = parseFloat(value))) {
                    return false;
                }
                if (this._max !== value) {
                    if (this._propertyNamesUsed) {
                        this._propertyNamesUsed.max = true;
                    }
                    this._max = value;
                    this.needsDraw = true;
                    if (typeof value === "number" && this.value > value) {
                        this.value = value;
                    }
                }
            }
        },

        _stepDecimal: {
            value: 1
        },

        /**
         * The amount the value changes when using the plus/minus buttons. Can be any positive number.
         * @type {number}
         * @default 1
         */
        step: {
            get: function () {
                return this._step;
            },
            set: function (value) {
                if (isNaN(value = parseFloat(value)) || value <= 0) {
                    return false;
                }
                if (this._step !== value) {
                    if (this._propertyNamesUsed) {
                        this._propertyNamesUsed.step = true;
                    }
                    this._step = value;
                    var decimalPart = String(value).match(/\.(\d+)$/);
                    if (decimalPart) {
                        this._stepDecimal = Math.pow(10, decimalPart[1].length);
                    } else {
                        this._stepDecimal = 1;
                    }
                }
            }
        },

        /**
         * The value of the InputNumber
         * @type {number}
         * @default 0
         */
        value: {
            get: function () {
                return this._value;
            },
            set: function (value) {
                if (value === null || value === undefined || typeof value.valueOf === "undefined") {
                    this._value = "";
                } else if (! isNaN(value = parseFloat(value))) {
                    if (typeof this.min === 'number' && value < this.min) {
                        value = this.min;
                    }
                    if (typeof this.max === 'number' && value > this.max) {
                        value = this.max;
                    }
                    if (this._value !== value) {
                        if (this._propertyNamesUsed) {
                            this._propertyNamesUsed.value = true;
                        }
                        this._value = value;
                        this.needsDraw = true;
                    }
                }
                if(this._numberFieldTextFieldComponent && this._value !==  this._numberFieldTextFieldComponent.value) {
                    this._numberFieldTextFieldComponent.value = this._value;
                }
            }
        },

        /**
         * Wether or not the number field acccepts user input
         * @type {number}
         * @default 0
         */
        enabled: {
            value: true
        },

        // Machinery

        _numberFieldTextFieldComponent: {
            value: null
        },

        _numberFieldMinusComponent: {
            value: null
        },

        _numberFieldPlusComponent: {
            value: null
        },

        _activeValueChange: {
            value: false
        }

    });