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

//++
// File:		MICmnLLDBDebugSessionInfoVarObj.cpp
//
// Overview:	CMICmnLLDBDebugSessionInfoVarObj implementation.
//
// Environment:	Compilers:	Visual C++ 12.
//							gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
//				Libraries:	See MIReadmetxt. 
//
// Copyright:	None.
//--

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

// Instantiations:
const MIchar * CMICmnLLDBDebugSessionInfoVarObj::ms_aVarFormatStrings[] =
{
	// CODETAG_SESSIONINFO_VARFORMAT_ENUM
	// *** Order is import here.
	"<Invalid var format>",
	"binary",
	"octal",
	"decimal",
	"hexadecimal",
	"natural"
};
const MIchar * 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

//++ ------------------------------------------------------------------------------------
// Details:	CMICmnLLDBDebugSessionInfoVarObj constructor.
// Type:	Method.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmnLLDBDebugSessionInfoVarObj::CMICmnLLDBDebugSessionInfoVarObj( void )
:	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 assignment opertator.
// 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:	Copy the other instance of *this 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:	CMICmnLLDBDebugSessionInfoVarObj destructor.
// Type:	Overridable.
// Args:	None.
// Return:	None.
// Throws:	None.
//--
CMICmnLLDBDebugSessionInfoVarObj::~CMICmnLLDBDebugSessionInfoVarObj( void )
{
}

//++ ------------------------------------------------------------------------------------
// 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 MIchar * 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:	vrcFormat	- (R) Character representing the var format.
// Return:	varFormat_e	- Var format enumeration.
//						- No match found return eVarFormat_Invalid.
// Throws:	None.
//--
CMICmnLLDBDebugSessionInfoVarObj::varFormat_e CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar( const MIchar & vrcFormat )
{
	if( 'r' == vrcFormat )
		return eVarFormat_Hex;

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

	return eVarFormat_Invalid;
}

//++ ------------------------------------------------------------------------------------
// Details:	Return the equivalent var value formatted string for the given value type.
//			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 )
{
	CMIUtilString strFormattedValue;
	
	MIuint64 nValue = 0;
	if( CMICmnLLDBProxySBValue::GetValueAsUnsigned( vrValue, nValue ) == MIstatus::success )
	{
		lldb::SBValue & rValue = const_cast< lldb::SBValue & >( vrValue );
		strFormattedValue = GetStringFormatted( nValue, rValue.GetValue(), veVarFormat );
	}
	else
	{
		// Composite variable type i.e. struct
		strFormattedValue = "{...}";
	}
	
	return strFormattedValue;
}

//++ ------------------------------------------------------------------------------------
// Details:	Return nuber 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 MIchar * vpStrValueNatural, const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat )
{
	CMIUtilString strFormattedValue;
	
	switch( veVarFormat )
	{
	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( void )
{
	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( void )
{
	ms_nVarUniqueId = 0;
}

//++ ------------------------------------------------------------------------------------
// 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( void )
{
	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( void )
{
	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( void ) 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( void ) 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( void ) const
{
	return m_strFormattedValue;
}

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

//++ ------------------------------------------------------------------------------------
// Details:	Set the var format type for *this object and upate 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( void )
{
	m_strFormattedValue = CMICmnLLDBDebugSessionInfoVarObj::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( void ) 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( void ) const
{
	return m_strVarObjParentName;
}
	