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

Key::Key() : AbstractKey(), m_type(KEY_UNDEFINED)
{
    
}

Key::Key(KeyboardKey keyboardKey) : AbstractKey(), m_type(KEY_KEYBOARD), m_keyboardKey(keyboardKey)
{

}

Key::Key(JoyButtonKey joyButtonKey) : AbstractKey(), m_type(KEY_JOYBUTTON), m_joyButtonKey(joyButtonKey)
{

}

Key::Key(JoyHatKey joyHatKey) : AbstractKey(), m_type(KEY_JOYHAT), m_joyHatKey(joyHatKey)
{

}

Key::Key(JoyAxisKey joyAxisKey) : AbstractKey(), m_type(KEY_JOYAXIS), m_joyAxisKey(joyAxisKey)
{

}

bool Key::isFromKeyboard() const
{
    return m_type == KEY_KEYBOARD;
}

bool Key::isFromJoystick() const
{
    return m_type == KEY_JOYBUTTON || m_type == KEY_JOYHAT || m_type == KEY_JOYAXIS;
}

std::string Key::getName() const
{
    if (m_type == KEY_KEYBOARD)
        return m_keyboardKey.getName();
    else if (m_type == KEY_JOYBUTTON)
        return m_joyButtonKey.getName();
    else if (m_type == KEY_JOYHAT)
        return m_joyHatKey.getName();
    else if (m_type == KEY_JOYAXIS)
        return m_joyAxisKey.getName();
    
    return "?";
}

std::string Key::getKeyCode() const
{
    if (m_type == KEY_KEYBOARD)
        return m_keyboardKey.getKeyCode();
    else if (m_type == KEY_JOYBUTTON)
        return m_joyButtonKey.getKeyCode();
    else if (m_type == KEY_JOYHAT)
        return m_joyHatKey.getKeyCode();
    else if (m_type == KEY_JOYAXIS)
        return m_joyAxisKey.getKeyCode();
    
    return "undef";
}

Key Key::fromKeyCode(const std::string &code, const std::string &deviceName)
{
    if (code == "undef" || code.size() < 2)
        return Key();
    else
    {
        std::string qualifier = code.substr(0,2);
        std::string codeStr = code.substr(2);
        
        long keyCode;
        std::istringstream convertToLong(codeStr);
        convertToLong >> keyCode;
        
        if (convertToLong.fail())
            return Key();
        
        if (qualifier == "kb")
        {
            return Key(static_cast<SDL_Scancode>(keyCode));
        }
        else if (qualifier == "jb")
        {
            return Key(JoyButtonKey(deviceName, static_cast<Uint8>(keyCode)));
        }
        else if (qualifier == "jh")
        {
            int hatID;
            std::istringstream convertHatID(codeStr.substr(0, codeStr.size() - 2));
            convertHatID >> hatID;
            
            if (convertHatID.fail())
                return Key();
            
            std::string hatMoveCode = codeStr.substr(codeStr.size() - 2);
            return Key(JoyHatKey(deviceName, hatID, JoyHatKey::hatMoveFromStringCode(hatMoveCode)));
        }
        else if (qualifier == "ja")
        {
            int axisID;
            std::istringstream convertAxisID(codeStr.substr(0, codeStr.size() - 1));
            convertAxisID >> axisID;
            
            if (convertAxisID.fail())
                return Key();
            
            std::string axisMoveCode = codeStr.substr(codeStr.size() - 1);
            return Key(JoyAxisKey(deviceName, axisID, JoyAxisKey::axisMoveFromStringCode(axisMoveCode)));
        }
    }
    
    return Key();
}

bool Key::pressedFromEvent(const SDL_Event &event, Key &dstKey, int &dstDeviceID)
{
    if (event.type == SDL_KEYDOWN)
    {
        dstKey = Key(event.key.keysym.scancode);
        dstDeviceID = DEVICE_KEYBOARD;
        return true;
    }
    else if (event.type == SDL_JOYBUTTONDOWN)
    {
        dstKey = Key(JoyButtonKey("noname", event.jbutton.button));
        dstDeviceID = event.jbutton.which;
        return true;
    }
    else if (event.type == SDL_JOYHATMOTION)
    {
        JoyHatMove hatMoveValue;
        if (JoyHatKey::hatMoveFromSDLCode(event.jhat.value, hatMoveValue))
        {
            dstKey = Key(JoyHatKey("noname", event.jhat.hat, hatMoveValue));
            dstDeviceID = event.jhat.which;
            return true;
        }
    }
    else if (event.type == SDL_JOYAXISMOTION)
    {
        AxisState axisStateValue = JoyAxisKey::axisStateFromSDLCode(event.jaxis.value);
        if (axisStateValue == AXIS_STATE_CENTERED)
            return false;
        else
        {
            dstKey = Key(JoyAxisKey("noname", event.jaxis.axis,
                                    axisStateValue == AXIS_STATE_NEGATIVE ?
                                    JOY_AXIS_NEGATIVE : JOY_AXIS_POSITIVE));
            dstDeviceID = event.jaxis.which;
            return true;
        }
    }
    
    return false;
}
