<template>
  <main id="mainContent">
    <canvas
      id="canvas-board"
      ref="canvas-board"
      :width="canvasWidth"
      :height="canvasHeight"
    />
  </main>
</template>
<script>
  import { mapActions, mapState, mapWritableState } from 'pinia'
  import { globalStore } from "../stores/index.js";
  import {
    create1dState,
    create1dStateOneCell,
    create2dState,
    createBoard,
    conwayRules,
    evolve2d,
  } from "../modules/automata.js";
  import { getRandomInt, sleep } from "../modules/common.js";

  export default {
    name: "CanvasBoard",
    data() {
      return {
        canvas: null,
        ctx: null,
      };
    },
    computed: {
      ...mapState(globalStore, {
        cellProperties: "cellProperties",
        rules: "rules1d",
        refreshRate: "refreshRate",
        initial1dState: "initial1dState",
        drawingDirection: "drawingDirection",
        canDraw: "canDraw",
        getDraw1d: "draw1d",
        getDraw2d: "draw2d",
        getDraw2dLast: "draw2dLast",
      }),
      ...mapWritableState(globalStore, {
        lastBoard: "lastBoard",
        canvasWidth: "canvasWidth",
        canvasHeight: "canvasHeight",
        getReset: "reset",
      }),
      boardWidth: function () {
        return Math.floor(this.canvasWidth / this.cellProperties.size);
      },
      boardHeight: function () {
        return Math.floor(this.canvasHeight / this.cellProperties.size);
      },
    },
    watch: {
      getDraw1d(value) {
        if (value == true) this.draw1d();
      },
      getDraw2d(value) {
        if (value == true) this.draw2dNew();
      },
      getDraw2dLast(value) {
        if (value == true) this.draw2dLast();
      },
      getReset(value) {
        if (value == true) this.reset();
      },
    },
    mounted() {
      this.canvas = Object.freeze(document.getElementById("canvas-board"));
      this.ctx = this.canvas.getContext("2d");
      this.canvasWidth = this.canvas.parentElement.clientWidth
      this.canvasHeight = this.canvas.parentElement.clientHeight
    },
    methods: {
      ...mapActions(globalStore, ["toggleStop"]),
      drawCanvas(board) {
        const props = this.cellProperties;
        board.map((row, y) => {
          const d = props.size;
          return row.map((cell, x) => {
            this.ctx.fillStyle = (() => {
              if (cell === 1) return props.liveColor;
              return props.deadColor;
            })();
            if (this.drawingDirection === "x")
              this.ctx.fillRect(y * d, x * d, d, d);
            else this.ctx.fillRect(x * d, y * d, d, d);
            return cell;
          });
        });
      },
      compute1dInitialState() {
        if (this.initial1dState === "onecell")
          return create1dStateOneCell(this.boardWidth);
        return create1dState(this.boardWidth, getRandomInt, [0, 2]);
      },
      draw1d() {
        const initialState = this.compute1dInitialState();
        const board = createBoard(
          initialState,
          this.rules.rules,
          this.boardWidth
        );
        this.lastBoard = Object.freeze(board)
        this.drawCanvas(board);
        this.toggleStop()
      },
      draw2d(board) {
        if (!this.canDraw) return;
        const draw2dNext = async (b) => {
          if (!this.canDraw) return;
          const newBoard = evolve2d(b, conwayRules);
          this.drawCanvas(b, this.cellProperties);
          await sleep(this.refreshRate);
          draw2dNext(newBoard);
        };
        return draw2dNext(board);
      },
      draw2dNew() {
        const initialState = create2dState(
          this.boardWidth,
          this.boardHeight,
          getRandomInt,
          [0, 2]
        );
        const board = evolve2d(initialState, conwayRules);
        this.lastBoard = Object.freeze(board)
        this.draw2d(board);
      },
      async draw2dLast() {
        if (this.lastBoard != undefined)
          this.draw2d(this.lastBoard);
      },
      reset() {
        this.toggleStop()
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.getReset = 0
      },
    },
  };
</script>
<style>
  #mainContent {
    min-width: 70%;
  }
</style>
