// Change History:

#include "ddp/ddp_vectdef.h"

// **************************************************************************
// DDP_VectorDef
// **************************************************************************
DDP_VectorDef::DDP_VectorDef(const DDP_VectorTree::RootNode * vroot,
    const VectorAddress * a, uint f, uint p) :
    HasAddr(false), Root(vroot), Decimals(DEFAULT_DECIMALS), bIsSumable(false),
    bLongName(true), DataSize(0), DataTextSize(0), MaxValue(0)
{
    SetVector(vroot);
    SetAddress(a);
    SetFormula(f);
    SetPeriod(p);
}
//--------------------------------------------------------------------------

DDP_VectorDef::DDP_VectorDef(const DDP_VectorDef & rhs) :
    DDP_ExportDef(rhs),
    Root(rhs.Root),
    FormulaDescr(rhs.FormulaDescr),
    PeriodDescr(rhs.PeriodDescr), HasAddr(rhs.HasAddr),
        AddressDescr(rhs.AddressDescr), Decimals(rhs.Decimals), bIsSumable(rhs.bIsSumable),
    bLongName(true),
    DataSize(rhs.DataSize),
    DataTextSize(rhs.DataTextSize),
    MaxValue(rhs.MaxValue)   
{
}
//--------------------------------------------------------------------------

bool DDP_VectorDef::SetVector(const DDP_VectorTree::RootNode * vroot)
{
    Root = vroot;
return true;
}
//--------------------------------------------------------------------------

bool DDP_VectorDef::SetAddress(const VectorAddress * a)
{
    if(!Root)
        return false;
    HasAddr = false;

    AddressDescr.Clear();
    AddressDescr.Add(Root);

    uint i, cnt = Root->GetMaxDepth();
    if(a)
        {
        for(i = 0; i < cnt; ++i)
            if(a[i] != MAXUINT)
                break;
        if(i == cnt)
            // all vector addresses
            a = NULL;
        }
    if(!a)
        {
        HasAddr = false;
        for(i = 0; i < cnt; ++i)
            AddressDescr.Add((const byte *)"~", (const byte *)"~", (const byte *)"~");
        return true;
        }

return RecursiveSetAddress(Root, a);
}
//--------------------------------------------------------------------------

bool DDP_VectorDef::RecursiveSetAddress(const DDP_VectorTree::Node * node,
    const VectorAddress * a)
{
    if(!node || !a)
        return false;
    if(!node->GetChildrenCount())
        return true;

    const DDP_VectorTree::Node * child;

    uint depth = node->GetDepth() + 1;

    child = node->GetChild(a[depth]);
    if(child)
        {
        AddressDescr.Add(child);
        HasAddr = true;
        }
    else
        return false;
        
return RecursiveSetAddress(child, a);
}

//--------------------------------------------------------------------------

bool DDP_VectorDef::SetPeriod(uint p)
{
    PeriodDescr.Clear();
    if(!Root)
        return false;
    const DDP_Descr * descr = Root->GetPeriod(p);
    if(!descr)
        return false;

    PeriodDescr = *descr;
return true;
}

//--------------------------------------------------------------------------

bool DDP_VectorDef::SetFormula(uint f)
{
    FormulaDescr.Clear();
    if(!Root)
        return false;
    const DDP_VectorTree::Formula * formula = Root->GetFormula(f);

    if(!formula)
        return false;

    FormulaDescr = *formula;
    bIsSumable = Root->GetSumable(f);
    
    DataSize = formula->GetDataSize();
    if(!DataSize)
        DataSize = Root->GetDataSize();

    DataTextSize = formula->GetDataTextSize();
    if(!DataTextSize)
        DataTextSize = Root->GetDataTextSize();
    if(formula->GetQuantile())
        SetDecimals(0);
        
    MaxValue = formula->GetMaxValue();

return true;
}
//--------------------------------------------------------------------------

bool DDP_VectorDef::SetIndexState(uint state)
{
    FormulaDescr.Clear();
    if(!Root)
        return false;
    const DDP_Descr * descr = Root->GetIndexState(state);
    if(!descr)
        return false;

    FormulaDescr = *descr;
return true;
}
//--------------------------------------------------------------------------

