/******************************************************************************
*	File		-	tile_set.h
*	Author		-	Joey Pollack
*	Date		-	2022/02/16 (y/m/d)
*	Mod Date	-	2022/02/16 (y/m/d)
*	Description	-	Manage a tile set for map making
******************************************************************************/

#include "tile_set.h"
#include <editor/editor.h>
#include <editor/editor_helpers.h>
#include <graphics/graphics.h>
#include <assets/types/image.h>
#include <utils/logger.h>
#include <nlohmann/json.hpp>

namespace lunarium { namespace editor 
{
    TileSet::TileSet()
        : EditorAsset(AssetType::EATYPE_TILE_SET), mTileSetID(-1), mSetImage(nullptr), mTileSize({ 0, 0})
    {
        
    }

    OpRes TileSet::LoadRawFile()
    {
        mSetImage = FileLoaders::LoadImage(mAssetDir / GetFileLocation());
        if (!mSetImage)
        {
            return OpRes::Fail("Could not load image file: %s", GetFileLocation().string().c_str());
        }

        // Set some default values
        mTileSize = { 16, 16 };
        mNumTiles = { mSetImage->GetWidth() / 16, mSetImage->GetHeight() / 16 };

        return OpRes::OK();
    }
    
    OpRes TileSet::LoadFromJSON(nlohmann::json& node)
    {
        // Load Image
        mSetImage = FileLoaders::LoadImage(mAssetDir / GetFileLocation());
        if (!mSetImage)
        {
            return OpRes::Fail("Could not load image file: %s", GetFileLocation().string().c_str());
        }

        if (!IsValidNode(node))
        {
            return OpRes::Fail("Asset node is invalid");
        }

        mTileSetID          = node["TileSetID"].get<int>();
        mTileSize.Width     = node["TileSizeWidth"].get<int>();
        mTileSize.Height    = node["TileSizeHeight"].get<int>();
        mNumTiles.Width     = node["NumTilesCol"].get<int>();
        mNumTiles.Height    = node["NumTilesRow"].get<int>();

        return OpRes::OK();
    }

    OpRes TileSet::SaveToJSON(nlohmann::json& node)
    {
        node["TileSetID"]      = mTileSetID;
        node["TileSizeWidth"]  = mTileSize.Width;
        node["TileSizeHeight"] = mTileSize.Height;
        node["NumTilesCol"]    = mNumTiles.Width;
        node["NumTilesRow"]    = mNumTiles.Height;

        return OpRes::OK();
    }

    bool TileSet::IsValidNode(nlohmann::json& node)
    {
        if (node["TileSetID"].is_null()) { return false; }
        if (!node["TileSetID"].is_number()) { return false; }

        if (node["TileSizeWidth"].is_null()) { return false; }
        if (!node["TileSizeWidth"].is_number()) { return false; }

        if (node["TileSizeHeight"].is_null()) { return false; }
        if (!node["TileSizeHeight"].is_number()) { return false; }

        if (node["NumTilesCol"].is_null()) { return false; }
        if (!node["NumTilesCol"].is_number()) { return false; }

        if (node["NumTilesRow"].is_null()) { return false; }
        if (!node["NumTilesRow"].is_number()) { return false; }

        return true;
    }

    void TileSet::SetTileSetID(int id)
    {
        mTileSetID = id;
    }

    int TileSet::GetTileSetID() const
    {
        return mTileSetID;
    }

    void TileSet::SetImage(Image* image)
    {
        mSetImage = image;
    }

    void TileSet::SetTileSize(Sizei size)
    {
        mTileSize = size;
        mNumTiles.Width = mSetImage->GetWidth() / mTileSize.Width;
        mNumTiles.Height = mSetImage->GetHeight() / mTileSize.Height;
    }

    Image* TileSet::GetImage()
    {
        return mSetImage;
    }

    Sizei TileSet::GetTileSize()
    {
        return mTileSize;
    }

    Rectangle TileSet::GetTileRect(Vec2i index)
    {
        return Rectangle::MakeFromTopLeft(index.X * mTileSize.Width, index.Y * mTileSize.Height, mTileSize.Width, mTileSize.Height);
    }

    void TileSet::Render(lunarium::IGraphics* g)
    {
        g->DrawImage(*mSetImage, glm::vec2(0, 0), Color::White());

        // Draw grid
        for (int i = 0; i < mNumTiles.Width; i++)
        {
            g->DrawLine(glm::vec2(i * mTileSize.Width, 0), glm::vec2(i * mTileSize.Width, mSetImage->GetHeight()), Color::Black(), 1.0f);
        }
        g->DrawLine(glm::vec2(mSetImage->GetWidth(), 0), glm::vec2(mSetImage->GetWidth(), mSetImage->GetHeight()), Color::Black(), 1.0f);

        for (int j = 0; j < mNumTiles.Height; j++)
        {
            g->DrawLine(glm::vec2(0, j * mTileSize.Height), glm::vec2(mSetImage->GetWidth(), j * mTileSize.Height), Color::Black(), 1.0f);
        }
        g->DrawLine(glm::vec2(0, mSetImage->GetHeight()), glm::vec2(mSetImage->GetWidth(), mSetImage->GetHeight()), Color::Black(), 1.0f);
    }
}}