/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : LevelEdit                                                    *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Tools/LevelEdit/OverlapPage.cpp      $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 4/11/00 5:48p                                               $*
 *                                                                                             *
 *                    $Revision:: 3                                                           $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


#include "stdafx.h"
#include "leveledit.h"
#include "OverlapPage.h"
#include "nodemgr.h"
#include "node.h"
#include "coltest.h"
#include "icons.h"
#include "cameramgr.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// Local constants
/////////////////////////////////////////////////////////////////////////////
static const int TOOLBAR_HEIGHT		= 25;
static const int TOOLBAR_V_SPACING	= 5;
static const int TOOLBAR_V_BORDER	= TOOLBAR_V_SPACING * 2;
static const int TOOLBAR_H_SPACING	= 5;
static const int TOOLBAR_H_BORDER	= TOOLBAR_H_SPACING * 2;



/////////////////////////////////////////////////////////////////////////////
//
// OverlapPageClass
//
/////////////////////////////////////////////////////////////////////////////
OverlapPageClass::OverlapPageClass(CWnd* pParent /*=NULL*/)
	:	CDialog(OverlapPageClass::IDD, pParent),
		m_SoundsRoot (NULL),
		m_LightsRoot (NULL)
{
	//{{AFX_DATA_INIT(OverlapPageClass)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	Create (OverlapPageClass::IDD, pParent);
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// ~OverlapPageClass
//
/////////////////////////////////////////////////////////////////////////////
OverlapPageClass::~OverlapPageClass (void)
{
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// DoDataExchange
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::DoDataExchange (CDataExchange *pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(OverlapPageClass)
	DDX_Control(pDX, IDC_OVERLAP_TREE, m_TreeCtrl);
	//}}AFX_DATA_MAP
	return ;
}


BEGIN_MESSAGE_MAP(OverlapPageClass, CDialog)
	//{{AFX_MSG_MAP(OverlapPageClass)
	ON_NOTIFY(TVN_DELETEITEM, IDC_OVERLAP_TREE, OnDeleteitemOverlapTree)
	ON_WM_SIZE()
	ON_WM_DESTROY()
	ON_COMMAND(IDC_REFRESH, OnRefresh)
	ON_NOTIFY(NM_DBLCLK, IDC_OVERLAP_TREE, OnDblclkOverlapTree)
	ON_NOTIFY(TVN_ITEMEXPANDED, IDC_OVERLAP_TREE, OnItemexpandedOverlapTree)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()



/////////////////////////////////////////////////////////////////////////////
//
// OnSize
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnSize
(
	UINT	nType,
	int	cx,
	int	cy
) 
{	
	// Allow the base class to process this message
	CDialog::OnSize (nType, cx, cy);

	if (::IsWindow (m_TreeCtrl) && (cx > 0) && (cy > 0)) {

		// Get the bounding rectangle of the form window
		CRect parentrect;
		GetWindowRect (&parentrect);
		
		// Get the bounding rectangle of the toolbar
		CRect toolbar_rect;
		m_Toolbar.GetWindowRect (&toolbar_rect);
		ScreenToClient (&toolbar_rect);

		// Move the toolbar so it is in its correct position
		m_Toolbar.SetWindowPos (NULL,
										TOOLBAR_H_SPACING,
										(cy - TOOLBAR_V_SPACING) - toolbar_rect.Height (),
										cx - TOOLBAR_H_BORDER,
										toolbar_rect.Height (),
										SWP_NOZORDER);

		// Get the bounding rectnagle of the list ctrl
		RECT list_rect;
		m_TreeCtrl.GetWindowRect (&list_rect);
				
		CRect client_rect = list_rect;
		ScreenToClient (&client_rect);
		int list_height = ((cy - TOOLBAR_V_BORDER) - toolbar_rect.Height ()) - client_rect.top;

		// Resize the tab control to fill the entire contents of the client area
		m_TreeCtrl.SetWindowPos (	NULL,
											0,
											0,
											cx-((list_rect.left - parentrect.left) << 1),
											list_height,
											SWP_NOZORDER | SWP_NOMOVE);	
	}

	return ;	
}


/////////////////////////////////////////////////////////////////////////////
//
// OnDestroy
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnDestroy (void) 
{
	// Free the state image list we associated with the control
	CImageList *imagelist = m_TreeCtrl.GetImageList (TVSIL_STATE);
	m_TreeCtrl.SetImageList (NULL, TVSIL_STATE);
	SAFE_DELETE (imagelist);

	// Remove the main image list we associated with the control
	m_TreeCtrl.SetImageList (NULL, TVSIL_NORMAL);
	m_TreeCtrl.DeleteAllItems ();

	::RemoveProp (m_TreeCtrl, "TRANS_ACCS");
	::RemoveProp (m_hWnd, "TRANS_ACCS");

	// Allow the base class to process this message
	CDialog::OnDestroy ();
	return ;	
}


////////////////////////////////////////////////////////////////////////////
//
//  OnInitDialog
//
////////////////////////////////////////////////////////////////////////////
BOOL
OverlapPageClass::OnInitDialog (void)
{
	CDialog::OnInitDialog ();

	m_Toolbar.CreateEx (this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect(0, 0, 0, 0), 101);
	m_Toolbar.SetOwner (this);
	m_Toolbar.LoadToolBar (IDR_OVERLAP_TOOLBAR);
	m_Toolbar.SetBarStyle (m_Toolbar.GetBarStyle () | CBRS_TOOLTIPS | CBRS_FLYBY);

	//
	// Size the toolbar
	//
	CRect parentrect;
	GetWindowRect (&parentrect);
	m_Toolbar.SetWindowPos (NULL, 0, 0, parentrect.Width () - TOOLBAR_H_BORDER, TOOLBAR_HEIGHT, SWP_NOZORDER | SWP_NOMOVE);	

	//
	// Pass the general use imagelist onto the tree control
	//
	m_TreeCtrl.SetImageList (::Get_Global_Image_List (), TVSIL_NORMAL);

	SetProp (m_TreeCtrl, "TRANS_ACCS", (HANDLE)1);
	SetProp (m_hWnd, "TRANS_ACCS", (HANDLE)1);

	Reset_Tree ();
	return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnDeleteitemOverlapTree
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnDeleteitemOverlapTree
(
	NMHDR *	pNMHDR,
	LRESULT *pResult
) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	(*pResult) = 0;
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Build_Tree
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::Build_Tree (void)
{
	Reset_Tree ();

	//
	//	Fill the sub-nodes
	//
	Detect_Overlaps (m_SoundsRoot, NODE_TYPE_SOUND);
	Detect_Overlaps (m_LightsRoot, NODE_TYPE_LIGHT);
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Reset_Tree
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::Reset_Tree (void)
{
	m_TreeCtrl.DeleteAllItems ();
	
	//
	//	Insert the root nodes
	//
	m_SoundsRoot = m_TreeCtrl.InsertItem ("Sounds", FOLDER_ICON, FOLDER_ICON);
	m_LightsRoot = m_TreeCtrl.InsertItem ("Lights", FOLDER_ICON, FOLDER_ICON);
	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Detect_Overlaps
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::Detect_Overlaps (HTREEITEM root_item, NODE_TYPE node_type)
{
	//
	//	Loop over each node (of the given type) in the world
	//
	NodeClass *node1 = NULL;
	for (	node1 = NodeMgrClass::Get_First (node_type);
			node1 != NULL;
			node1 = NodeMgrClass::Get_Next (node1, node_type))
	{
		//
		//	Check this node against every other node (of the sametype) in the world
		//
		HTREEITEM tree_item		= NULL;
		NodeClass *node2	= NULL;
		for (	node2 = NodeMgrClass::Get_First (node_type);
				node2 != NULL;
				node2 = NodeMgrClass::Get_Next (node2, node_type))
		{
			if (node1 != node2) {
				
				SphereClass sphere1 (node1->Get_Position (), node1->Get_Attenuation_Radius ());
				SphereClass sphere2 (node2->Get_Position (), node2->Get_Attenuation_Radius ());

				//
				//	Do these spheres intersect?
				//
				if (CollisionMath::Overlap_Test (sphere1, sphere2) != CollisionMath::OUTSIDE) {
					
					//
					//	Add a tree entry for this node (if necessary)
					//
					if (tree_item == NULL) {
						tree_item = Insert_Node (root_item, node1);
					}

					//
					//	Add this node as a sub-entry under the tree
					//
					Insert_Node (tree_item, node2);
				}
			}
		}		
	}

	return ;
}


/////////////////////////////////////////////////////////////////////////////
//
// Insert_Node
//
/////////////////////////////////////////////////////////////////////////////
HTREEITEM
OverlapPageClass::Insert_Node (HTREEITEM parent_item, NodeClass *node)
{
	//
	//	Add this node to the tree
	//
	int icon_index			= node->Get_Icon_Index ();
	HTREEITEM tree_item	= m_TreeCtrl.InsertItem (	node->Get_Name (),
																	icon_index,
																	icon_index,
																	parent_item);
	
	//
	//	Save the node's ID with the tree entry so we can look it up later...
	//
	if (tree_item != NULL) {
		m_TreeCtrl.SetItemData (tree_item, node->Get_ID ());
	}

	return tree_item;
}


/////////////////////////////////////////////////////////////////////////////
//
// OnRefresh
//
/////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnRefresh (void)
{
	Build_Tree ();
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnDblclkOverlapTree
//
////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnDblclkOverlapTree
(
	NMHDR *		pNMHDR,
	LRESULT *	pResult
) 
{
	//
	// Determine what client-coord location was double-clicked on
	//
	DWORD mouse_pos = ::GetMessagePos ();
	POINT hit_point = { GET_X_LPARAM (mouse_pos), GET_Y_LPARAM (mouse_pos) };
	m_TreeCtrl.ScreenToClient (&hit_point);

	//
	// Goto the node that was double-clicked on (if possible)
	//
	UINT flags				= 0;
	HTREEITEM tree_item	= m_TreeCtrl.HitTest (hit_point, &flags);
	if (tree_item != NULL && flags & TVHT_ONITEMLABEL) {
		
		//
		//	Lookup the node from its ID
		//
		int node_id = m_TreeCtrl.GetItemData (tree_item);
		NodeClass *node = NodeMgrClass::Find_Node (node_id);
		if (node != NULL) {
			
			//
			//	Reposition the camera so its looking at the node
			//
			::Get_Camera_Mgr ()->Goto_Node (node);
		}
	}
		
	(*pResult) = 0;
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnItemexpandedOverlapTree
//
////////////////////////////////////////////////////////////////////////////
void
OverlapPageClass::OnItemexpandedOverlapTree
(
	NMHDR *		pNMHDR,
	LRESULT *	pResult
)
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	//
	// If this is a folder, then change its image based
	// on its expanded state.
	//
	uint32 node_id = m_TreeCtrl.GetItemData (pNMTreeView->itemNew.hItem);
	if (node_id == 0) {
		if (pNMTreeView->itemNew.state & TVIS_EXPANDED) {
			m_TreeCtrl.SetItemImage (pNMTreeView->itemNew.hItem, OPEN_FOLDER_ICON, OPEN_FOLDER_ICON);
		} else {
			m_TreeCtrl.SetItemImage (pNMTreeView->itemNew.hItem, FOLDER_ICON, FOLDER_ICON);
		}
	}

	(*pResult) = 0;
	return ;
}
