text: /**
   * React component for a single board
   */
  import React from 'react';
  import { Button } from 'react-bootstrap';
  import PropTypes from 'prop-types';
  
  import WBishop from './asserts/white_bishop.png';
  import WKing from './asserts/white_king.png';
  import WKnight from './asserts/white_knight.png';
  import WPawn from './asserts/white_pawn.png';
  import WQueen from './asserts/white_queen.png';
  import WRook from './asserts/white_rook.png';
  import BBishop from './asserts/black_bishop.png';
  import BKing from './asserts/black_king.png';
  import BKnight from './asserts/black_knight.png';
  import BPawn from './asserts/black_pawn.png';
  import BQueen from './asserts/black_queen.png';
  import BRook from './asserts/black_rook.png';
  import boardItemMap from '../program/program-state';
  
  //TODO: add image for solana logo on default. rn it shows pawn
  const image_map = {
    'WKing': WKing,
    'WBishop': WBishop,
    'WKnight': WKnight,
    'WPawn': WPawn,
    'WPawn_en': WPawn,
    'WQueen': WQueen,
    'WRook': WRook,
    'BKing': BKing,
    'BBishop': BBishop,
    'BKnight': BKnight,
    'BPawn': BPawn,
    'BPawn_en': BPawn,
    'BQueen': BQueen,
    'BRook': BRook,
    'S': WPawn,
    ' ': null
  };
  
  function Square(props) {
    const style =
      props.bsSize === 'large'
        ? props.colorSquare === 'light'? { backgroundColor: '#f0d9b5', width: '70px', height: '70px', fontSize: '32px' } : { backgroundColor: '#b58863', width: '70px', height: '70px', fontSize: '32px' }
        : props.colorSquare === 'light'? { backgroundColor: '#f0d9b5', width: '35px', height: '35px' } : { backgroundColor: '#b58863', width: '35px', height: '35px' };
    return (
      // TODO: add  image formating eg. centerout, fit by size etc...
      <Button style={style} disabled={props.disabled} onClick={props.onClick}>
        {image_map[props.value] ? <img src={image_map[props.value]} /> : ''}
      </Button>
    );
  }
  Square.propTypes = {
    bsSize: PropTypes.oneOf(['xsmall', 'large']),
    colorSquare: PropTypes.oneOf(['light', 'dark']),
    value: PropTypes.oneOf(Object.keys(image_map)),
    onClick: PropTypes.func,
    disabled: PropTypes.boolean,
    onSelectingPiece: PropTypes.boolean
  };
  
  export class Board extends React.Component {
    renderSquare(i: number, x: number, y: number) {
      // TODO: Board should be flipped around for black.
      return (
        <Square
          disabled={this.props.disabled || this.isDisabled(i)}
          value={this.props.squares[i]}
          bsSize={this.props.bsSize}
          colorSquare={x%2==0?y%2==0?'light':'dark':y%2==0?'dark':'light'}
          onClick={() => this.props.onClick(i)}
        />
      );
    }
  
    isDisabled(i: number) {
      if (this.props.onSelectingPiece) {
        return !this.occupiedByOwnPiece(this.props.squares[i]);
      } else {
        return !(i === this.props.selectedPiece ||
          this.isValidMove(this.props.selectedPiece, i, this.props.squares[this.props.selectedPiece]));
      }
    }
  
    occupiedByOwnPiece(piece) {
      const { currentGame } = this.props;
  
      if (currentGame.isWhite) {
        return piece.charAt(0) === 'W';
      }
      return piece.charAt(0) === 'B';
    }
  
    isValidMove(from, to, piece) {
      if (from < 0 || from >= 64 || to < 0 || to >= 64) {
        console.error('Invalid coordinates in Board.isValidMove: ', from, to);
        return false;
      }
      if (!this.isMovePossible(from, to, piece)) {
        return false;
      }
  
      // Test if king is in check after the move
      // Temporarily move piece to test if in check
      // TODO: Handle castling
      let originalOccupant = this.props.squares[to];
      this.props.squares[to] = piece;
      this.props.squares[from] = ' ';
      const pieceColor = piece.charAt(0);
      let inCheck = this.inCheck(pieceColor);
  
      // Revert change
      this.props.squares[from] = piece;
      this.props.squares[to] = originalOccupant;
  
      return !inCheck;
    }
  
    isMovePossible(from, to, piece) {
      // Checks if the move is possible, but ignores other conditions (e.g. check).
  
      // Check if own piece occupies to square.
      const pieceColor = piece.charAt(0);
  
      const fromX = Math.floor(from % 8);
      const fromY = Math.floor(from / 8);
  
      const toX = Math.floor(to % 8);
      const toY = Math.floor(to / 8);
  
      const changeX = toX - fromX;
      const changeY = toY - fromY;
      if (this.occupiedByOwnPiece(this.props.squares[to])) {
        return false;
      }
  
      if (piece.includes('King')) {
        const isAdjacent = Math.abs(changeX) <= 1 && Math.abs(changeY) <= 1;
  
        // TODO: Handle castling. Need to keep track if king/rooks have moved.
        return isAdjacent;
      } else if (piece.includes('Queen')) {
        return this.isValidStraightMove(fromX, fromY, toX, toY, [
          [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]
        ]);
      } else if (piece.includes('Rook')) {
        return this.isValidStraightMove(fromX, fromY, toX, toY, [
          [1, 0], [0, 1], [-1, 0], [0, -1]
        ]);
      } else if (piece.includes('Bishop')) {
        return this.isValidStraightMove(fromX, fromY, toX, toY, [
          [1, 1], [-1, 1], [-1, -1], [1, -1]
        ]);
      } else if (piece.includes('Knight')) {
        return (Math.abs(changeX) + Math.abs(changeY) === 3 &&
          Math.abs(changeX) !== 0 && Math.abs(changeY) !== 0);
      } else if (piece.includes('Pawn')) {
        const moveDirection = (pieceColor === 'W') ? -1 : 1;
        const startY = (pieceColor === 'W') ? 6 : 1;
        const stopY = (pieceColor === 'W') ? 0 : 7;
  
        if (changeX === 0 && changeY === moveDirection) {
          // First handle regular move case. Just check if square above is empty
          if (toY === stopY) {
            // TODO: Handle promotion.
          }
  
          return this.isEmptySquare(toX, toY);
        } else if (changeX === 0 && changeY === moveDirection * 2) {
          // Handle move 2 space
          return (fromY === startY && this.isEmptySquare(fromX, fromY + moveDirection) &&
            this.isEmptySquare(toX, toY));
        } else if (Math.abs(changeX) === 1 && changeY === moveDirection) {
          // Attack and en passant. First check target square, then the square behind it.
          const targetColor = this.props.squares[to].charAt(0);
          if (targetColor === ((pieceColor === 'W') ? 'B' : 'W')) {
            return true;
          }
          // TODO: Check for en passant.
          // TODO: Since en passant can only happen if the last move was pawn moving forward 2 spaces
          //    need to keep track of the last move by the opponent.
        }
  
        return false;
      }
      console.error('Unrecognized piece detected :', piece);
      // Hopefully never happens but handle anyways?
      return false;
    }
  
    isValidStraightMove(fromX, fromY, toX, toY, allowedDirections) {
      // Checks if the direction is allowed, and the path between from and to is clear.
  
      const directionX = (toX === fromX) ? 0 : ((toX - fromX) / Math.abs(toX - fromX));
      const directionY = (toY === fromY) ? 0 : ((toY - fromY) / Math.abs(toY - fromY));
  
      let validDirection = false;
  
      for (let i = 0; i < allowedDirections.length; ++i) {
        if (directionX === allowedDirections[i][0] && directionY === allowedDirections[i][1]) {
          validDirection = true;
          break;
        }
      }
      if (!validDirection) {
        return false;
      }
  
      let currX = fromX + directionX;
      let currY = fromY + directionY;
  
      while (currX !== toX || currY !== toY) {
        if (!this.isEmptySquare(currX, currY)) {
          return false;
        }
  
        currX += directionX;
        currY += directionY;
      }
  
      return true;
    }
  
    inCheck(color) {
      console.warn(color);
      // Is the king of color under check?
      // First locate where the king is
      let kingPosition = -1;
      for (let i = 0; i < 64; ++i) {
        if (this.props.squares[i] === color + 'King') {
          kingPosition = i;
          break;
        }
      }
      if (kingPosition === -1) {
        console.error('King not found...?');
        return false;
      }
      // Go through each piece of the opposite color
      // Check if move from that piece to kingPosition is valid
      const otherColor = (color === 'W') ? 'B' : 'W';
      let { currentGame } = this.props;
      currentGame.isWhite = !currentGame.isWhite;
  
      for (let i = 0; i < 64; ++i) {
        if (this.props.squares[i].charAt(0) === otherColor && this.isMovePossible(i, kingPosition, this.props.squares[i])) {
          currentGame.isWhite = !currentGame.isWhite;
          return true;
        }
      }
      currentGame.isWhite = !currentGame.isWhite;
      return false;
    }
  
    isEmptySquare(x, y) {
      return x >= 0 && x < 8 && y >= 0 && y < 8
        && this.props.squares[8 * y + x] === ' ';
    }
  
    renderBoard() {
      let grid = [];
      if (!this.props.isWhite) {
        for (let i = 7; i >= 0; i--) {
          let row = [];
          for (let j = 7; j >= 0; j--) {
            row.push(this.renderSquare(i * 8 + j, i, j));
          }
          grid.push(<div className="board-row">{row}</div>);
        }
      } else {
        for (let i = 0; i < 8; i++) {
          let row = [];
          for (let j = 0; j < 8 ; j++) {
            row.push(this.renderSquare(i * 8 + j, i, j));
          }
          grid.push(<div className="board-row">{row}</div>);
        }
      }
      return grid;
    }
  
    render() {
      // console.log(this.props.squares);
      return (
        <div>
          {this.renderBoard()}
        </div>
      );
    }
  }
  Board.propTypes = {
    bsSize: PropTypes.oneOf(['xsmall', 'large']),
    squares: PropTypes.arrayOf(PropTypes.oneOf(boardItemMap)),
    onClick: PropTypes.func,
    disabled: PropTypes.boolean,
    onSelectingPiece: PropTypes.boolean,
    selectedPiece: PropTypes.number,
    currentGame: PropTypes.object,
    isWhite: PropTypes.boolean
  };
  
  