//===-- MICmnLLDBDebugSessionInfoVarObj.cpp ---------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// In-house headers:
#include "MICmnLLDBDebugSessionInfoVarObj.h"
#include "MICmnLLDBProxySBValue.h"
#include "MICmnLLDBUtilSBValue.h"

// Instantiations:
const char *CMICmnLLDBDebugSessionInfoVarObj::ms_aVarFormatStrings[] = {
    // CODETAG_SESSIONINFO_VARFORMAT_ENUM
    // *** Order is import here.
    "<Invalid var format>", "binary", "octal", "decimal",
    "hexadecimal",          "natural"};
const char *CMICmnLLDBDebugSessionInfoVarObj::ms_aVarFormatChars[] = {
    // CODETAG_SESSIONINFO_VARFORMAT_ENUM
    // *** Order is import here.
    "<Invalid var format>", "t", "o", "d", "x", "N"};
CMICmnLLDBDebugSessionInfoVarObj::MapKeyToVarObj_t
    CMICmnLLDBDebugSessionInfoVarObj::ms_mapVarIdToVarObj;
MIuint CMICmnLLDBDebugSessionInfoVarObj::ms_nVarUniqueId = 0; // Index from 0
CMICmnLLDBDebugSessionInfoVarObj::varFormat_e
    CMICmnLLDBDebugSessionInfoVarObj::ms_eDefaultFormat = eVarFormat_Natural;

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj constructor.
// Type:    Method.
// Args:    None.
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj()
    : m_eVarFormat(eVarFormat_Natural), m_eVarType(eVarType_Internal) {
  // Do not call UpdateValue() in here as not necessary
}

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj constructor.
// Type:    Method.
// Args:    vrStrNameReal   - (R) The actual name of the variable, the
// expression.
//          vrStrName       - (R) The name given for *this var object.
//          vrValue         - (R) The LLDB SBValue object represented by *this
//          object.
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj(
    const CMIUtilString &vrStrNameReal, const CMIUtilString &vrStrName,
    const lldb::SBValue &vrValue)
    : m_eVarFormat(eVarFormat_Natural), m_eVarType(eVarType_Internal),
      m_strName(vrStrName), m_SBValue(vrValue), m_strNameReal(vrStrNameReal) {
  UpdateValue();
}

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj constructor.
// Type:    Method.
// Args:    vrStrNameReal           - (R) The actual name of the variable, the
// expression.
//          vrStrName               - (R) The name given for *this var object.
//          vrValue                 - (R) The LLDB SBValue object represented by
//          *this object.
//          vrStrVarObjParentName   - (R) The var object parent to *this var
//          object (LLDB SBValue equivalent).
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj(
    const CMIUtilString &vrStrNameReal, const CMIUtilString &vrStrName,
    const lldb::SBValue &vrValue, const CMIUtilString &vrStrVarObjParentName)
    : m_eVarFormat(eVarFormat_Natural), m_eVarType(eVarType_Internal),
      m_strName(vrStrName), m_SBValue(vrValue), m_strNameReal(vrStrNameReal),
      m_strVarObjParentName(vrStrVarObjParentName) {
  UpdateValue();
}

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj copy constructor.
// Type:    Method.
// Args:    vrOther - (R) The object to copy from.
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj(
    const CMICmnLLDBDebugSessionInfoVarObj &vrOther) {
  CopyOther(vrOther);
}

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj copy constructor.
// Type:    Method.
// Args:    vrOther - (R) The object to copy from.
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj(
    CMICmnLLDBDebugSessionInfoVarObj &vrOther) {
  CopyOther(vrOther);
}

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj move constructor.
// Type:    Method.
// Args:    vrwOther    - (R) The object to copy from.
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj(
    CMICmnLLDBDebugSessionInfoVarObj &&vrwOther) {
  MoveOther(vrwOther);
}

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj assignment operator.
// Type:    Method.
// Args:    vrOther - (R) The object to copy from.
// Return:  CMICmnLLDBDebugSessionInfoVarObj & - Updated *this object.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj &CMICmnLLDBDebugSessionInfoVarObj::
operator=(const CMICmnLLDBDebugSessionInfoVarObj &vrOther) {
  CopyOther(vrOther);

  return *this;
}

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj assignment operator.
// Type:    Method.
// Args:    vrwOther    - (R) The object to copy from.
// Return:  CMICmnLLDBDebugSessionInfoVarObj & - Updated *this object.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj &CMICmnLLDBDebugSessionInfoVarObj::
operator=(CMICmnLLDBDebugSessionInfoVarObj &&vrwOther) {
  MoveOther(vrwOther);

  return *this;
}

