/* <copyright>
This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
(c) Copyright 2011 Motorola Mobility, Inc.  All Rights Reserved.
</copyright> */

var Montage = require("montage/core/core").Montage;
var SliderBase = require("js/components/sliderbase").SliderBase;

var HotText = exports.HotText = Montage.create(SliderBase, {
    /* Allow users to specify a function to format the display.
    * For example, the Color Picker can specify a function to map
    * the numeric hot text value to hex color values.
     */
    labelFunction: {
        serializable: true,
        enumerable: true,
        value: null
    },

    inputFunction: {
        serializable: true,
        enumerable: true,
        value: parseFloat
    },

    _numValue: {
        enumerable: false,
        value: 0
    },

    numValue: {
        serializable: false,
        enumerable: true,
        get: function() {
            return this._numValue;
        },
        set: function(value) {
            if (value < this._minValue) {
                value = this._minValue;
            }
            if (value > this._maxValue) {
                value = this._maxValue;
            }
            if (value !== this._numValue) {
                this._numValue = Math.round(value * this._decimalPlace)/this._decimalPlace;
            }
        }
    },

    _previousValue: {
        enumerable: false,
        value: null
    },

    _stepSize: {
        enumerable: false,
        value: 1
    },

    stepSize: {
        serializable: true,
        enumerable: true,
        get: function() {
            return this._stepSize;
        },
        set: function(value) {
            if (value !== this._stepSize) {
                this._stepSize = value;
                this.needsDraw = true;
            }
        }
    },

    _stepSizeShift: {
        enumerable: false,
        value: 10
    },

    _xStart: {
        enumerable: false,
        value: 0
    },

    _yStart: {
        enumerable: false,
        value: 0
    },

    // Needed to determine when to commit a value change
    _wasShiftKeyPressed: {
        enumerable: false,
        value: false
    },

    // for ones, use 1
    // for tenths, use 10
    // for hundredths, use 100, etc.
    _decimalPlace: {
        enumerable: false,
        value: 1
    },

    decimalPlace: {
        serializable: true,
        enumerable: true,
        get: function() {
            return this._decimalPlace;
        },
        set: function(value) {
            if (value !== this._decimalPlace) {
                this._decimalPlace = value;
                this.needsDraw = true;
            }
        }
    },

    // TODO - Need to set max value to 2000 for demo.
    _maxValue: {
        enumerable: false,
        value: 2000
    },

    value: {
        serializable: true,
        enumerable: true,
        get: function() {
            return this._value;
        },
        set: function(value, fromInput) {
            if (isNaN(value)) {
                this._valueSyncedWithInputField = false;
                this.needsDraw = true;
                return;
            }
            if (value < this._minValue) {
                value = this._minValue;
                this._valueSyncedWithInputField = false;
                this.needsDraw = true;
            }
            else if (value > this._maxValue) {
                value = this._maxValue;
                this._valueSyncedWithInputField = false;
                this.needsDraw = true;
            }

            if (value !== this._value) {
                this._value = this._numValue = Math.round(value * this._decimalPlace)/this._decimalPlace;
                this._valueSyncedWithInputField = false;
                this.needsDraw = true;
                this._dispatchActionEvent();
            }
        }
    },

    _valueSyncedWithInputField: {
        enumerable: false,
        value: false
    },

    // We don't want to handle every input; we only want to handle input from tab or enter
    // Thus, we don't listen for an input event; we call this from handleKeydown
    handleInput: {
        enumerable: false,
        value: function() {
            this._setEventFlags("change", false);
            Object.getPropertyDescriptor(this, "value").set.call(this, this.inputFunction(this.element.value), true);
        }
    },


    _valueFromPageOffset: {
        value: function(offset, pageY, isShiftKeyPressed, wasSetByCode) {
            if(!this._isMouseDown)
            {
                this._handleMoveEnd();  // If the user has moused up, check if we should go into input mode
                return;
            }

            var clickPoint = webkitConvertPointFromPageToNode(this.element, new WebKitPoint(offset,pageY));

            var dX = clickPoint.x - this._xStart;
            var dY = clickPoint.y - this._yStart;
            
            var dXAbs = Math.abs(dX);
            var dYAbs = Math.abs(dY);

            if( (dXAbs < 5) && (dYAbs < 5) )
            {
                return; // Don't process unless the user moves at least 5 pixels
            }

            var incrementVal = dXAbs-4;     // otherwise, the first value change will be 5 pixels
            var multFactor = 1;            

            if(dXAbs > dYAbs)
            {
                if(dX < 0)
                {
                    multFactor = -1;
                }
            }
            else
            {
                if(dY > 0)
                {
                    multFactor = -1;
                }
                incrementVal = dYAbs-4;
            }

            if(isShiftKeyPressed)
            {
                if(!this._wasShiftKeyPressed)
                {
                    this._xStart = clickPoint.x;
                    this._yStart = clickPoint.y;
                    this._previousValue = this._numValue;
                    incrementVal = 1;
                }
                this.numValue = this._previousValue + multFactor * incrementVal * this._stepSizeShift;
                this._wasShiftKeyPressed = true;
            }
            else
            {
                if(this._wasShiftKeyPressed)
                {
                    this._xStart = clickPoint.x;
                    this._yStart = clickPoint.y;
                    this._previousValue = this._numValue;
                    incrementVal = 1;
                    this._wasShiftKeyPressed = false;
                }
                this.numValue = this._previousValue + multFactor * incrementVal * this._stepSize;
            }

            this.value = this._numValue;
        }
    },

    handleKeydown: {
        enumerable: false,
        value: function(event) {
            switch(event.keyCode)
            {
                case 9: //tab
                case 13: // enter
                    this.handleInput();
                    break;
                case 27: // esc
                    this._valueSyncedWithInputField = false;
                    this.needsDraw = true;
                    break;
                case 38: // up
                    this._setEventFlags("change", false);
                    this.value += this._stepSize;
                    break;
                case 40: // down
                    this._setEventFlags("change", false);
                    this.value -= this._stepSize;
                    break;
                default:
//                    return;
            }
        }
    },

    handleBlur: {
        enumerable: false,
        value: function(event) {
            event.target = this;
            this._hasFocus = false;

            this.handleInput(); // Check if value has changed when focusing out
            this.needsDraw = true;

            this.dispatchEvent(event);
        }
    },

    handleFocus: {
        enumerable: false,
        value: function(event) {
            event.target = this;
            this._hasFocus = true;
            this.dispatchEvent(event);
        }
    },

    _handleMoveEnd: {
        value: function() {
            // If we don't change value (mouse up on ourself), we should go into text edit mode
            if(this._numValue === this._previousValue)
            {
                this._hasFocus = true;
            }
            else
            {
                this._hasFocus = false;
                this._dispatchActionEvent();
            }
            this.needsDraw = true;
        }
    },

    draw: {
        enumerable: false,
        value: function() {
            if(this._hasFocus)
            {
                if(!this._isMouseDown)
                {
                    this.element.classList.remove("hottext");
                    this.element.classList.add("hottextInput");

                    // if element targeted; balancing demands of multitouch
                    // with traditional single focus model
                    this.element.addEventListener("keydown", this, false);
                }
            }
            else
            {
                this.element.classList.remove("hottextInput");
                this.element.classList.add("hottext");
            }

            if (!this._valueSyncedWithInputField)
            {
                if(this.labelFunction)
                {
                    this.element.value = this.labelFunction(this._value);
                }
                else
                {
                    this.element.value = this._value;
                }
            }
        }
    },

    didDraw: {
        enumerable: false,
        value: function() {
            if(!this._isMouseDown && this._hasFocus)
            {
                var length = 0;
                if(this.labelFunction)
                {
                    length = this.labelFunction(this._value).length;
                }
                else
                {
                    length = this._value.toString().length;
                }
                this.element.setSelectionRange(0, length);
            }
            this._valueSyncedWithInputField = true;
        }
    },

    prepareForDraw: {
        value: function() {
            if(this._value)
            {
                this._numValue = this._value;
            }

            if(this._enabled)
            {
                this.element.addEventListener("blur", this);
                this.element.addEventListener("focus", this);

                // TODO only install low level event listeners for high level
                // events others listen to us for
                this.element.addEventListener("touchstart", this, false);
                this.element.addEventListener("mousedown", this, false);
            }
        }
    }

});