// pagerotcenter.cpp : implementation file
//

#include "stdafx.h"
#include "acp_base.h"
#include "camresrc.h"
#include "pagerotcenter.hpp"
#include "caminter.hpp"
#include "camera.hpp"


#define M_GetDLL(Camera) ((Camera_Interface*)((Camera)->GetEditor()))
/////////////////////////////////////////////////////////////////////////////
// PageRotationCenter property page

//IMPLEMENT_DYNCREATE(PageRotationCenter, CDialog)

PageRotationCenter::PageRotationCenter(Camera *p_oCamera)
 : PageBase(PageRotationCenter::IDD)
{
	//{{AFX_DATA_INIT(PageRotationCenter)
	m_csPointX = _T("");
	m_csPointY = _T("");
	m_csPointZ = _T("");
	m_csSuperObjectX = _T("");
	m_csSuperObjectY = _T("");
	m_csSuperObjectZ = _T("");
	m_iRotationCenterType = -1;
	m_iPointCoords = -1;
	m_csComboEdit = _T("");
	m_bPointRelative = FALSE;
	//}}AFX_DATA_INIT
	m_p_oCamera = p_oCamera;
	m_lIDofCurrentEdit = NULL;
}

PageRotationCenter::~PageRotationCenter()
{
}

void PageRotationCenter::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(PageRotationCenter)
	DDX_Control(pDX, IDC_COMBO_SUPEROBJECT, m_oComboSO);
	DDX_Text(pDX, IDC_EDIT_POINTX, m_csPointX);
	DDX_Text(pDX, IDC_EDIT_POINTY, m_csPointY);
	DDX_Text(pDX, IDC_EDIT_POINTZ, m_csPointZ);
	DDX_Text(pDX, IDC_EDIT_SOX, m_csSuperObjectX);
	DDX_Text(pDX, IDC_EDIT_SOY, m_csSuperObjectY);
	DDX_Text(pDX, IDC_EDIT_SOZ, m_csSuperObjectZ);
	DDX_Radio(pDX, IDC_RB_ROTPOINT, m_iRotationCenterType);
	DDX_Radio(pDX, IDC_RB_WORLDCOORDS, m_iPointCoords);
	DDX_CBString(pDX, IDC_COMBO_SUPEROBJECT, m_csComboEdit);
	DDX_Check(pDX, IDC_CHK_RELATIVE, m_bPointRelative);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(PageRotationCenter, CDialog)
	//{{AFX_MSG_MAP(PageRotationCenter)
	ON_BN_CLICKED(IDC_BT_COPYTOPOINT, OnBtCopytopoint)
	ON_BN_CLICKED(IDC_BT_RETURN, OnBtReturn)
	ON_EN_KILLFOCUS(IDC_EDIT_POINTX, OnKillfocusEditPointx)
	ON_EN_SETFOCUS(IDC_EDIT_POINTX, OnSetfocusEditPointx)
	ON_EN_KILLFOCUS(IDC_EDIT_POINTY, OnKillfocusEditPointy)
	ON_EN_SETFOCUS(IDC_EDIT_POINTY, OnSetfocusEditPointy)
	ON_EN_KILLFOCUS(IDC_EDIT_POINTZ, OnKillfocusEditPointz)
	ON_EN_SETFOCUS(IDC_EDIT_POINTZ, OnSetfocusEditPointz)
	ON_BN_CLICKED(IDC_RB_CAMERACOORDS, OnRbPointCoords)
	ON_CBN_SELCHANGE(IDC_COMBO_SUPEROBJECT, OnSelChangeComboSO)
	ON_CBN_EDITCHANGE(IDC_COMBO_SUPEROBJECT, OnEditChangeComboSO)
	ON_CBN_SETFOCUS(IDC_COMBO_SUPEROBJECT, OnSetfocusComboso)
	ON_CBN_KILLFOCUS(IDC_COMBO_SUPEROBJECT, OnKillfocusComboso)
	ON_WM_LBUTTONDOWN()
	ON_BN_CLICKED(IDC_RB_WORLDCOORDS, OnRbPointCoords)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// PageRotationCenter message handlers


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
BOOL PageRotationCenter::OnInitDialog() 
{
	MTH3D_tdstVector			stPoint;
	CPA_List<CPA_SuperObject>	*p_oListOfSO;
	POSITION					stPos;
	CPA_SuperObject				*p_oSO;
	long						lIndex;
	tdeCoordsType				eType;
	
	CDialog::OnInitDialog();
	
	// update the current Rotation Center type member
	switch (m_p_oCamera->GetRotationCenterType())
	{
	case rTarget :
		m_iRotationCenterType = 2;
		break;
	case rPoint :
		m_iRotationCenterType = 0;
		break;
	case rSuperObject :
		m_iRotationCenterType = 1;
		break;
	default:
		m_iRotationCenterType = -1;
		break;
	}

	// init the point coordinates
	m_p_oCamera->GetRotationCenterPoint(stPoint,eType);
	m_csPointX.Format("%.3f",MTH3D_M_xGetXofVector(&stPoint));
	m_csPointY.Format("%.3f",MTH3D_M_xGetYofVector(&stPoint));
	m_csPointZ.Format("%.3f",MTH3D_M_xGetZofVector(&stPoint));

	// init the point coordinates type according to type of point
	switch(eType)
	{
	case Absolute :
		m_iPointCoords = 0;
		m_bPointRelative = FALSE;
		break;
	case Relative :
		m_iPointCoords = 1;
		m_bPointRelative = TRUE;
		break;
	default:
		ASSERT(0);
		break;
	}

	// add the 'none' entry to the combo
	lIndex = m_oComboSO.AddString("none");
	m_oComboSO.SetItemData(lIndex,NULL);

	// init the SuperObject combobox entries
	// get the list of available superobjects for this world
	p_oListOfSO = (M_GetDLL(m_p_oCamera))->M_GetListAllObjects();
	stPos = p_oListOfSO->GetHeadPosition();
	while(stPos)
	{
		p_oSO = p_oListOfSO->GetNext(stPos);
		if (p_oSO->GetObject() != m_p_oCamera && p_oSO->GetObject() != NULL)
		{
			lIndex = m_oComboSO.AddString(p_oSO->GetObject()->GetName());
			m_oComboSO.SetItemData(lIndex,(DWORD)p_oSO);
		}
	}
	// select the current target in the combo
	p_oSO = m_p_oCamera->GetRotationCenterSuperObject();
	if (p_oSO == NULL)
	{
		m_oComboSO.SelectString(-1,"none");
		m_csComboEdit = "none";
	}
	
	else if (m_oComboSO.SelectString(-1,p_oSO->GetObject()->GetName()) != CB_ERR)
		m_csComboEdit = p_oSO->GetObject()->GetName();
	else
	{
		m_oComboSO.SetCurSel(-1);
		m_csComboEdit = "";
	}

	// update the SO coordinates
	if (m_oComboSO.GetCurSel() != -1 && p_oSO != NULL)
	{
		GEO_tdxHandleToMatrix	hMatrix;

		hMatrix = HIE_fn_hGetSuperObjectMatrix(p_oSO->GetStruct());
		POS_fn_vGetTranslationVector(hMatrix,&stPoint);
		m_csSuperObjectX.Format("%.3f",MTH3D_M_xGetXofVector(&stPoint));
		m_csSuperObjectY.Format("%.3f",MTH3D_M_xGetYofVector(&stPoint));
		m_csSuperObjectZ.Format("%.3f",MTH3D_M_xGetZofVector(&stPoint));
	}
	else
	{
		m_csSuperObjectX = "---";
		m_csSuperObjectY = "---";
		m_csSuperObjectZ = "---";
		GetDlgItem(IDC_RB_ROTSO)->EnableWindow(FALSE);
		GetDlgItem(IDC_BT_COPYTOPOINT)->EnableWindow(FALSE);
	}

	UpdateData(FALSE);

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}




