/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 * SPDX-FileCopyrightText: 2019-2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
 */

#include "countervalidator.h"

#include "util.h"

namespace validators
{
std::optional<qulonglong> parseUnsignedInteger(const QString &input, const QLocale &locale)
{
    bool ok = false;

    auto v = locale.toULongLong(input, &ok);
    if (ok) {
        return std::optional<qulonglong>(v);
    } else {
        /*
         * Fall back to parsing according to C locale for better UX.
         * This simplifies copy-pasting from websites which may be a bit
         * biased towards the Anglosphere.
         */
        const QLocale c = QLocale::c();
        v = c.toULongLong(input, &ok);
        return ok ? std::optional<qulonglong>(v) : std::nullopt;
    }
}

UnsignedLongValidator::UnsignedLongValidator(QObject *parent)
    : QValidator(parent)
{
}

void UnsignedLongValidator::fixup(QString &input) const
{
    /*
     * First of all: simplify the input to get rid of 'fluff' such as
     * digit group separators in partial input. E.g. if the user wants
     * to type the value 123456 then partial input might become "123,4"
     * at some point which would be invalid.
     */
    const QLocale l = locale();
    const auto c = l.groupSeparator();
    QString fixed = input.replace(c, QLatin1String(""));
    fixed = validators::strip_spaces(fixed);

    /*
     * Normalise to locale's preferred formatting if possible
     * I.e. if valid, re-instate any decorative fluff like digit group
     * separators depending on the locale.
     *
     * This may also involve switching from Latin script (C locale) to
     * whatever script the configured locale uses natively.
     */
    const auto v = parseUnsignedInteger(fixed, l);
    if (v) {
        fixed = l.toString(v.value());
    }

    input = fixed;
}

QValidator::State UnsignedLongValidator::validate(QString &input, int &cursor) const
{
    Q_UNUSED(cursor);
    // Avoid a hard error on empty string.
    if (input.size() == 0) {
        return QValidator::Intermediate;
    } else {
        const QLocale l = locale();
        const auto parsed = parseUnsignedInteger(input, l);

        /*
         * The actual value is a don't care at this point.
         * All that matters is the input can be parsed
         */
        return parsed ? QValidator::Acceptable : QValidator::Invalid;
    }
}
}

#include "moc_countervalidator.cpp"
