//===-- SBValueList.cpp -----------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//


#include "lldb/API/SBValueList.h"
#include "lldb/API/SBValue.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/ValueObjectList.h"

#include <vector>

using namespace lldb;
using namespace lldb_private;

class ValueListImpl
{
public:
    ValueListImpl () :
    m_values()
    {
    }
    
    ValueListImpl (const ValueListImpl& rhs) :
    m_values(rhs.m_values)
    {
    }
    
    ValueListImpl&
    operator = (const ValueListImpl& rhs)
    {
        if (this == &rhs)
            return *this;
        m_values = rhs.m_values;
        return *this;
    }
    
    uint32_t
    GetSize ()
    {
        return m_values.size();
    }
    
    void
    Append (const lldb::SBValue& sb_value)
    {
        m_values.push_back(sb_value);
    }
    
    void
    Append (const ValueListImpl& list)
    {
        for (auto val : list.m_values)
            Append (val);
    }
    
    lldb::SBValue
    GetValueAtIndex (uint32_t index)
    {
        if (index >= GetSize())
            return lldb::SBValue();
        return m_values[index];
    }
    
    lldb::SBValue
    FindValueByUID (lldb::user_id_t uid)
    {
        for (auto val : m_values)
        {
            if (val.IsValid() && val.GetID() == uid)
                return val;
        }
        return lldb::SBValue();
    }
    
    lldb::SBValue
    GetFirstValueByName (const char* name) const
    {
        if (name)
        {
            for (auto val : m_values)
            {
                if (val.IsValid() && val.GetName() &&
                    strcmp(name,val.GetName()) == 0)
                    return val;
            }
        }
        return lldb::SBValue();
    }

private:
    std::vector<lldb::SBValue> m_values;
};

SBValueList::SBValueList () :
    m_opaque_ap ()
{
}

SBValueList::SBValueList (const SBValueList &rhs) :
    m_opaque_ap ()
{
    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));

    if (rhs.IsValid())
        m_opaque_ap.reset (new ValueListImpl (*rhs));

    if (log)
    {
        log->Printf ("SBValueList::SBValueList (rhs.ap=%p) => this.ap = %p",
                     static_cast<void*>(rhs.IsValid() ? rhs.m_opaque_ap.get() : NULL),
                     static_cast<void*>(m_opaque_ap.get()));
    }
}

SBValueList::SBValueList (const ValueListImpl *lldb_object_ptr) :
    m_opaque_ap ()
{
    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));

    if (lldb_object_ptr)
        m_opaque_ap.reset (new ValueListImpl (*lldb_object_ptr));

    if (log)
    {
        log->Printf ("SBValueList::SBValueList (lldb_object_ptr=%p) => this.ap = %p",
                     static_cast<const void*>(lldb_object_ptr),
                     static_cast<void*>(m_opaque_ap.get()));
    }
}

SBValueList::~SBValueList ()
{
}

bool
SBValueList::IsValid () const
{
    return (m_opaque_ap.get() != NULL);
}

void
SBValueList::Clear()
{
    m_opaque_ap.reset();
}

const SBValueList &
SBValueList::operator = (const SBValueList &rhs)
{
    if (this != &rhs)
    {
        if (rhs.IsValid())
            m_opaque_ap.reset (new ValueListImpl (*rhs));
        else
            m_opaque_ap.reset ();
    }
    return *this;
}

ValueListImpl *
SBValueList::operator->()
{
    return m_opaque_ap.get();
}

ValueListImpl &
SBValueList::operator*()
{
    return *m_opaque_ap;
}

const ValueListImpl *
SBValueList::operator->() const
{
    return m_opaque_ap.get();
}

const ValueListImpl &
SBValueList::operator*() const
{
    return *m_opaque_ap;
}

void
SBValueList::Append (const SBValue &val_obj)
{
    CreateIfNeeded ();
    m_opaque_ap->Append (val_obj);
}

void
SBValueList::Append (lldb::ValueObjectSP& val_obj_sp)
{
    if (val_obj_sp)
    {
        CreateIfNeeded ();
        m_opaque_ap->Append (SBValue(val_obj_sp));
    }
}

void
SBValueList::Append (const lldb::SBValueList& value_list)
{
    if (value_list.IsValid())
    {
        CreateIfNeeded ();
        m_opaque_ap->Append (*value_list);
    }
}


SBValue
SBValueList::GetValueAtIndex (uint32_t idx) const
{
    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));

    //if (log)
    //    log->Printf ("SBValueList::GetValueAtIndex (uint32_t idx) idx = %d", idx);

    SBValue sb_value;
    if (m_opaque_ap.get())
        sb_value = m_opaque_ap->GetValueAtIndex (idx);

    if (log)
    {
        SBStream sstr;
        sb_value.GetDescription (sstr);
        log->Printf ("SBValueList::GetValueAtIndex (this.ap=%p, idx=%d) => SBValue (this.sp = %p, '%s')", 
                     static_cast<void*>(m_opaque_ap.get()), idx,
                     static_cast<void*>(sb_value.GetSP().get()), sstr.GetData());
    }

    return sb_value;
}

uint32_t
SBValueList::GetSize () const
{
    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));

    //if (log)
    //    log->Printf ("SBValueList::GetSize ()");

    uint32_t size = 0;
    if (m_opaque_ap.get())
        size = m_opaque_ap->GetSize();

    if (log)
        log->Printf ("SBValueList::GetSize (this.ap=%p) => %d",
                     static_cast<void*>(m_opaque_ap.get()), size);

    return size;
}

void
SBValueList::CreateIfNeeded ()
{
    if (m_opaque_ap.get() == NULL)
        m_opaque_ap.reset (new ValueListImpl());
}


SBValue
SBValueList::FindValueObjectByUID (lldb::user_id_t uid)
{
    SBValue sb_value;
    if (m_opaque_ap.get())
        sb_value = m_opaque_ap->FindValueByUID(uid);
    return sb_value;
}

SBValue
SBValueList::GetFirstValueByName (const char* name) const
{
    SBValue sb_value;
    if (m_opaque_ap.get())
        sb_value = m_opaque_ap->GetFirstValueByName(name);
    return sb_value;
}

void *
SBValueList::opaque_ptr ()
{
    return m_opaque_ap.get();
}

ValueListImpl &
SBValueList::ref ()
{
    CreateIfNeeded();
    return *m_opaque_ap.get();
}
