//-----------------------------------------------------------------------------
// Purpose: Links to any matching Source entities
//-----------------------------------------------------------------------------
void CEntityConnection::LinkSourceEntities()
{
	// Empty out the existing entity list
	m_pSourceEntityList->RemoveAll();

	// Get a list of all the entities in the world
	CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();

	if (pDoc)
	{
		CMapWorld *pWorld = pDoc->GetMapWorld();

		if (pWorld)
		{
			CMapEntityList matches;
			pWorld->FindEntitiesByName( matches, m_szSourceEntity, false );
		
			for ( int i = 0; i < matches.Count(); i++ )
			{
				CMapEntity *pEntity = matches.Element( i );

				m_pSourceEntityList->AddToTail( pEntity );
				//pEntity->Connection_Add( this ); // This should already be true on creation, investigate need for this func
			}
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : pView - 
//			nFlags - 
//			point - 
// Output : Returns true if the message was handled, false if not.
//-----------------------------------------------------------------------------
bool CToolMaterial::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, CPoint point)
{
	CMapDoc *pDoc = pView->GetDocument();
	CMapWorld *pWorld = pDoc->GetMapWorld();

	if (nFlags & MK_CONTROL)
	{
		//
		// CONTROL is down, perform selection only.
		//
		pView->SelectAt(point, FALSE, true);
	}
	else
	{
		pView->SelectAt(point, TRUE, true);
	}

	return (true);
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : pView - 
//			nFlags - 
//			point - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Marker3D::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, CPoint point)
{
	CMapDoc *pDoc = pView->GetDocument();
	if (pDoc == NULL)
	{
		return true;
	}

	CMapWorld *pWorld = pDoc->GetMapWorld();

	m_bLButtonDown = true;

	pView->SetCapture();

	//
	// Convert to some odd coordinate space that the base tools code uses.
	//
  	CPoint ptScreen = point;
	ptScreen.x += pView->GetScrollPos(SB_HORZ);
	ptScreen.y += pView->GetScrollPos(SB_VERT);
	
	//
	// Convert point to world coords.
	//
	pView->ClientToWorld(point);

	Vector ptOrg = vec3_origin;
	ptOrg[axHorz] = point.x;
	ptOrg[axVert] = point.y;

	//
	// Snap starting position to grid.
	//
	if (!(GetAsyncKeyState(VK_MENU) & 0x8000))
	{
		pDoc->Snap(ptOrg);
	}

	StartNew(ptOrg);
	pView->SetUpdateFlag(CMapView2D::updTool);

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Causes all objects in the world to update any object dependencies (pointers)
//			that they might be holding. This is a static function.
//-----------------------------------------------------------------------------
void CMapClass::UpdateAllDependencies(CMapClass *pObject)
{
	//
	// Try to locate the world object.
	//
	CMapWorld *pWorld;
	if (pObject == NULL)
	{
		CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
		if ((pDoc == NULL) || (pDoc->IsLoading()))
		{
			return;
		}
		
		pWorld = pDoc->GetMapWorld();
	}
	else
	{
		pWorld = pObject->GetWorldObject(pObject);
	}

	if (pWorld == NULL)
	{
		return;
	}

	//
	// We found the world. Tell all its children to update their dependencies
	// because of the given object.
	//
	EnumChildrenPos_t pos;
	CMapClass *pChild = pWorld->GetFirstDescendent(pos);
	while (pChild != NULL)
	{
		pChild->UpdateDependencies(pWorld, pObject);
		pChild = pWorld->GetNextDescendent(pos);
	}
}
//-----------------------------------------------------------------------------
// Purpose: creates a new keyframe at the specified time
// Input  : time - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
CMapEntity *CMapAnimator::CreateNewKeyFrame( float time )
{
	// work out where we are in the animation
	CMapKeyFrame *key;
	CMapKeyFrame *pPrevKey;
	float partialTime = GetKeyFramesAtTime( time, key, pPrevKey );

	CMapEntity *pCurrentEnt = dynamic_cast<CMapEntity*>( key->Parent );

	// check to see if we're direction on a key frame
	Vector posOffset( 0, 0, 0 );
	if ( partialTime == 0 )
	{
		// create this new key frame slightly after the current one, and offset
		posOffset[0] = 64;
	}

	// get our orientation and position at this time
	Vector vOrigin;
	QAngle angles;
	Quaternion qAngles;
	GetAnimationAtTime( key, pPrevKey, partialTime, vOrigin, qAngles, m_iPositionInterpolator, m_iRotationInterpolator );
	QuaternionAngles( qAngles, angles );

	// create the new map entity
	CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
	CMapWorld *pWorld = pDoc->GetMapWorld();

	CMapEntity *pNewEntity = new CMapEntity;

	Vector newPos;
	VectorAdd( vOrigin, posOffset, newPos );
	pNewEntity->SetPlaceholder( TRUE );
	pNewEntity->SetOrigin( newPos );
	pNewEntity->SetClass( "keyframe_track" );

	char buf[128];
	sprintf( buf, "%f %f %f", angles[0], angles[1], angles[2] );
	pNewEntity->SetKeyValue( "angles", buf );

	// link it into the keyframe list

	// take over this existing next keyframe pointer
	const char *nextKeyName = pCurrentEnt->GetKeyValue( "NextKey" );
	if ( nextKeyName )
	{
		pNewEntity->SetKeyValue( "NextKey", nextKeyName );
	}
		
	// create a new unique name for this ent
	char newName[128];
	const char *oldName = pCurrentEnt->GetKeyValue( "targetname" );
	if ( !oldName || oldName[0] == 0 )
		oldName = "keyframe";

	CMapEntity::GenerateNewTargetname( oldName, newName, 127 );
	pNewEntity->SetKeyValue( "targetname", newName );

	// point the current entity at the newly created one
	pCurrentEnt->SetKeyValue( "NextKey", newName );

	// copy any relevant values
	const char *keyValue = pCurrentEnt->GetKeyValue( "parentname" );
	if ( keyValue )
		pNewEntity->SetKeyValue( "parentname", keyValue );

	keyValue = pCurrentEnt->GetKeyValue( "MoveSpeed" );
	if ( keyValue )
		pNewEntity->SetKeyValue( "MoveSpeed", keyValue );

	return(pNewEntity);
}
//-----------------------------------------------------------------------------
// Purpose: Handles left mouse button down events in the 2D view.
// Input  : Per CWnd::OnLButtonDown.
// Output : Returns true if the message was handled, false if not.
//-----------------------------------------------------------------------------
bool Clipper3D::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, CPoint point)
{
	CMapDoc *pDoc = pView->GetDocument();
	CMapWorld *pWorld = pDoc->GetMapWorld();

	m_ptLDownClient = point;
	m_bLButtonDown = true;

	pView->SetCapture();

	//
	// Convert to some odd coordinate space that the base tools code uses.
	//
  	CPoint ptScreen = point;
	ptScreen.x += pView->GetScrollPos(SB_HORZ);
	ptScreen.y += pView->GetScrollPos(SB_VERT);
	
	//
	// Convert point to world coords.
	//
	pView->ClientToWorld(point);

	Vector ptOrg( COORD_NOTINIT, COORD_NOTINIT, COORD_NOTINIT );
	ptOrg[axHorz] = point.x;
	ptOrg[axVert] = point.y;

	// getvisiblepoint fills in any coord that's still set to COORD_NOTINIT:
	pDoc->GetBestVisiblePoint(ptOrg);

	// snap starting position to grid
	if (!(GetAsyncKeyState(VK_MENU) & 0x8000))
	{
		pDoc->Snap(ptOrg);
	}
	
	BOOL bStarting = FALSE;

	// if the tool is not empty, and shift is not held down (to
	//  start a new camera), don't do anything.
	if(!IsEmpty())
	{
		if(!StartTranslation(ptScreen))
		{
			if (nFlags & MK_SHIFT)
			{
				SetEmpty();
				bStarting = TRUE;
			}
			else
			{
				goto _DoNothing;
			}
		}
	}
	else
	{
		bStarting = TRUE;
	}

	SetClipObjects(pDoc->Selection_GetList());

	if (bStarting)
	{
		StartNew(ptOrg);
		pView->SetUpdateFlag(CMapView2D::updTool);
	}

_DoNothing:

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pView - 
//			nFlags - 
//			point - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool Marker3D::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, CPoint point)
{
	ULONG ulFace;
	CMapClass *pObject = pView->NearestObjectAt(point, ulFace);
	if (pObject != NULL)
	{
		CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pObject);
		if (pSolid == NULL)
		{
			// Clicked on a point entity - do nothing.
			return true;
		}

		CMapDoc *pDoc = pView->GetDocument();

		//
		// Build a ray to trace against the face that they clicked on to
		// find the point of intersection.
		//			
		Vector Start;
		Vector End;
		pView->BuildRay(point, Start, End);

		Vector HitPos, HitNormal;
		CMapFace *pFace = pSolid->GetFace(ulFace);
		if (pFace->TraceLine(HitPos, HitNormal, Start, End))
		{
			if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingPrefab())
			{
				//
				// Prefab creation.
				//
				pDoc->Snap(HitPos);

				GetHistory()->MarkUndoPosition(pDoc->Selection_GetList(), "New Prefab");

				// Get prefab object
				CMapClass *pPrefabObject = GetMainWnd()->m_ObjectBar.BuildPrefabObjectAtPoint(HitPos);

				//
				// Add prefab to the world.
				//
				CMapWorld *pWorld = pDoc->GetMapWorld();
				pDoc->ExpandObjectKeywords(pPrefabObject, pWorld);
				pDoc->AddObjectToWorld(pPrefabObject);
				GetHistory()->KeepNew(pPrefabObject);

				//
				// Select the new object.
				//
				pDoc->SelectObject(pPrefabObject, CMapDoc::scClear | CMapDoc::scSelect | CMapDoc::scUpdateDisplay);

				//
				// Update world bounds.
				//
				UpdateBox ub;
				CMapObjectList ObjectList;
				ObjectList.AddTail(pPrefabObject);
				ub.Objects = &ObjectList;

				Vector mins;
				Vector maxs;
				pPrefabObject->GetRender2DBox(mins, maxs);
				ub.Box.SetBounds(mins, maxs);

				pDoc->UpdateAllViews(NULL, MAPVIEW_UPDATE_OBJECTS, &ub);
				
				pDoc->SetModifiedFlag();
			}
			else if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingEntity())
			{
				//
				// Entity creation.
				//
				GetHistory()->MarkUndoPosition(pDoc->Selection_GetList(), "New Entity");
				
				CMapEntity *pEntity = new CMapEntity;
				pEntity->SetPlaceholder(TRUE);
				pEntity->SetOrigin(HitPos);
				pEntity->SetClass(CObjectBar::GetDefaultEntityClass());
				
				//Align the entity on the plane properly
				//				pEntity->AlignOnPlane(HitPos, &pFace->plane, (pFace->plane.normal[2] > 0.0f) ? CMapEntity::ALIGN_BOTTOM : CMapEntity::ALIGN_TOP);
				pEntity->AlignOnPlane(HitPos, &pFace->plane, (HitNormal[2] > 0.0f) ? CMapEntity::ALIGN_BOTTOM : CMapEntity::ALIGN_TOP);
									
				CMapWorld *pWorld = pDoc->GetMapWorld();
				pDoc->AddObjectToWorld(pEntity);
				
				GetHistory()->KeepNew(pEntity);

				//
				// Select the new object.
				//
				pDoc->SelectObject(pEntity, CMapDoc::scClear | CMapDoc::scSelect | CMapDoc::scUpdateDisplay);
				
 				UpdateBox ub;
				CMapObjectList ObjectList;
				ObjectList.AddTail(pEntity);
				ub.Objects = &ObjectList;

				Vector mins;
				Vector maxs;
				pEntity->GetRender2DBox(mins, maxs);
				ub.Box.SetBounds(mins, maxs);

				pDoc->UpdateAllViews(NULL, MAPVIEW_UPDATE_OBJECTS, &ub);
			
				pDoc->SetModifiedFlag();
			}
		}
	}

	return true;
}