//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//===========================================================================//

#include "stdafx.h"
#include "hammer_mathlib.h"
#include "MainFrm.h"
#include "ObjectProperties.h" 
#include "Box3D.h"
#include "BSPFile.h"
#include "const.h"
#include "MapDefs.h"		// dvs: For COORD_NOTINIT
#include "MapEntity.h"
#include "MapInstance.h"
#include "Manifest.h"
#include "Render2D.h"
#include "Render3D.h"
#include "MapView2D.h"
#include "MapView3D.h"
#include "hammer.h"
#include "Texture.h"
#include "TextureSystem.h"
#include "materialsystem/imesh.h"
#include "Material.h"
#include "Options.h"
#include "camera.h"
#include "MapWorld.h"
#include "mapview.h"

// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>


IMPLEMENT_MAPCLASS(CMapInstance)

char CMapInstance::m_InstancePath[ MAX_PATH ] = "";


//-----------------------------------------------------------------------------
// Purpose: Factory function. Used for creating a CMapInstance.
// Input  : pHelperInfo - Pointer to helper info class which gives us information
//			about how to create the class.
//			pParent - the owning entity ( func_instance )
// Output : Returns a pointer to the class, NULL if an error occurs.
//-----------------------------------------------------------------------------
CMapClass *CMapInstance::Create( CHelperInfo *pHelperInfo, CMapEntity *pParent )
{
	char		FileName[ MAX_PATH ];
	const char	*FileNameKey = pParent->GetKeyValue( "file" );
	CMapDoc		*pDoc = CMapDoc::GetActiveMapDoc();

	if ( FileNameKey )
	{
		V_strcpy_safe( FileName, pParent->GetKeyValue( "file" ) );
	}
	else
	{
		FileName[ 0 ] = 0;
	}

	CMapInstance *pInstance = new CMapInstance( pDoc->GetPathName(), FileName );

	return pInstance;
}


//-----------------------------------------------------------------------------
// Purpose: this function will set a secondary lookup path for instances.
// Input  : pszInstancePath - the secondary lookup path
//-----------------------------------------------------------------------------
void CMapInstance::SetInstancePath( const char *pszInstancePath )
{
	strcpy( m_InstancePath, pszInstancePath );
	V_strlower( m_InstancePath );
	V_FixSlashes( m_InstancePath );
}


//-----------------------------------------------------------------------------
// Purpose: This function will attempt to find a full path given the base and relative names.
// Input  : pszBaseFileName - the base file that referenced this instance
//			pszInstanceFileName - the relative file name of this instance
// Output : Returns true if it was able to locate the file
//			pszOutFileName - the full path to the file name if located
//-----------------------------------------------------------------------------
bool CMapInstance::DeterminePath( const char *pszBaseFileName, const char *pszInstanceFileName, char *pszOutFileName )
{
	char		szInstanceFileNameFixed[ MAX_PATH ];
	const char *pszMapPath = "\\maps\\";

	strcpy( szInstanceFileNameFixed, pszInstanceFileName );
	V_SetExtension( szInstanceFileNameFixed, ".vmf", sizeof( szInstanceFileNameFixed ) );
	V_FixSlashes( szInstanceFileNameFixed );

	// first, try to find a relative location based upon the Base file name
	strcpy( pszOutFileName, pszBaseFileName );
	V_StripFilename( pszOutFileName );

	strcat( pszOutFileName, "\\" );
	strcat( pszOutFileName, szInstanceFileNameFixed );

	if ( g_pFullFileSystem->FileExists( pszOutFileName ) )
	{
		return true;
	}

	// second, try to find the master 'maps' directory and make it relative from that
	strcpy( pszOutFileName, pszBaseFileName );
	V_StripFilename( pszOutFileName );
	V_RemoveDotSlashes( pszOutFileName );
	V_FixDoubleSlashes( pszOutFileName );
	V_strlower( pszOutFileName );
	strcat( pszOutFileName, "\\" );

	char *pos = strstr( pszOutFileName, pszMapPath );
	if ( pos )
	{
		pos += strlen( pszMapPath );
		*pos = 0;
		strcat( pszOutFileName, szInstanceFileNameFixed );

		if ( g_pFullFileSystem->FileExists( pszOutFileName ) )
		{
			return true;
		}
	}

	if ( m_InstancePath[ 0 ] != 0 )
	{
		sprintf( szInstanceFileNameFixed, "%s%s", m_InstancePath, pszInstanceFileName );

		if ( g_pFullFileSystem->FileExists( szInstanceFileNameFixed, "GAME" ) )
		{
			char FullPath[ MAX_PATH ];
			g_pFullFileSystem->RelativePathToFullPath( szInstanceFileNameFixed, "GAME", FullPath, sizeof( FullPath ) );
			strcpy( pszOutFileName, FullPath );

			return true;
		}
	}

	pszOutFileName[ 0 ] = 0;

	return false;
}