//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnBtCopytopoint() 
{
	UpdateData(TRUE);
	m_iPointCoords = 0;
	m_csPointX = m_csSuperObjectX;
	m_csPointY = m_csSuperObjectY;
	m_csPointZ = m_csSuperObjectZ;
	UpdateData(FALSE);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnBtReturn() 
{
	// if an edit had the focus, put the focus on the hidden button
	// to be sure to call the killfocus function for the dialog
	if (m_lIDofCurrentEdit != NULL)
	{
		GetDlgItem(IDC_BT_RETURN)->SetFocus();
		return;
	}
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnKillfocusEditPointx() 
{
	CString csOldValue;

	// translate old value into float and save it
	csOldValue = m_csPointX;

	// get the new text value
	UpdateData(TRUE);

	// check validity of text
	if ( ((float) atof(m_csPointX) == 0.0) && (m_csPointX[0] != '0') )
	{
		// value is not good, put back the old one
		m_csPointX = csOldValue;
		UpdateData(FALSE);
		// and give back the focus to the window
		GetDlgItem(IDC_EDIT_POINTX)->SetFocus();
	}
	else
	{
		// update drawing
		UpdateData(FALSE);
		m_lIDofCurrentEdit = NULL;
	}
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnSetfocusEditPointx() 
{
	m_lIDofCurrentEdit = IDC_EDIT_POINTX;	
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnKillfocusEditPointy() 
{
	CString csOldValue;

	// translate old value into float and save it
	csOldValue = m_csPointY;

	// get the new text value
	UpdateData(TRUE);

	// check validity of text
	if ( ((float) atof(m_csPointY) == 0.0) && (m_csPointY[0] != '0') )
	{
		// value is not good, put back the old one
		m_csPointY = csOldValue;
		UpdateData(FALSE);
		// and give back the focus to the window
		GetDlgItem(IDC_EDIT_POINTY)->SetFocus();
	}
	else
	{
		// update drawing
		UpdateData(FALSE);
		m_lIDofCurrentEdit = NULL;
	}
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnSetfocusEditPointy() 
{
	m_lIDofCurrentEdit = IDC_EDIT_POINTY;	
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnKillfocusEditPointz() 
{
	CString csOldValue;

	// translate old value into float and save it
	csOldValue = m_csPointZ;

	// get the new text value
	UpdateData(TRUE);

	// check validity of text
	if ( ((float) atof(m_csPointZ) == 0.0) && (m_csPointZ[0] != '0') )
	{
		// value is not good, put back the old one
		m_csPointZ = csOldValue;
		UpdateData(FALSE);
		// and give back the focus to the window
		GetDlgItem(IDC_EDIT_POINTZ)->SetFocus();
	}
	else
	{
		// update drawing
		UpdateData(FALSE);
		m_lIDofCurrentEdit = NULL;
	}
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnSetfocusEditPointz() 
{
	m_lIDofCurrentEdit = IDC_EDIT_POINTZ;	
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnRbPointCoords() 
{
	long				lLastValue;
	MTH3D_tdstVector	stPoint;
	float fX,fY,fZ;

	// get last value
	lLastValue = m_iPointCoords;

	// get new values
	UpdateData(TRUE);
	if (m_iPointCoords == lLastValue)
		return;

	// coords type changed -> translate
	fX = (float) atof(m_csPointX);
	fY = (float) atof(m_csPointY);
	fZ = (float) atof(m_csPointZ);

	MTH3D_M_vSetVectorElements(&stPoint,fX,fY,fZ);
	
	if (m_iPointCoords == 0)
		m_p_oCamera->CameraToWorldCoordinates_Point(stPoint);
	else
		m_p_oCamera->WorldToCameraCoordinates_Point(stPoint);

	MTH3D_M_vGetVectorElements(&fX,&fY,&fZ,&stPoint);

	m_csPointX.Format("%.3f",fX);
	m_csPointY.Format("%.3f",fY);
	m_csPointZ.Format("%.3f",fZ);
	
	UpdateData(FALSE);
	// TODO: Add your control notification handler code here
	
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnSelChangeComboSO() 
{
	long			lIndex;
	CPA_SuperObject	*p_oSO;

	UpdateData(TRUE);

	// get the new selected element;
	lIndex = m_oComboSO.GetCurSel();
	if (lIndex != -1)
	{
		p_oSO = (CPA_SuperObject*) m_oComboSO.GetItemData(lIndex);
		m_csComboEdit = p_oSO->GetObject()->GetName();
	}
	else
	{
		m_csComboEdit = "";
	}

	CheckComboSO();
	CheckRotationCenterType();

	UpdateData(FALSE);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnEditChangeComboSO() 
{
	long lIndex,lIndex2;

	lIndex = CB_ERR;
	lIndex2 = CB_ERR;
	// get the current combo text
//	UpdateData(TRUE);

	// look for the index of the string
/*	lIndex = m_oComboSO.FindString(-1,(char*)(LPCTSTR)m_csComboEdit);
	
	// look if there are more than one match
	if (lIndex != CB_ERR)
	{
		lIndex2 = m_oComboSO.FindString(lIndex,(char*)(LPCTSTR)m_csComboEdit);
	
		// open the combo droplist
		if (m_oComboSO.GetDroppedState() == FALSE)
		{
			// drop down, put back the original text, and put entry point at the end
			m_oComboSO.ShowDropDown(TRUE);
			m_oComboSO.SetWindowText(m_csComboEdit);
			m_oComboSO.SetEditSel(m_csComboEdit.GetLength(),m_csComboEdit.GetLength());
		}
		// if there's only one match, select it
		if (lIndex2 == CB_ERR || lIndex2 == lIndex)
			m_oComboSO.SetCurSel(lIndex);
		else	// else, just show the selected string
			m_oComboSO.SetTopIndex(lIndex);
	}
*/}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnSetfocusComboso() 
{
	m_lIDofCurrentEdit = IDC_COMBOSO;	
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnKillfocusComboso() 
{
	UpdateData(TRUE);
	CheckComboSO();
	CheckRotationCenterType();
	UpdateData(FALSE);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::MakeChangesAvailable() 
{
	float fX,fY,fZ;
	long lIndex;

	UpdateData(TRUE);

	// RotationCenter Point coords
	fX = (float) atof(m_csPointX);
	fY = (float) atof(m_csPointY);
	fZ = (float) atof(m_csPointZ);
	m_oRotationCenterPoint.SetXYZ(fX,fY,fZ);
	switch(m_iPointCoords)
	{
	case 0:	// world coordinates
		m_oRotationCenterPoint.SetAxisSystem(WorldCoordinates);
		break;
	case 1:	// camera coordinates
		m_oRotationCenterPoint.SetAxisSystem(CameraCoordinates);
		break;
	default:
		ASSERT(0);
		break;
	}

	// Rotation Center SuperObject
	lIndex = m_oComboSO.FindStringExact(-1,(char*)(LPCTSTR)m_csComboEdit);
	if (lIndex != -1)
		m_p_oRotationCenterSuperObject = (CPA_SuperObject*) m_oComboSO.GetItemData(lIndex);
	else
		m_p_oRotationCenterSuperObject = NULL;

	// RotationCenter Type
	switch(m_iRotationCenterType)
	{
	case 2:
		m_eRotationCenterType = rTarget;
		break;
	case 0:
		m_eRotationCenterType = rPoint;
		break;
	case 1:
		m_eRotationCenterType = rSuperObject;
		break;
	default:
		ASSERT(0);
	}
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
BOOL PageRotationCenter::IsPageValid()
{
	BOOL bResult;

	bResult = TRUE;

	UpdateData(TRUE);
	bResult = CheckComboSO(); 
	bResult &= CheckRotationCenterType();
	UpdateData(FALSE);

	return bResult;
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::DoUpdate()
{
	m_p_oCamera->SetRotationCenterType(rTarget);
	m_p_oCamera->SetRotationCenterSuperObject(m_p_oRotationCenterSuperObject);
	if (m_bPointRelative)
		m_p_oCamera->SetRotationCenterPoint(&m_oRotationCenterPoint,Relative);
	else
		m_p_oCamera->SetRotationCenterPoint(&m_oRotationCenterPoint,Absolute);
	m_p_oCamera->SetRotationCenterType(m_eRotationCenterType);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void PageRotationCenter::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// if an edit had the focus, put the focus on the hidden button
	// to be sure to call the killfocus function for the dialog
	if (m_lIDofCurrentEdit != NULL)
	{
		GetDlgItem(IDC_BT_RETURN)->SetFocus();
		return;
	}
	else
	{
		CDialog::OnLButtonDown(nFlags, point);
	}
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// check if combo SO is valid. If not, set to "none" and return FALSE
BOOL PageRotationCenter::CheckComboSO() 
{
	long			lIndex;
	CPA_SuperObject *p_oSO;
	BOOL			bResult;

	p_oSO = NULL;
	// get the new selected element;
	lIndex = m_oComboSO.FindStringExact(-1,(char*)(LPCTSTR)m_csComboEdit);
	if (lIndex != -1)
		p_oSO = (CPA_SuperObject*) m_oComboSO.GetItemData(lIndex);
	
	// check if the superobject is good
	if (p_oSO == NULL)
	{
		// not good!
		// disable copy to point
		GetDlgItem(IDC_BT_COPYTOPOINT)->EnableWindow(FALSE);
		// erase coords
		m_csSuperObjectX = "---";
		m_csSuperObjectY = "---";
		m_csSuperObjectZ = "---";
		// set name to none
		m_csComboEdit = "none";
		// if target was not valid, result = FALSE
		bResult = (lIndex != -1);
	}
	else
	{
		GEO_tdxHandleToMatrix	hMatrix;
		MTH3D_tdstVector		stPoint;
		
		//enable target SO and copy to point
		GetDlgItem(IDC_RB_ROTSO)->EnableWindow(TRUE);
		GetDlgItem(IDC_BT_COPYTOPOINT)->EnableWindow(TRUE);
		// update coords
		hMatrix = HIE_fn_hGetSuperObjectMatrix(p_oSO->GetStruct());
		POS_fn_vGetTranslationVector(hMatrix,&stPoint);
		m_csSuperObjectX.Format("%.3f",MTH3D_M_xGetXofVector(&stPoint));
		m_csSuperObjectY.Format("%.3f",MTH3D_M_xGetYofVector(&stPoint));
		m_csSuperObjectZ.Format("%.3f",MTH3D_M_xGetZofVector(&stPoint));
		// set new name in combo
		m_csComboEdit = p_oSO->GetObject()->GetName();
		bResult = TRUE;
	}
	return bResult;
}




//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// check if RotationCenter type is valid. if not, set to valid and return FALSE
BOOL PageRotationCenter::CheckRotationCenterType() 
{
	long			lIndex;
	CPA_SuperObject *p_oSO;
	BOOL			bResult;

	bResult = TRUE;
	// find the combo selection
	p_oSO = NULL;
	lIndex = m_oComboSO.FindStringExact(-1,(char*)(LPCTSTR)m_csComboEdit);
	if (lIndex != -1)	// selection valid
		p_oSO = (CPA_SuperObject*) m_oComboSO.GetItemData(lIndex);
	
	// check target type
	switch(m_iRotationCenterType)
	{
	case 2:				// rTarget --> ok
	case 0:				// rPoint --> ok
		bResult = TRUE;
		break;

	case 1:				// rSuperObject
		// if SO not valid, set target type to rTarget and return FALSE
		if (p_oSO == NULL)
		{
			m_iRotationCenterType = 2;
			bResult = FALSE;
		}
		break;
	default:
		ASSERT(0);
	}
	
	// if rotation center SO not valid, disable "rotation center is SO", else, enable
	if (p_oSO == NULL)		
		GetDlgItem(IDC_RB_ROTSO)->EnableWindow(FALSE);
	else
		GetDlgItem(IDC_RB_ROTSO)->EnableWindow(TRUE);
	return bResult;
}
