var ObjectComponent = require('./../core/ObjectComponent');

var Node      = require('../core/document/Node');
var ColorMode = require('../core/color/ColorMode');
var Picker    = require('./Picker');
var ColorUtil = require('../core/color/ColorUtil');
var Options   = require('./Options');
var ButtonPreset = require('./ButtonPreset');
var Metric = require('./Metric'),
    CSS    = require('../core/document/CSS');

var Event_         = require('../core/event/Event'),
    NodeEvent      = require('../core/document/NodeEvent'),
    ComponentEvent = require('../core/ComponentEvent');

var ColorFormatError = require('../core/color/ColorFormatError');

var DEFAULT_COLOR_MODE = ColorMode.HEX,
    DEFAULT_PRESETS = null;

var MSG_COLOR_FORMAT_HEX = 'Color format should be hex. Set colorMode to rgb, rgbfv or hsv.',
    MSG_COLOR_FORMAT_RGB_RGBFV_HSV = 'Color format should be rgb, rgbfv or hsv. Set colorMode to hex.',
    MSG_COLOR_PRESET_FORMAT_HEX = 'Preset color format should be hex.',
    MSG_COLOR_PRESET_FORMAT_RGB_RGBFV_HSV = 'Preset color format should be rgb, rgbfv or hsv.';

function Color(parent, object, value, params){
    ObjectComponent.apply(this, arguments);

    params = params || {};
    params.presets = params.presets || DEFAULT_PRESETS;
    params.colorMode = params.colorMode || DEFAULT_COLOR_MODE;
    params.onChange = params.onChange || this._onChange;


    this._presetsKey = params.presets;
    this._onChange = params.onChange;

    var color = this._color = new Node();
    value = this._value = this._obj[this._key];

    var colorMode = this._colorMode = params.colorMode;

    this._validateColorFormat(value, MSG_COLOR_FORMAT_HEX, MSG_COLOR_FORMAT_RGB_RGBFV_HSV);

    var wrap = this._wrapNode;

    if(!this._presetsKey){
        color.setStyleClass(CSS.Color);
        wrap.addChild(color);
    }
    else{
        color.setStyleClass(CSS.Color);

        var wrap_ = new Node();
        wrap_.setStyleClass(CSS.WrapColorWPreset);

        wrap.addChild(wrap_);
        wrap_.addChild(color);

        var presets = this._obj[this._presetsKey];

        var i = -1;
        while(++i < presets.length){
            this._validateColorFormat(presets[i], MSG_COLOR_PRESET_FORMAT_HEX,
                MSG_COLOR_PRESET_FORMAT_RGB_RGBFV_HSV);
        }

        var options = Options.get(),
            presetBtn = new ButtonPreset(wrap);

        var onPresetDeactivate = function(){
            options.clear();
            presetBtn.deactivate();
        };

        var self = this;
        var onPresetActivate = function(){
            options.build(presets,
                self._value,
                color,
                function(){
                    self.pushHistoryState();
                    self._value = presets[options.getSelectedIndex()];
                    self.applyValue();
                    self._onChange(self._obj[self._key]);
                },
                onPresetDeactivate,
                Metric.PADDING_PRESET,
                true,
                colorMode);
        };
        presetBtn.setOnActive(onPresetActivate);
        presetBtn.setOnDeactive(onPresetDeactivate);
    }

    color.addEventListener(NodeEvent.MOUSE_DOWN, this._onColorTrigger.bind(this));
    this._updateColor();
}
Color.prototype = Object.create(ObjectComponent.prototype);
Color.prototype.constructor = Color;

Color.prototype._onColorTrigger = function(){
    var colorMode = this._colorMode,
        colorModeHEX = ColorMode.HEX,
        colorModeRGB = ColorMode.RGB,
        colorModeRGBfv = ColorMode.RGBfv,
        colorModeHSV = ColorMode.HSV;

    var value = this._value,
        temp;

    var onPickerPick = function(){
        this.pushHistoryState();

        switch(colorMode){
            case colorModeHEX:
                this._value = Picker.get().getHEX();
                break;
            case colorModeRGB:
                //if val = Float32array or so
                temp = Picker.get().getRGB();
                value[0] = temp[0];
                value[1] = temp[1];
                value[2] = temp[2];
                break;

            case colorModeRGBfv:
                temp = Picker.get().getRGBfv();
                value[0] = temp[0];
                value[1] = temp[1];
                value[2] = temp[2];
                break;

            case colorModeHSV:
                this._value = Picker.get().getHSV();
                break;
        }

        this.applyValue();

    }.bind(this);

    var picker = Picker.get();

    switch(colorMode){
        case colorModeHEX:
            picker.setColorHEX(value);
            break;
        case colorModeRGB:
            picker.setColorRGB(value[0], value[1], value[2]);
            break;
        case colorModeRGBfv:
            picker.setColorRGBfv(value[0], value[1], value[2]);
            break;
        case colorModeHSV:
            picker.setColorHSV(value[0], value[1], value[2]);
            break;
    }

    picker.setCallbackPick(onPickerPick);
    picker.open();
};

Color.prototype.applyValue = function(){
    this._obj[this._key] = this._value;
    this._updateColor();
    this.dispatchEvent(new Event_(this, ComponentEvent.VALUE_UPDATED, null));
    this._onChange(this._obj[this._key]);
};

Color.prototype.onValueUpdate = function(e){
    if(e.data.origin == this)return;
    this._value = this._obj[this._key];
    this._updateColor();
};

Color.prototype._updateColor = function(){
    var color = this._value,
        colorNode = this._color,
        nodeColor;

    colorNode.setProperty('innerHTML', color);

    switch(this._colorMode){
        case ColorMode.HEX:
            nodeColor = color;
            break;

        case ColorMode.RGB:
            nodeColor = ColorUtil.RGB2HEX(color[0], color[1], color[2]);
            break;

        case ColorMode.RGBfv:
            nodeColor = ColorUtil.RGBfv2HEX(color[0], color[1], color[2]);
            break;

        case ColorMode.HSV:
            nodeColor = ColorUtil.HSV2RGB(color[0], color[1], color[2]);
            break;
    }

    colorNode.getStyle().backgroundColor = nodeColor;
};

Color.prototype._validateColorFormat = function(value, msgHex, msgArr){
    var colorMode = this._colorMode;

    if(colorMode == ColorMode.HEX && Object.prototype.toString.call(value) === '[object Array]' ||
        colorMode == ColorMode.HEX && Object.prototype.toString.call(value) === '[object Float32Array]'){
        throw new ColorFormatError(msgHex);
    }
    if((colorMode == ColorMode.RGB ||
        colorMode == ColorMode.RGBfv ||
        colorMode == ColorMode.HSV) &&
        Object.prototype.toString.call(value) !== '[object Array]' ||
        colorMode == ColorMode.HSV &&
        Object.prototype.toString.call(value) !== '[object Float32Array]'){
        throw new ColorFormatError(msgArr);
    }
};

module.exports = Color;
