/*******************************************************************************
 * Copyright (c) 2017-2018, Kyle Robbertze (AIMS, South Africa)
 *
 * This project is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License version 3 as 
 * published by the Free Software Foundation.
 *
 * It 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 project. If not, see <http://www.gnu.org/licenses/>.
 *
 *    Description: A MD5 sum check process 
 * 
 *        Created:  20/01/2018 10:39:45
 *       Compiler:  g++
 * 
 *         Author:  Kyle Robbertze (kr), kyle@aims.ac.za
 *******************************************************************************/

#include "md5_process.h"

#include <QDebug>
#include <utility>

MD5Process::MD5Process() :
    m_actualMD5 {},
    m_expectedMD5 {},
    m_file {},
    m_fileInfo {},
    m_process {}
{
}

MD5Process::MD5Process(QFile& file, QString expectedMD5) :
    m_actualMD5 {},
    m_expectedMD5 { expectedMD5 },
    m_file { file.fileName() },
    m_process {}
{
    m_fileInfo = QFileInfo(file.fileName());
}

MD5Process::MD5Process(const MD5Process& other) :
    m_actualMD5 { other.m_actualMD5 },
    m_expectedMD5 { other.m_expectedMD5 },
    m_file { other.m_file.fileName() },
    m_process {}
{
    m_fileInfo = QFileInfo(m_file.fileName());
}

void MD5Process::start() {
    //connect(&m_process, &QProcess::readyReadStandardOutput, this, &MD5Process::onOutputReady);
    connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
            this, &MD5Process::onFinish);
    //qDebug() << "MD5Process: starting pv -n" << m_file.fileName() << "| md5sum";
    //m_process.start("pv -n" + m_file.fileName() + " | md5sum");
    qDebug() << "MD5Process: starting md5sum" << m_file.fileName();
    m_process.start("md5sum " + m_file.fileName());
}

QString MD5Process::fileName() const {
    return m_file.fileName();
}

QString MD5Process::actualMD5() const {
    return m_actualMD5;
}

QString MD5Process::expectedMD5() const {
    return m_expectedMD5;
}

void MD5Process::onOutputReady() {
    qDebug() << "MD5Process: Output ready";
    QString output = QString::fromStdString(m_process.readAllStandardOutput().toStdString());
    qDebug() << "MD5Process:" << output;
    bool isProgress;
    int progressPercent = output.toInt(&isProgress);
    if (isProgress) {
        qDebug() << "MD5Process: md5sum progress" << progressPercent;
        // Amount of file processed in MB
        int progressValue = m_fileInfo.size() / 100000 * progressPercent;
        emit progressChanged(progressValue);
    } else {
        onFinish(m_process.exitCode(), m_process.exitStatus());
    }
}

void MD5Process::onFinish(int exitCode, QProcess::ExitStatus exitStatus) {
    qDebug() << "MD5Process: Finished checking file" << m_file.fileName()
        << "- exit code" << exitCode;
    emit progressChanged(m_fileInfo.size() / 1000);
    if (exitStatus != QProcess::NormalExit) {
        qWarning() << "MD5Process: md5sum exited with code" << exitCode;
        m_process.close();
        emit finished(Result::ERROR, exitStatus, this);
        return;
    }
    QString output { m_process.readAllStandardOutput() };
    m_actualMD5 = QString::fromStdString(output.toStdString()).split("  ").at(0);
    m_process.close();
    if (m_actualMD5 != m_expectedMD5) {
        qWarning() << "MD5Process: MD5 sum mismatch for" << m_file.fileName()
            << "- expected" << m_expectedMD5 << ", but found" << m_actualMD5;
        emit finished(Result::DIFFERENT, exitStatus, this);
        return;
    }
    qInfo() << "MD5Process: MD5 sums match for" << m_file.fileName();
    emit finished(Result::IDENTICAL, 0, this);
}

MD5Process& MD5Process::operator=(MD5Process other) {
    if (this != &other) {
        m_actualMD5 = other.m_actualMD5;
        m_expectedMD5 = other.m_expectedMD5;
        m_file.setFileName(other.fileName());
        m_fileInfo = QFileInfo(m_file.fileName());
    }
    return *this;
}

bool operator==(const MD5Process& lhs, const MD5Process& rhs) {
    return lhs.actualMD5() == rhs.actualMD5() && lhs.expectedMD5() == rhs.expectedMD5() &&
        lhs.fileName() == rhs.fileName();
}
