
const { ccclass, property } = cc._decorator;

@ccclass
export default class Palette extends cc.Component {
    @property(cc.Sprite)
    hueSprite: cc.Sprite = null;

    @property(cc.Node)
    huePointNode: cc.Node = null;

    @property(cc.Sprite)
    colorBoardSprite: cc.Sprite = null;

    @property(cc.Node)
    circleNode: cc.Node = null;

    @property(cc.Slider)
    rSlider: cc.Slider = null;

    @property(cc.EditBox)
    rEditBox: cc.EditBox = null;

    @property(cc.Slider)
    gSlider: cc.Slider = null;

    @property(cc.EditBox)
    gEditBox: cc.EditBox = null;

    @property(cc.Slider)
    bSlider: cc.Slider = null;

    @property(cc.EditBox)
    bEditBox: cc.EditBox = null;

    private h = 0;
    private s = 100;
    private v = 100;

    private colorBoardData = null;
    private colorBoardTexture = null;


    onLoad() {
        this.colorBoardTexture = new cc.Texture2D();
        this.createHueData();
        this.createColorBoardData();
        this.initRgbNode();
        this.addEvent();
    }

    createHueData() {
        let texture2D = new cc.Texture2D();

        let hueData: Uint8Array = new Uint8Array(360 * 4);
        for (let i = 0; i < 360; i++) {
            let color = this.hsv2rgb(i, 100, 100);
            hueData[i * 4] = color.getR();
            hueData[i * 4 + 1] = color.getG();
            hueData[i * 4 + 2] = color.getB();
            hueData[i * 4 + 3] = color.getA();
        }

        texture2D.initWithData(hueData as any, cc.Texture2D.PixelFormat.RGBA8888, 1, 360)
        this.hueSprite.spriteFrame = new cc.SpriteFrame(texture2D);

    }

    createColorBoardData(isFromRgba = false) {
        this.colorBoardData = new Uint8Array(101 * 101 * 4);
        for (let i = 0; i <= 100; i++) {
            for (let j = 0; j <= 100; j++) {
                let color = this.hsv2rgb(this.h, j, 100 - i);
                let index = (i * 101 + j) * 4;
                this.colorBoardData[index] = color.getR();
                this.colorBoardData[index + 1] = color.getG();
                this.colorBoardData[index + 2] = color.getB();
                this.colorBoardData[index + 3] = color.getA();
            }
        }
        this.colorBoardTexture.initWithData(this.colorBoardData as any, cc.Texture2D.PixelFormat.RGBA8888, 101, 101)
        this.colorBoardSprite.spriteFrame = new cc.SpriteFrame(this.colorBoardTexture);
        this.circleNode.position = cc.v2(this.s / 100 * this.colorBoardSprite.node.width, this.v / 100 * this.colorBoardSprite.node.height);
        this.setCircleColor();

        if (!isFromRgba) {
            this.initRgbNode();
        }
    }

    addEvent() {
        this.hueSprite.node.on(cc.Node.EventType.TOUCH_START, this.onHueTouch, this);
        this.hueSprite.node.on(cc.Node.EventType.TOUCH_MOVE, this.onHueTouch, this);
        this.huePointNode.on(cc.Node.EventType.TOUCH_MOVE, this.onHueTouch, this);

        this.colorBoardSprite.node.on(cc.Node.EventType.TOUCH_START, this.onColorBoardTouch, this);
        this.colorBoardSprite.node.on(cc.Node.EventType.TOUCH_MOVE, this.onColorBoardTouch, this);

        this.rSlider.node.on('slide', this.rgbChanged, this);
        this.gSlider.node.on('slide', this.rgbChanged, this);
        this.bSlider.node.on('slide', this.rgbChanged, this);

        this.rEditBox.node.on("editing-did-ended", this.editTextEnd, this);
        this.gEditBox.node.on("editing-did-ended", this.editTextEnd, this);
        this.bEditBox.node.on("editing-did-ended", this.editTextEnd, this);
    }

    editTextEnd() {
        let rText = this.rEditBox.string;
        let r = parseInt(rText);
        if (isNaN(r)) {
            r = 255;
        }
        r = Math.max(0, Math.min(r, 255));
        this.rEditBox.string = r + "";
        this.rSlider.progress = r / 255;

        let gText = this.gEditBox.string;
        let g = parseInt(gText);
        if (isNaN(g)) {
            g = 255;
        }
        g = Math.max(0, Math.min(g, 255));
        this.gEditBox.string = g + "";
        this.gSlider.progress = g / 255;

        let bText = this.bEditBox.string;
        let b = parseInt(bText);
        if (isNaN(b)) {
            b = 255;
        }
        b = Math.max(0, Math.min(b, 255));
        this.bEditBox.string = b + "";
        this.bSlider.progress = b / 255;

        let hsv = this.rgb2hsv(r, g, b);
        this.h = hsv[0];
        this.s = hsv[1];
        this.v = hsv[2];

        this.huePointNode.y = Math.round(this.hueSprite.node.height / 2 - this.h / 360 * this.hueSprite.node.height);

        this.createColorBoardData(true);
    }

