//-----------------------------------------------------------------------------
// Purpose: Invokes the replace texture dialog.
//-----------------------------------------------------------------------------
void CTextureBrowser::OnReplace(void)
{
	CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
	if(!pDoc)
		return;

	CReplaceTexDlg dlg(pDoc->Selection_GetCount());

	dlg.m_strFind = m_cTextureWindow.szCurTexture;

	if(dlg.DoModal() != IDOK)
		return;
	
	// mark undo position
	GetHistory()->MarkUndoPosition(pDoc->Selection_GetList(), "Replace Textures");

	if(dlg.m_bMarkOnly)
	{
		pDoc->SelectObject(NULL, CMapDoc::scClear);	// clear selection first
	}

	pDoc->ReplaceTextures(dlg.m_strFind, dlg.m_strReplace,
		dlg.m_iSearchAll, dlg.m_iAction | (dlg.m_bMarkOnly ? 0x100 : 0),
		dlg.m_bHidden);

	//EndDialog(IDOK);

	if (m_bUsed)
	{
		SetUsed(TRUE);
	}
}
//-----------------------------------------------------------------------------
// Purpose: Called when they hit the Find, the Replace, or the Replace All button.
// Input  : uCmd - The ID of the button the user hit, IDC_FIND_NEXT or IDC_REPLACE.
// Output : Returns TRUE to indicate that the message was handled.
//-----------------------------------------------------------------------------
BOOL CSearchReplaceDlg::OnFindReplace(UINT uCmd)
{
	CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
	if (!pDoc)
	{
		return TRUE;
	}

	static FindObject_t FindObject;
	static CMapClass *pLastFound = NULL;
	static nReplaceCount = 0;

	bool bDone = false;

	do
	{
		CMapClass *pObject = NULL;

		if (m_bNewSearch)
		{
			//
			// New search. Fetch the data from the controls.
			//
			UpdateData();
			GetFindCriteria(FindObject, pDoc);

			//
			// We have to keep track of the last object in the iteration for replacement,
			// because replacement is done when me advance to the next object.
			//
			pLastFound = NULL;
			nReplaceCount = 0;

			pObject = FindFirstObject(FindObject);
		}
		else
		{
			pObject = FindNextObject(FindObject);
		}

		//
		// Replace All is undone as single operation. Mark the undo position the first time
		// we find a match during a Replace All.
		//
		if (m_bNewSearch && (uCmd == IDC_REPLACE_ALL) && pObject)
		{
			GetHistory()->MarkUndoPosition(pDoc->Selection_GetList(), "Replace Text");
		}

		//
		// If we have an object to do the replace on, do the replace.
		//
		if (pLastFound && ((uCmd == IDC_REPLACE) || (uCmd == IDC_REPLACE_ALL)))
		{
			if (uCmd == IDC_REPLACE)
			{
				// Allow for undo each time we do a Replace.
				GetHistory()->MarkUndoPosition(NULL, "Replace Text");
			}

			//
			// Do the replace on the last matching object we found. This lets the user see what
			// object will be modified before it is done.
			//
			GetHistory()->Keep(pLastFound);
			nReplaceCount += FindReplace((CMapEntity *)pLastFound, FindObject, m_strReplaceText);

			GetDlgItem(IDCANCEL)->SetWindowText("Close");
		}

		if (pObject)
		{
			//
			// We found an object that satisfies our search.
			//
			if ((uCmd == IDC_FIND_NEXT) || (uCmd == IDC_REPLACE))
			{
				//
				// Highlight the match.
				//
				pDoc->SelectObject(pObject, CMapDoc::scClear | CMapDoc::scSelect);
				pDoc->CenterSelection();
			}

			//
			// Stop after one match unless we are doing a Replace All.
			//
			if (uCmd != IDC_REPLACE_ALL)
			{
				bDone = true;
			}

			m_bNewSearch = false;
			pLastFound = pObject;
		}
		else
		{
			//
			// No more objects in the search set match our criteria.
			//
			if ((m_bNewSearch) || (uCmd != IDC_REPLACE_ALL))
			{
				CString str;
				str.Format("Finished searching for '%s'.", m_strFindText);
				MessageBox(str, "Find/Replace Text", MB_OK);

				// TODO: put the old selection back
			}
			else if (uCmd == IDC_REPLACE_ALL)
			{
				CString str;
				str.Format("Replaced %d occurrences of the string '%s' with '%s'.", nReplaceCount, m_strFindText, m_strReplaceText);
				MessageBox(str, "Find/Replace Text", MB_OK);
			}

			m_bNewSearch = true;
			bDone = true;
		}

	} while (!bDone);

	return TRUE;
}
//-----------------------------------------------------------------------------
// 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;
}