//++
// Details: Copy the other instance of that object to *this object.
// Type:    Method.
// Args:    vrOther - (R) The object to copy from.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool CMICmnLLDBDebugSessionInfoVarObj::CopyOther(
    const CMICmnLLDBDebugSessionInfoVarObj &vrOther) {
  // Check for self-assignment
  if (this == &vrOther)
    return MIstatus::success;

  m_eVarFormat = vrOther.m_eVarFormat;
  m_eVarType = vrOther.m_eVarType;
  m_strName = vrOther.m_strName;
  m_SBValue = vrOther.m_SBValue;
  m_strNameReal = vrOther.m_strNameReal;
  m_strFormattedValue = vrOther.m_strFormattedValue;
  m_strVarObjParentName = vrOther.m_strVarObjParentName;

  return MIstatus::success;
}

//++
// Details: Move that object to *this object.
// Type:    Method.
// Args:    vrwOther    - (RW) The object to copy from.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool CMICmnLLDBDebugSessionInfoVarObj::MoveOther(
    CMICmnLLDBDebugSessionInfoVarObj &vrwOther) {
  // Check for self-assignment
  if (this == &vrwOther)
    return MIstatus::success;

  CopyOther(vrwOther);
  vrwOther.m_eVarFormat = eVarFormat_Natural;
  vrwOther.m_eVarType = eVarType_Internal;
  vrwOther.m_strName.clear();
  vrwOther.m_SBValue.Clear();
  vrwOther.m_strNameReal.clear();
  vrwOther.m_strFormattedValue.clear();
  vrwOther.m_strVarObjParentName.clear();

  return MIstatus::success;
}

//++
// Details: CMICmnLLDBDebugSessionInfoVarObj destructor.
// Type:    Overridden.
// Args:    None.
// Return:  None.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::~CMICmnLLDBDebugSessionInfoVarObj() {}

//++
// Details: Retrieve the var format enumeration for the specified string.
// Type:    Static method.
// Args:    vrStrFormat - (R) Text description of the var format.
// Return:  varFormat_e - Var format enumeration.
//                      - No match found return eVarFormat_Invalid.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::varFormat_e
CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForString(
    const CMIUtilString &vrStrFormat) {
  // CODETAG_SESSIONINFO_VARFORMAT_ENUM
  for (MIuint i = 0; i < eVarFormat_count; i++) {
    const char *pVarFormatString = ms_aVarFormatStrings[i];
    if (vrStrFormat == pVarFormatString)
      return static_cast<varFormat_e>(i);
  }

  return eVarFormat_Invalid;
}

//++
// Details: Retrieve the var format enumeration for the specified character.
// Type:    Static method.
// Args:    vcFormat    - Character representing the var format.
// Return:  varFormat_e - Var format enumeration.
//                      - No match found return eVarFormat_Invalid.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::varFormat_e
CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar(char vcFormat) {
  if ('r' == vcFormat)
    return eVarFormat_Hex;

  // CODETAG_SESSIONINFO_VARFORMAT_ENUM
  for (MIuint i = 0; i < eVarFormat_count; i++) {
    const char *pVarFormatChar = ms_aVarFormatChars[i];
    if (*pVarFormatChar == vcFormat)
      return static_cast<varFormat_e>(i);
  }

  return eVarFormat_Invalid;
}

//++
// Details: Return the equivalent var value formatted string for the given value
// type,
//          which was prepared for printing (i.e. value was escaped and now it's
//          ready
//          for wrapping into quotes).
//          The SBValue vrValue parameter is checked by LLDB private code for
//          valid
//          scalar type via MI Driver proxy function as the valued returned can
//          also be
//          an error condition. The proxy function determines if the check was
//          valid
//          otherwise return an error condition state by other means saying so.
// Type:    Static method.
// Args:    vrValue     - (R) The var value object.
//          veVarFormat - (R) Var format enumeration.
// Returns: CMIUtilString   - Value formatted string.
// Throws:  None.
//--
CMIUtilString CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(
    const lldb::SBValue &vrValue,
    const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat) {
  const CMICmnLLDBUtilSBValue utilValue(vrValue, true);
  if (utilValue.IsIntegerType()) {
    MIuint64 nValue = 0;
    if (CMICmnLLDBProxySBValue::GetValueAsUnsigned(vrValue, nValue)) {
      lldb::SBValue &rValue = const_cast<lldb::SBValue &>(vrValue);
      return GetStringFormatted(nValue, rValue.GetValue(), veVarFormat);
    }
  }

  return utilValue.GetValue().AddSlashes();
}

