//===-- TypeSummary.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/lldb-python.h"

// C Includes

// C++ Includes

// Other libraries and framework includes

// Project includes
#include "lldb/lldb-public.h"
#include "lldb/lldb-enumerations.h"

#include "lldb/Core/Debugger.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"

#include "lldb/Host/Host.h"

using namespace lldb;
using namespace lldb_private;

TypeSummaryImpl::TypeSummaryImpl (const TypeSummaryImpl::Flags& flags) :
m_flags(flags)
{
}


StringSummaryFormat::StringSummaryFormat (const TypeSummaryImpl::Flags& flags,
                                          const char *format_cstr) :
TypeSummaryImpl(flags),
m_format()
{
    if (format_cstr)
        m_format.assign(format_cstr);
}

bool
StringSummaryFormat::FormatObject (ValueObject *valobj,
                                   std::string& retval)
{
    if (!valobj)
    {
        retval.assign("NULL ValueObject");
        return false;
    }
    
    StreamString s;
    ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
    SymbolContext sc;
    StackFrame *frame = exe_ctx.GetFramePtr();
    if (frame)
        sc = frame->GetSymbolContext(lldb::eSymbolContextEverything);
    
    if (IsOneLiner())
    {
        ValueObjectPrinter printer(valobj,&s,DumpValueObjectOptions());
        printer.PrintChildrenOneLiner(HideNames(valobj));
        retval.assign(s.GetData());
        return true;
    }
    else
    {
        if (Debugger::FormatPrompt(m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, valobj))
        {
            retval.assign(s.GetString());
            return true;
        }
        else
        {
            retval.assign("error: summary string parsing error");
            return false;
        }
    }
}

std::string
StringSummaryFormat::GetDescription ()
{
    StreamString sstr;
    
    sstr.Printf ("`%s`%s%s%s%s%s%s%s",      m_format.c_str(),
                 Cascades() ? "" : " (not cascading)",
                 !DoesPrintChildren(nullptr) ? "" : " (show children)",
                 !DoesPrintValue(nullptr) ? " (hide value)" : "",
                 IsOneLiner() ? " (one-line printout)" : "",
                 SkipsPointers() ? " (skip pointers)" : "",
                 SkipsReferences() ? " (skip references)" : "",
                 HideNames(nullptr) ? " (hide member names)" : "");
    return sstr.GetString();
}

CXXFunctionSummaryFormat::CXXFunctionSummaryFormat (const TypeSummaryImpl::Flags& flags,
                                                    Callback impl,
                                                    const char* description) :
TypeSummaryImpl(flags),
m_impl(impl),
m_description(description ? description : "")
{
}

bool
CXXFunctionSummaryFormat::FormatObject (ValueObject *valobj,
                                        std::string& dest)
{
    dest.clear();
    StreamString stream;
    if (!m_impl || m_impl(*valobj,stream) == false)
        return false;
    dest.assign(stream.GetData());
    return true;
}

std::string
CXXFunctionSummaryFormat::GetDescription ()
{
    StreamString sstr;
    sstr.Printf ("`%s (%p) `%s%s%s%s%s%s%s", m_description.c_str(),
                 static_cast<void*>(&m_impl),
                 Cascades() ? "" : " (not cascading)",
                 !DoesPrintChildren(nullptr) ? "" : " (show children)",
                 !DoesPrintValue(nullptr) ? " (hide value)" : "",
                 IsOneLiner() ? " (one-line printout)" : "",
                 SkipsPointers() ? " (skip pointers)" : "",
                 SkipsReferences() ? " (skip references)" : "",
                 HideNames(nullptr) ? " (hide member names)" : "");
    return sstr.GetString();
}

#ifndef LLDB_DISABLE_PYTHON


ScriptSummaryFormat::ScriptSummaryFormat (const TypeSummaryImpl::Flags& flags,
                                          const char * function_name,
                                          const char * python_script) :
TypeSummaryImpl(flags),
m_function_name(),
m_python_script(),
m_script_function_sp()
{
    if (function_name)
        m_function_name.assign(function_name);
    if (python_script)
        m_python_script.assign(python_script);
}

bool
ScriptSummaryFormat::FormatObject (ValueObject *valobj,
                                   std::string& retval)
{
    Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
    
    if (!valobj)
        return false;
    
    Host::SetCrashDescriptionWithFormat("[Python summary] Name: %s - Function: %s",
                                        valobj->GetName().AsCString("unknown"),
                                        m_function_name.c_str());

    TargetSP target_sp(valobj->GetTargetSP());
    
    if (!target_sp)
    {
        retval.assign("error: no target");
        return false;
    }
    
    ScriptInterpreter *script_interpreter = target_sp->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
    
    if (!script_interpreter)
    {
        retval.assign("error: no ScriptInterpreter");
        return false;
    }
    
    return script_interpreter->GetScriptedSummary(m_function_name.c_str(),
                                                  valobj->GetSP(),
                                                  m_script_function_sp,
                                                  retval);
    
}

std::string
ScriptSummaryFormat::GetDescription ()
{
    StreamString sstr;
    sstr.Printf ("%s%s%s%s%s%s%s\n%s",       Cascades() ? "" : " (not cascading)",
                 !DoesPrintChildren(nullptr) ? "" : " (show children)",
                 !DoesPrintValue(nullptr) ? " (hide value)" : "",
                 IsOneLiner() ? " (one-line printout)" : "",
                 SkipsPointers() ? " (skip pointers)" : "",
                 SkipsReferences() ? " (skip references)" : "",
                 HideNames(nullptr) ? " (hide member names)" : "",
                 m_python_script.c_str());
    return sstr.GetString();
    
}

#endif // #ifndef LLDB_DISABLE_PYTHON
