/*
 *=======================================================================================
 * Name        :cohemngr.cpp
 * Author      :VL                           Date :16/01/97
 * Description :
 *=======================================================================================
 * Modification -> Author : VL               Date : 26/05/97
 * Description : 
 *	-> Links have now a weigth to allow multiple link
 *	-> object linked are now CPA_BaseObject
 *=======================================================================================
 */

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#include "stdafx.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#ifdef ACTIVE_EDITOR
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#include "itf/CMDlg.h"
#include "itf/CoheMngr.hpp"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

/*
 =======================================================================================
	Globals
 =======================================================================================
 */
CCoherenceManager g_oCoherenceManager;


/*
 =======================================================================================
	coherence manager class function
 =======================================================================================
 */

/*
 ----------------------------------------------------------------------------------------
   Description : constructor
 ----------------------------------------------------------------------------------------
 */
CCoherenceManager::CCoherenceManager()
{
	m_oChildMap.InitHashTable( 521 );
	m_oFatherMap.InitHashTable( 521 );
	m_oDeletedChildMap.InitHashTable( 521 );
	m_oIncoherenceMap.InitHashTable( 521 );
	// dialog box initialization
	m_p_oCMDlg = new (CCoherenceManagerDlg);
	m_p_oCMDlg->m_fn_vSetIncoherenceMap( &m_oIncoherenceMap );
	m_p_oCMDlg->m_fn_vSetFatherMap( &m_oFatherMap );
	m_p_oCMDlg->m_fn_vSetChildMap( &m_oChildMap );
	m_p_oCMDlg->m_fn_vSetDeletedChildMap( &m_oDeletedChildMap );
	
	m_bShowAlwaysDlg = FALSE;
}

/*
 ----------------------------------------------------------------------------------------
   Description : destructor
 ----------------------------------------------------------------------------------------
 */
CCoherenceManager::~CCoherenceManager()
{
	m_fn_vRemoveAllChild( &m_oChildMap );
	m_fn_vRemoveAllChild( &m_oDeletedChildMap );
	m_fn_vRemoveAllFather( &m_oFatherMap );
	m_fn_vRemoveAllFather( &m_oIncoherenceMap );
	delete (m_p_oCMDlg);

}


/*
 =======================================================================================
 private function : 
	Find functions
	Delete functions
 =======================================================================================
 */

/*
 ----------------------------------------------------------------------------------------
   Description : find if an object is in father map (should be father map or
 					incoherence map)
 ----------------------------------------------------------------------------------------
 */
tdstFather	*CCoherenceManager::m_fnp_stFindFather( CFatherMap *_p_oMap, CPA_BaseObject *_p_oFather )
{
	tdstFather *p_stFather;
	if (_p_oMap->Lookup( _p_oFather, p_stFather ))
		return p_stFather;
	return NULL;
}

/*
 ----------------------------------------------------------------------------------------
   Description : find if an object is in child map 
 ----------------------------------------------------------------------------------------
 */
tdstChild	*CCoherenceManager::m_fnp_stFindChild( CChildMap *_p_oMap, CPA_BaseObject *_p_oChild )
{
	tdstChild *p_stChild;
	if (_p_oMap->Lookup( _p_oChild, p_stChild ))
		return p_stChild;
	return NULL;
}

/*
 ----------------------------------------------------------------------------------------
   Description : find if an object is in a CFatherList
 ----------------------------------------------------------------------------------------
 */
tdstFather	*CCoherenceManager::m_fnp_stFindFather( CFatherList *_p_oList, CPA_BaseObject *_p_oFather )
{
	POSITION	xPos;
	tdstFather	*p_stFather;

	xPos = _p_oList->GetHeadPosition();
	while (xPos)
	{
		p_stFather = _p_oList->GetNext( xPos );
		if (p_stFather->m_p_oFather == _p_oFather)
			return p_stFather;
	}
	return NULL;
}

/*
 ----------------------------------------------------------------------------------------
   Description : find if an object is in a CChildList
 ----------------------------------------------------------------------------------------
 */

