// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

const {ccclass, property} = cc._decorator;

function getAngleByPos_CC(px, py, mx, my) {
    const x = Math.abs(px - mx);
    const y = Math.abs(py - my);
  
    const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
    const cos = y / z;
    const radina = Math.acos(cos); // 用反三角函数求弧度
    let angle = Math.floor(180 / (Math.PI / radina) * 100) / 100; // 将弧度转换成角度
  
    if (mx >= px && my == py) {// 鼠标在x轴正方向上
      angle = 270;
    }
    if (mx < px && my == py) {// 鼠标在x轴负方向上
      angle = 90;
    }
    if (mx == px && my >= py) {// 鼠标在y轴正方向上
      angle = 0;
    }
    if (mx == px && my < py) {// 鼠标在y轴负方向上
      angle = 180;
    }
  
    if (mx > px && my > py) {// 鼠标在第一象限
      angle = - angle;
    }
    if (mx < px && my > py) {// 鼠标在第二象限
      // angle = angle;
    }
    if (mx < px && my < py) {// 鼠标在第三象限
      angle = 180 - angle;
    }
    if (mx > px && my < py) {// 鼠标在第四象限
      angle = 180 + angle;
    }
    return angle;
}

function getPosByAngle(angle, len) {
    const radian = -angle * Math.PI / 180;
    const x = Math.sin(radian) * len;
    const y = Math.cos(radian) * len;
    return { x, y };
}

function getSprNode(resName) {
    const sf = cc.find('Canvas/res/img/' + resName).getComponent(cc.Sprite).spriteFrame;
    const node = new cc.Node();
    node.addComponent(cc.Sprite).spriteFrame = sf;
    return node;
}

@ccclass
export default class DrawingBoard extends cc.Component {

    // @property(cc.Label)
    // label: cc.Label = null;

    // @property
    // text: string = 'hello';

    // LIFE-CYCLE CALLBACKS:

    // onLoad () {}

    start () {
        this.initData();
        this.initButtons();
        this.initDrawBoardCenter();
    }

    lineW = null; // 笔粗
    brushWidth = []; // 笔粗列表
    touchPointArr = [];
    pointPicArr = [];
    poolLineArr = [];
    userLinePoolArr = [];
    lastDrawPointIndex = null;
    userLineIndex = -1;
    pathPointContainer = null; // 笔迹节点容器
    penColor = "#FFFFFF";
    initData() {
        this.poolLineArr = [];
        this.pointPicArr = [];
        this.brushWidth = [
            26/2, 34/2, 52/2, 64/2, 72/2, 92/2, 110/2, 140/2
        ]
        this.lineW = this.brushWidth[0];
    }