//++
// Details: Return number formatted string according to the given value type.
// Type:    Static method.
// Args:    vnValue             - (R) The number value to get formatted.
//          vpStrValueNatural   - (R) The natural representation of the number
//          value.
//          veVarFormat         - (R) Var format enumeration.
// Returns: CMIUtilString       - Numerical formatted string.
// Throws:  None.
//--
CMIUtilString CMICmnLLDBDebugSessionInfoVarObj::GetStringFormatted(
    const MIuint64 vnValue, const char *vpStrValueNatural,
    const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat) {
  CMIUtilString strFormattedValue;
  CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veFormat = veVarFormat;
  if (ms_eDefaultFormat != eVarFormat_Invalid &&
      veVarFormat == eVarFormat_Natural) {
    veFormat = ms_eDefaultFormat;
  }

  switch (veFormat) {
  case eVarFormat_Binary:
    strFormattedValue = CMIUtilString::FormatBinary(vnValue);
    break;
  case eVarFormat_Octal:
    strFormattedValue = CMIUtilString::Format("0%llo", vnValue);
    break;
  case eVarFormat_Decimal:
    strFormattedValue = CMIUtilString::Format("%lld", vnValue);
    break;
  case eVarFormat_Hex:
    strFormattedValue = CMIUtilString::Format("0x%llx", vnValue);
    break;
  case eVarFormat_Natural:
  default: {
    strFormattedValue = (vpStrValueNatural != nullptr) ? vpStrValueNatural : "";
  }
  }

  return strFormattedValue;
}

//++
// Details: Delete internal container contents.
// Type:    Static method.
// Args:    None.
// Returns: None.
// Throws:  None.
//--
void CMICmnLLDBDebugSessionInfoVarObj::VarObjClear() {
  ms_mapVarIdToVarObj.clear();
}

//++
// Details: Add a var object to the internal container.
// Type:    Static method.
// Args:    vrVarObj    - (R) The var value object.
// Returns: None.
// Throws:  None.
//--
void CMICmnLLDBDebugSessionInfoVarObj::VarObjAdd(
    const CMICmnLLDBDebugSessionInfoVarObj &vrVarObj) {
  VarObjDelete(vrVarObj.GetName());
  MapPairKeyToVarObj_t pr(vrVarObj.GetName(), vrVarObj);
  ms_mapVarIdToVarObj.insert(pr);
}

//++
// Details: Delete the var object from the internal container matching the
// specified name.
// Type:    Static method.
// Args:    vrVarName   - (R) The var value name.
// Returns: None.
// Throws:  None.
//--
void CMICmnLLDBDebugSessionInfoVarObj::VarObjDelete(
    const CMIUtilString &vrVarName) {
  const MapKeyToVarObj_t::const_iterator it =
      ms_mapVarIdToVarObj.find(vrVarName);
  if (it != ms_mapVarIdToVarObj.end()) {
    ms_mapVarIdToVarObj.erase(it);
  }
}

//++
// Details: Update an existing var object in the internal container.
// Type:    Static method.
// Args:    vrVarObj    - (R) The var value object.
// Returns: None.
// Throws:  None.
//--
void CMICmnLLDBDebugSessionInfoVarObj::VarObjUpdate(
    const CMICmnLLDBDebugSessionInfoVarObj &vrVarObj) {
  VarObjAdd(vrVarObj);
}

//++
// Details: Retrieve the var object matching the specified name.
// Type:    Static method.
// Args:    vrVarName   - (R) The var value name.
//          vrwVarObj   - (W) A var object.
// Returns: bool    - True = object found, false = object not found.
// Throws:  None.
//--
bool CMICmnLLDBDebugSessionInfoVarObj::VarObjGet(
    const CMIUtilString &vrVarName,
    CMICmnLLDBDebugSessionInfoVarObj &vrwVarObj) {
  const MapKeyToVarObj_t::const_iterator it =
      ms_mapVarIdToVarObj.find(vrVarName);
  if (it != ms_mapVarIdToVarObj.end()) {
    const CMICmnLLDBDebugSessionInfoVarObj &rVarObj = (*it).second;
    vrwVarObj = rVarObj;
    return true;
  }

  return false;
}

//++
// Details: A count is kept of the number of var value objects created. This is
// count is
//          used to ID the var value object. Reset the count to 0.
// Type:    Static method.
// Args:    None.
// Returns: None.
// Throws:  None.
//--
void CMICmnLLDBDebugSessionInfoVarObj::VarObjIdResetToZero() {
  ms_nVarUniqueId = 0;
}

