/*Copyright (C) 2010-2020 Duncan Deveaux

This file is part of Hikou no mizu.

Hikou no mizu is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Hikou no mizu is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Hikou no mizu.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "Configuration.hpp"

Configuration::Configuration() :
m_windowWidth(1024), m_windowHeight(576), m_frameRate(60),
m_fullscreen(false), m_debugMode(false), m_dynamicCamera(true),
m_masterVolume(70), m_musicVolume(20), m_soundVolume(100)
{
    m_playerKeys[1] = PlayerKeys(); //Player 1 : Default keys
    m_playerKeys[2] = PlayerKeys(Key(KeyboardKey(SDL_SCANCODE_I)),
                                    Key(KeyboardKey(SDL_SCANCODE_O)),
                                    Key(KeyboardKey(SDL_SCANCODE_P)),
                                    Key(KeyboardKey(SDL_SCANCODE_UP)),
                                    Key(KeyboardKey(SDL_SCANCODE_LEFT)),
                                    Key(KeyboardKey(SDL_SCANCODE_RIGHT)),
                                    Key(KeyboardKey(SDL_SCANCODE_DOWN))); //Player 2 : Other keys
    
    m_cfgDirectory = Directory::getHNMHome();
}

void Configuration::load()
{
    //Main configuration
    ConfReader mainCfgReader;
    if (mainCfgReader.load(m_cfgDirectory + "main.cfg"))
    {
        //Init variables
        int windowWidth, windowHeight, frameRate;
        int masterVolume, musicVolume, soundVolume;
        bool fullscreen, debugMode, dynamicCamera;
        
        //Get elements
        //Video
        if (mainCfgReader.getIntItem("window_width", windowWidth) && mainCfgReader.getIntItem("window_height", windowHeight))
        {
            setWindowWidth(windowWidth);
            setWindowHeight(windowHeight);
        }
        
        if (mainCfgReader.getBoolItem("fullscreen", fullscreen))
            setFullscreen(fullscreen);
        
        if (mainCfgReader.getIntItem("framerate", frameRate))
            setFrameRate(frameRate);
        
        //Audio
        if (mainCfgReader.getIntItem("master_volume", masterVolume))
            setMasterVolume(masterVolume);
        
        if (mainCfgReader.getIntItem("music_volume", musicVolume))
            setMusicVolume(musicVolume);
        
        if (mainCfgReader.getIntItem("sound_volume", soundVolume))
            setSoundVolume(soundVolume);
        
        //Misc
        if (mainCfgReader.getBoolItem("debug_mode", debugMode))
            setDebugMode(debugMode);
        
        if (mainCfgReader.getBoolItem("dynamic_camera", dynamicCamera))
            setCameraDynamic(dynamicCamera);
    }
    
    //Keys configuration
    ConfReader keysCfgReader;
    
    bool browsing = true;
    int i = 1;
    while (browsing)
    {
        std::ostringstream keysFilePath;
        keysFilePath << m_cfgDirectory << "keys/player" << i << "/main.cfg";
        
        if (keysCfgReader.load(keysFilePath.str()))
        {
            PlayerKeys keys;
            keysCfgReader.getPlayerKeysList(keys, "keyboard");
            
            setPlayerKeys(i, keys);
            
            //Joystick keys
            bool browsingJoystick = true;
            int j = 0;
            while (browsingJoystick)
            {
                std::ostringstream joyKeysFilePath;
                joyKeysFilePath << m_cfgDirectory << "keys/player" << i << "/joystick" << j << ".cfg";
                
                if (keysCfgReader.load(joyKeysFilePath.str()))
                {
                    std::string joystickName;
                    if (keysCfgReader.getItem("joystick", joystickName))
                    {
                        PlayerKeys joyKeys;
                        keysCfgReader.getPlayerKeysList(joyKeys, joystickName);
                        
                        setPlayerJoystickKeys(i, joystickName, joyKeys);
                    }
                }
                else
                    browsingJoystick = false;
                
                j++;
            }
        }
        else
            browsing = false;
        
        i++;
    }
}

void Configuration::save()
{
    //Create directories if needed
    Directory::create(m_cfgDirectory);
    Directory::create(m_cfgDirectory + "keys");
    
    //Main configuration
    ConfWriter mainCfgWriter;
    
    //Video
    mainCfgWriter.addIntItem("window_width", m_windowWidth);
    mainCfgWriter.addIntItem("window_height", m_windowHeight);
    mainCfgWriter.addBoolItem("fullscreen", m_fullscreen);
    
    mainCfgWriter.addIntItem("framerate", m_frameRate);
    
    //Audio
    mainCfgWriter.addIntItem("master_volume", m_masterVolume);
    mainCfgWriter.addIntItem("music_volume", m_musicVolume);
    mainCfgWriter.addIntItem("sound_volume", m_soundVolume);
    
    //Misc
    mainCfgWriter.addBoolItem("debug_mode", m_debugMode);
    mainCfgWriter.addBoolItem("dynamic_camera", m_dynamicCamera);
    
    mainCfgWriter.writeFile(m_cfgDirectory + "main.cfg");
    
    //Keys configuration
    std::map<unsigned int, PlayerKeys>::iterator it;
    for (it = m_playerKeys.begin(); it != m_playerKeys.end(); it++)
    {
        //Create directory if needed.
        std::ostringstream keysDirectoryPath;
        keysDirectoryPath << m_cfgDirectory << "keys/player" << it->first << "/";
        Directory::create(keysDirectoryPath.str());
        
        //Set elements
        ConfWriter keysCfgWriter;
        keysCfgWriter.addPlayerKeysList(it->second);
        
        std::ostringstream mainKeysFilePath; //Keyboard.
        mainKeysFilePath << keysDirectoryPath.str() << "main.cfg";
        keysCfgWriter.writeFile(mainKeysFilePath.str());
        
        //Joysticks
        int i = 0;
        std::map<std::string, PlayerKeys> joyKeys = m_playerJoystickKeys[it->first];
        for (std::map<std::string, PlayerKeys>::iterator it2 = joyKeys.begin(); it2 != joyKeys.end(); it2++)
        {
            ConfWriter joyKeysCfgWriter;
            joyKeysCfgWriter.addItem("joystick", it2->first);
            joyKeysCfgWriter.addPlayerKeysList(it2->second);
            
            std::ostringstream joyKeysFilePath; //Keyboard.
            joyKeysFilePath << keysDirectoryPath.str() << "joystick" << i << ".cfg";
            joyKeysCfgWriter.writeFile(joyKeysFilePath.str());
            
            i++;
        }
    }
}

//Get and set methods
    //Video
void Configuration::setWindowWidth(int windowWidth)
{
    if (windowWidth > 0)
        m_windowWidth = windowWidth;
}

int Configuration::getWindowWidth() const
{
    return m_windowWidth;
}

void Configuration::setWindowHeight(int windowHeight)
{
    if (windowHeight > 0)
        m_windowHeight = windowHeight;
}

int Configuration::getWindowHeight() const
{
    return m_windowHeight;
}

void Configuration::setFullscreen(bool fullscreen)
{
    m_fullscreen = fullscreen;
}

bool Configuration::getFullscreen() const
{
    return m_fullscreen;
}

void Configuration::setFrameRate(int frameRate)
{
    if (m_frameRate >= 0)
        m_frameRate = frameRate;
}

int Configuration::getFrameRate() const
{
    return m_frameRate;
}

    //Audio
void Configuration::setMasterVolume(int masterVolume)
{
    if (masterVolume >= 0)
        m_masterVolume = masterVolume;
}

int Configuration::getMasterVolume() const
{
    return m_masterVolume;
}

void Configuration::setMusicVolume(int musicVolume)
{
    if (musicVolume >= 0)
        m_musicVolume = musicVolume;
}

int Configuration::getMusicVolume() const
{
    return m_musicVolume;
}

void Configuration::setSoundVolume(int soundVolume)
{
    if (soundVolume >= 0)
        m_soundVolume = soundVolume;
}

int Configuration::getSoundVolume() const
{
    return m_soundVolume;
}

    //Misc
void Configuration::setDebugMode(bool debugMode)
{
    m_debugMode = debugMode;
}

bool Configuration::getDebugMode() const
{
    return m_debugMode;
}

void Configuration::setCameraDynamic(bool dynamicCamera)
{
    m_dynamicCamera = dynamicCamera;
}

bool Configuration::isCameraDynamic() const
{
    return m_dynamicCamera;
}

    //Keys binding
void Configuration::setPlayerKeys(unsigned int ix, const PlayerKeys &playerKeys)
{
    m_playerKeys[ix] = playerKeys;
}

bool Configuration::getPlayerKeys(unsigned int ix, PlayerKeys &target) const
{
    std::map<unsigned int, PlayerKeys>::const_iterator it = m_playerKeys.find(ix);
    
    if (it != m_playerKeys.end())
    {
        target = it->second;
        return true;
    }
    
    return false;
}

void Configuration::setPlayerJoystickKeys(unsigned int ix, std::string joystickName, const PlayerKeys &playerKeys)
{
    m_playerJoystickKeys[ix][joystickName] = playerKeys;
}

int Configuration::getPlayerJoystickKeys(unsigned int ix, std::string joystickName, PlayerKeys &target) const
{
    std::map<unsigned int, std::map<std::string, PlayerKeys> >::const_iterator it = m_playerJoystickKeys.find(ix);
    
    if (it != m_playerJoystickKeys.end())
    {
        std::map<std::string, PlayerKeys>::const_iterator it2 = it->second.find(joystickName);
        if (it2 != it->second.end())
        {
            target = it2->second;
            return true;
        }
    }
    
    return false;
}

///Return player devices to keyboard if removed.
void Configuration::updatePlayerDevices(int removedDevice)
{
    std::map<unsigned int, int>::iterator it;
    for (it = m_playerDevices.begin(); it != m_playerDevices.end(); it++)
    {
        if (it->second == removedDevice)
            it->second = DEVICE_KEYBOARD;
    }
}

void Configuration::setPlayerDevice(unsigned int ix, int deviceID)
{
    m_playerDevices[ix] = deviceID;
}

int Configuration::getPlayerDevice(unsigned int ix) const
{
    std::map<unsigned int, int>::const_iterator it = m_playerDevices.find(ix);
    
    if (it != m_playerDevices.end())
        return it->second;
    
    return DEVICE_KEYBOARD;
}
