import Dom from '../util/Dom'
import ColorSetsList from './module/ColorSetsList'
import UIElement from './UIElement'
import ColorManager from './module/ColorManager';
import BaseStore from './BaseStore';

export default class BaseColorPicker extends UIElement {

    constructor (opt) {
        super(opt);

        this.isColorPickerShow = false;
        this.isShortCut = false;
        this.hideDelay = +(typeof this.opt.hideDeplay == 'undefined' ? 2000 : this.opt.hideDelay);
        this.timerCloseColorPicker;
        this.autoHide = this.opt.autoHide || true;
        this.outputFormat = this.opt.outputFormat
        this.$checkColorPickerClass = this.checkColorPickerClass.bind(this);

    }

    initialize () {
        this.$body = null;
        this.$root = null; 
        
        this.$store = new BaseStore({
            modules: [
                ColorManager,
                ColorSetsList
            ]
        });

        this.callbackChange = () => {
            this.callbackColorValue()
        }

        this.callbackLastUpdate = () => {
            this.callbackLastUpdateColorValue()
        }        

        this.colorpickerShowCallback = function () { };
        this.colorpickerHideCallback = function () { };   
        this.colorpickerLastUpdateCallback = function () { };           


        this.$body = new Dom(this.getContainer());
        this.$root = new Dom('div', 'codemirror-colorpicker');

        //  append colorpicker to container (ex : body)
        if (this.opt.position == 'inline') {
            this.$body.append(this.$root);
        }

        if (this.opt.type) {    // to change css style
            this.$root.addClass(this.opt.type);
        }

        if (this.opt.hideInformation) {
            this.$root.addClass('hide-information')
        }

        if (this.opt.hideColorsets) {
            this.$root.addClass('hide-colorsets')
        }        

        this.$arrow = new Dom('div', 'arrow');
        
        this.$root.append(this.$arrow);

        this.$store.dispatch('/setUserPalette', this.opt.colorSets);

        this.render()

        this.$root.append(this.$el)

        this.initColorWithoutChangeEvent(this.opt.color);

        // 이벤트 연결 
        this.initializeEvent();           

    }

    initColorWithoutChangeEvent (color) {
        this.$store.dispatch('/initColor', color);
    }

    /** 
     * public method 
     * 
     */

    /**
     * 
     * show colorpicker with position  
     * 
     * @param {{left, top, hideDelay, isShortCut}} opt 
     * @param {String|Object} color  
     * @param {Function} showCallback  it is called when colorpicker is shown
     * @param {Function} hideCallback  it is called once when colorpicker is hidden
     */
    show(opt, color, showCallback, hideCallback, lastUpdateCallback) {

        // 매번 이벤트를 지우고 다시 생성할 필요가 없어서 초기화 코드는 지움. 
        // this.destroy();
        // this.initializeEvent();
        // define colorpicker callback
        this.colorpickerShowCallback = showCallback;
        this.colorpickerHideCallback = hideCallback;    
        this.colorpickerLastUpdateCallback = lastUpdateCallback;        
        this.$root.css(this.getInitalizePosition()).show();


        this.isColorPickerShow = true;
        this.isShortCut = opt.isShortCut || false;
        this.outputFormat = opt.outputFormat  

        // define hide delay
        this.hideDelay = +(typeof opt.hideDelay == 'undefined' ? 2000 : opt.hideDelay );
        if (this.hideDelay > 0) {
            this.setHideDelay(this.hideDelay);
        }        
        
        this.$root.appendTo(this.$body);
        this.definePosition(opt);
        this.initColorWithoutChangeEvent(color);
    }     

    /**
     * 
     * initialize color for colorpicker
     * 
     * @param {String|Object} newColor 
     * @param {String} format  hex, rgb, hsl
     */
    initColor(newColor, format) {
        this.$store.dispatch('/changeColor', newColor, format);
    }


    /**
     * hide colorpicker 
     * 
     */
    hide() {
        if (this.isColorPickerShow) {
            // this.destroy();
            this.$root.hide();
            this.$root.remove();  // not empty 
            this.isColorPickerShow = false;

            this.callbackHideColorValue()
        }
    }

    /**
     * set to colors in current sets that you see 
     * @param {Array} colors 
     */
    setColorsInPalette (colors = []) {
        this.$store.dispatch('/setCurrentColorAll', colors);
    }    

    /**
     * refresh all color palette 
     * 
     * @param {*} list 
     */
    setUserPalette (list = []) {
        this.$store.dispatch('/setUserPalette', list);
    }


    /**
     * private method 
     */

    getOption(key) {
        return this.opt[key];
    }

    setOption (key, value) {
        this.opt[key] = value; 
    }

    isType (key) {
        return this.getOption('type') == key;
    }

    isPaletteType() {
        return this.isType('palette');
    }

    isSketchType() {
        return this.isType('sketch');
    }

    getContainer () {
        return this.opt.container || document.body;
    }

    getColor(type) {
        return this.$store.dispatch('/toColor', type);
    }

    definePositionForArrow(opt, elementScreenLeft, elementScreenTop) {
        // console.log(arguments)
    }