    // 编辑模式
    editMode = false;
    // 橡皮模式
    eraserMode = false;
    // 调色板开启状态
    openPalette = false;
    // 初始化按钮
    initButtons() {
        const pencilDataArr = [
            { 'resName': 'color_red', 'color': '#ff1500' },
            { 'resName': 'color_orange', 'color': '#ff8e13' },
            { 'resName': 'color_yellow', 'color': '#ffd900' },
            { 'resName': 'color_green', 'color': '#3cd31b' },
            { 'resName': 'color_blue', 'color': '#00bbf9' },
            { 'resName': 'color_purple', 'color': '#a282ea' },
            { 'resName': 'color_pink', 'color': '#ff84b3' },
            { 'resName': 'color_brown', 'color': '#a45e10' },
            { 'resName': 'color_black', 'color': '#000000' }
        ];

        const paletteBtn = cc.find("ToolBox/Palette", this.node)
        const btnColors = cc.find("ToolBox/Palette/btnColors", this.node)
        const bgPalette = cc.find("ToolBox/Palette/bgPalette", this.node)

        const eraserBtn = cc.find("ToolBox/Eraser", this.node)
        const eraserIconNormal = cc.find("normal", eraserBtn)
        const eraserIconActive = cc.find("active", eraserBtn)
        eraserBtn.on("click", ()=>{
            // 切换橡皮模式
            this.eraserMode = !this.eraserMode;
            if(this.eraserMode) {
                eraserIconNormal.active = false;
                eraserIconActive.active = true;
            } else {
                eraserIconNormal.active = true;
                eraserIconActive.active = false;
            }

            // 点击橡皮 关闭颜色盘
            this.openPalette = false;
            btnColors.active = false;
            bgPalette.active = false;
        })

        const painterBtn = cc.find("ToolBox/Painter", this.node)
        painterBtn.on("click", ()=>{
            eraserBtn.active = true; // 显示橡皮按钮
            painterBtn.active = false; // 隐藏画笔按钮
            closeBtn.active = true; // 显示关闭按钮
            paletteBtn.active = true; // 显示画板按钮
            this.editMode = true; // 开启编辑模式
            this.eraserMode = false; // 关闭橡皮模式
            eraserIconNormal.active = true; // 橡皮显示切换为正常
            eraserIconActive.active = false; // 隐藏橡皮高亮

            // 关闭颜色盘
            this.openPalette = false;
            btnColors.active = false;
            bgPalette.active = false;

            // 设置调色板初始颜色
            this.penColor = pencilDataArr[4].color;
            activeColor.children.forEach(acNode => {
                if(acNode.name == pencilDataArr[4].resName) {
                    acNode.active = true;
                } else {
                    acNode.active = false;
                }
            });

            this.node.emit("onPaintingStart");
        })

        const closeBtn = cc.find("ToolBox/Close", this.node)
        closeBtn.on("click", ()=>{
            eraserBtn.active = false; // 隐藏橡皮按钮
            painterBtn.active = true; // 显示画笔按钮
            closeBtn.active = false; // 隐藏关闭按钮
            paletteBtn.active = false; // 隐藏画板按钮
            this.editMode = false; // 关闭编辑模式
            this.eraserMode = false; // 关闭橡皮模式
            eraserIconNormal.active = true; // 橡皮显示切换为正常
            eraserIconActive.active = false; // 隐藏橡皮高亮
            this.node.emit("onPaintingEnd");
        })

        paletteBtn.on("click", ()=>{
            this.openPalette = !this.openPalette;
            btnColors.active = this.openPalette;
            bgPalette.active = this.openPalette;
            this.eraserMode = false; // 关闭橡皮模式
            eraserIconNormal.active = true; // 橡皮显示切换为正常
            eraserIconActive.active = false; // 隐藏橡皮高亮
        })

        const activeColor = cc.find("ToolBox/Palette/active_color", this.node)
        pencilDataArr.forEach(btnColor => {
            const colorBtn = cc.find(btnColor.resName, btnColors)
            colorBtn.on("click", ()=>{
                this.penColor = btnColor.color;
                // 点击颜色 关闭颜色盘
                this.openPalette = false;
                btnColors.active = false;
                bgPalette.active = false;
                activeColor.children.forEach(acNode => {
                    if(acNode.name == colorBtn.name) {
                        acNode.active = true;
                    } else {
                        acNode.active = false;
                    }
                });
            })
        })

        eraserBtn.active = false;
        painterBtn.active = true;
        closeBtn.active = false;
        paletteBtn.active = false;
    }

    initDrawBoardCenter() {
        this.pathPointContainer = cc.find("PathPointContainer", this.node)
        this.node.on(cc.Node.EventType.TOUCH_START, (e) => {
            if(!this.editMode) {
                return
            }
            
            // 如果调色板开打状态 则关闭
            if(this.openPalette) {
                const bgPalette = cc.find("ToolBox/Palette/bgPalette", this.node)
                const btnColors = cc.find("ToolBox/Palette/btnColors", this.node)
                this.openPalette = false;
                bgPalette.active = false;
                btnColors.active = false;
            }

            const worldPos = e.getLocation();
            const startPos = this.pathPointContainer.convertToNodeSpaceAR(worldPos);
            this.touchPointArr = [startPos];
            this.pointPicArr = [];
        })

        this.node.on(cc.Node.EventType.TOUCH_MOVE, (e) => {
            if(!this.editMode) {
                return
            }
            if (this.touchPointArr.length == 0) {
                return;
            }

            const worldPos = e.getLocation();
            const movePos = this.pathPointContainer.convertToNodeSpaceAR(worldPos);

            // 判断是否超出画图区域
            if(movePos.x < -this.node.width / 2 || movePos.y < -this.node.height / 2 || movePos.x > this.node.width / 2 || movePos.y > this.node.height / 2) {
                return
            }

            if(this.eraserMode) {
                // 橡皮功能
                const touchedPathPoints = [];
                const eraserWidth = this.lineW * 1.5;
                this.pathPointContainer.children.forEach(pathPoint => {
                    // 判断是否有轨迹点需要被擦除
                    if(pathPoint.active && pathPoint.x < (movePos.x + eraserWidth / 2) && pathPoint.x > (movePos.x - eraserWidth / 2) && pathPoint.y < (movePos.y + eraserWidth / 2) && pathPoint.y > (movePos.y - eraserWidth / 2)) {
                        touchedPathPoints.push(pathPoint);
                        pathPoint.active = false;
                    } 
                })
                this.cleanPoints(touchedPathPoints)
            } else {
                // 画笔功能
                this.addTouchPoint(movePos);
                this.drawLine();
            }
        })

        this.node.on(cc.Node.EventType.TOUCH_END, (e) => {
            if(!this.editMode) {
                return
            }
            this.saveUserLine();
            this.touchPointArr = [];
        })

        this.node.on(cc.Node.EventType.TOUCH_CANCEL, (e) => {
            if(!this.editMode) {
                return
            }
            this.saveUserLine();
            this.touchPointArr = [];
        })
    }

