/*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 "KeyBindTab.hpp"

KeyBindTab::KeyBindTab() : Tab(), m_currentDeviceID(DEVICE_KEYBOARD),
m_configuration(NULL), m_textureManager(NULL), m_labelFont(NULL), m_soundEngine(NULL), m_playerIx(0)
{
    
}

KeyBindTab::KeyBindTab(Configuration &configuration, unsigned int playerIx, TextureManager &manager, Font &titleFont, Font &labelFont, SoundEngine &soundEngine) :
Tab(375, 290, Color(50, 93, 151)), m_configuration(&configuration), m_textureManager(&manager),
m_labelFont(&labelFont), m_soundEngine(&soundEngine), m_playerIx(playerIx)
{
    Sprite chooser_default( (*manager.getTexture("gfx/ui/ui.png")), Box(0, 0, 240.f / 512, 60.f / 512) ),
    chooser_hover( (*manager.getTexture("gfx/ui/ui.png")), Box(0, 64.f / 512, 240.f / 512, 60.f / 512) );
    
    //Title text & apply Button
    std::ostringstream titleStr;
    titleStr << "Player #" << m_playerIx << " key binder";
    
    m_titleText.setText(titleStr.str());
    m_titleText.setFont(titleFont);
    m_titleText.setPosition( (getWidth() - m_titleText.getWidth()) / 2, 10);
    
    m_activeGameDeviceText.setText("Active gaming device:");
    m_activeGameDeviceText.setFont(labelFont);
    m_activeGameDeviceText.setPosition(10, m_titleText.getYPosition() + m_titleText.getHeight() + 25);
    
    SkinBox chooserButton_skin(200.f, 30.f, chooser_default, chooser_hover);
    SkinSound button_sounds(soundEngine, "sound/ui/menuFocus.ogg", "sound/ui/menuClick.ogg");
    
    TextButton chooserButton = TextButton("", chooserButton_skin, button_sounds);
    chooserButton.setTextFont(labelFont);
    
    //Key binders
    m_selectionToDevice[0] = DEVICE_KEYBOARD;
    m_deviceNames[DEVICE_KEYBOARD] = KEYBOARD_NAME;
    
    std::vector<std::string> chooserData;
    chooserData.push_back(KEYBOARD_NAME);
    
    m_deviceChooser = Chooser(chooserButton, chooserData, 0);
    m_deviceChooser.setPosition( m_activeGameDeviceText.getXPosition() + m_activeGameDeviceText.getWidth() + 10,
                                 m_activeGameDeviceText.getYPosition() + (m_activeGameDeviceText.getHeight() - m_deviceChooser.getHeight()) / 2 );
    
    PlayerKeys initialKeys; //Keys to initialize the Key Binders
    m_configuration->getPlayerKeys(m_playerIx, initialKeys);
    
    m_keyBinders[DEVICE_KEYBOARD] = MultipleKeyBinder(DEVICE_KEYBOARD, initialKeys, manager, labelFont, soundEngine);
    m_keyBinders[DEVICE_KEYBOARD].setPosition( (getWidth() - m_keyBinders[DEVICE_KEYBOARD].getWidth()) / 2,
                                                m_deviceChooser.getYPosition() + m_deviceChooser.getHeight() + 10 );

    m_currentDeviceID = DEVICE_KEYBOARD;
}

void KeyBindTab::draw()
{
    //Update matrix
    Drawable::pushMatrix();
    Drawable::updateMatrix();
    
    m_background.draw();
    
    //Draw title text
    m_titleText.draw();
    m_activeGameDeviceText.draw();
    m_deviceChooser.draw();
    
    //Draw binders
    m_keyBinders[m_currentDeviceID].draw();
    
    Drawable::popMatrix();
}

void KeyBindTab::addJoystickBinder(int joystickID, std::string joystickName)
{
    if (m_configuration == NULL || m_textureManager == NULL || m_labelFont == NULL || m_soundEngine == NULL)
    {
        std::cout << "Key binders: No resources specified." << std::endl;
        return;
    }
    else if (m_deviceNames.count(joystickID) > 0)
    {
        std::cout << "Joystick ID " << joystickID << " already known." << std::endl;
        return;
    }
    
    PlayerKeys joystickKeys = PlayerKeys::undefinedKeys();
    m_configuration->getPlayerJoystickKeys(m_playerIx, joystickName, joystickKeys);
    
    m_keyBinders[joystickID] = MultipleKeyBinder(joystickID, joystickKeys, (*m_textureManager), (*m_labelFont), (*m_soundEngine));
    m_keyBinders[joystickID].setPosition((getWidth() - m_keyBinders[joystickID].getWidth()) / 2,
                                          m_deviceChooser.getYPosition() + m_deviceChooser.getHeight() + 10 );
    
    m_deviceNames[joystickID] = joystickName;
    
    if (m_configuration->getPlayerDevice(m_playerIx) == joystickID)
        m_currentDeviceID = joystickID;
    
    resetChooser();
}

void KeyBindTab::removeJoystickBinder(int joystickID)
{
    //Do not remove keyboard input.
    if (joystickID == DEVICE_KEYBOARD)
        return;
    
    m_deviceNames.erase(joystickID);
    m_keyBinders.erase(joystickID);
    
    if (joystickID == m_currentDeviceID)
        m_currentDeviceID = m_configuration->getPlayerDevice(m_playerIx);
    
    resetChooser();
}

bool KeyBindTab::mouseClick(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);
    
    if (m_deviceChooser.mouseClick(localMouse))
    {
        m_currentDeviceID = m_selectionToDevice[m_deviceChooser.getSelection()];
        applyActiveDevice();
    }
    
    m_keyBinders[m_currentDeviceID].mouseClick(localMouse);
    
    return Widget::contains(localMouse);
}

bool KeyBindTab::mouseMove(const Vector &mouseCoords)
{
    Vector localMouse = Widget::localCoords(mouseCoords);
    m_deviceChooser.mouseMove(localMouse);
    m_keyBinders[m_currentDeviceID].mouseMove(localMouse);
    
    return Widget::contains(localMouse);
}

void KeyBindTab::keyEvent(const SDL_Event &event)
{
    Key key;
    int deviceID;
    if (Key::pressedFromEvent(event, key, deviceID))
    {
        m_keyBinders[m_currentDeviceID].keyDown(key, deviceID);
        applyKeys();
    }
}

void KeyBindTab::applyKeys()
{
    if (m_configuration != NULL)
    {
        PlayerKeys mainKeys = m_keyBinders[DEVICE_KEYBOARD].getKeys();
        m_configuration->setPlayerKeys(m_playerIx, mainKeys);
        
        for (std::map<int, MultipleKeyBinder>::iterator it = m_keyBinders.begin(); it != m_keyBinders.end(); it++)
        {
            if (it->first != DEVICE_KEYBOARD)
                m_configuration->setPlayerJoystickKeys(m_playerIx, m_deviceNames[it->first], it->second.getKeys());
        }
    }
}

void KeyBindTab::applyActiveDevice()
{
    if (m_configuration != NULL)
        m_configuration->setPlayerDevice(m_playerIx, m_currentDeviceID);
}

void KeyBindTab::resetChooser()
{
    m_selectionToDevice.clear();
    std::vector<std::string> devicesList;
    
    int i = 0;
    int defaultSelectionID = 0;
    std::map<int, std::string>::iterator it;
    for (it = m_deviceNames.begin(); it != m_deviceNames.end(); it++)
    {
        devicesList.push_back(it->second);
        m_selectionToDevice[i] = it->first;
        
        if (it->first == m_currentDeviceID)
            defaultSelectionID = i;
        
        i++;
    }
    
    m_deviceChooser.setData(devicesList, defaultSelectionID);
}
