import CMath from "./CMath";

/**
 * 摇杆
 */
const { ccclass, property } = cc._decorator;

const TouchType = cc.Enum({
    DEFAULT: 0,//摇杆固定位置
    FOLLOW: 1//摇杆跟随
});

const DirectionType = cc.Enum({
    FOUR: 4,
    EIGHT: 8,
    ALL: 0,
});

@ccclass
export default class Joystick extends cc.Component {

    @property({
        type: TouchType,
        displayName: '触摸类型',
    })
    mTouchType = TouchType.DEFAULT;

    @property({
        type: DirectionType,
        displayName: '方向类型',
    })
    mDirectionType = TouchType.DEFAULT;

    @property(cc.Node)
    mDot: cc.Node = null;//摇杆

    @property(cc.Node)
    mRing: cc.Node = null;//摇杆底

    @property(cc.Node)
    mDir: cc.Node = null;//方向指示图


    public isDisable = false;

    private _radius: number;//半径
    private _angle: number;//当前触摸的角度
    private _distance: number = 0;//点击与中心的距离

    private tmpDir = { x: 0, y: 0 }
    /**
     * @runing 行走
     * @angle 角度
     * @distance 距离[0-1]
     */
    private callback: (move: boolean, v2: any, angle: number) => void;

    public onLoad() {
        this._radius = (this.mRing.width - this.mDot.width) / 2;
        this.mDir.opacity = 0;
        this.mDot.opacity = 100;
        this._initTouchEvent();
    }
    public stop() {
        // this.isDisable = true;
        this._touchEndEvent();
    }
    public setCallback(callback: (move: boolean, any, angle: number) => void) {
        this.callback = callback;
    }
    //对圆圈的触摸监听
    private _initTouchEvent() {
        this.node.on(cc.Node.EventType.TOUCH_START, this._touchStartEvent, this);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this._touchMoveEvent, this);
        // // 触摸在圆圈内离开或在圆圈外离开后,摇杆归位,player速度为0
        this.node.on(cc.Node.EventType.TOUCH_END, this._touchEndEvent, this);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this._touchEndEvent, this);

        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyPressed, this);
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyReleased, this);
    }
    private _touchStartEvent(event) {
        if (this.isDisable) {
            return;
        }
        // 获取触摸位置的世界坐标转换成圆圈的相对坐标(以圆圈的锚点为基准)
        let touchPos = this.node.convertToNodeSpaceAR(event.getLocation());
        // let ringPos = this.mRing.getPosition();
        // //触摸点与圆圈中心的距离
        // let distance = this._getDistance(touchPos, ringPos);
        // //手指在圆圈内触摸,控杆跟随触摸点
        // if (this._radius > distance) {
        //     this.mDot.setPosition(touchPos);
        //     this.updateAngle();
        //     return true;
        // }else{
        //     if(this.mTouchType == TouchType.FOLLOW){
        //         this.mRing.setPosition(touchPos);
        //         this.mDot.setPosition(touchPos);
        //         return true;
        //     }
        // }

        this.mDir.opacity = 255;
        this.mDot.opacity = 255;

        if (this.mTouchType == TouchType.FOLLOW) {
            this.mRing.setPosition(touchPos);
            this.mDot.setPosition(touchPos);
            this.mDir.setPosition(touchPos);
            return true;
        }
        return false;
    }
    private _touchMoveEvent(event) {
        if (this.isDisable) {
            return;
        }
        var touchPos = this.node.convertToNodeSpaceAR(event.getLocation());
        let ringPos = this.mRing.getPosition();
        var distance = this._getDistance(touchPos, ringPos);
        this._distance = distance;
        if (this._radius > distance) {
            this.mDot.setPosition(touchPos);
        } else {
            //控杆永远保持在圈内,并在圈内跟随触摸更新角度
            let radian = CMath.getAngle(ringPos, touchPos);
            let x = ringPos.x + Math.cos(radian) * this._radius;
            let y = ringPos.y + Math.sin(radian) * this._radius;
            this.mDot.setPosition(cc.v2(x, y));
        }
        //更新角度
        this.updateAngle();
    }
    private getDisTance(): number {
        if (this._distance > this._radius) {
            return 1;
        } else {
            return this._distance / this._radius;
        }
    }
    private _touchEndEvent() {
        this.mDot.setPosition(this.mRing.getPosition());
        this._angle = 0;
        if (this.callback) {
            this.callback(false, { x: 0, y: 0 }, 0);
        }
        this.mDir.opacity = 0;
        this.mDot.opacity = 100;
    }
    private onKeyPressed(event) {
        let keyCode = event.keyCode;
        switch (keyCode) {
            case cc.macro.KEY.w:
            case cc.macro.KEY.up:
                this.tmpDir.y = 1;
                break;
            case cc.macro.KEY.s:
            case cc.macro.KEY.down:
                this.tmpDir.y = -1;
                break;
            case cc.macro.KEY.a:
            case cc.macro.KEY.left:
                this.tmpDir.x = -1;
                break;
            case cc.macro.KEY.d:
            case cc.macro.KEY.right:
                this.tmpDir.x = 1;
                break;
        }
        this.reviseValue();
    }

    private onKeyReleased(event) {
        let keyCode = event.keyCode;
        switch (keyCode) {
            case cc.macro.KEY.w:
            case cc.macro.KEY.up:
                this.tmpDir.y = 0;
                break;
            case cc.macro.KEY.s:
            case cc.macro.KEY.down:
                this.tmpDir.y = 0;
                break;
            case cc.macro.KEY.a:
            case cc.macro.KEY.left:
                this.tmpDir.x = 0;
                break;
            case cc.macro.KEY.d:
            case cc.macro.KEY.right:
                this.tmpDir.x = 0;
                break;
        }
        this.reviseValue();
    }
    private reviseValue() {
        if (this.callback) {
            if (this.tmpDir.x == 0 && this.tmpDir.y == 0) {
                this.callback(false, { x: 0, y: 0 }, 0);
            } else {
                let angle = Math.atan2(this.tmpDir.y, this.tmpDir.x);
                this.callback(true, { x: this.tmpDir.x, y: this.tmpDir.y }, angle);
            }
        }
    }
    private updateAngle() {
        let p1 = this.mRing.getPosition();
        let p2 = this.mDot.getPosition();
        let angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
        this.mDir.angle = angle * 180 / Math.PI;
        this._angle = angle;
        let xx = this.getDir(this.mDir.angle)
        if (this.callback) {
            this.callback(true, xx, angle);
        }
        return this._angle;
    }
    //计算两点间的距离并返回
    private _getDistance(pos1: cc.Vec2, pos2: cc.Vec2) {
        return Math.sqrt(Math.pow(pos1.x - pos2.x, 2) + Math.pow(pos1.y - pos2.y, 2));
    }
    /**
     * 根据弧度获取方向
     * @param angle 
     */
    private getDir(angle: number) {
        if (angle >= -30 && angle < 30) {
            return { x: 1.4, y: 0 }
        } else if (angle >= 30 && angle < 60) {
            return { x: 1, y: 1 }
        } else if (angle >= 60 && angle < 120) {
            return { x: 0, y: 1.4 }
        } else if (angle >= 120 && angle < 150) {
            return { x: -1, y: 1 }
        } else if (angle >= 150 && angle < 180) {
            return { x: -1.4, y: 0 }
        } else if (angle >= -180 && angle < -150) {
            return { x: -1.4, y: 0 }
        } else if (angle >= -150 && angle < -120) {
            return { x: -1, y: -1 }
        } else if (angle >= -120 && angle < -60) {
            return { x: 0, y: -1.4 }
        } else if (angle >= -60 && angle < -30) {
            return { x: 1, y: -1 }
        } else {
            return { x: 0, y: 0 }
        }
    }
}