    addTouchPoint(movePos) {
        const lastPoint = this.touchPointArr[this.touchPointArr.length-1];
        const distance = movePos.sub(lastPoint).len();
        if (distance < 0.1) {
            return;
        }
        if (distance > this.lineW / 2) {
            const angle = getAngleByPos_CC(lastPoint.x, lastPoint.y, movePos.x, movePos.y);
            const newMovePos = getPosByAngle(angle, this.lineW / 2);

            this.touchPointArr.push(new cc.v2(lastPoint.x + newMovePos.x, lastPoint.y + newMovePos.y));
            this.addTouchPoint(movePos);
        } else {
            this.touchPointArr.push(movePos);
        } 
    }

    drawLine() {
        if (!this.lastDrawPointIndex) {
            this.lastDrawPointIndex = 0;
        }
        
        const lineW = this.lineW;
        for (let i=this.lastDrawPointIndex; i<this.touchPointArr.length; i++) {
            const curP = this.touchPointArr[i];
            const nextP = this.touchPointArr[i+1];
            if (!nextP) {
                break;
            }

            const line = this.getLine();
            const color = new cc.Color();
            line.color = cc.Color.fromHEX(color, this.penColor);
            line.scale = lineW / line.width;
            line.x = curP.x;
            line.y = curP.y;
            this.pointPicArr.push(line);
        }

        this.lastDrawPointIndex = this.touchPointArr.length - 1                                            ;
    }
    
    getLine() {
        let line;
        if (this.poolLineArr.length == 0) {
            line = getSprNode('dot_rect');
            // line.anchorY = 0
            this.pathPointContainer.addChild(line);
        } else {
            line = this.poolLineArr.pop();
        }
        line.active = true;
        return line;
    }

    saveUserLine() {
        const data = {pointPicArr: this.pointPicArr};
        if (this.userLineIndex >= 0 && this.userLinePoolArr.length-1 > this.userLineIndex) {
            this.resetUserLinePoolArr();
        }

        this.userLinePoolArr.push(data);
        this.userLineIndex = this.userLinePoolArr.length - 1;
    }

    resetUserLinePoolArr() {
        for (let i=this.userLineIndex+1; i<this.userLinePoolArr.length; i++) {
            const cleanData= this.userLinePoolArr[i];
            this.cleanOneLineData(cleanData);
        }

        this.userLinePoolArr.length = this.userLineIndex + 1;
    }

    // 给定数组，清掉数组中的轨迹点
    cleanPoints(pathNodes) {
        for (let i=0; i<pathNodes.length; i++) {
            this.poolLineArr.push(pathNodes[i]);
            // pathNodes[i].opacity = 100;
            pathNodes[i].active = false;
        }
    }

    // 获取已经画到画板上的颜色 用来判断答案是否正确
    rgbaToHex(r, g, b) {
        r = Math.round(r);
        g = Math.round(g);
        b = Math.round(b);
        var hexR = r.toString(16).padStart(2, '0');
        var hexG = g.toString(16).padStart(2, '0');
        var hexB = b.toString(16).padStart(2, '0');
        return '#' + hexR + hexG + hexB;
    }
    getColors() {
        const colorArray = [];
        this.pathPointContainer.children.forEach(element => {            
            let curColor = this.rgbaToHex(element.color.r, element.color.g, element.color.b);
            if (curColor == '#ff1500' && !colorArray.includes('color_red')) {
                colorArray.push('color_red');
            }
            if (curColor == '#ff8e13' && !colorArray.includes('color_orange')) {
                colorArray.push('color_orange');
            }
            if (curColor == '#ffd900' && !colorArray.includes('color_yellow')) {
                colorArray.push('color_yellow');
            }                
            if (curColor == '#3cd31b' && !colorArray.includes('color_green')) {
                colorArray.push('color_green');
            }
            if (curColor == '#00bbf9' && !colorArray.includes('color_blue')) {
                colorArray.push('color_blue');
            }
            if (curColor == '#a282ea' && !colorArray.includes('color_purple')) {
                colorArray.push('color_purple');
            }
            if (curColor == '#ff84b3' && !colorArray.includes('color_pink')) {
                colorArray.push('color_pink');
            }
            if (curColor == '#a45e10' && !colorArray.includes('color_brown')) {
                colorArray.push('color_brown');
            }
            if (curColor == '#000000' && !colorArray.includes('color_black')) {
                colorArray.push('color_black');
            }            
        });
        return colorArray;
    }

    // 清除一条线的轨迹点
    cleanOneLineData(data) {
        const {pointPicArr} = data;
        for (let i=0; i<pointPicArr.length; i++) {
            this.poolLineArr.push(pointPicArr[i]);
            // pointPicArr[i].opacity = 100;
            pointPicArr[i].active = false;
        }
    }

    // update (dt) {}
}
