/*
   This file is part of MDic Dictionary

   Copyright (C) 2007-2010 Mehrdad Momeny <mehrdad.momeny@gmail.com
   Copyright (C) 2007-2010 Majid Ramezanpour <majid.ramezanpour@gmail.com>

   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,
   (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 "settings.h"
#include <aspell.h>
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QFileInfo>
#include <QDir>
#include <QFont>
#include <QMessageBox>
#include <QDebug>
#include <QProcess>
#include <QTimer>

Settings::Settings()
        : QObject(qApp)
{
    m_dbsDir = QDir::homePath() + "/.config/MGroup/DBs/";
    QDir dbDir(dbsDir());
    if (!dbDir.exists())
        dbDir.mkpath(dbsDir());
    readConfig();
    QTimer::singleShot(500, this, SLOT(loadSpeechLanguages()) );
}

Settings::~Settings()
{
    writeConfig();
    closeConnection();
}

QPointer<Settings> Settings::m_self = 0L;

Settings* Settings::self()
{
    if (!m_self)
        m_self = new Settings;
    return m_self;
}

void Settings::readConfig()
{
    QSettings set;

    onTop = set.value("onTop", true).toBool();
    isMove = set.value("move", true).toBool();
    showInterval = set.value("interval", 5).toInt();
    clipboardWatcher = set.value("clipboardwatcher", true).toBool();
    showOnStart = set.value("showonstart", true).toBool();
    notifyNotAvailable = set.value("notifyNotAvailable", true).toBool();
    histLen = set.value("historyLenght", 10).toInt();
    output = (OutputTypes) set.value("outputtype", Main).toInt();
    stay = set.value("stay", true).toBool();
    stayTime = set.value("stayTime", 2).toDouble();

    modStatus = set.value("modifierStatus", false).toBool();
    mod = set.value("modifier", 0).toInt();
    showJustFirst = set.value("showJustFirst", false).toBool();

    //FONT
    const QString st = set.value("fontfamily", "Sans Serif").toString();
    fontD = QFont(st, set.value("pointsize", 10).toInt(), set.value("fontweight", 50).toInt(), set.value("fontitalic", false).toBool());
    fontD.setBold(set.value("fontbold", false).toBool());


    //SPEECH
    speech = set.value("speech", true).toBool();
    speakAny = set.value("speakAnyThing", false).toBool();
    spchSysIdx = set.value("speechSysIdx", 0).toInt();
    spchSpeed = set.value("speechSpeed", 170).toInt();
    spchAmplitude = set.value("speechAmplitude", 100).toInt();
    spchPitch = set.value("speechPitch", 50).toInt();
    inLang_espeak = set.value("inputLang_espeak", 6).toString();
    festivalSwitches = set.value("festivalSwitches", 0).toString();
    spchVoice = set.value("speechVoice", 'm').toChar();

    //SPELL
    isSpellingEnabled = set.value("isSpellingEnabled", true).toBool();
    spellingLang = set.value("spellingLang", "en").toString();

    alwaysSearchRemoteResources = set.value("AlwaysSearchRemoteResources", true).toBool();
    triggerMaxChar = set.value("SearchTriggerMaxChar", 0).toUInt();

    loadDicts(set);
    setSpeechCmd();
}

void Settings::writeConfig()
{
    QSettings set;

    set.setValue("onTop", onTop);
    set.setValue("move", isMove);
    set.setValue("clipboardwatcher", clipboardWatcher);
    set.setValue("showonstart", showOnStart);
    set.setValue("interval", showInterval);
    set.setValue("pointsize", fontD.pointSize());
    set.setValue("notifyNotAvailable", notifyNotAvailable);
    set.setValue("historyLenght", histLen);
    set.setValue("outputtype", output);

    set.setValue("fontfamily", fontD.family());
    set.setValue("fontweight", fontD.weight());
    set.setValue("fontitalic", fontD.italic());
    set.setValue("fontbold", fontD.bold());

    set.setValue("speech", speech);

    set.setValue("speakAnyThing", speakAny);
    set.setValue("stay", stay);
    set.setValue("stayTime", stayTime);
    set.setValue("modifierStatus", modStatus);
    set.setValue("modifier", mod);
    set.setValue("showJustFirst", showJustFirst);


    set.setValue("speechSysIdx", spchSysIdx);
    set.setValue("speechSpeed", spchSpeed);
    set.setValue("speechAmplitude", spchAmplitude);
    set.setValue("speechPitch", spchPitch);
    set.setValue("inputLang_espeak", inLang_espeak);
    set.setValue("festivalSwitches", festivalSwitches);
    set.setValue("speechVoice", spchVoice);

    set.setValue("spellingLang", spellingLang);
    set.setValue("isSpellingEnabled", isSpellingEnabled);

    set.setValue("AlwaysSearchRemoteResources", alwaysSearchRemoteResources);
    set.setValue("SearchTriggerMaxChar", triggerMaxChar);

    saveDicts(set);
    set.sync();
    emit configChanged();
}

void Settings::loadDicts(QSettings &get)
{
    dicts.clear();

    get.beginGroup("/Database");
    QStringList dbnames = get.allKeys();
    int rc = dbnames.count();
//     qDebug() << rc;
    QList<QVariant> configs;
    for (int row = 0;row < rc;row++) {
        QString s = dbnames.at(row);
        DictCore::Dictionary dic;
        dic.setName( s.remove(0, 1) );
        configs = get.value(dbnames.at(row), QStringList()).toList();
        if( configs.count()<2 ){
            dic.setEnabled(get.value(dbnames.at(row), true).toBool());
            dic.setBackendType(DictCore::MDic);
            dic.setCode(s);
        } else {
            dic.setBackendType( (DictCore::BackendType) configs[0].toInt() );
            dic.setEnabled( configs[1].toBool() );
            dic.setCode( configs[2].toString() );
        }
        dicts.append(dic);
    }
    get.endGroup();

    if (createConnection()){
        DictCore::self()->setLoadedDicts(dicts);
    } else {
        QMessageBox::critical(0, tr("Failed!"),
                              tr("Cannot Open one or more of Databases, Please Check DBs Path or Access privileges"));
    }
}

void Settings::saveDicts(QSettings &set)
{
    set.remove("/Database/");
    QList<QVariant> configs;
    for (int row = 0;row < dicts.count();++row) {
        QString dbName = dicts[row].name();
        configs.clear();
        configs.append(dicts[row].backendType());
        configs.append(dicts[row].isEnabled());
        configs.append(dicts[row].code());
        set.setValue("/Database/" + dbName.prepend(row), configs);
    }
}

QString Settings::dbsDir()
{
    return m_dbsDir;
}

void Settings::setSpeechCmd()
{
    QString language_small;
    speechArgs.clear();
    switch (spchSysIdx) {
    case 0:
        if (noEspeak)
            break;
        speechSysText = "espeak";
        speechArgs.append("-s" + ((QVariant) spchSpeed).toString());
        speechArgs.append("-a" + ((QVariant) spchAmplitude).toString());
        speechArgs.append("-p" + ((QVariant) spchPitch).toString());
        speechArgs.append("-v" + inLang_espeak);
        if ( inLang_espeak.startsWith( QLatin1String("en") ) )
            speechArgs.append( QString("-v+%1%2").arg(spchVoice).arg(1) );
        break;
    case 1:
        speechSysText = "festival";
        speechArgs.append("--tts");
        speechArgs << festivalSwitches.split(' ');
    default:
        break;
    }
}

bool Settings::createConnection()
{
    bool ret = true;

    for (int row = 0; row < dicts.count(); row++) {
        if( !dicts.at(row).isEnabled() || dicts.at(row).backendType() != DictCore::MDic )
            continue;

        QString dbName = dicts.at(row).name();
        if (QSqlDatabase::contains(dbName))
            continue;
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", dbName);
        db.setDatabaseName(dbsDir() + dbName);
        if (!db.open()) {
            ret = false;
        }
    }
    return ret;
}

void Settings::closeConnection()
{
    for (int row = 0; row < dicts.count(); row++) {
        QSqlDatabase::removeDatabase(dicts.takeAt(row).name());
    }
}

void Settings::loadSpeechLanguages()
{
    if(spchSysIdx == 0) {
        QProcess *langsPro = new QProcess(this);
        langsPro->start("espeak", QStringList("--voices"), QIODevice::ReadOnly);
        connect(langsPro, SIGNAL(finished(int)), this, SLOT(slotCheckAvailableLanguages(int)));
    }
}

void Settings::slotCheckAvailableLanguages(int result)
{
//     spchLangs.clear();
    QProcess *langsPro = qobject_cast<QProcess*>(sender());
    if(!langsPro){
        return;
    }

    if (result == 0) {
        qDebug() << "espeak found, parsing result.";
        char buf[200];
        if (langsPro->readLine(buf, sizeof(buf)) != -1) { //this also remove first line of output, that's unusable!
            while (langsPro->readLine(buf, sizeof(buf)) != -1) {
                QString line(buf);
                QStringList lineSplite = line.split(' ', QString::SkipEmptyParts);
//                 spchLangs.append(lineSplite[1]);
                espeakLangsMap.insert(lineSplite[3], lineSplite[1]);
            }
        }
        noEspeak = false;
        if (inLang_espeak.isEmpty())
            inLang_espeak = "en";
        setSpeechCmd();
    } else {
        qDebug() << "espeak not found, result is: "
        << langsPro->readAllStandardError();
        noEspeak = true;
    }
    langsPro->deleteLater();
}

#include "settings.moc"