    initRgbNode() {
        let curColor = this.hsv2rgb(this.h, this.s, this.v);
        this.rSlider.progress = curColor.getR() / 255;
        this.rEditBox.string = curColor.getR() + "";
        this.gSlider.progress = curColor.getG() / 255;
        this.gEditBox.string = curColor.getG() + "";
        this.bSlider.progress = curColor.getB() / 255;
        this.bEditBox.string = curColor.getB() + "";
    }


    rgbChanged() {
        let r = Math.round(255 * this.rSlider.progress);
        this.rEditBox.string = r + "";
        let g = Math.round(255 * this.gSlider.progress);
        this.gEditBox.string = g + "";
        let b = Math.round(255 * this.bSlider.progress);
        this.bEditBox.string = b + "";

        let hsv = this.rgb2hsv(r, g, b);
        this.h = hsv[0];
        this.s = hsv[1];
        this.v = hsv[2];

        this.huePointNode.y = Math.round(this.hueSprite.node.height / 2 - this.h / 360 * this.hueSprite.node.height);

        this.createColorBoardData(true);
    }

    onHueTouch(event: any) {
        let pos = this.hueSprite.node.convertToNodeSpace(event.touch.getLocation());
        let index = Math.round((this.hueSprite.node.height - pos.y) / this.hueSprite.node.height * 360);
        index = Math.max(0, Math.min(index, 359));
        this.h = index;
        this.huePointNode.y = Math.round(this.hueSprite.node.height / 2 - index / 360 * this.hueSprite.node.height);

        this.createColorBoardData();
    }

    onColorBoardTouch(event: any) {
        let pos = this.colorBoardSprite.node.convertToNodeSpace(event.touch.getLocation());

        pos.x = Math.max(0, Math.min(pos.x, this.colorBoardSprite.node.width));
        pos.y = Math.max(0, Math.min(pos.y, this.colorBoardSprite.node.height));
        this.circleNode.position = pos;

        this.s = Math.round(pos.x / this.colorBoardSprite.node.width * 100);
        this.v = Math.round(pos.y / this.colorBoardSprite.node.height * 100);
        this.s = Math.max(0, Math.min(this.s, 100));
        this.v = Math.max(0, Math.min(this.v, 100));

        this.setCircleColor();
        this.initRgbNode();
    }

    setCircleColor() {
        let curColor = this.hsv2rgb(this.h, this.s, this.v);
        let isBlack = .299 * curColor.getR() + .578 * curColor.getG() + .114 * curColor.getB() >= 192;
        this.circleNode.color = isBlack ? cc.Color.BLACK : cc.Color.WHITE;
    }


    hsv2rgb(h, s, v) {
        h /= 1;
        s /= 100;
        v /= 100;
        var r = 0;
        var g = 0;
        var b = 0;

        if (s === 0) {
            r = g = b = v;
        } else {
            var _h = h / 60;

            var i = Math.floor(_h);
            var f = _h - i;
            var p = v * (1 - s);
            var q = v * (1 - f * s);
            var t = v * (1 - (1 - f) * s);

            switch (i) {
                case 0:
                    r = v;
                    g = t;
                    b = p;
                    break;

                case 1:
                    r = q;
                    g = v;
                    b = p;
                    break;

                case 2:
                    r = p;
                    g = v;
                    b = t;
                    break;

                case 3:
                    r = p;
                    g = q;
                    b = v;
                    break;

                case 4:
                    r = t;
                    g = p;
                    b = v;
                    break;

                case 5:
                    r = v;
                    g = p;
                    b = q;
                    break;
            }
        }

        return cc.color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), 255);
    }

    rgb2hsv(r, g, b) {
        r /= 255;
        g /= 255;
        b /= 255;
        var max = Math.max(r, g, b);
        var min = Math.min(r, g, b);
        var diff = max - min;
        var h = 0;
        var v = max;
        var s = max === 0 ? 0 : diff / max; // h

        if (max === min) {
            h = 0;
        } else if (max === r && g >= b) {
            h = 60 * ((g - b) / diff);
        } else if (max === r && g < b) {
            h = 60 * ((g - b) / diff) + 360;
        } else if (max === g) {
            h = 60 * ((b - r) / diff) + 120;
        } else if (max === b) {
            h = 60 * ((r - g) / diff) + 240;
        }
        return [Math.round(h), Math.round(s * 100), Math.round(v * 100)];
    }

    // update (dt) {}
}
