// 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 "trustsummary.h"

const std::set<Shared::TrustLevel> Shared::TrustSummary::trustedLevels({
    Shared::TrustLevel::authenticated,
    Shared::TrustLevel::automaticallyTrusted,
    Shared::TrustLevel::manuallyTrusted
});
const std::set<Shared::TrustLevel> Shared::TrustSummary::untrustedLevels({
    Shared::TrustLevel::undecided,
    Shared::TrustLevel::automaticallyDistrusted,
    Shared::TrustLevel::manuallyDistrusted
});

const std::map<Shared::EncryptionProtocol, QString> Shared::TrustSummary::protocolKeys({
    {Shared::EncryptionProtocol::none, "none"},
    {Shared::EncryptionProtocol::omemo, "eu.siacs.conversations.axolotl"},
    {Shared::EncryptionProtocol::omemo1, "urn:xmpp:omemo:1"},
    {Shared::EncryptionProtocol::omemo2, "urn:xmpp:omemo:2"}
});
const std::map<QString, Shared::EncryptionProtocol> Shared::TrustSummary::protocolValues({
    {"none", Shared::EncryptionProtocol::none},
    {"eu.siacs.conversations.axolotl", Shared::EncryptionProtocol::omemo},
    {"urn:xmpp:omemo:1", Shared::EncryptionProtocol::omemo1},
    {"urn:xmpp:omemo:2", Shared::EncryptionProtocol::omemo2}
});

Shared::TrustSummary::TrustSummary():
    data()
{}

void Shared::TrustSummary::set(Shared::EncryptionProtocol protocol, Shared::TrustLevel level, uint8_t amount) {
    Data::iterator itr = data.find(protocol);
    if (itr == data.end()) {
        if (amount == 0)
            return;

        itr = data.insert(std::make_pair(protocol, Amounts())).first;
    }

    Amounts& am = itr->second;
    Amounts::iterator aitr = am.find(level);
    if (aitr == am.end()) {
        if (amount == 0)
            return;

        am.emplace(level, amount);
        return;
    }
    if (amount == 0) {
        if (am.size() == 1)
            data.erase(itr);
        else
            am.erase(aitr);

        return;
    }
    aitr->second = amount;
}

uint8_t Shared::TrustSummary::amount(Shared::EncryptionProtocol protocol, Shared::TrustLevel level) const {
    Data::const_iterator itr = data.find(protocol);
    if (itr == data.end())
        return 0;

    const Amounts& am = itr->second;
    Amounts::const_iterator aitr = am.find(level);
    if (aitr == am.end())
        return 0;

    return aitr->second;
}

uint8_t Shared::TrustSummary::increment(Shared::EncryptionProtocol protocol, Shared::TrustLevel level) {
    Data::iterator itr = data.find(protocol);
    if (itr == data.end())
        itr = data.insert(std::make_pair(protocol, Amounts())).first;

    Amounts& am = itr->second;
    Amounts::iterator aitr = am.find(level);
    if (aitr == am.end()) {
        am.emplace(level, 1);
        return 1;
    }
    uint8_t& value = aitr->second;
    return ++value;
}

uint8_t Shared::TrustSummary::decrement(Shared::EncryptionProtocol protocol, Shared::TrustLevel level) {
    Data::iterator itr = data.find(protocol);
    if (itr == data.end())
        return 0;                   //should never happen, shall I better throw an exception?

    Amounts& am = itr->second;
    Amounts::iterator aitr = am.find(level);
    if (aitr == am.end())
        return 0;                   //should never happen, shall I better throw an exception?

    uint8_t& value = aitr->second;
    uint8_t result = --value;
    if (value == 0) {
        if (am.size() == 1)
            data.erase(itr);
        else
            am.erase(aitr);
    }
    return result;
}

bool Shared::TrustSummary::hasKeys(Shared::EncryptionProtocol protocol) const {
    return data.count(protocol) > 0;
}

bool Shared::TrustSummary::hasTrustedKeys(Shared::EncryptionProtocol protocol) const {
    Data::const_iterator itr = data.find(protocol);
    if (itr == data.end())
        return false;

    for (const std::pair<const TrustLevel, uint8_t>& pair : itr->second) {
        if (trustedLevels.count(pair.first) > 0)
            return true;
    }

    return false;
}

bool Shared::TrustSummary::hasUntrustedKeys(Shared::EncryptionProtocol protocol) const {
    Data::const_iterator itr = data.find(protocol);
    if (itr == data.end())
        return false;

    for (const std::pair<const TrustLevel, uint8_t>& pair : itr->second) {
        if (untrustedLevels.count(pair.first) > 0)
            return true;
    }

    return false;
}

bool Shared::TrustSummary::operator==(const Shared::TrustSummary& other) {
    return data == other.data;
}

bool Shared::TrustSummary::operator!=(const Shared::TrustSummary& other) {
    return data != other.data;
}