#include "Keybinds.h"

#include "../Core/Action.h"

#include <map>
#include <set>
#include <fstream>
#include <SFML/Graphics.hpp>


Keybinds::Keybinds(int layoutNumber) :
    layoutNumber(layoutNumber) {

    for (Action action : ACTION_LIST_IN_ORDER) {
        this->keybinds.insert({action, std::set<sfKey>()});
    }
    this->modifiable = (layoutNumber == CUSTOMIZABLE_KEYBINDS);

    this->loadKeybindsFromFile();
}

void Keybinds::loadKeybindsFromFile() {
    std::ifstream layoutFile("data/config/keybinds/layout" + std::to_string(this->layoutNumber) + ".bin", std::ios::binary);

    for (Action action : ACTION_LIST_IN_ORDER) {
        this->keybinds.at(action).clear();
    }

    char byte;
    while (layoutFile.peek() != EOF) {
        layoutFile.get(byte);
        Action action = Action(byte);

        bool separatorMet = false;
        while (!separatorMet) {
            layoutFile.get(byte);
            if (byte == (char) 0xFF) {
                separatorMet = true;
            }
            else {
                this->keybinds.at(action).insert(sfKey(byte));
            }
        }
    }
}

void Keybinds::saveKeybindsToFile() const {
    if (!this->modifiable) return;

    std::ofstream layoutFile("data/config/keybinds/layout" + std::to_string(this->layoutNumber) + ".bin", std::ios::trunc | std::ios::binary);

    char byte;
    for (Action action : ACTION_LIST_IN_ORDER) {
        byte = action;
        layoutFile.write(&byte, 1);

        for (sfKey key : this->keybinds.at(action)) {
            byte = (int) key;
            layoutFile.write(&byte, 1);
        }
        
        byte = 0xFF;
        layoutFile.write(&byte, 1);
    }
}

void Keybinds::addKey(Action action, sfKey key) {
    if (!this->modifiable) return;
    if (!KEYS_TO_STRING.contains(key)) return;

    this->keybinds.at(action).insert(key);
}

void Keybinds::clearKeys(Action action) {
    if (!this->modifiable) return;
    
    this->keybinds.at(action).clear();
}

bool Keybinds::isModifiable() const {
    return this->modifiable;
}

const std::set<Action> Keybinds::getActions(sfKey key) const {
    std::set<Action> actions;

    for (const auto& [action, keys] : this->keybinds) {
        if (keys.contains(key)) {
            actions.insert(action);
        }
    }

    return actions;
}

const std::set<sfKey>& Keybinds::getKeybinds(Action action) const {
    return this->keybinds.at(action);
}
