/*
    SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>

    SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "singledatachecker.h"

#include <KLocalizedString>

#include <torrent/globals.h>
#include <torrent/torrent.h>
#include <util/array.h>
#include <util/error.h>
#include <util/file.h>
#include <util/functions.h>
#include <util/log.h>

using namespace Qt::Literals::StringLiterals;

namespace bt
{
SingleDataChecker::SingleDataChecker(bt::Uint32 from, bt::Uint32 to)
    : DataChecker(from, to)
{
}

SingleDataChecker::~SingleDataChecker()
{
}

void SingleDataChecker::check(const QString &path, const Torrent &tor, const QString &, const BitSet &current_status)
{
    // open the file
    const Uint32 num_chunks = tor.getNumChunks();
    const Uint32 chunk_size = tor.getChunkSize();
    File fptr;
    if (!fptr.open(path, u"rb"_s)) {
        throw Error(i18n("Cannot open file %1: %2", path, fptr.errorString()));
    }

    if (from >= tor.getNumChunks()) {
        from = 0;
    }
    if (to >= tor.getNumChunks()) {
        to = tor.getNumChunks() - 1;
    }

    // initialize the bitset
    result = BitSet(num_chunks);
    // loop over all chunks
    Array<Uint8> buf(chunk_size);
    TimeStamp last_emitted = bt::Now();
    for (Uint32 i = from; i <= to && !need_to_stop; i++) {
        if (!fptr.eof()) {
            // read the chunk
            const Uint32 size = i == num_chunks - 1 ? tor.getLastChunkSize() : tor.getChunkSize();

            fptr.seek(File::BEGIN, (Int64)i * tor.getChunkSize());
            fptr.read(buf.data(), size);
            // generate and test hash
            const SHA1Hash h = SHA1Hash::generate(buf.data(), size);
            const bool ok = (h == tor.getHash(i));
            result.set(i, ok);
            if (ok && current_status.get(i)) {
                downloaded++;
            } else if (!ok && current_status.get(i)) {
                failed++;
            } else if (!ok && !current_status.get(i)) {
                not_downloaded++;
            } else if (ok && !current_status.get(i)) {
                found++;
            }
        } else {
            // at end of file so set to default values for a failed chunk
            result.set(i, false);
            if (!current_status.get(i)) {
                not_downloaded++;
            } else {
                failed++;
            }
        }

        const TimeStamp now = Now();
        if (now - last_emitted > 1000 || i == num_chunks - 1) { // Emit signals once every second
            Q_EMIT status(failed, found, downloaded, not_downloaded);
            Q_EMIT progress(i - from, from - to + 1);
            last_emitted = now;
        }
    }

    Q_EMIT status(failed, found, downloaded, not_downloaded);
}

}