//-----------------------------------------------------------------------------
// Purpose: Constructor.
//-----------------------------------------------------------------------------
CMapInstance::CMapInstance( void )
{
	Initialize();
}


//-----------------------------------------------------------------------------
// Purpose: Constructor.
// Input  : pszBaseFileName - the root path of where the instance will be loaded from.
//			pszInstanceFileName - the relative name of the instance to be loaded.
// Output : 
//-----------------------------------------------------------------------------
CMapInstance::CMapInstance( const char *pszBaseFileName, const char *pszInstanceFileName )
{
	Initialize();

	if ( pszInstanceFileName[ 0 ] && DeterminePath( pszBaseFileName, pszInstanceFileName, m_FileName ) )
	{
		bool	bSaveVisible = CHammer::IsNewDocumentVisible();
		CMapDoc	*activeDoc = CMapDoc::GetActiveMapDoc();

		CHammer::SetIsNewDocumentVisible( false );
		m_pInstancedMap = ( CMapDoc * )APP()->OpenDocumentFile( m_FileName );
		if ( m_pInstancedMap )
		{
			m_pInstancedMap->AddReference();
			m_pInstancedMap->Update();
		}

		CMapDoc::SetActiveMapDoc( activeDoc );
		CHammer::SetIsNewDocumentVisible( bSaveVisible );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CMapInstance::~CMapInstance(void)
{
	if ( m_pInstancedMap )
	{
		m_pInstancedMap->RemoveReference();
		m_pInstancedMap = NULL;
	}
}


GDIV_TYPE CMapInstance::GetFieldType( const char *pInstanceValue )
{
	CMapEntityList	entityList;
	GDinputvariable	TempVar;

	m_pInstancedMap->FindEntitiesByClassName( entityList, "func_instance_parms", false );
	if ( entityList.Count() != 1 )
	{
		return ivBadType;
	}

	CMapEntity *pInstanceParmsEntity = entityList.Element( 0 );

	const char *InstancePos = strchr( pInstanceValue, ' ' );
	if ( InstancePos == NULL )
	{
		return ivBadType;
	}
	int		len = InstancePos - pInstanceValue;

	for ( int i = pInstanceParmsEntity->GetFirstKeyValue(); i != pInstanceParmsEntity->GetInvalidKeyValue(); i = pInstanceParmsEntity->GetNextKeyValue( i ) )
	{
		LPCTSTR	pKey = pInstanceParmsEntity->GetKey( i );
		LPCTSTR	pValue = pInstanceParmsEntity->GetKeyValue( i );

		if ( strnicmp( pKey, "parm", strlen( "parm" ) ) == 0 )
		{
			const char *InstanceParmsPos = strchr( pValue, ' ' );
			if ( InstanceParmsPos == NULL )
			{
				continue;
			}

			if ( strnicmp( pInstanceValue, pValue, len ) == 0 )
			{
				return TempVar.GetTypeFromToken( InstanceParmsPos + 1 );
			}
		}
	}

	return ivBadType;
}


void CMapInstance::FindTargetNames( CUtlVector< const char * > &Names )
{
	CMapEntity *pEntity = dynamic_cast< CMapEntity * >( GetParent() );

	for ( int j = pEntity->GetFirstKeyValue(); j != pEntity->GetInvalidKeyValue(); j = pEntity->GetNextKeyValue( j ) )
	{
		LPCTSTR	pInstanceKey = pEntity->GetKey( j );
		LPCTSTR	pInstanceValue = pEntity->GetKeyValue( j );
		if ( strnicmp( pInstanceKey, "replace", strlen( "replace" ) ) == 0 )
		{
			GDIV_TYPE	FieldType = GetFieldType( pInstanceValue );

			if ( FieldType == ivTargetDest ||
				FieldType == ivTargetNameOrClass ||
				FieldType == ivTargetSrc )
			{
				const char *pszInstancePos = strchr( pInstanceValue, ' ' );

				if ( pszInstancePos )
				{
					pszInstancePos++;

					char	*temp = new char[ strlen( pszInstancePos ) + 1 ];
					strcpy( temp, pszInstancePos );

					Names.AddToTail( temp );
				}
			}
		}
	}

}


void CMapInstance::ReplaceTargetname( const char *szOldName, const char *szNewName )
{
	BaseClass::ReplaceTargetname( szOldName, szNewName );

	CMapEntity *pEntity = dynamic_cast< CMapEntity * >( GetParent() );

	for ( int j = pEntity->GetFirstKeyValue(); j != pEntity->GetInvalidKeyValue(); j = pEntity->GetNextKeyValue( j ) )
	{
		LPCTSTR	pInstanceKey = pEntity->GetKey( j );
		LPCTSTR	pInstanceValue = pEntity->GetKeyValue( j );
		if ( strnicmp( pInstanceKey, "replace", strlen( "replace" ) ) == 0 )
		{
			const char *InstancePos = strchr( pInstanceValue, ' ' );
			if ( InstancePos == NULL )
			{
				continue;
			}

			int	nLen = InstancePos - pInstanceValue;

			if ( strcmp( szOldName, InstancePos + 1 ) == 0 )
			{
				nLen++;

				char	*pszResult = ( char * )stackalloc( nLen + strlen( szNewName ) + 1 );

				strncpy( pszResult, pInstanceValue, nLen );
				strcpy( &pszResult[ nLen ], szNewName );

				pEntity->SetKeyValue( pInstanceKey, pszResult );
			}
		}
	}
}


//-----------------------------------------------------------------------------
// Purpose: This function is called when the owning entity's Key/Value pairs have
//			been updated.  This will attempt to load a new instance if the map has
//			been changed.
// Input  : none.
// Output : none.
//-----------------------------------------------------------------------------
bool CMapInstance::OnApply( void )
{
	CString	MapFileName;
	char	FileName[ MAX_PATH ];
	CMapDoc	*activeDoc = CMapDoc::GetActiveMapDoc();

	MapFileName = activeDoc->GetPathName();

	CMapEntity *ent = dynamic_cast< CMapEntity * >( GetParent() );
	if ( m_pInstancedMap )
	{
		m_pInstancedMap->RemoveReference();
	}
	if ( ent && ent->GetKeyValue( "file" ) )
	{
		DeterminePath( MapFileName, ent->GetKeyValue( "file" ), FileName );
		if ( strcmpi( FileName, m_FileName ) != 0 ) 
		{
			bool	bSaveVisible = CHammer::IsNewDocumentVisible();

			CHammer::SetIsNewDocumentVisible( false );
			strcpy( m_FileName, FileName );
			m_pInstancedMap = ( CMapDoc * )APP()->OpenDocumentFile( m_FileName );

			CHammer::SetIsNewDocumentVisible( bSaveVisible );
		}
	}
	else
	{
		m_pInstancedMap = NULL;
	}

	if ( m_pInstancedMap == NULL )
	{
		m_FileName[ 0 ] = 0;
	}
	else
	{
		m_pInstancedMap->AddReference();
		m_pInstancedMap->Update();
	}

	GetMainWnd()->pObjectProperties->MarkDataDirty();

	// loading this instance will bring it forward in the MDI - we want to show the original map though
	CMapDoc::ActivateMapDoc( activeDoc );

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: Calculates our bounding box based on instance map's dimensions.
// Input  : bFullUpdate - Whether we should recalculate our children's bounds.
// Output : none.
//-----------------------------------------------------------------------------
void CMapInstance::CalcBounds(BOOL bFullUpdate)
{
	CMapClass::CalcBounds(bFullUpdate);
	
	//
	// Build our bounds for frustum culling in the 3D view.
	//
	if ( m_pInstancedMap && GetParent() && m_pInstancedMap->GetMapWorld() )
	{
		Vector		vecMins, vecMaxs, vecExpandedMins, vecExpandedMaxs;
		matrix3x4_t	Instance3x4Matrix;

		CMapClass *pParent = GetParent();
		pParent->GetOrigin( m_Origin );
		AngleMatrix( m_Angles, m_Origin, Instance3x4Matrix );
		m_pInstancedMap->GetMapWorld()->CalcBounds( true );

#if 0
		m_pInstancedMap->GetMapWorld()->GetCullBox( vecMins, vecMaxs );
		TransformAABB( Instance3x4Matrix, vecMins, vecMaxs, vecExpandedMins, vecExpandedMaxs );
		m_CullBox.UpdateBounds( vecExpandedMins, vecExpandedMaxs );
#endif

		m_pInstancedMap->GetMapWorld()->GetBoundingBox( vecMins, vecMaxs );
		TransformAABB( Instance3x4Matrix, vecMins, vecMaxs, vecExpandedMins, vecExpandedMaxs );
		m_CullBox.UpdateBounds( vecExpandedMins, vecExpandedMaxs );
		m_BoundingBox.UpdateBounds( vecExpandedMins, vecExpandedMaxs );
		m_Render2DBox.UpdateBounds( vecExpandedMins, vecExpandedMaxs );
	}
	else
	{
		Vector		vecExpandedMins, vecExpandedMaxs;

		vecExpandedMins.Init( -32.0f, -32.0f, -32.0f );
		vecExpandedMins += m_Origin;
		vecExpandedMaxs.Init( 32.0f, 32.0f, 32.0f );
		vecExpandedMaxs += m_Origin;

		m_CullBox.UpdateBounds( vecExpandedMins, vecExpandedMaxs );
		m_BoundingBox.UpdateBounds( vecExpandedMins, vecExpandedMaxs );
		m_Render2DBox.UpdateBounds( vecExpandedMins, vecExpandedMaxs );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Will calculate the bounding box of the instance as a child has changed
// Input  : pChild - Pointer to the object that changed.
//-----------------------------------------------------------------------------
void CMapInstance::UpdateChild(CMapClass *pChild)
{
	CalcBounds( TRUE );
}


//-----------------------------------------------------------------------------
// Purpose: this function will attempt to find a child inside of the instance.  If the bool and matrix
//			are supplied, the localized matrix will be built.
// Input  : key - the key field to lookup
//			value - the value to find
// Output : returns the entity found 
//			bIsInInstance - optional parameter to indicate if the found entity is inside of an instance
//			InstanceMatrix - optional parameter to set the localized matrix of the instance stack
//-----------------------------------------------------------------------------
CMapEntity *CMapInstance::FindChildByKeyValue( const char* key, const char* value, bool *bIsInInstance, VMatrix *InstanceMatrix )
{
	if ( m_pInstancedMap && bIsInInstance )
	{
		CMapEntity *result = m_pInstancedMap->GetMapWorld()->FindChildByKeyValue( key, value );
		if ( result )
		{
			if ( ( *bIsInInstance ) == false )
			{
				*bIsInInstance = true;
				if ( InstanceMatrix )
				{
					InstanceMatrix->Identity();
				}
			}

			if ( InstanceMatrix )
			{
				VMatrix	LocalInstanceMatrix, Result;

				LocalInstanceMatrix.SetupMatrixOrgAngles( m_Origin, m_Angles );
				Result = ( *InstanceMatrix ) * LocalInstanceMatrix;
				*InstanceMatrix = Result;
			}
		}

		return result;
	}

	return NULL;
}


//-----------------------------------------------------------------------------
// Purpose: this function is called for when an instance has moved
//-----------------------------------------------------------------------------
void CMapInstance::InstanceMoved( void )
{
	if ( m_pInstancedMap )
	{
		m_pInstancedMap->InstanceMoved();
	}
}


//-----------------------------------------------------------------------------
// Purpose: Returns a copy of this object.
// Output : Pointer to the new object.
//-----------------------------------------------------------------------------
CMapClass *CMapInstance::Copy(bool bUpdateDependencies)
{
	CMapInstance *pCopy = new CMapInstance;

	if (pCopy != NULL)
	{
		pCopy->CopyFrom(this, bUpdateDependencies);
	}

	return(pCopy);
}


//-----------------------------------------------------------------------------
// Purpose: Turns this into a duplicate of the given object.
// Input  : pObject - Pointer to the object to copy from.
// Output : Returns a pointer to this object.
//-----------------------------------------------------------------------------
CMapClass *CMapInstance::CopyFrom(CMapClass *pObject, bool bUpdateDependencies)
{
	CMapInstance *pFrom = dynamic_cast<CMapInstance *>(pObject);
	Assert(pObject != NULL);

	if (pObject != NULL)
	{
		CMapClass::CopyFrom(pObject, bUpdateDependencies);

		m_Angles = pFrom->m_Angles;
		strcpy( m_FileName, pFrom->m_FileName );
		m_pInstancedMap = pFrom->m_pInstancedMap;
		if ( m_pInstancedMap )
		{
			m_pInstancedMap->AddReference();
			m_pInstancedMap->Update();
		}
	}

	return(this);
}


//-----------------------------------------------------------------------------
// Purpose: Set's the map instance's angles
// Input  : Angles - the angles to set to
//-----------------------------------------------------------------------------
void CMapInstance::GetAngles(QAngle &Angles)
{
	Angles = m_Angles;
}


//-----------------------------------------------------------------------------
// Purpose: Initialized the map instance
//-----------------------------------------------------------------------------
void CMapInstance::Initialize(void)
{
	m_Angles.Init();
	m_pInstancedMap = NULL;
	m_FileName[ 0 ] = 0;
	m_pManifestMap = NULL;
}


//-----------------------------------------------------------------------------
// Purpose: Sets the manifest that loaded this instance
// Input  : pManifestMap - the manifest
//-----------------------------------------------------------------------------
void CMapInstance::SetManifest( CManifestMap *pManifestMap )
{
	Initialize();

	m_pManifestMap = pManifestMap;
	m_pInstancedMap = m_pManifestMap->m_Map;
	strcpy( m_FileName, m_pManifestMap->m_AbsoluteMapFileName );
}


//-----------------------------------------------------------------------------
// Purpose: This will render the map instance into the 3d view.
// Input  : pRender - the 3d render
//-----------------------------------------------------------------------------
void CMapInstance::Render3D(CRender3D *pRender)
{
	if ( m_pInstancedMap )
	{
		pRender->RenderInstanceMapClass( this, m_pInstancedMap->GetMapWorld(), m_Origin, m_Angles );
	}
}


//-----------------------------------------------------------------------------
// Purpose: this function will display an instance map window.  it will also set the
//			views to the approx same camera position.
//-----------------------------------------------------------------------------
void CMapInstance::SwitchTo( void )
{
	if ( !m_pInstancedMap )
	{
		return;
	}

	CMapDoc		*pCurrentDoc = CMapDoc::GetActiveMapDoc();

	m_pInstancedMap->ShowWindow( true );

	CMapDoc::ActivateMapDoc( m_pInstancedMap );

	POSITION PositionCurrentView = pCurrentDoc->GetFirstViewPosition();
	POSITION PositionNewView = m_pInstancedMap->GetFirstViewPosition();

	while ( PositionCurrentView && PositionNewView )
	{
		CMapView	*pViewCurrent = dynamic_cast< CMapView * >( pCurrentDoc->GetNextView( PositionCurrentView ) );
		CMapView2D	*pViewCurrent2D = dynamic_cast< CMapView2D * >( pViewCurrent );
		CMapView3D	*pViewCurrent3D = dynamic_cast< CMapView3D * >( pViewCurrent );
		CMapView	*pViewNew = dynamic_cast< CMapView * >( m_pInstancedMap->GetNextView( PositionNewView ) );
		CMapView2D	*pViewNew2D = dynamic_cast< CMapView2D * >( pViewNew );
		CMapView3D	*pViewNew3D = dynamic_cast< CMapView3D * >( pViewNew );

		if ( ( !pViewCurrent2D || !pViewNew2D ) && ( !pViewCurrent3D || !pViewNew3D ) )
		{
			continue;
		}

		Vector			CameraVector;
		CCamera			*CurrentCamera;

		CurrentCamera = pViewCurrent->GetCamera();
		CurrentCamera->GetViewPoint( CameraVector );

		if ( pViewCurrent2D )
		{
			CameraVector = CameraVector - m_Origin;
			pViewNew2D->GetCamera()->SetViewPoint( CameraVector );
			pViewNew2D->GetCamera()->SetZoom( pViewCurrent2D->GetZoom() );
		}
		else
		{
			matrix3x4_t		Camera3x4Matrix, InstanceMatrix, InstanceInverseMatrix;
			matrix3x4_t		ResultMatrix;
			QAngle			InstanceAngles, CameraAngles;

			CameraAngles.Init( CurrentCamera->GetPitch(), CurrentCamera->GetYaw(), CurrentCamera->GetRoll() );

			InstanceAngles = m_Angles;
			InstanceAngles.x = 0;
			InstanceAngles.z = 0;
			AngleMatrix( InstanceAngles, m_Origin, InstanceMatrix );
			MatrixInvert( InstanceMatrix, InstanceInverseMatrix );
			AngleMatrix( CameraAngles, CameraVector, Camera3x4Matrix );

			MatrixMultiply( InstanceInverseMatrix, Camera3x4Matrix, ResultMatrix );
			MatrixPosition( ResultMatrix, CameraVector );

			MatrixMultiply( InstanceMatrix, Camera3x4Matrix, ResultMatrix );
			MatrixAngles( ResultMatrix, CameraAngles );

			pViewNew3D->GetCamera()->SetViewPoint( CameraVector );
			pViewNew3D->GetCamera()->SetPitch( CameraAngles.x );
			pViewNew3D->GetCamera()->SetYaw( CameraAngles.y );
//			pViewNew3D->GetCamera()->SetRoll( CameraAngles.z );			we probably don't want to set this!
		}
		pViewNew->UpdateView( MAPVIEW_OPTIONS_CHANGED );
	}
}


//-----------------------------------------------------------------------------
// Purpose: we do not want to serialize this
// Input  : &File - 
//			bRMF - 
// Output : int
//-----------------------------------------------------------------------------
int CMapInstance::SerializeRMF(std::fstream &File, BOOL bRMF)
{
	return(0);
}


//-----------------------------------------------------------------------------
// Purpose: we do not want to serialize this
// Input  : &File - 
//			bRMF - 
// Output : int
//-----------------------------------------------------------------------------
int CMapInstance::SerializeMAP(std::fstream &File, BOOL bRMF)
{
	return(0);
}


//-----------------------------------------------------------------------------
// Purpose: Canculate angles based upon the transform
// Input  : pTransBox - 
//-----------------------------------------------------------------------------
void CMapInstance::DoTransform(const VMatrix &matrix)
{
	CMapClass *pParent = GetParent();
	pParent->GetOrigin( m_Origin );

//	BaseClass::DoTransform(matrix);

	matrix3x4_t fCurrentMatrix,fMatrixNew;
	AngleMatrix(m_Angles, fCurrentMatrix);
	ConcatTransforms(matrix.As3x4(), fCurrentMatrix, fMatrixNew);
	MatrixAngles(fMatrixNew, m_Angles);

	CMapEntity *pEntity = dynamic_cast< CMapEntity * >( m_pParent );
	if (pEntity != NULL)
	{
		char szValue[ 80 ];
		sprintf( szValue, "%g %g %g", m_Angles[ 0 ], m_Angles[ 1 ], m_Angles[ 2 ] );
		pEntity->NotifyChildKeyChanged( this, "angles", szValue );
	}

	InstanceMoved();
}


//-----------------------------------------------------------------------------
// Purpose: Notifies that this object's parent entity has had a key value change.
// Input  : szKey - The key that changed.
//			szValue - The new value of the key.
//-----------------------------------------------------------------------------
void CMapInstance::OnParentKeyChanged(const char* szKey, const char* szValue)
{
	if (!stricmp(szKey, "angles"))
	{
		sscanf(szValue, "%f %f %f", &m_Angles[PITCH], &m_Angles[YAW], &m_Angles[ROLL]);
		PostUpdate(Notify_Changed);
	}
}


//-----------------------------------------------------------------------------
// Purpose: indicates that we should not render last
// Output : returns false.
//-----------------------------------------------------------------------------
bool CMapInstance::ShouldRenderLast(void)
{
	return( false );
}


//-----------------------------------------------------------------------------
// Purpose: This will render the map instance into the 2d view as well as a
//			bounding box.
// Input  : pRender - the 2d render
//-----------------------------------------------------------------------------
void CMapInstance::Render2D(CRender2D *pRender)
{
	CMapView2D *pView = ( CMapView2D * )pRender->GetView();

	if ( m_pInstancedMap )
	{
		pView->RenderInstance( this, m_pInstancedMap->GetMapWorld(), m_Origin, m_Angles );
	}

	if ( m_pManifestMap )
	{
		return;
	}

	Vector vecMins;
	Vector vecMaxs;
	GetRender2DBox(vecMins, vecMaxs);

	Vector2D pt,pt2;
	pRender->TransformPoint(pt, vecMins);
	pRender->TransformPoint(pt2, vecMaxs);

	if (!IsSelected())
	{
	    pRender->SetDrawColor( r, g, b );
		pRender->SetHandleColor( r, g, b );
	}
	else
	{
	    pRender->SetDrawColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
		pRender->SetHandleColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
	}

	// Draw the bounding box.
		
	pRender->DrawBox( vecMins, vecMaxs );

	//
	// Draw center handle.
	//

	if ( pRender->IsActiveView() )
	{
		int sizex = abs(pt.x - pt2.x)+1;
		int sizey = abs(pt.y - pt2.y)+1;

		// dont draw handle if object is too small
		if ( sizex > 6 && sizey > 6 )
		{
			pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_CROSS );
			pRender->DrawHandle( (vecMins+vecMaxs)/2 );
		}
	}
}


//-----------------------------------------------------------------------------
// Called by entity code to render sprites
//-----------------------------------------------------------------------------
void CMapInstance::RenderLogicalAt(CRender2D *pRender, const Vector2D &vecMins, const Vector2D &vecMaxs )
{
}


//-----------------------------------------------------------------------------
// Purpose: Returns if this instance is editable.  A pure instance is not editable.
//			If it is part of a manifest, it must be the primary map of the manifest
//			in order for it to be editable.
//-----------------------------------------------------------------------------
bool CMapInstance::IsEditable( void )
{
	if ( m_pManifestMap )
	{
		return m_pManifestMap->IsEditable();
	}

	return false;
}


//-----------------------------------------------------------------------------
// Purpose: this function checks to see if the instance is visible.
// Output : returns true if the instance is visible.
//-----------------------------------------------------------------------------
bool CMapInstance::IsInstanceVisible( void )
{
	if ( IsInstance() )
	{
		if ( CMapDoc::GetActiveMapDoc()  && CMapDoc::GetActiveMapDoc()->GetShowInstance() == INSTANCES_HIDE )
		{
			return false;
		}
	}
	else
	{
		if ( GetManifestMap()  && GetManifestMap()->m_bVisible == false )
		{
			return false;
		}
	}

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: this function will recalculate its bounds because map has changed
//-----------------------------------------------------------------------------
void CMapInstance::UpdateInstanceMap( void )
{
	CalcBounds();
}