#pragma once

#include "../Pieces/Piece.h"

#include <vector>
#include <iostream>


/**
 * A 2D grid of blocks
 */
class Board {
    private:
        std::vector<std::vector<Block>> grid; // the grid, (0,0) is downleft
        std::vector<Block> emptyRow;          // an empty row of blocks
        unsigned width;                            // the width of the grid
        unsigned height;                           // the base height of the grid, which can extend indefinitely

    public:
        /**
         * Creates a new board of the specified size
         */
        Board(int width, int height);

        /**
         * Changes the block at the specified position, if the block is out of bounds it is simply ignored
         */
        void changeBlock(const Position& position, Block block);

        /**
         * Inserts a row of the specified block type (unless on the specified column that has a hole), at the specified height
         */
        void insertRow(int height, int holePosition, Block blockType);

        /**
         * Clears any complete row and moves down the rows on top
         * @return The number of cleared rows
         */
        int clearRows();

        /**
         * Deletes any block currently on the board
         */
        void clearBoard();

        /**
         * @return The block at the specified position
         */
        Block getBlock(const Position& position) const;

        /**
         * @return The grid
         */
        const std::vector<std::vector<Block>>& getBlocks() const;

        /**
         * @return The width of the grid
         */
        int getWidth() const;

        /**
         * @return The actual height of the grid
         */
        int getGridHeight() const;

        /**
         * @return The base height of the grid
         */
        int getBaseHeight() const;
        
        /**
         * Stream output operator, adds a 2D grid representing the board
         * @return A reference to the output stream
         */
        friend std::ostream& operator<<(std::ostream& os, const Board& board);
};
