/*
 Virtual Piano test using the MIDI Sequencer C++ library
 Copyright (C) 2006-2022 Pedro Lopez-Cabanillas <plcl@users.sf.net>

 This program 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.

 This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "vpianosettings.h"
#include <QDir>
#include <QFileInfo>
#include <drumstick/settingsfactory.h>

using namespace drumstick::rt;
using namespace drumstick::widgets;

VPianoSettings::VPianoSettings(QObject *parent) : QObject(parent)
{
    ResetDefaults();
}

VPianoSettings* VPianoSettings::instance()
{
    static VPianoSettings inst;
    return &inst;
}

void VPianoSettings::ResetDefaults()
{
    m_midiThru = false;
    m_advanced = false;
    m_inChannel = 0;
    m_outChannel = 0;
    m_velocity = 100;
    m_baseOctave = 1;
    m_numKeys = 88;
    m_startingKey = 9;
    m_defaultsMap = QVariantMap{
        { BackendManager::QSTR_DRUMSTICKRT_PUBLICNAMEIN, QStringLiteral("Virtual Piano IN")},
        { BackendManager::QSTR_DRUMSTICKRT_PUBLICNAMEOUT, QStringLiteral("Virtual Piano OUT")}
    };
    emit ValuesChanged();
}

void VPianoSettings::ReadSettings()
{
    SettingsFactory settings;
    internalRead(*settings.getQSettings());
}

void VPianoSettings::SaveSettings()
{
    SettingsFactory settings;
    internalSave(*settings.getQSettings());
}

void VPianoSettings::ReadFromFile(const QString &filepath)
{
    QSettings settings(filepath, QSettings::IniFormat);
    internalRead(settings);
}

void VPianoSettings::SaveToFile(const QString &filepath)
{
    QSettings settings(filepath, QSettings::IniFormat);
    internalSave(settings);
}

void VPianoSettings::internalRead(QSettings &settings)
{
    const QStringList STD_NAMES_S{"do", "do♯", "re", "re♯", "mi", "fa", "fa♯", "sol", "sol♯", "la", "la♯", "si"};
    const QStringList STD_NAMES_F{"do", "re♭", "re", "mi♭", "mi", "fa", "sol♭", "sol", "la♭", "la", "si♭", "si"};

    settings.beginGroup("Window");
    m_geometry = settings.value("Geometry").toByteArray();
    m_state = settings.value("State").toByteArray();
    settings.endGroup();

    settings.beginGroup(BackendManager::QSTR_DRUMSTICKRT_GROUP);
    QStringList keys = settings.allKeys();
    for(auto it = m_defaultsMap.begin(); it != m_defaultsMap.end(); ++it) {
        if (!keys.contains(it.key())) {
            keys.append(it.key());
        }
    }
    for(const QString& key : qAsConst(keys)) {
        QVariant defval = m_defaultsMap.contains(key) ? m_defaultsMap[key] : QString();
        m_settingsMap.insert(key, settings.value(key, defval));
    }
    settings.endGroup();

    settings.beginGroup("Connections");
    m_lastInputBackend = settings.value("inputBackend").toString();
    m_lastOutputBackend = settings.value("outputBackend").toString();
    m_lastInputConnection = settings.value("inputConnection").toString();
    m_lastOutputConnection = settings.value("outputConnection").toString();
    m_midiThru = settings.value("midiThru", false).toBool();
    m_advanced = settings.value("advanced", false).toBool();
    settings.endGroup();

    settings.beginGroup("Preferences");
    setInChannel(settings.value("inputChannel", 0).toInt());
    setOutChannel(settings.value("outputChannel", 0).toInt());
    setVelocity(settings.value("velocity", 100).toInt());
    setBaseOctave(settings.value("baseOctave", 1).toInt());
    setNumKeys(settings.value("numKeys", 88).toInt());
    setStartingKey(settings.value("startingKey", 9).toInt());
    setBaseOctave(settings.value("baseOctave", 1).toInt());
    setNumKeys(settings.value("numKeys", 88).toInt());
    setStartingKey(settings.value("startingKey", 9).toInt());
    settings.endGroup();

    settings.beginGroup("TextSettings");
    QFont f = QGuiApplication::font();
    f.setPointSize(50);
    if (f.fromString(settings.value("namesFont", f.toString()).toString())) {
        setNamesFont(f);
    }
    setNamesOrientation(static_cast<LabelOrientation>(settings.value("namesOrientation", HorizontalOrientation).toInt()));
    setNamesVisibility(static_cast<LabelVisibility>(settings.value("namesVisibility", ShowNever).toInt()));
    setNamesAlterations(static_cast<LabelAlteration>(settings.value("namesAlteration", ShowSharps).toInt()));
    setNamingPolicy(static_cast<LabelNaming>(settings.value("namingPolicy", StandardNames).toInt()));
    setNamesOctave(static_cast<LabelCentralOctave>(settings.value("namesOctave", OctaveC4).toInt()));
    setNames_sharps(settings.value("names_sharps", STD_NAMES_S).toStringList());
    setNames_flats(settings.value("names_flats", STD_NAMES_F).toStringList());
    setInvertedKeys(settings.value("inverted_keys", false).toBool());
    settings.endGroup();

    emit ValuesChanged();
}

void VPianoSettings::internalSave(QSettings &settings)
{
    settings.beginGroup("Window");
    settings.setValue("Geometry", m_geometry);
    settings.setValue("State", m_state);
    settings.endGroup();

    settings.beginGroup(BackendManager::QSTR_DRUMSTICKRT_GROUP);
    for (auto it = m_settingsMap.begin(); it != m_settingsMap.end(); ++it) {
        settings.setValue(it.key(), it.value());
    }
    settings.endGroup();

    settings.beginGroup("Connections");
    settings.setValue("inputBackend", m_lastInputBackend);
    settings.setValue("outputBackend", m_lastOutputBackend);
    settings.setValue("inputConnection", m_lastInputConnection);
    settings.setValue("outputConnection", m_lastOutputConnection);
    settings.setValue("midiThru", m_midiThru);
    settings.setValue("advanced", m_advanced);
    settings.endGroup();

    settings.beginGroup("Preferences");
    settings.setValue("inputChannel", m_inChannel);
    settings.setValue("outputChannel", m_outChannel);
    settings.setValue("velocity", m_velocity);
    settings.setValue("baseOctave", m_baseOctave);
    settings.setValue("numKeys", m_numKeys);
    settings.setValue("startingKey", m_startingKey);
    settings.endGroup();

    settings.beginGroup("TextSettings");
    settings.setValue("namesFont", m_namesFont.toString());
    settings.setValue("namesOrientation", m_namesOrientation);
    settings.setValue("namesVisibility", m_namesVisibility);
    settings.setValue("namesAlteration", m_namesAlteration);
    settings.setValue("namingPolicy", m_namingPolicy);
    settings.setValue("namesOctave", m_namesOctave);
    settings.setValue("names_sharps", m_names_sharps);
    settings.setValue("names_flats", m_names_flats);
    settings.setValue("inverted_keys", m_invertedKeys);
    settings.endGroup();

    settings.sync();
}

bool VPianoSettings::invertedKeys() const
{
    return m_invertedKeys;
}

void VPianoSettings::setInvertedKeys(bool newInvertedKeys)
{
    m_invertedKeys = newInvertedKeys;
}

QStringList VPianoSettings::names_flats() const
{
    return m_names_flats;
}

void VPianoSettings::setNames_flats(const QStringList &names_flats)
{
    m_names_flats = names_flats;
}

QStringList VPianoSettings::names_sharps() const
{
    return m_names_sharps;
}

void VPianoSettings::setNames_sharps(const QStringList &names_sharps)
{
    m_names_sharps = names_sharps;
}

LabelNaming VPianoSettings::namingPolicy() const
{
    return m_namingPolicy;
}

void VPianoSettings::setNamingPolicy(const LabelNaming namingPolicy)
{
    m_namingPolicy = namingPolicy;
}

LabelCentralOctave VPianoSettings::namesOctave() const
{
    return m_namesOctave;
}

void VPianoSettings::setNamesOctave(const LabelCentralOctave namesOctave)
{
    m_namesOctave = namesOctave;
}

QFont VPianoSettings::namesFont() const
{
    return m_namesFont;
}

void VPianoSettings::setNamesFont(const QFont &namesFont)
{
    m_namesFont = namesFont;
}

LabelAlteration VPianoSettings::alterations() const
{
    return m_namesAlteration;
}

void VPianoSettings::setNamesAlterations(const LabelAlteration alterations)
{
    m_namesAlteration = alterations;
}

LabelVisibility VPianoSettings::namesVisibility() const
{
    return m_namesVisibility;
}

void VPianoSettings::setNamesVisibility(const LabelVisibility namesVisibility)
{
    m_namesVisibility = namesVisibility;
}

LabelOrientation VPianoSettings::namesOrientation() const
{
    return m_namesOrientation;
}

void VPianoSettings::setNamesOrientation(const LabelOrientation namesOrientation)
{
    m_namesOrientation = namesOrientation;
}

QVariantMap VPianoSettings::settingsMap() const
{
    return m_settingsMap;
}

int VPianoSettings::startingKey() const
{
    return m_startingKey;
}

void VPianoSettings::setStartingKey(int startingKey)
{
    m_startingKey = startingKey;
}

int VPianoSettings::numKeys() const
{
    return m_numKeys;
}

void VPianoSettings::setNumKeys(int numKeys)
{
    m_numKeys = numKeys;
}

int VPianoSettings::baseOctave() const
{
    return m_baseOctave;
}

void VPianoSettings::setBaseOctave(int baseOctave)
{
    m_baseOctave = baseOctave;
}

int VPianoSettings::velocity() const
{
    return m_velocity;
}

void VPianoSettings::setVelocity(int velocity)
{
    m_velocity = velocity;
}

int VPianoSettings::outChannel() const
{
    return m_outChannel;
}

void VPianoSettings::setOutChannel(int outChannel)
{
    m_outChannel = outChannel;
}

int VPianoSettings::inChannel() const
{
    return m_inChannel;
}

void VPianoSettings::setInChannel(int inChannel)
{
    m_inChannel = inChannel;
}

bool VPianoSettings::advanced() const
{
    return m_advanced;
}

void VPianoSettings::setAdvanced(bool advanced)
{
    m_advanced = advanced;
}

bool VPianoSettings::midiThru() const
{
    return m_midiThru;
}

void VPianoSettings::setMidiThru(bool midiThru)
{
    m_midiThru = midiThru;
}

QString VPianoSettings::lastOutputConnection() const
{
    return m_lastOutputConnection;
}

void VPianoSettings::setLastOutputConnection(const QString &lastOutputConnection)
{
    m_lastOutputConnection = lastOutputConnection;
}

QString VPianoSettings::lastInputConnection() const
{
    return m_lastInputConnection;
}

void VPianoSettings::setLastInputConnection(const QString &lastInputConnection)
{
    m_lastInputConnection = lastInputConnection;
}

QString VPianoSettings::lastOutputBackend() const
{
    return m_lastOutputBackend;
}

void VPianoSettings::setLastOutputBackend(const QString &lastOutputBackend)
{
    m_lastOutputBackend = lastOutputBackend;
}

QString VPianoSettings::lastInputBackend() const
{
    return m_lastInputBackend;
}

void VPianoSettings::setLastInputBackend(const QString &lastInputBackend)
{
    m_lastInputBackend = lastInputBackend;
}

QByteArray VPianoSettings::state() const
{
    return m_state;
}

void VPianoSettings::setState(const QByteArray &state)
{
    m_state = state;
}

QByteArray VPianoSettings::geometry() const
{
    return m_geometry;
}

void VPianoSettings::setGeometry(const QByteArray &geometry)
{
    m_geometry = geometry;
}
