#include <QDebug>
#include <QFile>
#include <QRegularExpression>

#include "file.h"

#include "vymlock.h"

void VymLock::operator==(const VymLock &other)
{
    author = other.author;
    host = other.host;
    mapPath = other.mapPath;
    lockPath = other.lockPath;
    state = other.state;
}

VymLock::VymLock() { init(); }

VymLock::VymLock(const QString &path)
{
    init();
    setMapPath(path);
}

VymLock::~VymLock()
{
}

void VymLock::init()
{
    state = Undefined;
}

bool VymLock::tryLock()
{
    QFile lockFile(lockPath);
    if (lockFile.exists()) {
        // File is already locked
        if (debug)
            qDebug() << QString("VymLock::tryLock  failed: LockFile exists: %1").arg(lockFile.fileName());

        QString s;
        if (!loadStringFromDisk(lockFile.fileName(), s))
            qWarning("Failed to read from existing lockFile");
        else {
            QRegularExpression re("^author:\\s\\\"(.*)\\\"$");
            re.setPatternOptions(QRegularExpression::MultilineOption);
            QRegularExpressionMatch match = re.match(s);
            if (match.hasMatch())
                author = match.captured(1);

            re.setPattern("^host:\\s\\\"(.*)\\\"$");
            match = re.match(s);
            if (match.hasMatch())
                host = match.captured(1);
        }
        state = LockedByOther;
        return false;
    }

    if (!lockFile.open(QFile::WriteOnly | QFile::Text)) {
        if (debug)
            qWarning()
                << QString(
                       "VymLock::tryLock failed: Cannot open lockFile %1\n%2")
                       .arg(lockFile.fileName())
                       .arg(lockFile.errorString());
        state = NotWritable;
        return false;
    }

    QString s;
    if (!author.isEmpty())
        s = QString("author: \"%1\"\n").arg(author);
    if (!host.isEmpty())
        s += QString("host: \"%1\"\n").arg(host);

    if (!s.isEmpty()) {
        QTextStream out(&lockFile);
        out.setCodec("UTF-8");
        out << s;
    }

    state = LockedByMyself;
    lockFile.close();

    return true;
}

VymLock::LockState VymLock::getState() { return state; }

bool VymLock::releaseLock()
{
    if (state == LockedByMyself) {
        QFile lockFile(lockPath);
        if (lockFile.remove()) {
            state = Undefined;
            return true;
        }
    }
    if (state == Undefined)
        // No lockfile yet, e.g. in new map
        return true;

    qWarning() << "VymLock::releaseLock  failed for " << lockPath;
    return false;
}

bool VymLock::removeLockForced()
{
    QFile lockFile(lockPath);
    if (lockFile.remove()) {
        state = Undefined;
        return true;
    }
    qWarning() << "VymLock::removeLockForced  failed for " << lockPath;
    return false;
}

void VymLock::setAuthor(const QString &s) { author = s; }

QString VymLock::getAuthor() { return author; }

void VymLock::setHost(const QString &s) { host = s; }

QString VymLock::getHost() { return host; }

void VymLock::setMapPath(const QString &path)
{
    mapPath = path;
    lockPath = path + ".lock";

    // Reset state for a new path
    state = Undefined;
}

QString VymLock::getMapPath()
{
    return mapPath;
}