uint DDP_VectorDef::GetDescr(byte * buf, uint sz, const byte * delim, bool IsLong) const
{
    if(!buf || !sz || !AddressDescr.GetCount())
        return 0;

    uint i, s = 0, n = AddressDescr.GetCount();
    const DDP_Descr * Descr;
    const byte * desc;
    for(i = 0; i < n; ++i)
        {
        Descr = AddressDescr.Get(i);
        desc = Descr->Get(IsLong);
        if(!desc)
            return 0;
        s += PORT_snprintf_1(&buf[s], sz - s, "%s", desc);
        if(i < n - 1)
            s += PORT_snprintf_1(&buf[s], sz - s, "%s", delim);
        }

    if(FormulaDescr.MaxLen())
        {
        s += PORT_snprintf_1(&buf[s], sz - s,  "%s", delim);
        desc = FormulaDescr.Get(IsLong);
        if(!desc)
            return 0;
        s += PORT_snprintf_1(&buf[s], sz - s,  "%s", desc);
        }

    if(PeriodDescr.MaxLen())
        {
        s += PORT_snprintf_1(&buf[s], sz - s,  "%s", delim);
        desc = PeriodDescr.Get(IsLong);
        if(!desc)
            return 0;
        s += PORT_snprintf_1(&buf[s], sz - s,  "%s", desc);
        }

return s;
}
//--------------------------------------------------------------------------

uint DDP_VectorDef::RetrieveUserName(byte * buf, uint sz, const byte * delim,
    bool IsLong) const
{
    if(!buf || !sz)
        return 0;
    const byte * un = DDP_ExportDef::GetUserDefinedName();
    if(un)
        {
        PORT_strncpy(buf, un, sz);
        return min(sz, PORT_strlen(un));
        }
return GetDescr(buf, sz, delim, IsLong);
}
//--------------------------------------------------------------------------

bool DDP_VectorDef::Dump(DDP_PrintFile * file, const byte * prefix) const
{
    if(!DDP_ExportDef::Dump(file, prefix))
        return false;

    const byte * sp = prefix ? prefix : (const byte *)"";

    if(IsNull())
        {
        if(!file->Print(PORT_cbyte("LO_%s%sName = NULL\r\n"), sp, GetDefLabel() ))
            return false;
        if(!file->Print(PORT_cbyte("LO_%s%sAddress = NULL\r\n"), sp, GetDefLabel() ))
            return false;
        if(!file->Print(PORT_cbyte("LO_%s%sAddressFormula = NULL\r\n"), sp, GetDefLabel() ))
            return false;
        if(!file->Print(PORT_cbyte("LO_%s%sDecimals = NA\r\n"), sp, GetDefLabel() ))
            return false;
        if(!file->Print(PORT_cbyte("LO_%s%sSize = 0\r\n"), sp, GetDefLabel() ))
            return false;
        if(!file->Print(PORT_cbyte("LO_%s%sTextSize = 0\r\n"), sp, GetDefLabel() ))
            return false;
        if(!file->Print(PORT_cbyte("LO_%s%sMaxValue = 0\r\n"), sp, GetDefLabel() ))
            return false;
        }
    else
        {
        byte bb[DDP_PrintFile::LINE_SIZE];
        std::string sName;

        if(RetrieveUserName(bb, sizeof(bb), PORT_cbyte(" | "), IsLongName() ))
            sName = (char *)bb;
        else
            sName = "NULL";

        if(!file->Print(PORT_cbyte("LO_%s%sName = %s\r\n"), sp, GetDefLabel(), PORT_c_str(sName) ))
            return false;

        if(!file->Print(PORT_cbyte("LO_%s%sAddress = %s\r\n"), sp, GetDefLabel(), get_descr(bb, sizeof(bb)) ))
            return false;
        if(!file->Print(PORT_cbyte("LO_%s%sAddressFormula = %s\r\n"), sp, GetDefLabel(), get_formula(bb, sizeof(bb)) ))
            return false;

        if(GetDecimals() != DEFAULT_DECIMALS)
            {
            if(!file->Print(PORT_cbyte("LO_%s%sDecimals = %u\r\n"), sp, GetDefLabel(), GetDecimals() ))
                return false;
            }
        else
            if(!file->Print(PORT_cbyte("LO_%s%sDecimals = NA\r\n"), sp, GetDefLabel() ))
                return false;

        if(!file->Print(PORT_cbyte("LO_%s%sSize = %u\r\n"), sp, GetDefLabel(), DataSize ))
            return false;
        if(!file->Print(PORT_cbyte("LO_%s%sTextSize = %u\r\n"), sp, GetDefLabel(), DataTextSize ))
            return false;

        byte snum[37];
        AT_Numtoa(MaxValue, snum);
        if(!file->Print(PORT_cbyte("LO_%s%sMaxValue = %s\r\n"), sp, GetDefLabel(), snum ))
            return false;
        }
        
return true;
}

/****************************************************************************
 NOTES
 ****************************************************************************/
