#include <memory>
#include <tuple>
#include "src/pico_server_dispatcher.hpp"

using namespace std;

extern std::ostream out(cout.rdbuf());
extern SimpleLogger logger(out, "pico", "");

void createDirectoryRecursively(const std::string &directory) {
  static const std::string separators("\\/");

  // If the specified directory name doesn't exist, do our thing
  DWORD fileAttributes = ::GetFileAttributesA(directory.c_str());
  if(fileAttributes == INVALID_FILE_ATTRIBUTES) {

    // Recursively do it all again for the parent directory, if any
    std::size_t slashIndex = directory.find_last_of(separators);
    if(slashIndex != std::wstring::npos) {
      createDirectoryRecursively(directory.substr(0, slashIndex));
    }

    // Create the last directory on the path (the recursive calls will have taken
    // care of the parent directories by now)
    BOOL result = ::CreateDirectoryA(directory.c_str(), nullptr);
    if(result == FALSE) {
      throw std::runtime_error("Could not create directory");
    }

  } else { // Specified directory name already exists as a file or directory

    bool isDirectoryOrJunction =
      ((fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) ||
      ((fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0);

    if(!isDirectoryOrJunction) {
      throw std::runtime_error(
        "Could not create directory because a file with the same name exists"
      );
    }

  }
}

int main()
{
    logger.enableConsoleOutput(true);

    logger << "Open socket" << endl;
    CPassiveSocket SocketPassive(CSimpleSocket::CSocketType::SocketTypeTcp);
    if (!SocketPassive.Initialize())
    {
        logger << LogPref::Flag(ERROR) << "Socket initialization failed" << endl;
        return -1;
    }
    if(!SocketPassive.Listen("localhost", 5003))
    {
        logger << LogPref::Flag(ERROR) << "Socket listening failed" << endl;
        return -1;
    }

    logger << "Socket initialized!" << endl;

    CActiveSocket* ClientSocket;
    pico_server_dispatcher* pico_server;
    pico_server = new pico_server_dispatcher(ClientSocket);

    msgpack::sbuffer sbuf;
    msgpack::packer pk(sbuf);
    msgpack::unpacker upk;

    pico_server->configureMsgpack(&sbuf, &pk, &upk);

    while(true)
    {
        logger << LogPref::Flag(INFO) << "Wait for connection..." << endl;
        logger.closeLogger();

        if ((ClientSocket = SocketPassive.Accept()) == nullptr)
        {
            logger.closeLogger();
            logger.initializeLogger("picologs", "pico");
            logger.enableConsoleOutput(true);
            logger << LogPref::Flag(ERROR) << "Socket accept failed" << endl;
            logger.closeLogger();
            if(pico_server != nullptr) delete pico_server;
            return -1;
        }

        pico_server->changeSocket(ClientSocket);

        logger.initializeLogger("pico", "");
        logger.enableConsoleOutput(true);
        logger << LogPref::Flag(INFO) << "Client connected" << endl;

        while(pico_server->acceptRequest() != 0)
        {
            logger << LogPref::Flag(INFO) << "Request received" << endl;
        }

        logger << LogPref::Flag(INFO) << "Request processing finished" << endl;

        delete ClientSocket;
        ClientSocket = nullptr;
    }

    return 0;
}


