#include "app.h"

#include "map/map.h"
#include "tiles/rainbow.h"
#include "tiles/dirt.h"
#include "tiles/grass.h"
#include "util/vector2.h"
#include "util/vector3.h"
#include "util/matrix3x3.h"

#include <iostream>

App::App() :
    m_render(this) {
	sAppName = "Automation";
}

bool App::OnUserCreate()
{
    std::cout << "Create" << std::endl;
    return true;
}

bool App::OnUserUpdate(float delta)
{
    Vector2<int> screen = {ScreenWidth(), ScreenHeight()};
    Vector2<int> mouse = {GetMouseX(), GetMouseY()};

    // Save and load keys
    if(GetKey(olc::Key::S).bReleased)
        m_map.save();
    if(GetKey(olc::Key::L).bReleased)
        m_map.load();

    // Basic block placing
    if(GetMouse(0).bPressed) {
        auto screen_pos = mouse - m_camera_pos;
        auto tile_pos = screen_pos / (TILE_SIZE + 1);
        if(screen_pos.x() < 0) tile_pos -= {1, 0};
        if(screen_pos.y() < 0) tile_pos -= {0, 1};
        m_map.set_tile(tile_pos, new Rainbow());
    }
    if(GetMouse(1).bPressed) {
        auto screen_pos = mouse - m_camera_pos;
        auto tile_pos = screen_pos / (TILE_SIZE + 1);
        if(screen_pos.x() < 0) tile_pos -= {1, 0};
        if(screen_pos.y() < 0) tile_pos -= {0, 1};
        m_map.set_tile(tile_pos, new Dirt());
    }

    // Pan camera with middle mouse
    if(GetMouse(2).bPressed) {
        m_drag_start = {GetMouseX(), GetMouseY()};
    }
    if(GetMouse(2).bHeld) {
        m_camera_pos += mouse - m_drag_start;
        m_drag_start = mouse;
    }

    m_render.set_camera_pos(m_camera_pos);

    // Clear screen
    Clear({24, 24, 24});

    // Render only what we can see
    auto min = -m_camera_pos / (TILE_SIZE + 1);
    auto max = (screen - m_camera_pos) / (TILE_SIZE + 1);

    for(int y = min.y() - 1; y < max.y() + 1; y++) {
        for(int x = min.x() - 1; x < max.x() + 1; x++) {
            auto &node = m_map.at(Vector2<int>(x, y));
            node.update(delta);
            node.render(m_render);
        }
    }

    // Draw current coordinates in top left
    char buf[128] = "";
    sprintf(buf, "%d, %d", -m_camera_pos.x() / TILE_SIZE, -m_camera_pos.y() / TILE_SIZE);
    DrawString(0, 0, buf, {255, 255, 255}, 1);

    return true;
}

bool App::OnUserDestroy() {
    std::cout << "Destroy" << std::endl;
    return true;
}

int main()
{
	App app;
	if (app.Construct(800, 600, 1, 1))
		app.Start();

	return 0;
}