//-----------------------------------------------------------------------------
#include "PropData.h"
#include "PropTree.h"

//------------------------------------------------------------------------------
using namespace std;
using namespace mvIMPACT::acquire;

//------------------------------------------------------------------------------
PropTree::PropTree( HOBJ hObj, wxPGId rootProp, const char *pTitle, wxPropertyGrid* pPropGrid, bool boDisplayDebugInfo, bool boDisplayInvisibleComponents ) :
	m_rootList(hObj), m_pPropGrid(pPropGrid), m_RootProp(rootProp),
	m_boDisplayDebugInfo(boDisplayDebugInfo), m_boDisplayInvisibleComponents(boDisplayInvisibleComponents)
//------------------------------------------------------------------------------
{
	if( pTitle )
	{
		m_Title = pTitle;
	}
}

//------------------------------------------------------------------------------
PropTree::~PropTree( void )
//------------------------------------------------------------------------------
{
	//m_pOptionTree->EnableUpdate(false);
	Delete();
	CompToDataMap::iterator itStart = m_CompToDataMap.begin();
	CompToDataMap::iterator itEnd = m_CompToDataMap.end();
	while( itStart != itEnd )
	{
		delete itStart->second;
		++itStart;
	}
}

//-----------------------------------------------------------------------------
void PropTree::Delete( void )
//-----------------------------------------------------------------------------
{
	if( m_TopLevelProp.GetPropertyPtr() )
	{
		m_pPropGrid->Delete( m_TopLevelProp );
		m_TopLevelProp = wxPGId();
	}
}

//------------------------------------------------------------------------------
wxPGId PropTree::CreateGridProperty( HOBJ hObj, wxPGId parentProp, int index /* = -1 */, bool* boModified /* = 0 */, const char* pTitle /* = 0 */ )
//------------------------------------------------------------------------------
{
	if( boModified )
	{
		*boModified = false;
	}

	// check if item is already present
	PropData *pPropData = GetPropData( hObj );
	Component comp(hObj);
	if( !pPropData )
	{
		bool boCompToDataMap = true;
		switch( comp.type() )
		{
		case ctList:
			pPropData = new ListObject( hObj, pTitle );
			break;
		case ctMeth:
			pPropData = new MethodObject( hObj );
			break;
		case ctPropInt:
		case ctPropFloat:
		case ctPropString:
		case ctPropPtr:
			{
				boCompToDataMap = index == -1;
				bool boPropVector = (index == -1)  && (comp.flags() & cfShouldBeDisplayedAsList);
				if( boPropVector )
				{
					pPropData = new VectorPropertyObject( hObj );
				}
				else
				{
					pPropData = new PropertyObject( hObj, index );
				}
			}
			break;
		default:
			// an unrecognized component type
			wxASSERT(0);
			break;
		}
		if( boCompToDataMap )
		{
			m_CompToDataMap.insert( CompDataPair( hObj, pPropData ) );
		}
	}
	else if ( index != -1 )
	{
		VectorPropertyObject* pPropVec = dynamic_cast<VectorPropertyObject*>( pPropData );
		wxASSERT( pPropVec != 0 );
		pPropVec->Resize();
		pPropData = pPropVec->GetVectorItem( index );
	}
	wxASSERT( pPropData != 0 );
	pPropData->EnsureValidGridItem( this, parentProp, boModified );
	//if( !m_pPropGrid->IsPropertySelected( pPropData->GetGridItem() ) )
	//{
		pPropData->UpdateGridItem( this, m_boDisplayDebugInfo, m_boDisplayInvisibleComponents, boModified );
	//}
	return pPropData->GetGridItem();
}

