#include "MainApplication.h"
#include "FileLogger.h"
#include "MidiReader.h"
#include "File.h"
#include "DocumentConverter.h"
#include "DrawingManager.h"
#include "DrawingSurface.h"
#include "DrawingContext.h"
#include "Rasterizer.h"
#include "Grid.h"
#include "Image.h"

#include "TextElement.h"
#include "DiscretePoint.h"


#include <filesystem>

MainApplication::MainApplication()
     : mDatabaseManager(),
       mCommandLineArgs()
{

}

MainApplication::~MainApplication()
{

}

void MainApplication::Initialize(CommandLineArgsUPtr commandLineArgs, std::unique_ptr<IApplicationContext> applicationContext)
{
    if (applicationContext)
    {
        mApplicationContext = std::move(applicationContext);
    }
    
    mCommandLineArgs = std::move(commandLineArgs);
    const auto launch_path = mCommandLineArgs->getLaunchPath().string();

    FileLogger::GetInstance().SetWorkDirectory(launch_path);
    FileLogger::GetInstance().Open();
    MLOG_INFO("Launched");

    mDatabaseManager = DatabaseManager::Create();
    mDatabaseManager->CreateDatabase(launch_path + "/database.db");
    MLOG_INFO("Created DB");

    mNetworkManager = NetworkManager::Create();
    MLOG_INFO("Created Network Manager");

    mAudioManager = AudioManager::Create();
    MLOG_INFO("Created Audio Manager");
}

void MainApplication::Run()
{
    std::string program_type;
    if(mCommandLineArgs->getNumberOfArgs() > 1)
    {
        program_type = mCommandLineArgs->getArg(1);
    }

    std::string input_path;
    std::string output_path;
    for(unsigned idx=1; idx<mCommandLineArgs->getNumberOfArgs(); idx++)
    {
        auto arg = mCommandLineArgs->getArg(idx);
        if(arg == "-input" && mCommandLineArgs->getNumberOfArgs() > idx+1)
        {
            input_path = mCommandLineArgs->getArg(idx + 1);
        }
        else if(arg == "-output" && mCommandLineArgs->getNumberOfArgs() > idx+1)
        {
            output_path = mCommandLineArgs->getArg(idx + 1);
        }
    }

    if(program_type == "-server")
    {
        RunServer();
    }
    else if(program_type == "-audio")
    {
        PlayAudio();
    }
    else if(program_type == "-convert")
    {
        ConvertDocument(input_path, output_path);
    }
    else if(program_type == "-draw")
    {
        auto drawing_manager = DrawingManager::Create();
        drawing_manager->InitalizeSurface(400, 400);

        auto text = TextElement::Create("Hello World", DiscretePoint(20, 20));
        drawing_manager->AddText(text.get());
        drawing_manager->RenderToFile("test.png");
    }
    else
    {
        MLOG_ERROR("Unknown program type: " + program_type);
    }
}

void MainApplication::RunServer()
{
    mNetworkManager->RunHttpServer();
}

void MainApplication::PlayAudio()
{
    //MidiReader reader;
    //reader.Read("/home/james/sample.mid");
    mAudioManager->Play();
}

void MainApplication::ConvertDocument(const std::string& inputPath, const std::string& outputPath)
{
    auto input_file = File(std::filesystem::path(inputPath));
    auto output_file = File(std::filesystem::path(outputPath));
    MLOG_INFO("Converting: " + inputPath + " to " + outputPath);
    DocumentConverter converter;
    converter.Convert(&input_file, &output_file);
}

CommandLineArgs* MainApplication::GetCommandLineArgs() const
{
    return mCommandLineArgs.get();
}

void MainApplication::ShutDown()
{
    mDatabaseManager->OnShutDown();
    mNetworkManager->ShutDown();
    MLOG_INFO("Shut down");
    FileLogger::GetInstance().Close();
}

std::shared_ptr<MainApplication> MainApplication::Create()
{
    return std::make_shared<MainApplication>();
}
