/******************************************************************************
*	File		-	state.cpp
*	Author		-	Joey Pollack
*	Date		-	2021/08/30 (y/m/d)
*	Mod Date	-	2021/08/30 (y/m/d)
*	Description	-	Stores all of the settings for the engine.
******************************************************************************/

#include "state.h"
#include <utils/helpers.h>
#include <utils/logger.h>
#include <pugixml.hpp>

namespace lunarium
{
    State State::CreateEmpty()
    {
        State s;
        s.DataDirectory = "";
        s.Display.FullScreenResolution.Width = 0;
        s.Display.FullScreenResolution.Height = 0;
        s.Display.RenderFramework = Renderer::OPENGL;
        s.Display.IsFullScreen = false;
        s.Display.VSyncEnabled = false;
        s.Display.WindowedSize.Width = 0;
        s.Display.WindowedSize.Height = 0;
        s.Display.WindowStartPosition.X = 0;
        s.Display.WindowStartPosition.Y = 0;
        s.Interface.MainFont = "";
        s.Mode = RunMode::MODE_TEST;

        return s;
    }

    State State::CreateDefault()
    {

        State s;
        s.DataDirectory = "data/";
        Sizei size = System::GetScreenResolution();
        s.Display.FullScreenResolution.Width = size.Width;
        s.Display.FullScreenResolution.Height = size.Height;
        s.Display.RenderFramework = Renderer::OPENGL;
        s.Display.IsFullScreen = false;
        s.Display.VSyncEnabled = true;
        s.Display.WindowedSize.Width = 800;
        s.Display.WindowedSize.Height = 600;
        s.Display.WindowStartPosition.X = 100;
        s.Display.WindowStartPosition.Y = 100;
        s.Interface.MainFont = "";
        s.Mode = RunMode::MODE_TEST;

        return s;
    }

    OpRes State::CreateFromFile(std::string filename, State& state)
    {        
        pugi::xml_document doc;
        pugi::xml_parse_result result = doc.load_file(filename.c_str());

        if (!result)
        {
            return OpRes::Fail((std::string("Could not open file: ") + filename).c_str());
        }

        pugi::xml_node root = doc.child("State");
        if (pugi::node_null == root.type())
        {
            return OpRes::Fail((filename + " does not contain a State element").c_str());
        }

        // Read in each state variable, fill in with a default if it is not found
        state.DataDirectory = root.child("DataDirectory").child_value();
        if ("" == state.DataDirectory)
        {
            state.DataDirectory = "data/";
        }

        std::string mode = String::StringToLower(root.child("Mode").attribute("Type").as_string());
        if ("test" == mode)
        {
            state.Mode = RunMode::MODE_TEST;
        }
        else if ("editor" == mode)
        {
            state.Mode = RunMode::MODE_EDITOR;
        }
        else if ("game" == mode)
        {
            state.Mode = RunMode::MODE_GAME;
        }
        else
        {
            Logger::Log(LogCategory::CORE, LogLevel::WARNING, 
                    "Can not find Run Mode in state file: %s, defaulting to MODE_TEST", filename);
            state.Mode = RunMode::MODE_TEST;
        }

        pugi::xml_node display = root.child("Display");
        if (pugi::node_null == display.type())
        {
            Sizei size = System::GetScreenResolution();
            state.Display.FullScreenResolution.Width = size.Width;
            state.Display.FullScreenResolution.Height = size.Height;
            state.Display.RenderFramework = Renderer::OPENGL;
            state.Display.IsFullScreen = false;
            state.Display.VSyncEnabled = true;
            state.Display.WindowedSize.Width = 800;
            state.Display.WindowedSize.Height = 600;
            state.Display.WindowStartPosition.X = 100;
            state.Display.WindowStartPosition.Y = 100;
        }
        else
        {
            state.Display.FullScreenResolution.Width = display.child("FullScreenResolution").attribute("Width").as_int();
            state.Display.FullScreenResolution.Height = display.child("FullScreenResolution").attribute("Height").as_int();

            std::string framework = display.attribute("RenderFramework").as_string();
            if (String::StringToLower(framework) == "opengl")
            {
                state.Display.RenderFramework = Renderer::OPENGL;
            }
            else if (String::StringToLower(framework) == "vulkan")
            {
                state.Display.RenderFramework = Renderer::VULKAN;
            }
            else
            {
                state.Display.RenderFramework = Renderer::UNKNOWN;
            }

            state.Display.IsFullScreen = display.attribute("IsFullScreen").as_bool();
            state.Display.VSyncEnabled = display.attribute("VSyncEnabled").as_bool();
            state.Display.WindowedSize.Width = display.child("WindowedSize").attribute("Width").as_int();
            state.Display.WindowedSize.Height = display.child("WindowedSize").attribute("Height").as_int();;
            state.Display.WindowStartPosition.X = display.child("WindowStartPosition").attribute("X").as_int();
            state.Display.WindowStartPosition.Y = display.child("WindowStartPosition").attribute("Y").as_int();
        }


        pugi::xml_node interface = root.child("Interface");
        if (pugi::node_null == display.type())
        {
            state.Interface.MainFont = "";
        }
        else
        {
            state.Interface.MainFont = interface.attribute("MainFont").value();
        }

        

        return OpRes::OK();
    }

    OpRes State::SaveToFile(std::string filename)
    {
        pugi::xml_document doc;
        doc.append_child("State");

        doc.child("State").append_child("DataDirectory");
        doc.child("State").child("DataDirectory").text().set(DataDirectory.c_str());

        const char* types[] = { "game", "editor", "test"};
        doc.child("State").append_child("Mode").append_attribute("Type").set_value(types[Mode]);

        // Display
        pugi::xml_node display = doc.child("State").append_child("Display");
        display.append_attribute("IsFullScreen").set_value(Display.IsFullScreen);
        display.append_attribute("VSyncEnabled").set_value(Display.VSyncEnabled);
        
        const char* names[] = { "opengl", "vulkan", "unknown" };
        display.append_attribute("RenderFramework").set_value(names[Display.RenderFramework]);
        
        pugi::xml_node fsr = display.append_child("FullScreenResolution");
        fsr.append_attribute("Width").set_value(Display.FullScreenResolution.Width);
        fsr.append_attribute("Height").set_value(Display.FullScreenResolution.Height);

        pugi::xml_node ws = display.append_child("WindowedSize");
        ws.append_attribute("Width").set_value(Display.WindowedSize.Width);
        ws.append_attribute("Height").set_value(Display.WindowedSize.Height);

        pugi::xml_node wsp = display.append_child("WindowStartPosition");
        wsp.append_attribute("X").set_value(Display.WindowStartPosition.X);
        wsp.append_attribute("Y").set_value(Display.WindowStartPosition.Y);

        // Interface
        pugi::xml_node interface = doc.child("State").append_child("Interface");
        interface.append_attribute("MainFont").set_value(Interface.MainFont.c_str());

        return doc.save_file(filename.c_str()) 
            ? OpRes::OK() 
            : OpRes::Fail((std::string("Could not save xml file: ") + filename).c_str());
    }
}