//------------------------------------------------------------------------------
int	PropTree::Draw( void )
//------------------------------------------------------------------------------
{
	const char *str = 0;
	if( !m_Title.empty() )
	{
		str = m_Title.c_str();
	}

	bool boModified = false;
	/// \todo freeze / thaw mechanism causes flickering editors (focus problem)
	//m_pPropGrid->Freeze();
	m_TopLevelProp = CreateGridProperty( m_rootList, m_RootProp, -1, &boModified, str );
	// do NOT change the order of the next two calls as then deleted entries won't be
	// removed from the property grid correctly...
	// As an alternative the '&& pPropData->HasChanged()' could be removed from 'UpdateGridPropsRecursively2'
	UpdateGridPropsRecursively2( m_pPropGrid->GetFirstChild( m_TopLevelProp ) );
	UpdateGridPropsRecursively( ComponentIterator( m_rootList.firstChild() ), m_TopLevelProp );
	//m_pPropGrid->Thaw();
	//m_pPropGrid->CalculateYs( NULL, -1 );
	//m_pPropGrid->Refresh();
	return m_rootList.changedCounter();
}

//-----------------------------------------------------------------------------
unsigned int PropTree::GetChangedCounter( void ) const
//-----------------------------------------------------------------------------
{
	return m_rootList.changedCounter();
}

//------------------------------------------------------------------------------
PropData* PropTree::GetPropData( HOBJ hObj ) const
//------------------------------------------------------------------------------
{
	CompToDataMap::const_iterator it = m_CompToDataMap.find( hObj );
	if( it != m_CompToDataMap.end( ) )
	{
		return it->second;
	}
	return 0;
}

//------------------------------------------------------------------------------
PropData* PropTree::GetPropData( const string& name ) const
//------------------------------------------------------------------------------
{
	CompToDataMap::const_iterator itStart = m_CompToDataMap.begin();
	CompToDataMap::const_iterator itEnd = m_CompToDataMap.end();
	while( itStart != itEnd )
	{
		if( itStart->second->Component().name() == name )
		{
			return itStart->second;
		}
		++itStart;
	}
	return 0;
}

//------------------------------------------------------------------------------
/// \brief Updates and/or creates grid properties
void PropTree::UpdateGridPropsRecursively( ComponentIterator iter, wxPGId listRoot )
//------------------------------------------------------------------------------
{
	while( iter.isValid() )
	{
		bool boModified;
		wxPGId gridProp = CreateGridProperty( iter, listRoot, -1, &boModified );
		if( iter.isList() && gridProp.GetPropertyPtr() && boModified )
		{
			PropData* pPropData = ( PropData* )m_pPropGrid->GetPropertyClientData(gridProp);
			if( pPropData && boModified )
			{
				// this sublist needs to be updated as there have been changes in it...
				UpdateGridPropsRecursively( iter.firstChild(), gridProp );
			}
		}
		++iter;
	}
}

//-----------------------------------------------------------------------------
/// \brief Removes references and grid items that became invalid.
void PropTree::UpdateGridPropsRecursively2( wxPGId iter )
//-----------------------------------------------------------------------------
{
	while( iter.IsOk() )
	{
		PropData* pPropData = ( PropData* )m_pPropGrid->GetPropertyClientData(iter);
		wxPGId toDelete;
		if( !pPropData->Component().isValid() )
		{
			if( m_pPropGrid->GetChildrenCount() > 0 )
			{
				// if we have to delete an entry we also have to delete all childs of this entry.
				UpdateGridPropsRecursively2( m_pPropGrid->GetFirstChild( iter ) );
			}
			m_CompToDataMap.erase( m_CompToDataMap.find( pPropData->Component() ) );
			delete pPropData;
			toDelete = iter;			
		}
		else if( pPropData->Component().isList() && pPropData->HasChanged() )
		{
			UpdateGridPropsRecursively2( m_pPropGrid->GetFirstChild( iter ) );
		}

		iter = m_pPropGrid->GetNextSibling( iter );
		if( toDelete.IsOk() )
		{
			m_pPropGrid->Delete( toDelete );
		}
	}
}