//++
// Details: Default format is globally used as the data format when "natural" is
// in effect, that is, this overrides the default
// Type:    Static method.
// Args:    None.
// Returns: None.
// Throws:  None.
//--
void CMICmnLLDBDebugSessionInfoVarObj::VarObjSetFormat(
    varFormat_e eDefaultFormat) {
  ms_eDefaultFormat = eDefaultFormat;
}

//++
// Details: A count is kept of the number of var value objects created. This is
// count is
//          used to ID the var value object. Increment the count by 1.
// Type:    Static method.
// Args:    None.
// Returns: None.
// Throws:  None.
//--
void CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc() { ms_nVarUniqueId++; }

//++
// Details: A count is kept of the number of var value objects created. This is
// count is
//          used to ID the var value object. Retrieve ID.
// Type:    Static method.
// Args:    None.
// Returns: None.
// Throws:  None.
//--
MIuint CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet() {
  return ms_nVarUniqueId;
}

//++
// Details: Retrieve the value formatted object's name.
// Type:    Method.
// Args:    None.
// Returns: CMIUtilString & - Value's var%u name text.
// Throws:  None.
//--
const CMIUtilString &CMICmnLLDBDebugSessionInfoVarObj::GetName() const {
  return m_strName;
}

//++
// Details: Retrieve the value formatted object's variable name as given in the
// MI command
//          to create the var object.
// Type:    Method.
// Args:    None.
// Returns: CMIUtilString & - Value's real name text.
// Throws:  None.
//--
const CMIUtilString &CMICmnLLDBDebugSessionInfoVarObj::GetNameReal() const {
  return m_strNameReal;
}

//++
// Details: Retrieve the value formatted string.
// Type:    Method.
// Args:    None.
// Returns: CMIUtilString & - Value formatted string.
// Throws:  None.
//--
const CMIUtilString &
CMICmnLLDBDebugSessionInfoVarObj::GetValueFormatted() const {
  return m_strFormattedValue;
}

//++
// Details: Retrieve the LLDB Value object.
// Type:    Method.
// Args:    None.
// Returns: lldb::SBValue & - LLDB Value object.
// Throws:  None.
//--
lldb::SBValue &CMICmnLLDBDebugSessionInfoVarObj::GetValue() {
  return m_SBValue;
}

//++
// Details: Retrieve the LLDB Value object.
// Type:    Method.
// Args:    None.
// Returns: lldb::SBValue & - Constant LLDB Value object.
// Throws:  None.
//--
const lldb::SBValue &CMICmnLLDBDebugSessionInfoVarObj::GetValue() const {
  return m_SBValue;
}

//++
// Details: Set the var format type for *this object and update the formatting.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool CMICmnLLDBDebugSessionInfoVarObj::SetVarFormat(
    const varFormat_e veVarFormat) {
  if (veVarFormat >= eVarFormat_count)
    return MIstatus::failure;

  m_eVarFormat = veVarFormat;
  UpdateValue();
  return MIstatus::success;
}

//++
// Details: Update *this var obj. Update it's value and type.
// Type:    Method.
// Args:    None.
// Returns: None.
// Throws:  None.
//--
void CMICmnLLDBDebugSessionInfoVarObj::UpdateValue() {
  m_strFormattedValue = GetValueStringFormatted(m_SBValue, m_eVarFormat);

  MIuint64 nValue = 0;
  if (CMICmnLLDBProxySBValue::GetValueAsUnsigned(m_SBValue, nValue) ==
      MIstatus::failure)
    m_eVarType = eVarType_Composite;

  CMICmnLLDBDebugSessionInfoVarObj::VarObjUpdate(*this);
}

//++
// Details: Retrieve the enumeration type of the var object.
// Type:    Method.
// Args:    None.
// Returns: varType_e   - Enumeration value.
// Throws:  None.
//--
CMICmnLLDBDebugSessionInfoVarObj::varType_e
CMICmnLLDBDebugSessionInfoVarObj::GetType() const {
  return m_eVarType;
}

//++
// Details: Retrieve the parent var object's name, the parent var object  to
// *this var
//          object (if assigned). The parent is equivalent to LLDB SBValue
//          variable's
//          parent.
// Type:    Method.
// Args:    None.
// Returns: CMIUtilString & - Pointer to var object, NULL = no parent.
// Throws:  None.
//--
const CMIUtilString &
CMICmnLLDBDebugSessionInfoVarObj::GetVarParentName() const {
  return m_strVarObjParentName;
}