tdstChild	*CCoherenceManager::m_fnp_stFindChild( CChildList *_p_oList, CPA_BaseObject *_p_oChild )
{
	POSITION	xPos;
	tdstChild	*p_stChild;

	xPos = _p_oList->GetHeadPosition();
	while (xPos)
	{
		p_stChild = _p_oList->GetNext( xPos );
		if (p_stChild->m_p_oChild == _p_oChild )
			return p_stChild;
	}
	return NULL;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : find a child in a Linked child list
  _p_oList            -> list to search for
  _p_stChild          -> child to search
  Returns (tdstLinkedChild ) linked child found or NULL
 ----------------------------------------------------------------------------------------
 */
tdstLinkedChild *CCoherenceManager::m_fnp_stFindLinkedChild( CLinkedChildList *_p_oList, tdstChild *_p_stChild)
{
	POSITION		xPos;
	tdstLinkedChild	*p_stLinkedChild;

	xPos = _p_oList->GetHeadPosition();
	while (xPos)
	{
		p_stLinkedChild = _p_oList->GetNext( xPos );
		if (p_stLinkedChild->m_p_stChild == _p_stChild )
			return p_stLinkedChild;
	}
	return NULL;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : find a ReachableObject child in a Linked child list
  _p_oList            -> list to search for
  _p_oChild           -> child to search
  Returns (tdstLinkedChild ) linked child found or NULL
 ----------------------------------------------------------------------------------------
 */
tdstLinkedChild *CCoherenceManager::m_fnp_stFindLinkedChild( CLinkedChildList *_p_oList, CPA_BaseObject *_p_oChild)
{
	POSITION		xPos;
	tdstLinkedChild	*p_stLinkedChild;

	xPos = _p_oList->GetHeadPosition();
	while (xPos)
	{
		p_stLinkedChild = _p_oList->GetNext( xPos );
		if (p_stLinkedChild->m_p_stChild->m_p_oChild == _p_oChild )
			return p_stLinkedChild;
	}
	return NULL;
}

/*
 ----------------------------------------------------------------------------------------
   Description : say if a tdstFather struct is in a child's father list
 ----------------------------------------------------------------------------------------
 */

BOOL CCoherenceManager::m_fn_bIsFather( CFatherList *_p_oList, tdstFather *_p_stFather )
{
	return ( _p_oList->Find( _p_stFather ) != NULL );
}

/*
 ----------------------------------------------------------------------------------------
   Description : say if a tdstChild struct is in a father's child list
 ----------------------------------------------------------------------------------------
 */
BOOL CCoherenceManager::m_fn_bIsChild ( CChildList *_p_oList, tdstChild *_p_stChild )
{
	return ( _p_oList->Find( _p_stChild ) != NULL );
}

/*
 ----------------------------------------------------------------------------------------
   Description : say if a tdstChild struct is in a father's linked child list
 ----------------------------------------------------------------------------------------
 */
BOOL CCoherenceManager::m_fn_bIsChild ( CLinkedChildList *_p_oList, tdstChild *_p_stChild )
{
	return ( m_fnp_stFindLinkedChild( _p_oList, _p_stChild) != NULL );
}

/*
 ----------------------------------------------------------------------------------------
   Description : delete all Father in a father map
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vRemoveAllFather( CFatherMap *_p_oMap )
{
	POSITION			xPos;
	tdstFather			*p_stFather;
	CPA_BaseObject	*p_oObject;
	POSITION			xPosChild;
	tdstLinkedChild		*p_stLinkedChild;

	xPos = _p_oMap->GetStartPosition();
	while ( xPos )
	{
		_p_oMap->GetNextAssoc( xPos, p_oObject, p_stFather );
		// delete all tdstLinkedChild structure
		xPosChild = p_stFather->m_oChildList.GetHeadPosition();
		while (xPosChild)
		{
			p_stLinkedChild = p_stFather->m_oChildList.GetNext(xPosChild);
			delete p_stLinkedChild;
		}
		// emptied child list
		p_stFather->m_oChildList.RemoveAll();
		delete( p_stFather );
	}
	_p_oMap->RemoveAll();
}

/*
 ----------------------------------------------------------------------------------------
   Description : delete all child in a child map
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vRemoveAllChild( CChildMap *_p_oMap )
{
	POSITION		xPos;
	tdstChild		*p_stChild;
	CPA_BaseObject	*p_oObject;

	xPos = _p_oMap->GetStartPosition();
	while ( xPos )
	{
		_p_oMap->GetNextAssoc( xPos, p_oObject, p_stChild );
		p_stChild->m_oFatherList.RemoveAll();
		delete( p_stChild );
	}
	_p_oMap->RemoveAll();
}

/*
 ----------------------------------------------------------------------------------------
   Description : detach all child from his father
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vDetachAllChild( tdstFather *_p_stFather, CChildMap *_p_oChildMap )
{
	POSITION			xPos;
	POSITION			xFatherPos;
	tdstChild			*p_stChild;
	tdstLinkedChild		*p_stLinkedChild;

	// for each child
	xPos = _p_stFather->m_oChildList.GetHeadPosition();
	while (xPos)
	{
		//p_stChild = _p_stFather->m_oChildList.GetNext( xPos );
		p_stLinkedChild = _p_stFather->m_oChildList.GetNext( xPos );
		p_stChild = p_stLinkedChild->m_p_stChild;
		// find father position in list and delete it
		xFatherPos = p_stChild->m_oFatherList.Find( _p_stFather );
		p_stChild->m_oFatherList.RemoveAt( xFatherPos );
		// if no more links, delete object from child list
		if (p_stChild->m_oFatherList.IsEmpty())
		{
			_p_oChildMap->RemoveKey( p_stChild->m_p_oChild );
			delete( p_stChild );
		}
	}
	// no more child for this father
	_p_stFather->m_oChildList.RemoveAll();
}

/*
 ----------------------------------------------------------------------------------------
   Description : detach all father of this object (in reality transfert links
 				in DeletedChildMap and Incoherence Map )
   return TRUE if father was really Detached
 ----------------------------------------------------------------------------------------
 */
BOOL CCoherenceManager::m_fn_bDetachAllFather( tdstChild *_p_stChild, char _cChildState )
{
	POSITION		xPos;
	POSITION		xChildPos;
	tdstFather		*p_stSourceFather;
	tdstFather		*p_stTargetFather;
	CFatherList		m_oTempList;
	CFatherMap		*p_oSourceMap = (_cChildState == C_cChildIsRestored)?&m_oIncoherenceMap:&m_oFatherMap;
	CFatherMap		*p_oTargetMap = (_cChildState == C_cChildIsRestored)?&m_oFatherMap:&m_oIncoherenceMap;
	tdstLinkedChild	*p_stLinkedChild;

	BOOL			bResult;
	BOOL			bCreated;
	BOOL			bAdd;

	xPos = _p_stChild->m_oFatherList.GetHeadPosition();
	
	while ( xPos )
	{
		// for each father in child list
		p_stSourceFather = _p_stChild->m_oFatherList.GetNext( xPos );
		
		// look if this father is not in target map
		if ( !p_oTargetMap->Lookup( p_stSourceFather->m_p_oFather, p_stTargetFather ) )
		{
			// create a new father to put in target list
			p_stTargetFather = new(tdstFather);
			p_stTargetFather->m_p_oFather = p_stSourceFather->m_p_oFather;
			(*p_oTargetMap)[ p_stSourceFather->m_p_oFather ] = p_stTargetFather;
			bCreated = TRUE;
		}
		else
		{
			bCreated = FALSE;
		}
		bAdd = TRUE;

		// find child in source father
		p_stLinkedChild = m_fnp_stFindLinkedChild( &p_stSourceFather->m_oChildList, _p_stChild );

		// delete child in source father child list
		xChildPos = p_stSourceFather->m_oChildList.Find( p_stLinkedChild );
		p_stSourceFather->m_oChildList.RemoveAt( xChildPos );

		// remove source father if it's empty
		if (p_stSourceFather->m_oChildList.IsEmpty() && p_stSourceFather->m_oDestroyedChildList.IsEmpty() )
		{
			p_oSourceMap->RemoveKey( p_stSourceFather->m_p_oFather );
			delete(p_stSourceFather);
		}


		// transfert child to target father
		if (_cChildState == C_cChildIsRestored)
		{
			//p_stTargetFather->m_oChildList.AddTail( _p_stChild );
			p_stTargetFather->m_oChildList.AddTail( p_stLinkedChild );
			p_stTargetFather->m_p_oFather->GetEditor()->fn_vOnRestoreLink( p_stTargetFather->m_p_oFather, _p_stChild->m_p_oChild);
		}
		else
		{
			if (_cChildState == C_cChildIsDeleted)
			{
				//p_stTargetFather->m_oChildList.AddTail( _p_stChild );
				p_stTargetFather->m_oChildList.AddTail( p_stLinkedChild );
			}
			else
			{
				char *szName = (char *) malloc ( strlen( _p_stChild->m_p_oChild->GetName() ) + 1 );
				strcpy ( szName, _p_stChild->m_p_oChild->GetName() );
				p_stTargetFather->m_oDestroyedChildList.AddHead( szName );
			}

			if (p_stTargetFather->m_p_oFather->GetEditor()->fn_bOnInvalidateLink(p_stTargetFather->m_p_oFather, _p_stChild->m_p_oChild, (_cChildState == C_cChildIsDestroyed)))
			{
				if (_cChildState == C_cChildIsDeleted)
					p_stTargetFather->m_oChildList.RemoveTail();
				else
					p_stTargetFather->m_oDestroyedChildList.RemoveTail();

				if (bCreated)
				{
					delete p_stTargetFather;
					p_oTargetMap->RemoveKey( p_stTargetFather->m_p_oFather );
					bAdd = FALSE;
				}
			}
		}

		if (bAdd)
			m_oTempList.AddTail( p_stTargetFather );
	}
	_p_stChild->m_oFatherList.RemoveAll();
	_p_stChild->m_oFatherList.AddHead( &m_oTempList );
	
	bResult = !m_oTempList.IsEmpty();
	m_oTempList.RemoveAll();
	
	return bResult;
}

/*
 =======================================================================================
	public function 
 =======================================================================================
 */

/*
 ----------------------------------------------------------------------------------------
   Description : return true if given object is in list of Incoherent object
 ----------------------------------------------------------------------------------------
 */
BOOL CCoherenceManager::m_fn_bIsIncoherent( CPA_BaseObject *_p_oFather )
{
	tdstFather *p_stFather;
	return m_oIncoherenceMap.Lookup( _p_oFather, p_stFather );
}

/*
 ----------------------------------------------------------------------------------------
   Description : return true if given object is in list of Father object
 ----------------------------------------------------------------------------------------
 */
BOOL CCoherenceManager::m_fn_bIsFather( CPA_BaseObject *_p_oFather )
{
	tdstFather *p_stFather;
	return m_oFatherMap.Lookup( _p_oFather, p_stFather );
}

/*
 ----------------------------------------------------------------------------------------
   Description : return true if given object is in list of Child object
 ----------------------------------------------------------------------------------------
 */
BOOL CCoherenceManager::m_fn_bIsChild( CPA_BaseObject *_p_oChild )
{
	tdstChild *p_stChild;
	return m_oChildMap.Lookup( _p_oChild, p_stChild );
}


/*
 ----------------------------------------------------------------------------------------
   Description : returns number of childs for this father
   
 ----------------------------------------------------------------------------------------
 */
int	CCoherenceManager::m_fn_iGetChildCount( CPA_BaseObject *_p_oFather )
{
	tdstFather		*p_stFather;

	if ( !m_oFatherMap.Lookup( _p_oFather, p_stFather ) )
		return 0;

	return p_stFather->m_oChildList.GetCount();
}
/*
 ----------------------------------------------------------------------------------------
   Description : add in given list all child of given father, 
   returns number of object added in list
 ----------------------------------------------------------------------------------------
 */
int	CCoherenceManager::m_fn_iGetChildList( CPA_BaseObject *_p_oFather, CList< CPA_BaseObject *, CPA_BaseObject *> *_p_oChildList )
{
	POSITION		xPos;
	tdstFather		*p_stFather;
	tdstLinkedChild	*p_stLinkedChild;

	if (!m_oFatherMap.Lookup( _p_oFather, p_stFather ))
		return 0;

	xPos = p_stFather->m_oChildList.GetHeadPosition();
	while (xPos)
	{
		p_stLinkedChild = p_stFather->m_oChildList.GetNext( xPos );
		_p_oChildList->AddTail( p_stLinkedChild->m_p_stChild->m_p_oChild );
	}
	return  p_stFather->m_oChildList.GetCount();
}

/*
 ----------------------------------------------------------------------------------------
   Description : add in given list the deleted child of given father.
   returns number of object added in list
 ----------------------------------------------------------------------------------------
 */
int CCoherenceManager::m_fn_iGetDeletedChildList( CPA_BaseObject *_p_oFather, CList< CPA_BaseObject *, CPA_BaseObject *> *_p_oDeletedChildList )
{
	POSITION		xPos;
	tdstFather		*p_stFather;
	tdstLinkedChild	*p_stLinkedChild;

	if (!m_oIncoherenceMap.Lookup( _p_oFather, p_stFather ))
		return 0;

	xPos = p_stFather->m_oChildList.GetHeadPosition();
	while (xPos)
	{
		p_stLinkedChild = p_stFather->m_oChildList.GetNext( xPos );
		_p_oDeletedChildList->AddTail( p_stLinkedChild->m_p_stChild->m_p_oChild );
	}
	return (p_stFather->m_oChildList.GetCount());
}

/*
 ----------------------------------------------------------------------------------------
   Description : add in given list the name of destroyed child of given father.
   returns number of object added in list
 ----------------------------------------------------------------------------------------
 */
int CCoherenceManager::m_fn_iGetDestroyedChildNameList( CPA_BaseObject *_p_oFather, CList< char *, char *> *_p_oDestroyedChildNameList )
{
	tdstFather	*p_stFather;

	if (!m_oIncoherenceMap.Lookup( _p_oFather, p_stFather ))
		return 0;

	_p_oDestroyedChildNameList->AddTail( &p_stFather->m_oDestroyedChildList );
	return (p_stFather->m_oChildList.GetCount());
}

/*
 ----------------------------------------------------------------------------------------
   Description : returns number of fathers for the child
 ----------------------------------------------------------------------------------------
 */
int CCoherenceManager::m_fn_iGetFatherCount( CPA_BaseObject *_p_oChild )
{
	tdstChild	*p_stChild;

	if (!m_oChildMap.Lookup( _p_oChild, p_stChild ))
		return 0;

	return p_stChild->m_oFatherList.GetCount();
}

/*
 ----------------------------------------------------------------------------------------
   Description : add in given list the father of given child object
   returns number of object added in list
 ----------------------------------------------------------------------------------------
 */
int CCoherenceManager::m_fn_iGetFatherList( CPA_BaseObject *_p_oChild, CList< CPA_BaseObject *, CPA_BaseObject *> *_p_oFatherList )
{
	POSITION	xPos;
	tdstChild	*p_stChild;
	tdstFather	*p_stFather;

	if (!m_oChildMap.Lookup( _p_oChild, p_stChild ))
		return 0;

	xPos = p_stChild->m_oFatherList.GetHeadPosition();
	while (xPos)
	{
		p_stFather = p_stChild->m_oFatherList.GetNext( xPos );
		_p_oFatherList->AddTail( p_stFather->m_p_oFather );
	}
	return (p_stChild->m_oFatherList.GetCount());
}

/*
 ----------------------------------------------------------------------------------------
  Description : add in given list the invalid father of given child object
  returns number of object added in list
 ----------------------------------------------------------------------------------------
 */
int CCoherenceManager::m_fn_iGetInvalidFatherList( CPA_BaseObject *_p_oChild, CList< CPA_BaseObject *, CPA_BaseObject *> *_p_oInvalidFatherList )
{
	POSITION	xPos;
	tdstChild	*p_stChild;
	tdstFather	*p_stFather;

	if (!m_oDeletedChildMap.Lookup( _p_oChild, p_stChild ))
		return 0;

	xPos = p_stChild->m_oFatherList.GetHeadPosition();
	while (xPos)
	{
		p_stFather = p_stChild->m_oFatherList.GetNext( xPos );
		_p_oInvalidFatherList->AddTail( p_stFather->m_p_oFather );
	}
	return (p_stChild->m_oFatherList.GetCount());
}


/*
 ----------------------------------------------------------------------------------------
   Description : dump list in a file
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vDumpListsInFile( char *_szFile )
{
	FILE					*hpFile;
	POSITION				xPos;
	POSITION				xPosList;
	CPA_BaseObject		*p_oObject;
	tdstFather				*p_stFather;
	tdstChild				*p_stChild;
	tdstLinkedChild			*p_stLinkedChild;
	char					*szName;

	if ( (hpFile = fopen( _szFile, "at")) == NULL)
		return;

	fprintf( hpFile, "*******************************\n");
	fprintf( hpFile, "******* Dumping Lists *********\n");
	fprintf( hpFile, "*******************************\n");
	// display Child map
	fprintf( hpFile, "**** Dumping Child list *******\n");
	xPos = m_oChildMap.GetStartPosition();
	while ( xPos )
	{
		m_oChildMap.GetNextAssoc( xPos, p_oObject, p_stChild );
		fprintf(hpFile, "Child : %s\n", p_oObject->GetName() );
		xPosList = p_stChild->m_oFatherList.GetHeadPosition();
		while (xPosList)
		{
			p_stFather = p_stChild->m_oFatherList.GetNext( xPosList );
			fprintf(hpFile, "    %s\n", p_stFather->m_p_oFather->GetName() );
		}
	}
	// display Father map
	fprintf( hpFile, "**** Dumping Father list *******\n");
	xPos = m_oFatherMap.GetStartPosition();
	while ( xPos )
	{
		m_oFatherMap.GetNextAssoc( xPos, p_oObject, p_stFather );
		fprintf(hpFile, "Father : %s (%X)\n", p_oObject->GetName() , p_oObject->GetEditor()->GetCurrentEditorName() );
		xPosList = p_stFather->m_oChildList.GetHeadPosition();
		while (xPosList)
		{
			p_stLinkedChild = p_stFather->m_oChildList.GetNext( xPosList );
			fprintf(hpFile, "    %s\n", p_stLinkedChild->m_p_stChild->m_p_oChild->GetName() );
		}
	}
	// display deleted Child map
	fprintf( hpFile, "**** Dumping Deleted Child list *******\n");
	xPos = m_oDeletedChildMap.GetStartPosition();
	while ( xPos )
	{
		m_oDeletedChildMap.GetNextAssoc( xPos, p_oObject, p_stChild );
		fprintf(hpFile, "Child : %s\n", p_oObject->GetName() );
		xPosList = p_stChild->m_oFatherList.GetHeadPosition();
		while (xPosList)
		{
			p_stFather = p_stChild->m_oFatherList.GetNext( xPosList );
			fprintf(hpFile, "    %s\n", p_stFather->m_p_oFather->GetName() );
		}
	}
	// display Incoherent map
	fprintf( hpFile, "**** Dumping Incoherence list *******\n");
	xPos = m_oIncoherenceMap.GetStartPosition();
	while ( xPos )
	{
		m_oIncoherenceMap.GetNextAssoc( xPos, p_oObject, p_stFather );
		fprintf(hpFile, "Father : %s (%X)\n", p_oObject->GetName() , p_oObject->GetEditor()->GetCurrentEditorName() );
		xPosList = p_stFather->m_oChildList.GetHeadPosition();
		while (xPosList)
		{
			p_stLinkedChild = p_stFather->m_oChildList.GetNext( xPosList );
			fprintf(hpFile, "    %s\n", p_stLinkedChild->m_p_stChild->m_p_oChild->GetName());
		}

		// write destroyed child
		xPosList = p_stFather->m_oDestroyedChildList.GetHeadPosition();
		while (xPosList)
		{
			szName = p_stFather->m_oDestroyedChildList.GetNext( xPosList );
			fprintf(hpFile, "    %s (d)", szName );
		}
	}

	fclose(hpFile);
}

/*
 ----------------------------------------------------------------------------------------
   Description : Add a link in list
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vAddALink( CPA_BaseObject *_p_oFather, CPA_BaseObject *_p_oChild )
{
	tdstFather		*p_stFather = m_fnp_stFindFather( &m_oFatherMap, _p_oFather );
	tdstChild		*p_stChild  = m_fnp_stFindChild ( &m_oChildMap,  _p_oChild );
	tdstLinkedChild	*p_stLinkedChild;
	BOOL			bFatherExist = (p_stFather != NULL);
	BOOL			bChildExist = (p_stChild != NULL );

	// verify or create father structure
	if (!bFatherExist)
	{
		p_stFather = new(tdstFather);
		p_stFather->m_p_oFather = _p_oFather;
		m_oFatherMap[ _p_oFather ] = p_stFather;
	}

	// create child struct if child doesn't exist
	if(!bChildExist)
	{
		p_stChild = new(tdstChild);
		p_stChild->m_p_oChild = _p_oChild;
		m_oChildMap[ _p_oChild ] = p_stChild;
	}

	// add link in Father map
	p_stLinkedChild = m_fnp_stFindLinkedChild( &p_stFather->m_oChildList, p_stChild );
	if (p_stLinkedChild != NULL)
	{
		p_stLinkedChild->m_ulLinkWeight++;
	}
	else
	{
		p_stLinkedChild = new tdstLinkedChild;
		p_stLinkedChild->m_p_stChild = p_stChild;
		p_stLinkedChild->m_ulLinkWeight = 1;
		p_stFather->m_oChildList.AddTail( p_stLinkedChild );
		p_stChild->m_oFatherList.AddTail( p_stFather );
	}
}

/*
 ----------------------------------------------------------------------------------------
   Description : remove a given number of link
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vRemoveLinks( CPA_BaseObject *_p_oFather, CPA_BaseObject *_p_oChild, unsigned long _ulNbLinkRemoved )
{
	tdstChild		*p_stChild;
	tdstLinkedChild	*p_stLinkedChild;
	tdstFather		*p_stFather;
	BOOL			bDeleted = FALSE;
	POSITION		xPos;

	// search child in valid child list
	if ( (p_stChild = m_fnp_stFindChild( &m_oChildMap, _p_oChild )) == NULL)
	{
		// search child in deleted child list
		if ( (p_stChild = m_fnp_stFindChild( &m_oDeletedChildMap, _p_oChild )) == NULL)
			return;
		else
		{
			// child is a deleted child, find father in incoherence map
			p_stFather = m_fnp_stFindFather( &m_oIncoherenceMap, _p_oFather );
			bDeleted = TRUE;
		}
	}
	else
	{
		// child is valid, find father in valid father map
		p_stFather = m_fnp_stFindFather( &m_oFatherMap, _p_oFather );
	}

	if (p_stFather == NULL)
		return; // no link found

	// search in father the linked child
	if ( (p_stLinkedChild = m_fnp_stFindLinkedChild( &p_stFather->m_oChildList, p_stChild)) == NULL)
		return;

	// remove a link
	if (_ulNbLinkRemoved == 0)
		p_stLinkedChild->m_ulLinkWeight = 0;
	else
		p_stLinkedChild->m_ulLinkWeight -= _ulNbLinkRemoved;

	if (p_stLinkedChild->m_ulLinkWeight <= 0)
	{
		// no more link between the two object, delete child from father list and father from child list
	
		// delete father in child list
		xPos = p_stChild->m_oFatherList.Find( p_stFather );
		if (xPos)
		{
			p_stChild->m_oFatherList.RemoveAt( xPos );
			if (p_stChild->m_oFatherList.IsEmpty())
			{
				if (bDeleted)
					m_oDeletedChildMap.RemoveKey( _p_oChild );
				else
					m_oChildMap.RemoveKey( _p_oChild );
			}
		}
	
		// delete child in father list
		xPos = p_stFather->m_oChildList.Find( p_stLinkedChild );
		if (xPos)
		{
			p_stFather->m_oChildList.RemoveAt( xPos );
			if (p_stFather->m_oChildList.IsEmpty() && p_stFather->m_oDestroyedChildList.IsEmpty() )
			{
				if (bDeleted)
					m_oIncoherenceMap.RemoveKey( _p_oFather );
				else
					m_oFatherMap.RemoveKey( _p_oFather );
			}
			delete p_stLinkedChild;
		}
	}
}

/*
 ----------------------------------------------------------------------------------------
   Description : remove a given number of link
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vRemoveALink( CPA_BaseObject *_p_oFather, CPA_BaseObject *_p_oChild )
{
	m_fn_vRemoveLinks( _p_oFather, _p_oChild, 1 );
}


/*
 ----------------------------------------------------------------------------------------
   Description : remove all links between two objects
   _p_oFather	-> father object of link to remove
   _p_oChild	-> child object of link to remove
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vRemoveAllLinks( CPA_BaseObject *_p_oFather, CPA_BaseObject *_p_oChild )
{
	m_fn_vRemoveLinks( _p_oFather, _p_oChild, 0 );
}

/*
 ----------------------------------------------------------------------------------------
   Description : remove all that attach an object with another one
   _p_oObject	-> object to detach
   _cLinkType	-> possible value are
		C_cLinkedAsValidChild		-> remove all links were object is child 
		C_cLinkedAsDeletedChild		-> remove all links were object is deleted child
		C_cLinkedAsChild			-> remove all links were object is child (valid or deleted)
		C_cLinkedAsValidFather		-> remove all links were object is a valid father
		C_cLinkedAsIncoherentFather	-> remove all links were object is a incoherent father
		C_cLinkedAsFather			-> remove all links were object is father (valid or incoherent)
		C_cLinkedAsChildAndFather	-> remove all links
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vRemoveAllLinks( CPA_BaseObject *_p_oObject, char _cLinkType )
{
	POSITION		xPos;
	tdstChild		*p_stChild;
	tdstFather		*p_stFather;
	tdstLinkedChild	*p_stLinkedChild;

	/* 
	 * delete links were object is a child
	 */
	if (_cLinkType & C_cLinkedAsValidChild)
	{
		if ( (p_stChild = m_fnp_stFindChild( &m_oChildMap, _p_oObject )) != NULL)
		{
			xPos = p_stChild->m_oFatherList.GetHeadPosition();
			while (xPos)
			{
				p_stFather = p_stChild->m_oFatherList.GetNext( xPos );
				m_fn_vRemoveAllLinks( p_stFather->m_p_oFather, _p_oObject );
			}
		}
	}
	/* 
	 * delete links were object is a deleted child
	 */
	if (_cLinkType & C_cLinkedAsDeletedChild)
	{
		if ( (p_stChild = m_fnp_stFindChild( &m_oDeletedChildMap, _p_oObject )) != NULL)
		{
			xPos = p_stChild->m_oFatherList.GetHeadPosition();
			while (xPos)
			{
				p_stFather = p_stChild->m_oFatherList.GetNext( xPos );
				m_fn_vRemoveAllLinks( p_stFather->m_p_oFather, _p_oObject );
			}
		}
	}
	/* 
	 * delete links were object is a father
	 */
	if (_cLinkType & C_cLinkedAsValidFather)
	{
		if ( (p_stFather = m_fnp_stFindFather( &m_oFatherMap, _p_oObject )) != NULL)
		{
			xPos = p_stFather->m_oChildList.GetHeadPosition();
			while (xPos)
			{
				p_stLinkedChild = p_stFather->m_oChildList.GetNext( xPos );
				m_fn_vRemoveAllLinks( _p_oObject, p_stLinkedChild->m_p_stChild->m_p_oChild);
			}
		}
	}
	/* 
	 * delete links were object is an incoherent father
	 */
	if (_cLinkType & C_cLinkedAsIncoherentFather)
	{
		if ( (p_stFather = m_fnp_stFindFather( &m_oIncoherenceMap, _p_oObject )) != NULL)
		{
			xPos = p_stFather->m_oChildList.GetHeadPosition();
			while (xPos)
			{
				p_stLinkedChild = p_stFather->m_oChildList.GetNext( xPos );
				m_fn_vRemoveAllLinks( _p_oObject, p_stLinkedChild->m_p_stChild->m_p_oChild);
			}
		}
	}
}

/*
 ----------------------------------------------------------------------------------------
   Description : return number of links between two object
 ----------------------------------------------------------------------------------------
 */
unsigned long CCoherenceManager::m_fn_ulGetLinkWeight( CPA_BaseObject *_p_oFather, CPA_BaseObject *_p_oChild)
{
	tdstFather		*p_stFather = m_fnp_stFindFather( &m_oFatherMap, _p_oFather );
	tdstLinkedChild *p_stLinkedChild;

	if (p_stFather == NULL)
		return 0;

	if ( (p_stLinkedChild = m_fnp_stFindLinkedChild( &p_stFather->m_oChildList, _p_oChild)) == NULL)
		return 0;

	return p_stLinkedChild->m_ulLinkWeight;

}

/*
 ----------------------------------------------------------------------------------------
   Description : Delete an object
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vDeleteObject( CPA_BaseObject *_p_oObject )
{
	tdstFather	*p_stFather;
	tdstChild	*p_stChild;
	
	// first: erase all link between this object as father and his child
	if ( (p_stFather = m_fnp_stFindFather( &m_oFatherMap, _p_oObject )) != NULL)
	{
		m_fn_vDetachAllChild( p_stFather, &m_oChildMap );
		m_oFatherMap.RemoveKey( _p_oObject );
		delete( p_stFather );
	}
	// second : Erase all incoherence with this object
	if ( (p_stFather = m_fnp_stFindFather( &m_oIncoherenceMap, _p_oObject )) != NULL)
	{
		m_fn_vDetachAllChild( p_stFather, &m_oDeletedChildMap );
		m_oIncoherenceMap.RemoveKey( _p_oObject );
		delete(p_stFather);
	}
	// third : put all parent of this object in incoherent list
	if ( (p_stChild = m_fnp_stFindChild (&m_oChildMap, _p_oObject)) != NULL)
	{
		BOOL bIncoherence;
		bIncoherence = m_fn_bDetachAllFather( p_stChild, C_cChildIsDeleted );
		m_oChildMap.RemoveKey( _p_oObject );
		m_oDeletedChildMap[_p_oObject] = p_stChild;
		if (bIncoherence && m_bShowAlwaysDlg)
			m_fn_vShowIncoherence();
	}
}

/*
 ----------------------------------------------------------------------------------------
   Description : Restore an object
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vRestoreObject( CPA_BaseObject *_p_oObject )
{
	tdstChild *p_stChild;

	if ( (p_stChild = m_fnp_stFindChild (&m_oDeletedChildMap, _p_oObject)) != NULL)
	{
		m_fn_bDetachAllFather( p_stChild, C_cChildIsRestored);
		m_oDeletedChildMap.RemoveKey( _p_oObject );
		m_oChildMap[_p_oObject] = p_stChild;
	}
}

/*
 ----------------------------------------------------------------------------------------
   Description : Destroy an object
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vDestroyObject( CPA_BaseObject *_p_oObject )
{
	tdstFather	*p_stFather;
	tdstChild	*p_stChild;
	
	// first: erase all link between this object as father and his child
	if ( (p_stFather = m_fnp_stFindFather( &m_oFatherMap, _p_oObject )) != NULL)
	{
		m_fn_vDetachAllChild( p_stFather, &m_oChildMap );
		m_oFatherMap.RemoveKey( _p_oObject );
		delete( p_stFather );
	}
	// second : Erase all incoherence with this object
	if ( (p_stFather = m_fnp_stFindFather( &m_oIncoherenceMap, _p_oObject )) != NULL)
	{
		m_fn_vDetachAllChild( p_stFather, &m_oDeletedChildMap );
		m_oIncoherenceMap.RemoveKey( _p_oObject );
		delete(p_stFather);
	}
	// third : put all parent of this object in incoherent list
	if ( (p_stChild = m_fnp_stFindChild (&m_oChildMap, _p_oObject)) != NULL)
	{
		BOOL bIncoherence;
		bIncoherence = m_fn_bDetachAllFather( p_stChild, C_cChildIsDestroyed );
		m_oChildMap.RemoveKey( _p_oObject );
		if (bIncoherence && m_bShowAlwaysDlg)
			m_fn_vShowIncoherence();
	}
}

/*
 ----------------------------------------------------------------------------------------
   Description : Modify an object ( notify all father )
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vNotifyObjectModification( CPA_BaseObject *_p_oObject, unsigned long _ulData )
{
	tdstChild	*p_stChild;
	tdstFather	*p_stFather;
	POSITION	xPos;

	if ( (p_stChild = m_fnp_stFindChild( &m_oChildMap, _p_oObject )) != NULL)
	{
		xPos = p_stChild->m_oFatherList.GetHeadPosition();
		while (xPos)
		{
			p_stFather = p_stChild->m_oFatherList.GetNext( xPos );
			if ( (p_stFather != NULL) && (p_stFather->m_p_oFather != NULL) )
			{
				p_stFather->m_p_oFather->GetEditor()->fn_vOnModifyChild( p_stFather->m_p_oFather, _p_oObject, _ulData );
			}
		}

	}
}

/*
 ----------------------------------------------------------------------------------------
   Description : Show all incoherence in a dialog box
 ----------------------------------------------------------------------------------------
 */
void CCoherenceManager::m_fn_vShowIncoherence( void )
{
	m_p_oCMDlg->DoModal();
}

#endif // ACTIVE_EDITOR 