/**
 * 移动拼图模块
 */
export class Pintu extends FYGE.Container {
    /**
     * 完成事件名
     */
    static COMPLETE = "onPintuComplete";
    private pices: Piece[];
    private choosed: Piece;
    private rect: FYGE.Container;
    /**
     * 移动拼图模块，倒计时啥的自行处理
     * @param textures 所有的贴图传入，固定图片自行切图，网络图片可用createCutTextures生成
     * @param winCallback 拼完后的回调，先传入吧，是考虑用事件的方式还是传入函数
     * @param pieceWidth 
     * @param pieceHeight 
     * @param row 
     * @param col 
     * @param gap 
     */
    constructor(
        textures: FYGE.Texture[],
        private winCallback?,
        //每片宽度
        private pieceWidth: number = 211,
        //每片高度
        private pieceHeight: number = 211,
        //行数
        private row: number = 3,
        //列数
        private col: number = 3,
        //间隙，默认横向纵向一致
        private gap: number = 3
    ) {
        super();
        this.pices = [];
        let all = row * col;
        //纹理不够
        if (textures.length < all) console.error("纹理数量不足" + all)
        //初始化位置及索引信息
        this.initPosition();
        //加拼图片
        for (var i = 0; i < all; i++) {
            let p = this.addChild(new Piece(i, textures[i], pieceWidth, pieceHeight))
            this.pices.push(p);
            var pos = this.getPositionByIndex(i);
            p.position.set(pos[0], pos[1]);
        }
        //鼠标事件down
        this.addEventListener(FYGE.MouseEvent.MOUSE_DOWN, (e: FYGE.MouseEvent) => {
            var ele = e.currentTarget;
            if (ele && ele instanceof Piece) {
                if (this.choosed && this.checkNeb(ele, this.choosed)) {
                    this.exchange(this.choosed, ele);
                    if (this.rect) this.choosed.removeChild(this.rect);
                    this.choosed = null;
                } else {
                    this.choosed = ele;
                    this.addChild(ele);
                    if (this.rect) this.choosed.addChild(this.rect);
                }
            }
        }, this);
        //鼠标事件move
        this.addEventListener(FYGE.MouseEvent.MOUSE_MOVE, (e) => {
            if (this.choosed && e.currentTarget instanceof Piece) {
                var ele = e.currentTarget
                if (this.checkNeb(ele, this.choosed)) {
                    this.exchange(this.choosed, ele);
                    this.choosed.removeChild(this.rect);
                    this.choosed = null;
                }
            }
        }, this);
    }
    /**
     * 设置选中框,外部自行调用设置
     * @param rect 
     * @param setCenter 是否设置居中，默认true
     */
    setChooseRect(rect: FYGE.Container, setCenter: boolean = true) {
        this.rect = rect;
        rect.mouseEnable = rect.mouseChildren = false;
        if (setCenter) {
            rect.position.set(
                (this.pieceWidth - rect.width) / 2,
                (this.pieceHeight - rect.height) / 2
            );
        }
    }
    /**
     * 打乱
     * @param time 
     * @param callback 
     */
    disturb(time: number = 500, callback?) {
        var anis: [Piece, number][] = [];
        var ranNums = this.indices.slice();
        for (var i = 0; i < this.pices.length; i++) {
            let ele = this.pices[i];
            if (ranNums.length == 1) {//只剩一个了
                anis.push([ele, ranNums[0]])
                break
            }
            //先去掉自己
            var has = removeEle(ele.index, ranNums)
            var rand = ranNums[Math.floor(Math.random() * ranNums.length)]
            anis.push([ele, rand])
            //移除已选
            removeEle(rand, ranNums);
            //加回自己
            if (has) ranNums.push(ele.index);
        }
        let count = 0;
        let countAll = anis.length;
        for (var j = 0; j < anis.length; j++) {
            let ani = anis[j];
            let targetIndex = ani[1];
            let pice = ani[0];
            var p = this.getPositionByIndex(targetIndex);
            //索引先赋值了
            pice.index = targetIndex;
            //动画
            FYGE.Tween.get(pice)
                .to({ x: p[0], y: p[1] }, time)
                .call(() => {
                    if (++count == countAll) {
                        callback && callback();
                    }
                })
        }
    }
    /**
     * 恢复原图
     * @param time 
     * @param callback 
     */
    recover(time: number = 500, callback?) {
        let count = 0;
        let countAll = this.pices.length;
        for (var i = 0; i < this.pices.length; i++) {
            let pice = this.pices[i];
            pice.index = pice.trueIndex
            let p = this.getPositionByIndex(pice.trueIndex);
            FYGE.Tween.get(pice)
                .to({ x: p[0], y: p[1] }, time)
                .call(() => {
                    if (++count == countAll) {
                        callback && callback();
                    }
                })

        }
    }
    /**
     * 设置是否可以移动
     * @param b 
     */
    setCanMove(b: boolean) {
        this.mouseEnable = this.mouseChildren = b
    }
    private exchange(ele1: Piece, ele2: Piece) {
        var tempIndex = ele1.index;
        ele1.index = ele2.index;
        ele2.index = tempIndex;
        FYGE.Tween.get(ele1)
            .to({ x: ele2.x, y: ele2.y }, 166)
            .call(() => {
                this.checkWin();
            })
        FYGE.Tween.get(ele2)
            .to({ x: ele1.x, y: ele1.y }, 166)
    }
    private checkWin() {
        let notWin = false;
        for (var i = 0; i < this.pices.length; i++) {
            if (this.pices[i].index != this.pices[i].trueIndex) {
                notWin = true;
                break;
            }
        }
        //赢了
        if (!notWin) {
            this.winCallback && this.winCallback();
            //派发个完成事件
            this.dispatchEvent(Pintu.COMPLETE);
        }
    }
    //所有的所有数组
    private indices: number[];
    private indexPositions: number[][] = [];
    private indexToRcMap: number[][] = [];

