#ifndef LEVEL_H
#define LEVEL_H

#include <memory>
#include <string>
#include <array>
#include <map>
#include <sstream>

#include "cell.h"

// Very desirable to create module for default values
const std::string default_file_path = "test_map";

/// Abstraction over 2D array to quickly get access to level cells
class Level
{
private:
    struct Map
    {
        using Row = std::vector<CellPtr>;
        using Matrix = std::vector<Row>;

        enum class SECTION
        {
            SIZE,
            MAP,
            TELEPORT,
            CHARGE,
            TRIGGER,
            NONE
        };

        std::map<std::string, SECTION> map_section =
        {
            { "size", SECTION::SIZE },
            { "map", SECTION::MAP },
            { "teleport", SECTION::TELEPORT },
            { "charge", SECTION::CHARGE },
            { "trigger", SECTION::TRIGGER },
            { "", SECTION::NONE }
        };

        Matrix data;
        size_t rows, cols;
        std::array<CellPtr, N_CELLS> default_cells;

        void init(const std::string &path = default_file_path);

        /// Prepare prototypes of default cells
        void prepareDefaultCells();

        // Map file section readers
        void readMapSize(std::istringstream &sstr);
        void readMapRow(std::istringstream &sstr);
        void readCellSection(std::istringstream &sstr, const SECTION &section);
        std::unique_ptr<TeleportCell> &&readTeleport(std::istringstream &sstr, std::unique_ptr<TeleportCell> &&cell);
        std::unique_ptr<ChargeCell> &&readCharge(std::istringstream &sstr, std::unique_ptr<ChargeCell> &&cell);
        std::unique_ptr<TriggerCell> &&readTrigger(std::istringstream &sstr, std::unique_ptr<TriggerCell> &&cell);
    };

    Map map;
    sf::Color color_ground;

public:
    Level(const std::string &path = default_file_path);

    /// Number of map rows
    size_t rows() const;

    /// Number of map columns
    size_t cols() const;

    /// Get cell at position row, col
    CellPtr &getCellAt(coordinate row, coordinate col);

    /// Place a bridge cell
    void placeBridge(coordinate x, coordinate y);

    /// Replace a charge cell with a ground cell
    void removeCharge(coordinate x, coordinate y);

    /// Get default color for passable cells
    sf::Color defaultGroundColor();

    /// Set default color for passable cells
    void setDefaultGroundColor(const sf::Color &color);
};

#endif // LEVEL_H
