#include <iostream>
#include <string>

#include "ncurses.h"

// Additional helpers
class Point2D {
public:
    Point2D (uint8_t x = 0, uint8_t y = 0) {
        this -> x = x;
        this -> y = y;
    }

    void SetX (uint8_t x) {
        this -> x = x;
    }

    void SetY (uint8_t y) {
        this -> y = y;
    }

    uint8_t GetX () {
        return this -> x;
    }

    uint8_t GetY () {
        return this -> y;
    }
private:
    uint8_t x, y;
};

class Entity {
public:
    Entity (wchar_t Symbol = L' ') {
        SetSymbol (Symbol);
        setcchar (&this -> Presentation, &this -> Symbol, this -> Attributes, 0, NULL);
    }

    void SetName (std::string Name) { this -> Name = Name; }
    void SetAttributes (attr_t Attributes) { this -> Attributes = Attributes; }
    void SetSymbol (wchar_t Symbol) { this -> Symbol = Symbol; }

    std::string GetName () { return Name; }
    attr_t GetAttributes () { return this -> Attributes; }
    wchar_t GetSymbol () { return this -> Symbol; }

private:
    wchar_t Symbol;
    cchar_t Presentation;
    attr_t Attributes = A_NORMAL;
    std::string Name = std::string();
    // CollisionLayer
};

class Tile : public Entity {
public:
    Tile () : Entity() {
        
    }
    Tile (Point2D WorldPosition, std::string Name) : Entity() {
        
    }
    ~Tile () {  }

    void CheckFlags () {
    }

    void SetPosition (Point2D WorldPosition) { this->WorldPosition = WorldPosition; }
    void SetName (std::string Name) { this->Name = Name; }

    void SetVisible (bool Visible) { this->Visible = Visible; }
    void SetControlable (bool Control) { this->Control = Control; }

    Point2D GetPosition () { return this -> WorldPosition; }

    bool GetVisible () { return this -> Visible; }
    bool GetControlable () { return this -> Control; }

    std::string GetName () { return Name; }
private:
    bool Interact, Visible, Control, Solid;
    std::string Name = std::string();
    Point2D WorldPosition;
};

class Layer {
public:
    Layer(std::string Name, Point2D Size, Point2D Position) {
        SetSize(Size);
        SetPosition(Position);
        this -> TileLayer = new Tile *[GetSize().GetX()];
        for (int i = 0; i < GetSize().GetX(); i++)
            this -> TileLayer [i] = new Tile [GetSize().GetY()];
    }

    ~Layer() {
        for (int i = 0; i < GetSize().GetX(); i++)
            delete [] this -> TileLayer [i];
        delete [] this -> TileLayer; 
    }

    void AddTile (Tile Cell, Point2D Position = NULL) {
        TileLayer [Position.GetX()][Position.GetY()] = Cell;
    }

    void FillMapByTile (Tile Cell) {
        for (int i = 0; i < GetSize().GetX(); i++) {
            for (int j = 0; j < GetSize().GetY(); j++) {
                TileLayer [i][j] = Cell;
            }
        }
    }

    Tile GetTileByPos (Point2D Position) {
        return TileLayer[Position.GetX()][Position.GetY()];
    }

    void SetSize (Point2D Size) { this -> Size = Size; }
    void SetPosition (Point2D Position) { this -> Position = Position; }

    Point2D GetSize () { return this -> Size;  }
    Point2D GetPosition () { return this -> Position; }
private:
    Tile **TileLayer;
    std::string Name = std::string();
    Point2D Position;
    Point2D Size;
    bool CollisionLayer;
};

class Player : Tile {
public:
    Player (Point2D WorldPosition, std::string Name, char Character) : Tile (WorldPosition, Name) {
        SetName(Name);
        SetPosition(WorldPosition);
        SetControlable(true);
    }

    ~Player () {
        
    }
private:
};

int main() {
    initscr();
    
    refresh();
    
    getch();
    
    endwin();

    return 0;
}