    definePosition(opt) {

        var width = this.$root.width();
        var height = this.$root.height();

        // set left position for color picker
        var elementScreenLeft = opt.left - this.$body.scrollLeft();
        if (width + elementScreenLeft > window.innerWidth) {
            elementScreenLeft -= (width + elementScreenLeft) - window.innerWidth;
        }
        if (elementScreenLeft < 0) { elementScreenLeft = 0; }

        // set top position for color picker
        var elementScreenTop = opt.top - this.$body.scrollTop();
        if (height + elementScreenTop > window.innerHeight) {
            elementScreenTop -= (height + elementScreenTop) - window.innerHeight;
        }
        if (elementScreenTop < 0) { elementScreenTop = 0; }

        // set position
        this.$root.css({
            left: (elementScreenLeft) + 'px',
            top: (elementScreenTop) + 'px'
        });

        // this.definePositionForArrow(opt, elementScreenLeft, elementScreenTop);
    }

    getInitalizePosition() {
        if (this.opt.position == 'inline') {
            return {
                position: 'relative',
                left: 'auto',
                top: 'auto',
                display: 'inline-block'
            }
        } else {
           return {
                position: 'fixed',  // color picker has fixed position
                left: '-10000px',
                top: '-10000px'
            }
        }
    }

    isAbsolute () {
        return this.opt.position !== 'inline'
    }

    // Event Bindings 
    'mouseup.isAbsolute document' (e) {

        this.__isMouseDown = false; 
        // when color picker clicked in outside
        if (this.checkInHtml(e.target)) {
            //this.setHideDelay(hideDelay);
        } else if (this.checkColorPickerClass(e.target) == false) {
            this.hide();
        } else {
            if (!this.__isMouseIn) {
                clearTimeout(this.timerCloseColorPicker);
                this.timerCloseColorPicker = setTimeout(this.hide.bind(this), this.delayTime || this.hideDelay);
            }

        }
    }
    
    'keyup.isAbsolute.escape $root' (e) {
        this.hide();
    }

    'mouseover.isAbsolute $root' (e) {
        clearTimeout(this.timerCloseColorPicker);
        // this.__isMouseDown = true; 
    }

    'mousemove.isAbsolute $root' (e) {
        clearTimeout(this.timerCloseColorPicker)
    }

    'mouseenter.isAbsolute $root' (e) {
        clearTimeout(this.timerCloseColorPicker);
        this.__isMouseIn = true; 
    }    

    'mouseleave.isAbsolute $root' (e) {
        this.__isMouseIn = false; 
        if (!this.__isMouseDown) {
            clearTimeout(this.timerCloseColorPicker);
            this.timerCloseColorPicker = setTimeout(this.hide.bind(this), this.delayTime || this.hideDelay);
        }
    }

    'mousedown.isAbsolute $root' (e) {
        this.__isMouseDown = true; 
    }
    

    setHideDelay(delayTime) {
        this.delayTime = delayTime || 0;
    }

    runHideDelay () {

        if (this.isColorPickerShow) {
            this.setHideDelay();
            // const hideCallback = this.setHideDelay(delayTime);
            
            // this.timerCloseColorPicker = setTimeout(hideCallback, delayTime);
        }

    }

    callbackColorValue(color) {
        color = color || this.getCurrentColor();

        if (typeof this.opt.onChange == 'function') {
            this.opt.onChange.call(this, color);
        }

        if (typeof this.colorpickerShowCallback == 'function') {
            this.colorpickerShowCallback(color);
        }        
    }

    callbackLastUpdateColorValue(color) {
        color = color || this.getCurrentColor();

        if (typeof this.opt.onLastUpdate == 'function') {
            this.opt.onLastUpdate.call(this, color);
        }

        if (typeof this.colorpickerLastUpdateCallback == 'function') {
            this.colorpickerLastUpdateCallback(color);
        }                
    }


    callbackHideColorValue(color) {
        color = color || this.getCurrentColor();
        if (typeof this.opt.onHide == 'function') {
            this.opt.onHide.call(this, color);
        }

        if (typeof this.colorpickerHideCallback == 'function') {
            this.colorpickerHideCallback(color);
        }        
    }    

    getCurrentColor() {
        return this.$store.dispatch('/toColor', this.outputFormat);
    }


    checkColorPickerClass(el) {
        var hasColorView = new Dom(el).closest('codemirror-colorview');
        var hasColorPicker = new Dom(el).closest('codemirror-colorpicker');
        var hasCodeMirror = new Dom(el).closest('CodeMirror');
        var IsInHtml = el.nodeName == 'HTML';

        return !!(hasColorPicker || hasColorView || hasCodeMirror);
    }

    checkInHtml(el) {
        var IsInHtml = el.nodeName == 'HTML';

        return IsInHtml;
    }

    initializeStoreEvent () {
        super.initializeStoreEvent()

        this.$store.on('changeColor', this.callbackChange)
        this.$store.on('lastUpdateColor', this.callbackLastUpdate)
        this.$store.on('changeFormat', this.callbackChange)        
    }
 
    destroy() {
        super.destroy();

        this.$store.off('changeColor', this.callbackChange);
        this.$store.off('lastUpdateColor', this.callbackLastUpdate)
        this.$store.off('changeFormat', this.callbackChange);

        this.callbackChange = undefined; 
        this.callbackLastUpdate = undefined;

        // remove color picker callback
        this.colorpickerShowCallback = undefined;
        this.colorpickerHideCallback = undefined;   
    }


    
}