//-----------------------------------------------------------------------------
#include "CaptureThread.h"
#include "DevCtrl.h"
#include "DevData.h"
#include "PropTree.h"

using namespace std;
using namespace mvIMPACT::acquire;

//-----------------------------------------------------------------------------
DevicePropertyHandler::DevicePropertyHandler( wxPropertyGrid* pGrid, bool boDisplayDebugInfo, bool boDisplayFullTree, bool boDisplayInvisibleComponents ) :
	m_actDevListChangedCounter(0), m_boDisplayDebugInfo(boDisplayDebugInfo), m_boDisplayInvisibleComponents(boDisplayInvisibleComponents),
	m_fullTreeChangedCounter(0), m_pFullTree(0), m_pActiveDevData(0), m_pActiveDevice(0),
	m_pPropertyGrid(pGrid), m_viewMode(vmStandard)
//-----------------------------------------------------------------------------
{
	if( boDisplayFullTree )
	{
		m_pFullTree = new PropTree( ROOT_LIST, 0, "Full Tree", pGrid, boDisplayDebugInfo, boDisplayInvisibleComponents );
		m_pFullTree->Draw();
	}
	else
	{
		PrepareTreeArray();
	}
}

//-----------------------------------------------------------------------------
DevicePropertyHandler::~DevicePropertyHandler()
//-----------------------------------------------------------------------------
{
	m_pPropertyGrid->Freeze();
	DevToTreeMap::iterator itStart = m_devToTreeMap.begin();
	DevToTreeMap::iterator itEnd = m_devToTreeMap.end();
	while( itStart != itEnd )
	{
		CloseDriver( itStart->first->serial.read() );
		delete itStart->second->pCaptureThread;
		DeleteDriverTrees( itStart );
		delete itStart->second->pDeviceTree;
		delete itStart->second->pFuncInterface;
		delete itStart->second->pStatistics;
		delete itStart->second;
		++itStart;
	}
	delete m_pFullTree;
	m_pPropertyGrid->Thaw();
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::CloseDriver( const string& name )
//-----------------------------------------------------------------------------
{
	Device* pDev = m_devMgr.getDeviceBySerial( name );
	if( pDev && pDev->isOpen() )
	{
		DevToTreeMap::iterator it = m_devToTreeMap.find( pDev );
		if( it != m_devToTreeMap.end() )
		{
			wxCriticalSectionLocker locker( m_critSect );
			it->second->pCaptureThread->SetLiveMode( false );
			delete it->second->pCaptureThread;
			it->second->pCaptureThread = 0;
			it->second->boWasLive = false;
			DeleteDriverTrees( it );
			delete it->second->pFuncInterface;
			it->second->pFuncInterface = 0;
			delete it->second->pStatistics;
			it->second->pStatistics = 0;
		}
		pDev->close();
	}

	if( m_pFullTree )
	{
		delete m_pFullTree;
		// there has been one before, so there should be one now! WORK AROUND!!!
		m_pFullTree = new PropTree( ROOT_LIST, 0, "Full Tree", m_pPropertyGrid, m_boDisplayDebugInfo, m_boDisplayInvisibleComponents );
		m_pFullTree->Draw();
	}
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::CreateDriverTrees( DevToTreeMap::iterator& it )
//-----------------------------------------------------------------------------
{
	ComponentLocator cl(it->first->hDrv());
	for( unsigned int i=0; i<m_vTreeProps.size(); i++ )
	{
		HOBJ hObj = cl.findComponent( m_vTreeProps[i].ListName.c_str() );
		if( hObj != INVALID_ID )
		{
			PropTree* pTree = new PropTree( cl.findComponent( m_vTreeProps[i].ListName.c_str() ), 0, m_vTreeProps[i].DisplayName.c_str(), m_pPropertyGrid, m_boDisplayDebugInfo, m_boDisplayInvisibleComponents );
			it->second->vDriverTrees.push_back(	pTree );
			pTree->Draw();
		}
	}
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::DeleteDriverTrees( DevToTreeMap::iterator& it )
//-----------------------------------------------------------------------------
{
	while( !it->second->vDriverTrees.empty())
	{
		delete it->second->vDriverTrees.back();
		it->second->vDriverTrees.pop_back();
	}
}

//-----------------------------------------------------------------------------
Device* DevicePropertyHandler::GetActiveDevice( FunctionInterface** ppFI /* = 0 */, const Statistics** ppS /* = 0 */, CaptureThread** ppCT /* = 0 */ ) const
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker( m_critSect );
	if( m_pActiveDevData )
	{
		if( ppFI )
		{
			*ppFI = m_pActiveDevData->pFuncInterface;
		}
		if( ppS )
		{
			*ppS = m_pActiveDevData->pStatistics;
		}
		if( ppCT )
		{
			*ppCT = m_pActiveDevData->pCaptureThread;
		}
	}
	return m_pActiveDevice;
}

//-----------------------------------------------------------------------------
bool DevicePropertyHandler::GetDeviceData( mvIMPACT::acquire::Device* pDev, mvIMPACT::acquire::FunctionInterface** ppFI /* = 0 */, const mvIMPACT::acquire::Statistics** ppS /* = 0 */, CaptureThread** ppCT /* = 0  */ ) const
//-----------------------------------------------------------------------------
{
	DevToTreeMap::const_iterator it = m_devToTreeMap.find( pDev );
	if( it != m_devToTreeMap.end() )
	{
		if( ppFI )
		{
			*ppFI = it->second->pFuncInterface;
		}
		if( ppS )
		{
			*ppS = it->second->pStatistics;
		}
		if( ppCT )
		{
			*ppCT = it->second->pCaptureThread;
		}
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::OpenDriver( const string& name, wxWindow* pParentWindow )
//-----------------------------------------------------------------------------
{
	Device* pDev = m_devMgr.getDeviceBySerial( name );
	if( pDev && !pDev->isOpen() )
	{
		UpdateTreeMap();
		pDev->open();
		DevToTreeMap::iterator it = m_devToTreeMap.find( pDev );
		if( it != m_devToTreeMap.end() )
		{
			{
				wxCriticalSectionLocker locker( m_critSect );
				if( it->second->vDriverTrees.size() != m_vTreeProps.size())
				{
					CreateDriverTrees( it );
				}

				if( it->second->pFuncInterface == 0 )
				{
					it->second->pFuncInterface = new FunctionInterface( pDev );
				}
				if( it->second->pCaptureThread == 0 )
				{
					it->second->pCaptureThread = new CaptureThread( it->second->pFuncInterface, pDev, pParentWindow );
					it->second->pCaptureThread->Create();
					it->second->pCaptureThread->Run();
					it->second->pCaptureThread->SetActive();
				}
				if( it->second->pStatistics == 0 )
				{
					it->second->pStatistics = new Statistics( pDev );
				}
				it->second->boWasLive = false;
			}

			if( m_pFullTree )
			{
				m_pFullTree->Draw();
			}
		}
	}
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::PrepareTreeArray( void )
//-----------------------------------------------------------------------------
{
	m_vTreeProps.clear();
	switch( m_viewMode )
	{
	case vmDeveloper:
		m_vTreeProps.push_back(TreeProp("CameraDescriptions", "CameraDescriptions" ));
		m_vTreeProps.push_back(TreeProp("DeviceSpecificData", "DeviceSpecificData"));		
		m_vTreeProps.push_back(TreeProp("ImageRequestCtrl", "ImageRequestCtrl"));
		m_vTreeProps.push_back(TreeProp("Info", "Info"));
		m_vTreeProps.push_back(TreeProp("Requests", "Requests"));		
		m_vTreeProps.push_back(TreeProp("IOSubSystem", "IOSubSystem"));
		m_vTreeProps.push_back(TreeProp("Setting", "Setting"));
		m_vTreeProps.push_back(TreeProp("Statistics", "Statistics"));
		m_vTreeProps.push_back(TreeProp("System", "SystemSettings"));
		break;
	default:
	case vmStandard:
		m_vTreeProps.push_back(TreeProp("Base", "Image Setting"));
		m_vTreeProps.push_back(TreeProp("CameraDescriptions", "Camera Descriptions" ));
		m_vTreeProps.push_back(TreeProp("IOSubSystem", "Digital I/O"));
		m_vTreeProps.push_back(TreeProp("ImageMemoryManager", "Image Memory Manager"));
		m_vTreeProps.push_back(TreeProp("Info", "Info"));
		m_vTreeProps.push_back(TreeProp("Requests", "Requests"));
		m_vTreeProps.push_back(TreeProp("Statistics", "Statistics"));
		m_vTreeProps.push_back(TreeProp("System", "System Settings"));
		m_vTreeProps.push_back(TreeProp("DeviceSpecificData", "Device Specific Data"));
		break;
	}
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::SetActiveDevice( const std::string& devName )
//-----------------------------------------------------------------------------
{
	wxCriticalSectionLocker locker( m_critSect );
	Device* pDev = m_devMgr.getDeviceBySerial( devName );

	if( pDev )
	{
		UpdateTreeMap();
		DevToTreeMap::iterator itNewDev = m_devToTreeMap.find( pDev );

		if( itNewDev != m_devToTreeMap.end() )
		{
			if( m_pActiveDevice && ( m_pActiveDevice != pDev ) )
			{
				DevToTreeMap::iterator itCurDev = m_devToTreeMap.find( m_pActiveDevice );
				if( itCurDev != m_devToTreeMap.end() )
				{
					if( !m_pFullTree )
					{
						delete itCurDev->second->pDeviceTree;
						itCurDev->second->pDeviceTree = 0;
						DeleteDriverTrees( itCurDev );
					}
					CaptureThread* pThread = itCurDev->second->pCaptureThread;
					if( pThread )
					{
						itCurDev->second->boWasLive = pThread->GetLiveMode();
						pThread->SetLiveMode(false);
					}
					else
					{
						itCurDev->second->boWasLive = false;
					}
				}
			}

			if( m_pActiveDevice != pDev )
			{
				m_pActiveDevice = pDev;
				m_pActiveDevData = itNewDev->second;

				if( m_pFullTree )
				{
					m_fullTreeChangedCounter = m_pFullTree->Draw();
				}
				else
				{
					if( !itNewDev->second->pDeviceTree )
					{
						itNewDev->second->pDeviceTree = new PropTree( pDev->hDev(), 0, "Device", m_pPropertyGrid, m_boDisplayDebugInfo, m_boDisplayInvisibleComponents );
					}
					m_actDevListChangedCounter = itNewDev->second->pDeviceTree->Draw();
					if( pDev->isOpen() )
					{
						CreateDriverTrees( itNewDev );
					}
				}

				PropTreeVector::size_type vSize = itNewDev->second->vDriverTrees.size();
				for( PropTreeVector::size_type i=0; i<vSize; i++ )
				{
					if( itNewDev->second->vDriverTrees[i] )
					{
						m_vTreeProps[i].ChangedCounter = itNewDev->second->vDriverTrees[i]->Draw();
					}
				}

				CaptureThread* pThread = itNewDev->second->pCaptureThread;
				if( pThread )
				{
					pThread->SetActive();
					if( itNewDev->second->boWasLive )
					{
						itNewDev->second->boWasLive = pThread->GetLiveMode();
						pThread->SetLiveMode( true );
					}
				}
			}
		}
	}
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::SetViewMode( TViewMode mode )
//-----------------------------------------------------------------------------
{
	if( mode != m_viewMode )
	{
		m_viewMode = mode;
		PrepareTreeArray();
		if( !m_pFullTree )
		{
			DevToTreeMap::iterator itCurDev = m_devToTreeMap.find( m_pActiveDevice );
			if( itCurDev != m_devToTreeMap.end() )
			{
				DeleteDriverTrees( itCurDev );
				CreateDriverTrees( itCurDev );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::UpdateTreeMap()
//-----------------------------------------------------------------------------
{
	if( m_devMgr.deviceCount() != m_devToTreeMap.size() )
	{
		for( unsigned int i=0; i<m_devMgr.deviceCount(); i++ )
		{
			DevToTreeMap::iterator it = m_devToTreeMap.find( m_devMgr[i] );
			if( it == m_devToTreeMap.end() )
			{
				m_devToTreeMap.insert( DevTreePair( m_devMgr[i], new DeviceData( m_pFullTree ? 0 : new PropTree( m_devMgr[i]->hDev(), 0, "Device", m_pPropertyGrid, m_boDisplayDebugInfo, m_boDisplayInvisibleComponents ) ) ) );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void DevicePropertyHandler::ValidateTrees( void )
//-----------------------------------------------------------------------------
{
	bool boUpdate = false;

	if( m_pFullTree )
	{
		if( m_fullTreeChangedCounter != ComponentList(ROOT_LIST).changedCounter() )
		{
			m_fullTreeChangedCounter = m_pFullTree->Draw();
			boUpdate = true;
		}
	}
	else if( m_pActiveDevData )
	{
		if(	m_actDevListChangedCounter != m_pActiveDevData->pDeviceTree->GetChangedCounter()   )
		{
			m_actDevListChangedCounter = m_pActiveDevData->pDeviceTree->Draw();
			boUpdate = true;
		}

		PropTreeVector::size_type vSize = m_pActiveDevData->vDriverTrees.size();
		for( PropTreeVector::size_type i=0; i<vSize; i++ )
		{
			if( m_pActiveDevData->vDriverTrees[i] &&
				( m_pActiveDevData->vDriverTrees[i]->GetChangedCounter() != m_vTreeProps[i].ChangedCounter )  )
			{
				m_vTreeProps[i].ChangedCounter = m_pActiveDevData->vDriverTrees[i]->Draw();
				boUpdate = true;
			}
		}
	}

	if( boUpdate )
	{
		m_pPropertyGrid->Refresh();
	}
}

