<template>
    <div>
        <canvas :id="id" width="320" height="620" tabindex="0"/>
    </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { v1 as uuid } from "uuid";
import { SCanvasView, SColor, SPainter } from "@persagy-web/draw/lib";

/**
 * 俄罗斯方块视图
 *
 * @author 郝洁 <haojie@persagy.com>
 */
class TestView extends SCanvasView {
    /** 背景表示数组 */
    map: number[][] = [];
    /** 方块类型索引 */
    fkType: number = Number(Math.floor(Math.random() * 7));  // 0-6
    /** 方块变形索引 */
    dir: number = Number(Math.floor((Math.random() * 4)));  // 0-3
    /** 所有方块集合 */
    fk: number[][][] = [
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [0, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [0, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [0, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [0, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 1, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [1, 1, 1, 1],
            [0, 0, 0, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 1, 0],
            [0, 0, 1, 0],
            [0, 0, 1, 0],
            [0, 0, 1, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 0, 0, 0],
            [1, 1, 1, 1],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [1, 1, 0, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 1, 0, 0],
            [0, 1, 1, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 0, 1, 1],
            [0, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 1, 0],
            [0, 0, 1, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [0, 0, 1, 1],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 0, 1, 0],
            [0, 1, 1, 0],
            [0, 1, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [1, 1, 0, 0],
            [0, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 1, 0],
            [0, 1, 1, 0],
            [0, 1, 0, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [0, 0, 1, 0],
            [0, 0, 1, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 0, 1, 0],
            [1, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 1, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 1, 1],
            [0, 1, 0, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 1, 0],
            [0, 1, 0, 0],
            [0, 1, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [1, 1, 1, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 1, 0],
            [0, 0, 1, 0],
            [0, 1, 1, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 1, 1],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 0, 1, 0],
            [0, 1, 1, 1],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 1, 0],
            [0, 1, 0, 0],
        ],
        [
            [0, 0, 0, 0],
            [1, 1, 1, 0],
            [0, 1, 0, 0],
            [0, 0, 0, 0],
        ],
        [
            [0, 0, 1, 0],
            [0, 1, 1, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 0],
        ]
    ];
    /** 方块初始位置x坐标 */
    x = 5;
    /** 方块初始位置y坐标 */
    y = 0;
    /** 记录上次刷新时间 */
    t = Date.now();

    /**
     * 构造函数
     * @param id canvas DOM id
     */
    constructor(id: string) {
        super(id);
        this.initMap();
    }

    /**
     * 键盘按下事件
     * @param event 事件对象
     */
    onKeyDown(event: KeyboardEvent): void {
        if (event.code == "KeyW") { // 按键 w
            if (!this.isPz(this.x, this.y, (this.dir + 1) % 4)) { // 检查变形后是否碰撞
                this.dir = (this.dir + 1) % 4;
            }
        } else if (event.code == "KeyA") {  // 按键 a
            if (!this.isPz(this.x - 1, this.y, this.dir)) { // 检查左移后是否碰撞
                this.x--;
            }
        } else if (event.code == "KeyD") { // 按键 d
            if (!this.isPz(this.x + 1, this.y, this.dir)) { // 检查右移后是否碰撞
                this.x++;
            }
        } else if (event.code == "KeyS") { // 按键 s
            if (!this.isPz(this.x, this.y + 1, this.dir)) { // 检查下移后是否碰撞
                this.y++;
            } else {
                this.fullMap();
                this.xc();
            }
        }

        this.update();
    }

    /**
     * Item 绘制操作
     *
     * @param painter   绘制对象
     */
    onDraw(painter: SPainter): void {
        //清除画布
        painter.clearRect(0, 0, this.width, this.height);
        //绘制操作相关命令
        painter.pen.color = SColor.Transparent;
        painter.brush.color = SColor.Red;

        this.drawMap(painter);
        this.drawFk(painter);

        if (Date.now() - this.t > 500) {  // 下落速度，下移一格
            if (!this.isPz(this.x, this.y + 1, this.dir)) {  // 下移是否碰撞
                this.y++;
            } else {
                this.fullMap();
                this.xc();
            }

            this.t = Date.now();
        }
        this.update();
    }

    /**
     *初始化背景
     */
    private initMap(): void {
        this.map = [];
        for (let row = 0; row < 22; row++) {   // 循环行数
            const m1: number[] = []
            for (let col = 0; col < 14; col++) {  // 循环列数
                if (row > 19 || col < 2 || col > 11) {  // 左侧，右侧，底部补充两个格
                    // -1 代表左右填充
                    m1.push(2);
                } else {
                    m1.push(0);
                }
            }
            this.map.push(m1);
        }
    }

    /**
     * 绘制背景
     *
     * @param painter 绘制对象
     */
    private drawMap(painter: SPainter): void {
        for (let row = 0; row < 22; row++) { // 行数
            for (let col = 0; col < 14; col++) {  // 列数
                const x = col * 30 + 11 - 60;
                const y = row * 30 + 11;
                if (this.map[row][col] == 1) { //赋到背景
                    painter.drawRect(col * 30 + 11 - 60, row * 30 + 11, 28, 28);
                }

                if (this.map[row][col] == 2) { //底加一行
                    painter.drawRect(col * 30 + 11 - 60, row * 30 + 11, 28, 28);
                }
            }
        }
    }

    /**
     * 绘制实体图形
     *
     * @param painter   绘制对象
     */
    private drawFk(painter: SPainter): void {
        for (let row = 0; row < 4; row++) { // 绘制图形行数
            for (let col = 0; col < 4; col++) { // 绘制图形列数
                if (this.fk[this.fkType * 4 + this.dir][row][col] == 1) {
                    painter.drawRect((col + this.x) * 30 + 11 - 60, (row + this.y) * 30 + 11, 28, 28);
                }
            }
        }
    }

    /**
     * 是否碰撞
     *
     * @param x     x坐标
     * @param y     y坐标
     * @param dir   方块变形索引
     * @return 是否碰撞
     */
    private isPz(x: number, y: number, dir: number): boolean {
        for (let row = 0; row < 4; row++) { // 绘制图形行数
            for (let col = 0; col < 4; col++) {  // 绘制图形列数
                // 判断是否重合，每种图形四个一组，四种变形的某种变形，不为零表示绘制（确定方块），坐标转换，背景图中绘制
                if (this.fk[this.fkType * 4 + dir][row][col] == 1 && this.map[y + row][x + col] != 0) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 将方块合到背景中
     */
    private fullMap() {
        for (let row = 0; row < 4; row++) { // 遍历图形的行数
            for (let col = 0; col < 4; col++) { // 遍历图形的列数
                if (this.fk[this.fkType * 4 + this.dir][row][col] == 1) {
                    this.map[this.y + row][this.x + col] = 1;
                }
            }
        }

        this.x = 5;
        this.y = 0;
        this.fkType = Number((Math.random() * 6).toFixed());
        this.dir = Number((Math.random() * 2).toFixed());
    }

    /**
     * 消除满行
     */
    private xc(): void {
        // 循环行数，不包含底部填充2行
        for (let row = 0; row < 20; row++) {
            // 消除标记，true 是
            let flag = true;
            // 若当前行有一个空格，则不消除
            for (let col = 2; col < 12; col++) {
                if (this.map[row][col] == 0) {  // 存在空格
                    flag = false;
                    break;
                }
            }

            if (flag) { // 标记删除
                this.map.splice(row, 1);
                this.map.unshift()
                // 顶部加一行空行
                this.map.unshift(this.randomRow(10, 0))
                // this.map.unshift([2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2]);
                // row--;
            }
        }
    }

    /**
     * 随机数组生成
     *
     * @return 数组
     */
    private randomRow(len: number = 10, num: number = 2): number[] {
        let array = new Array(len + 4).fill(2);
        // 生成随机数，循环不包含左右填充格
        for (let i = 2; i < array.length - 2; i++) {
            array[i] = Math.floor(num * Math.random())
        }
        return array
    }
}

@Component
export default class ElsfkCanvas extends Vue {
    /** 图 id */
    id: string = uuid();

    /**
     * 页面挂载
     */
    mounted(): void {
        new TestView(this.id);
    }
}
</script>
