#include "factors_abstract.h"

#include <saas/util/bit_array_remap.h>

#include <kernel/factor_storage/factor_storage.h>
#include <library/cpp/digest/md5/md5.h>
#include "factor.h"

TString IRTYStaticFactors::GetHash() const {
    MD5 md5Calcer;
    md5Calcer.Init();

    ui32 count = GetStaticFactorsCount();
    md5Calcer.Update(&count, sizeof(count));
    for (ui32 i = 0; i < count; ++i) {
        const NRTYFactors::TSimpleFactorDescription& factor = GetFactor(i);
        TString hashFactor = factor.GetHash();
        md5Calcer.Update(hashFactor.data(), hashFactor.size());
    }
    char result[33];
    md5Calcer.End(result);
    return result;
}

ui32 IRTYStaticFactors::GetSumWidthBits() const {
    ui32 result = 0;
    for (ui32 i = 0; i < GetStaticFactorsCount(); ++i)
        result += GetFactor(i).Width;
    return result;
}

ui32 IRTYStaticFactors::GetSumWidthBytes() const {
    ui32 bitsSize = GetSumWidthBits();
    return bitsSize / 8 + (bitsSize % 8 ? 1 : 0);
}


ui32 IRTYStaticFactors::GetOffsetInBits(ui32 index) const {
    ui32 result = 0;
    VERIFY_WITH_LOG(GetStaticFactorsCount() > index, "%u > %u", GetStaticFactorsCount(), index);
    for (ui32 i = 0; i < index; ++i)
        result += GetFactor(i).Width;
    return result;
}


ui32 IRTYStaticFactors::GetOffsetInBytes(ui32 index) const {
    return GetOffsetInBits(index) / 8;
}

TErfBitsRemapper::TErfBitsRemapper(const IRTYStaticFactors& info) {
    TVector<TBitsReader::TFieldDescr> descrSimple;
    TVector<TBitsReader::TFieldDescr> descrFormula;
    descrSimple.resize(info.GetStaticFactorsCount());
    descrFormula.resize(info.GetStaticFactorsCount());
    for (ui32 i = 0; i < info.GetStaticFactorsCount(); ++i) {
        descrSimple[i].Width = descrFormula[i].Width = info.GetFactor(i).Width;
        descrSimple[i].Type = descrFormula[i].Type = info.GetFactor(i).Type;
        descrSimple[i].IndexRemap = i;
        descrFormula[i].IndexRemap = info.GetFactor(i).IndexGlobal;
    }
    SimpleRemapper.Reset(new TBitsRemapper(descrSimple));
    FormulaRemapper.Reset(new TBitsRemapper(descrFormula));
}

bool IRTYStaticFactors::CheckFactorValue(ui32 index, float value) const {
    return GetFactor(index).CheckValue(value);
}

bool IRTYStaticFactors::CheckFactorName(const TStringBuf& name, ui32& index) const {
    for (ui32 i = 0; i < GetStaticFactorsCount(); ++i)
        if (GetFactor(i).Name == name) {
            index = i;
            return true;
        }
    return false;
}

bool IRTYStaticFactors::LoadErfBlock(TBasicFactorStorage& /*data*/, const TParsedDocument& /*document*/) const {
    FAIL_LOG("Incorrect class usage: this implementation of IRTYStaticFactors cannot be used for RTY Erf");
    return true;
}

void TErfBitsRemapper::PackSimple(const TBasicFactorStorage& data, ui8* storage) const {
    SimpleRemapper->Pack(data.factors, storage);
}

void TErfBitsRemapper::UnpackSimple(TBasicFactorStorage& data, const ui8* storage) const {
    SimpleRemapper->UnPack(data.factors, storage);
}

void TErfBitsRemapper::UnpackSimple(TFactorView& data, const ui8* storage) const {
    SimpleRemapper->UnPack(data.begin(), storage);
}

void TErfBitsRemapper::UnpackFormula(TBasicFactorStorage& data, const ui8* storage) const {
    FormulaRemapper->UnPack(data.factors, storage);
}

void TErfBitsRemapper::UnpackFormula(TFactorView& data, const ui8* storage) const {
    FormulaRemapper->UnPack(data.begin(), storage);
}