    private getPositionByIndex(index: number): number[] {
        return this.indexPositions[index]
    }

    private indexToRc(index: number): number[] {
        return this.indexToRcMap[index]
    }
    private initPosition() {
        for (var i = 0; i < this.row; i++) {
            for (var j = 0; j < this.col; j++) {
                this.indexPositions[i * this.col + j] = [
                    j * (this.pieceWidth + this.gap),
                    i * (this.pieceHeight + this.gap)
                ];
                this.indexToRcMap[i * this.col + j] = [i, j];
            }
        }
        this.indices = Array.apply(null, Array(this.row * this.col)).map(function (item, i: number) { return i })
    }
    /**
     * 检查相邻
     * @param p1 
     * @param p2 
     */
    private checkNeb(p1: Piece, p2: Piece) {
        var rc1 = this.indexToRc(p1.index);
        var rc2 = this.indexToRc(p2.index);
        if (Math.abs(rc1[0] - rc2[0]) == 1 && Math.abs(rc1[1] - rc2[1]) == 0) {
            return true
        } else if (Math.abs(rc1[0] - rc2[0]) == 0 && Math.abs(rc1[1] - rc2[1]) == 1) {
            return true
        }
        return false
    }
}

/**
 * 根据一张图片，生成n张纹理
 * @param imageUrl 
 */
export function createCutTextures(imageUrl: string, row: number = 3, col: number = 3): Promise<FYGE.Texture[]> {
    return new Promise((resolve, reject) => {
        FYGE.GlobalLoader.loadImage((s, image) => {
            if (s) {
                var bt = new FYGE.BaseTexture(image)
                var arr = [];
                var w = image.width / col;
                var h = image.height / row;
                //生成散图的数据
                for (var i = 0; i < col * row; i++) {
                    arr.push(new FYGE.Texture(bt, new FYGE.Rectangle(
                        i % col * w,
                        ~~(i / col) * h,
                        w,
                        h
                    )))
                }
                resolve(arr)
            } else {
                reject(image)
            }
        }, imageUrl)
    })
}

function removeEle(e, arr) {
    var index = arr.indexOf(e);
    if (index >= 0) {
        arr.splice(index, 1);
        return true
    }
    return false
}

class Piece extends FYGE.Sprite {
    private _trueIndex: number;
    get trueIndex() {
        return this._trueIndex;
    }
    constructor(
        public index: number,
        texture: FYGE.Texture,
        width?: number,
        height?: number
    ) {
        super(texture);
        //记录真实的索引
        this._trueIndex = index;
        //部分图片偏大的，按照配置矫正
        if (width) this.width = width;
        if (height) this.height = height;
    }
}