/*Copyright (C) 2010-2023 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/>.
*/

#ifndef DEF_CONFIGURATION
#define DEF_CONFIGURATION

#include "Graphics/Display.hpp"
#include "Fight/FightCameraHandler.hpp" ///< FightCameraHandler::CameraMode
#include "Player/PlayerKeys.hpp"
#include "Tools/Utf8.hpp"
#include <map>
#include <string>
#include <cstddef>
#include <cstdint>

/// Class managing configuration.
/// It can edit, load and save conf items.
class Configuration
{
    public:
        enum : size_t { MaxAddressLength = 48 };

        Configuration();
        void load();
        void save();

        //Get and set methods
            //Video
        void setDisplayLayout(const Display::DisplayLayout &displayLayout);
        const Display::DisplayLayout &getDisplayLayout() const;

        void setVSyncMode(Display::VSyncMode vsyncMode);
        Display::VSyncMode getVSyncMode() const;

        void setFrameRate(int frameRate);
        int getFrameRate() const;

            //Audio
        void setMasterVolume(int masterVolume);
        int getMasterVolume() const;

        void setMusicVolume(int musicVolume);
        int getMusicVolume() const;

        void setAmbientVolume(int ambientVolume);
        int getAmbientVolume() const;

        void setSoundVolume(int soundVolume);
        int getSoundVolume() const;

        /// Weigh the music volume by the master volume and normalize it
        float outputMusicVolume() const;

        /// Weigh the ambient volume by the master volume and normalize it
        float outputAmbientVolume() const;

        /// Weigh the sound volume by the master volume and normalize it
        float outputSoundVolume() const;

            //Network
        void setNetworkAddress(const std::string &address);
        const std::string &getNetworkAddress() const;

        void setNetworkPort(std::uint16_t port);
        std::uint16_t getNetworkPort() const;

        void setNetworkUsername(const Utf8::utf8_string &username);
        const Utf8::utf8_string &getNetworkUsername() const;

        void setNetworkCharacter(const std::string &character);
        const std::string &getNetworkCharacter() const;

            //Locale
        void setLocale(const std::string &localeName);
        void setLocale(); ///< Initialize to the user default language
        const std::string &getLocale() const;

            //Misc
        void setEnableCameraShake(bool cameraShake);
        bool getEnableCameraShake() const;

        void setShowFps(bool showFps);
        bool getShowFps() const;

        void setShowHitboxes(bool showHitboxes);
        bool getShowHitboxes() const;

        void setCameraMode(FightCameraHandler::CameraMode cameraMode);
        FightCameraHandler::CameraMode getCameraMode() const;

            //Keys binding
        void setPlayerKeys(std::size_t ix, const PlayerKeys &playerKeys);
        bool getPlayerKeys(std::size_t ix, PlayerKeys &target) const;

        void setPlayerJoystickKeys(std::size_t ix,
                                   const std::string &joystickName,
                                   const PlayerKeys &playerKeys);
        bool getPlayerJoystickKeys(std::size_t ix,
                                   const std::string &joystickName,
                                   PlayerKeys &target) const;

        /// Revert a player's device to keyboard if it was removed
        void updatePlayerDevices(int removedDevice);
        void setPlayerDevice(std::size_t ix, int deviceID);
        int getPlayerDevice(std::size_t ix) const;

    private:
        Display::DisplayLayout m_displayLayout;
        Display::VSyncMode m_vsyncMode;
        int m_frameRate;
        int m_masterVolume, m_musicVolume, m_ambientVolume, m_soundVolume;
        bool m_enableCameraShake, m_showFps, m_showHitboxes;
        FightCameraHandler::CameraMode m_cameraMode;
        Utf8::utf8_string m_networkUsername;
        std::string m_networkAddress, m_networkCharacter;
        std::uint16_t m_networkPort;
        std::string m_locale;

        std::map<std::size_t, int> m_playerDevices; ///< Keyboard? Joystick?
        std::map<std::size_t, PlayerKeys> m_playerKeys;
        std::map<std::size_t, std::map<std::string, PlayerKeys>> m_playerJoystickKeys;
};

#endif
