#include <DatSubsystems/DatStatus.h>
#include <DatFile.h>

#include <math.h>

namespace LOTRO_DAT {
    unsigned long long DatStatus::CallbackStorage::free_handler_ = 0;

    bool equalOfftoOneDecimalPoint(double x, double y) {
        return int(x * 10.0) == int(y * 10.0);
    }

    DatStatus::DatStatus(DatFile *datFilePtr) : dat(datFilePtr) {
    }

    void DatStatus::SetStatus(DatStatus::DAT_STATUS status) {
        bool need_to_invoke_progress_callback_functions = (status_ != status);
        status_ = status;
        if (need_to_invoke_progress_callback_functions) {
            InvokeCallbackFunctions();
        }
    }
        
    void DatStatus::SetFinishedParts(unsigned long long finished_parts) {
        finished_parts_ = finished_parts;
        if (!equalOfftoOneDecimalPoint(GetPercentage(), percentage_)) {
            percentage_ = GetPercentage();
            InvokeCallbackFunctions();
        }
    }

    void DatStatus::SetTotalParts(unsigned long long total_parts) {
        total_parts_ = total_parts;
    }

    void DatStatus::SetDebugMessage(const std::string &message) {
        debug_message_ = message;
    }

    DatStatus::DAT_STATUS DatStatus::GetStatus() {
        return status_;
    }

    double DatStatus::GetPercentage() {
        return total_parts_ != 0 ? double(finished_parts_) * 100.0 / double(total_parts_) : 0;
    }

    unsigned long long DatStatus::GetFinishedParts() {
        return finished_parts_;
    }

    unsigned long long DatStatus::GetTotalParts() {
        return total_parts_;
    }

    std::string DatStatus::GetDebugMessage() {
        return debug_message_;
    }
    
    void DatStatus::SetDefaultStatus() {
        debug_message_ = "";
        total_parts_ = 0;
        finished_parts_ = 0;
        status_ = E_FREE;
        InvokeCallbackFunctions();
    }

    bool DatStatus::CheckIfNotPatched() {
        return dat->GetLocaleManager().patch_dict_.empty();
    }

    unsigned long long DatStatus::AddStatusChangedCallbackFunction(Callback func) {
        CallbackStorage storage(func);
        callback_functions_.insert(storage);
        return storage.GetHandler();
    }

    void DatStatus::RemoveStatusChangedCallbackFunction(unsigned long long handler) {
        callback_functions_.erase(CallbackStorage(handler));
    }

    void DatStatus::EraseAllCallbackFunctions() {
        callback_functions_.clear();
    }

    void DatStatus::InvokeCallbackFunctions() {
        for (const auto& func : callback_functions_) {
            func(ProgressInfo({GetStatus(), GetPercentage(), GetFinishedParts(), GetTotalParts()})); // evaluating callback functions, transfering all needed information.
        }
    }
} // namespace LOTRO_DAT