// Squawk messenger. 
// Copyright (C) 2019  Yury Gubich <blue@macaw.me>
// 
// 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, or
// (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 "clientinfo.h"

const std::map<QString, QCryptographicHash::Algorithm> Shared::ClientInfo::hashes = {
    //md2 is missing
    {"md5", QCryptographicHash::Md5},
    {"sha-1", QCryptographicHash::Sha1},
    {"sha-224", QCryptographicHash::Sha224},
    {"sha-256", QCryptographicHash::Sha256},
    {"sha-384", QCryptographicHash::Sha384},
    {"sha-512", QCryptographicHash::Sha512},
    //shake128 is missing
    //shake256 is missing

};

Shared::ClientInfo::ClientInfo():
    identities(),
    extensions(),
    node(),
    verification(),
    hash(),
    specificPresence() {}

QString Shared::ClientInfo::getId() const {
    return node + "/" + verification;
}


QDataStream & Shared::ClientInfo::operator >> (QDataStream& stream) const {
    stream << node;
    stream << verification;
    stream << hash;
    stream << (quint8)identities.size();
    for (const Shared::Identity& identity : identities) {
        stream << identity;
    }
    stream << (quint8)extensions.size();
    for (const QString& ext : extensions) {
        stream << ext;
    }

    return stream;
}

QDataStream & Shared::ClientInfo::operator << (QDataStream& stream) {
    stream >> node;
    stream >> verification;
    stream >> hash;

    quint8 size;
    stream >> size;
    for (quint8 i = 0; i < size; ++i) {
        Shared::Identity identity;
        stream >> identity;
        identities.insert(identity);
    }

    stream >> size;
    for (quint8 i = 0; i < size; ++i) {
        QString ext;
        stream >> ext;
        extensions.insert(ext);
    }

    return stream;
}

bool Shared::ClientInfo::valid() const {
    std::map<QString, QCryptographicHash::Algorithm>::const_iterator itr = hashes.find(hash);
    if (itr == hashes.end()) {
        return false;
    }

    QCryptographicHash calc(itr->second);
    QString validationString = "";
    for (const Identity& identity : identities) {
        calc.addData((identity.category + "/" + identity.type + "/" + identity.language + "/" + identity.name + "<").toUtf8());
    }
    for (const QString& ext : extensions) {
        calc.addData((ext + "<").toUtf8());
    }

    QString result = calc.result().toBase64();

    return result == verification;
}

QDataStream& operator << (QDataStream& stream, const Shared::ClientInfo& info) {
    info >> stream;
    return stream;
}
QDataStream& operator >> (QDataStream& stream, Shared::ClientInfo& info) {
    info << stream;
    return stream;
}