// JointEditDialog.cpp : implementation file
//

#include "stdafx.h"

#ifdef STRICT							// Already defined by stdafx,
#undef STRICT							// so we avoid warning linking msg
#endif
#ifdef _MBCS							// The same as above
#undef _MBCS
#endif

#include "JointEditDialog.h"

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


/////////////////////////////////////////////////////////////////////////////
// JointEditDialog dialog


JointEditDialog::JointEditDialog(INode *root_node, Interface *ip, CWnd* pParent /*=NULL*/)
	: CDialog(JointEditDialog::IDD, pParent)
{
	//{{AFX_DATA_INIT(JointEditDialog)
	m_rotOptCheck = FALSE;
	m_tranOptCheck = FALSE;
	m_rotRangeCheck = FALSE;
	m_tranRangeCheck = FALSE;
	m_encodeVelocityCheck = FALSE;
	m_rotThresholdEdit = 0.0f;
	m_tranThresholdEdit = 0.0f;
	m_rotMaxRange = 0;
	m_rotMinRange = 0;
	m_tranMaxRange = 0;
	m_tranMinRange = 0;
	m_rotConvertCheck = FALSE;
	m_tranConvertCheck = FALSE;
	//}}AFX_DATA_INIT
	m_max_interface = ip;
	m_rootNode = root_node;

	m_forceExclude = false;
	m_forceConvertRotation = false;
	m_forceConvertTranslation = false;
}


void JointEditDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);

	if (m_firstDataSave)
	{
		//{{AFX_DATA_MAP(JointEditDialog)
		DDX_Control(pDX, IDC_COMBO_TRAN_CONVERT, m_tranConvertCombo);
		DDX_Control(pDX, IDC_COMBO_ROT_CONVERT, m_rotConvertCombo);
		DDX_Control(pDX, IDC_COMBO_INCLUDE, m_includeCombo);
		DDX_Check(pDX, IDC_CHECK_ROT_OPT, m_rotOptCheck);
		DDX_Check(pDX, IDC_CHECK_TRAN_OPT, m_tranOptCheck);
		DDX_Check(pDX, IDC_CHECK_ROT_RANGE, m_rotRangeCheck);
		DDX_Check(pDX, IDC_CHECK_TRAN_RANGE, m_tranRangeCheck);
		DDX_Check(pDX, IDC_CHECK_ENCODE_VELOCITY, m_encodeVelocityCheck);
		DDX_Text(pDX, IDC_EDIT_ROT_THRESH, m_rotThresholdEdit);
		DDX_Text(pDX, IDC_EDIT_TRAN_THRESH, m_tranThresholdEdit);
		DDX_Text(pDX, IDC_ROT_MAX_RANGE, m_rotMaxRange);
		DDX_Text(pDX, IDC_ROT_MIN_RANGE, m_rotMinRange);
		DDX_Text(pDX, IDC_TRAN_MAX_RANGE, m_tranMaxRange);
		DDX_Text(pDX, IDC_TRAN_MIN_RANGE, m_tranMinRange);
		DDX_Check(pDX, IDC_CONVERT_ROT_CHECK, m_rotConvertCheck);
		DDX_Check(pDX, IDC_CONVERT_TRAN_CHECK, m_tranConvertCheck);
		//}}AFX_DATA_MAP

		m_firstDataSave = false;
	}
	
	GetDlgItem(IDC_COMBO_INCLUDE)->EnableWindow(true);
	GetDlgItem(IDC_CONVERT_ROT_CHECK)->EnableWindow(true);
	GetDlgItem(IDC_CONVERT_TRAN_CHECK)->EnableWindow(true);


	{

	
		DDX_Control(pDX, IDC_COMBO_INCLUDE, m_includeCombo);

		if (m_forceExclude)
		{
			GetDlgItem(IDC_COMBO_INCLUDE)->EnableWindow(false);
		}
		else
		{
			GetDlgItem(IDC_COMBO_INCLUDE)->EnableWindow(true);
		}


		DDX_Check(pDX, IDC_CHECK_ENCODE_VELOCITY, m_encodeVelocityCheck);

		//-----------------------------------------------------------
		// Do the rotation

		DDX_Check(pDX, IDC_CONVERT_ROT_CHECK, m_rotConvertCheck);
		if (m_rotConvertCheck)
		{
			DDX_Control(pDX, IDC_COMBO_ROT_CONVERT, m_rotConvertCombo);
			GetDlgItem(IDC_COMBO_ROT_CONVERT)->EnableWindow(true);

			if (m_forceConvertRotation)
			{
				GetDlgItem(IDC_CONVERT_ROT_CHECK)->EnableWindow(false);
			}
			else
			{
				GetDlgItem(IDC_CONVERT_ROT_CHECK)->EnableWindow(true);
			}

		}
		else
		{	
			// if we are loading then disable the controls
			if (!pDX->m_bSaveAndValidate)
			{
				GetDlgItem(IDC_COMBO_ROT_CONVERT)->EnableWindow(false);
				CComboBox *box = (CComboBox *)GetDlgItem(IDC_COMBO_ROT_CONVERT);
				box->SetCurSel( -1 );
			}
		}

		
		DDX_Check(pDX, IDC_CHECK_ROT_OPT, m_rotOptCheck);
		if (m_rotOptCheck)
		{
			DDX_Text(pDX, IDC_EDIT_ROT_THRESH, m_rotThresholdEdit);
			DDX_Check(pDX, IDC_CHECK_ROT_RANGE, m_rotRangeCheck);

			GetDlgItem(IDC_EDIT_ROT_THRESH)->EnableWindow(true);
			GetDlgItem(IDC_CHECK_ROT_RANGE)->EnableWindow(true);


			if (m_rotRangeCheck)
			{
				DDX_Text(pDX, IDC_ROT_MAX_RANGE, m_rotMaxRange);
				DDX_Text(pDX, IDC_ROT_MIN_RANGE, m_rotMinRange);
				GetDlgItem(IDC_ROT_MIN_RANGE)->EnableWindow(true);
				GetDlgItem(IDC_ROT_MAX_RANGE)->EnableWindow(true);
			}
			else
			{	
				// if we are loading then disable the controls
				if (!pDX->m_bSaveAndValidate)
				{	
					GetDlgItem(IDC_ROT_MIN_RANGE)->EnableWindow(false);
					GetDlgItem(IDC_ROT_MAX_RANGE)->EnableWindow(false);
					CEdit *edit;
					edit = (CEdit *)GetDlgItem(IDC_ROT_MIN_RANGE);
					edit->SetWindowText("");
					edit = (CEdit *)GetDlgItem(IDC_ROT_MAX_RANGE);
					edit->SetWindowText("");
				}
			}
		}
		else
		{	
			// if we are loading then disable the controls
			if (!pDX->m_bSaveAndValidate)
			{
				GetDlgItem(IDC_EDIT_ROT_THRESH)->EnableWindow(false);
				GetDlgItem(IDC_CHECK_ROT_RANGE)->EnableWindow(false);

				CEdit *edit = (CEdit *)GetDlgItem(IDC_EDIT_ROT_THRESH);
				edit->SetWindowText("");

				GetDlgItem(IDC_ROT_MIN_RANGE)->EnableWindow(false);
				GetDlgItem(IDC_ROT_MAX_RANGE)->EnableWindow(false);
				
				edit = (CEdit *)GetDlgItem(IDC_ROT_MIN_RANGE);
				edit->SetWindowText("");
				edit = (CEdit *)GetDlgItem(IDC_ROT_MAX_RANGE);
				edit->SetWindowText("");
			}
		}

		//-----------------------------------------------------------
		// Do the translation
		
		DDX_Check(pDX, IDC_CONVERT_TRAN_CHECK, m_tranConvertCheck);
		if (m_tranConvertCheck)
		{
			DDX_Control(pDX, IDC_COMBO_TRAN_CONVERT, m_tranConvertCombo);
			GetDlgItem(IDC_COMBO_TRAN_CONVERT)->EnableWindow(true);

			if (m_forceConvertTranslation)
			{
				GetDlgItem(IDC_CONVERT_TRAN_CHECK)->EnableWindow(false);
			}
			else
			{
				GetDlgItem(IDC_CONVERT_TRAN_CHECK)->EnableWindow(true);
			}
		}
		else
		{	
			// if we are loading then disable the controls
			if (!pDX->m_bSaveAndValidate)
			{
				GetDlgItem(IDC_COMBO_TRAN_CONVERT)->EnableWindow(false);
				CComboBox *box = (CComboBox *)GetDlgItem(IDC_COMBO_TRAN_CONVERT);
				box->SetCurSel( -1 );
			}
		}
		
		DDX_Check(pDX, IDC_CHECK_TRAN_OPT, m_tranOptCheck);
		if (m_tranOptCheck)
		{
			DDX_Text(pDX, IDC_EDIT_TRAN_THRESH, m_tranThresholdEdit);
			DDX_Check(pDX, IDC_CHECK_TRAN_RANGE, m_tranRangeCheck);
			GetDlgItem(IDC_EDIT_TRAN_THRESH)->EnableWindow(true);
			GetDlgItem(IDC_CHECK_TRAN_RANGE)->EnableWindow(true);

			if (m_tranRangeCheck)
			{
				DDX_Text(pDX, IDC_TRAN_MAX_RANGE, m_tranMaxRange);
				DDX_Text(pDX, IDC_TRAN_MIN_RANGE, m_tranMinRange);
				GetDlgItem(IDC_TRAN_MIN_RANGE)->EnableWindow(true);
				GetDlgItem(IDC_TRAN_MAX_RANGE)->EnableWindow(true);
			}
			else
			{	
				// if we are loading then disable the controls
				if (!pDX->m_bSaveAndValidate)
				{
					GetDlgItem(IDC_TRAN_MIN_RANGE)->EnableWindow(false);
					GetDlgItem(IDC_TRAN_MAX_RANGE)->EnableWindow(false);
					CEdit *edit;
					edit = (CEdit *)GetDlgItem(IDC_TRAN_MIN_RANGE);
					edit->SetWindowText("");
					edit = (CEdit *)GetDlgItem(IDC_TRAN_MAX_RANGE);
					edit->SetWindowText("");
				}
			}
		}
		else
		{	
			// if we are loading then disable the controls
			if (!pDX->m_bSaveAndValidate)
			{
				GetDlgItem(IDC_EDIT_TRAN_THRESH)->EnableWindow(false);
				GetDlgItem(IDC_CHECK_TRAN_RANGE)->EnableWindow(false);
			

				CEdit *edit = (CEdit *)GetDlgItem(IDC_EDIT_TRAN_THRESH);
				edit->SetWindowText("");

				GetDlgItem(IDC_TRAN_MIN_RANGE)->EnableWindow(false);
				GetDlgItem(IDC_TRAN_MAX_RANGE)->EnableWindow(false);
		
				edit = (CEdit *)GetDlgItem(IDC_TRAN_MIN_RANGE);
				edit->SetWindowText("");
				edit = (CEdit *)GetDlgItem(IDC_TRAN_MAX_RANGE);
				edit->SetWindowText("");

			}
		}
	}
}


BEGIN_MESSAGE_MAP(JointEditDialog, CDialog)
	//{{AFX_MSG_MAP(JointEditDialog)
	ON_BN_CLICKED(ID_REVERT_JOINT, OnRevertJoint)
	ON_NOTIFY(TVN_SELCHANGED, IDC_NODE_TREE, OnSelchangedNodeTree)
	ON_BN_CLICKED(IDC_CHECK_ROT_OPT, OnCheckRotOpt)
	ON_BN_CLICKED(IDC_CONVERT_ROT_CHECK, OnConvertRotCheck)
	ON_BN_CLICKED(IDC_CHECK_ROT_RANGE, OnCheckRotRange)
	ON_BN_CLICKED(IDC_CONVERT_TRAN_CHECK, OnConvertTranCheck)
	ON_BN_CLICKED(IDC_CHECK_TRAN_OPT, OnCheckTranOpt)
	ON_BN_CLICKED(IDC_CHECK_TRAN_RANGE, OnCheckTranRange)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// JointEditDialog message handlers

BOOL JointEditDialog::OnInitDialog() 
{

	// prime the pump...
	AddJointPreference(m_rootNode);


	m_firstDataSave = true;
	CDialog::OnInitDialog();


	// set up the combos...
	m_tranConvertCombo.InsertString(-1, "Linear");
	m_tranConvertCombo.InsertString(-1, "EulerXYZ");
	m_tranConvertCombo.InsertString(-1, "PositionXYZ");

	m_rotConvertCombo.InsertString(-1, "Linear");
	m_rotConvertCombo.InsertString(-1, "EulerXYZ");
	m_rotConvertCombo.InsertString(-1, "PositionXYZ");

	m_includeCombo.InsertString(-1, "Exclude");
	m_includeCombo.InsertString(-1, "Include");
	m_includeCombo.InsertString(-1, "Auto");

	// init the tree...
	
	CTreeCtrl *tree	 = (CTreeCtrl *)GetDlgItem(IDC_NODE_TREE);
	
	HTREEITEM top_item = AddToTree(tree, m_rootNode, TVI_ROOT);

	tree->EnsureVisible(top_item);
	tree->SelectItem(top_item);





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


HTREEITEM JointEditDialog::AddToTree(CTreeCtrl *tree, INode *node, HTREEITEM parent)
{
	
	HTREEITEM new_entry = tree->InsertItem( node->GetName(), parent, TVI_LAST );
	tree->SetItemData(new_entry, (DWORD)node); 

	for (int c = 0; c < node->NumberOfChildren(); c++) 
	{
		AddToTree(tree, node->GetChildNode(c), new_entry);
	}

	tree->Expand(new_entry, TVE_EXPAND );

	return new_entry;
}
/////////////////////////////////////////////////////////////////////////////

void JointEditDialog::OnOK() 
{
	
	// save the current node...
	CTreeCtrl *tree	 = (CTreeCtrl *)GetDlgItem(IDC_NODE_TREE);

	INode *node = (INode*)tree->GetItemData(tree->GetSelectedItem());

	if (!node->IsRootNode())
	{
	

		AppDataChunk *ad = 
			node->GetAppDataChunk(
				JOINTPREFS_SAVE_CLASS_ID, 
				JOINT_SAVE_SUPER_CLASS_ID, 
				TEMP_DATA_ID
			);
		
		JointPreference *j_pref = (JointPreference *)ad->data;
		SaveControls(j_pref);
	}



	AcceptTempData(m_max_interface->GetRootNode());

	CDialog::OnOK();
}




/////////////////////////////////////////////////////////////////////////////


void JointEditDialog::OnCancel() 
{
	

	CancelTempData(m_max_interface->GetRootNode());

	CDialog::OnCancel();
}

/////////////////////////////////////////////////////////////////////////////

JointPreference * JointEditDialog::GetJointPrefrence(INode* node)
{
	AppDataChunk *ad = 
		node->GetAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID
		);

	if (ad != NULL) 
	{
		return (JointPreference *)ad->data;
	}
	
	return NULL;
}


/////////////////////////////////////////////////////////////////////////////


void JointEditDialog::CopyJointPrefrence(INode* source_node, INode* target_node)
{
		AppDataChunk *ad = 
		source_node->GetAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID
		);

	if (ad != NULL) 
	{
		size_t size = ad->length;
		BYTE *data = new BYTE[size];

		Mem_Copy(data, ad->data, ad->length, size);

		target_node->AddAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID,
			size, data);
	}
}

/////////////////////////////////////////////////////////////////////////////

void JointEditDialog::AcceptTempData(INode *node) 
{
	AppDataChunk *ad = 
		node->GetAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			TEMP_DATA_ID
		);
	if (ad)
	{
		node->RemoveAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID);


		size_t size = ad->length;
		BYTE *data = new BYTE[size];

		Mem_Copy(data, ad->data, ad->length, size);

		node->AddAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID,
			size, data);

		// now kill the temp data
		node->RemoveAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			TEMP_DATA_ID);

		SetSaveRequiredFlag(TRUE);
	}

	for (int c = 0; c < node->NumberOfChildren(); c++) 
	{
		AcceptTempData(node->GetChildNode(c));
	}
}


/////////////////////////////////////////////////////////////////////////////


void JointEditDialog::CancelTempData(INode *node) 
{

	node->RemoveAppDataChunk(
		JOINTPREFS_SAVE_CLASS_ID, 
		JOINT_SAVE_SUPER_CLASS_ID, 
		TEMP_DATA_ID);

	for (int c = 0; c < node->NumberOfChildren(); c++) 
	{
		CancelTempData(node->GetChildNode(c));
	}
}


/////////////////////////////////////////////////////////////////////////////

void JointEditDialog::DeleteAllJointPrefrence(INode* node)
{

	
	if (!node->IsRootNode())
	{
		node->RemoveAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			TEMP_DATA_ID);

		node->RemoveAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID);

	}

	for (int c = 0; c < node->NumberOfChildren(); c++) 
	{
		DeleteAllJointPrefrence(node->GetChildNode(c));
	}

	
}

/////////////////////////////////////////////////////////////////////////////


void JointEditDialog::OnRevertJoint() 
{
	
	// reinitialize this joints temporary data with it's perminate data.

	// remove temp data
	// copy perm data into temp data

	CTreeCtrl *tree	 = (CTreeCtrl *)GetDlgItem(IDC_NODE_TREE);

	INode *node = (INode*)tree->GetItemData(tree->GetSelectedItem());


	AppDataChunk *ad_perm = 
		node->GetAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID
		);
		
	Verify(ad_perm != NULL);

	size_t size = ad_perm->length;
	BYTE *data = new BYTE[size];

	Mem_Copy(data, ad_perm->data, ad_perm->length, size);

	// remove it if it exists...
	node->RemoveAppDataChunk(
		JOINTPREFS_SAVE_CLASS_ID, 
		JOINT_SAVE_SUPER_CLASS_ID, 
		TEMP_DATA_ID);

	node->AddAppDataChunk(
		JOINTPREFS_SAVE_CLASS_ID, 
		JOINT_SAVE_SUPER_CLASS_ID, 
		TEMP_DATA_ID,
		size, data);

	AppDataChunk *ad = 
		node->GetAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			TEMP_DATA_ID
		);

	Verify(ad != NULL);
	// we just added it!

	ClearControls();

	JointPreference *j_pref = (JointPreference *)ad->data;
	InitControls(j_pref);

}
/////////////////////////////////////////////////////////////////////////////


void JointEditDialog::OnSelchangedNodeTree(NMHDR* pNMHDR, LRESULT* pResult) 
{

	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	CTreeCtrl *tree	 = (CTreeCtrl *)GetDlgItem(IDC_NODE_TREE);

	// Save old node data...
	if (pNMTreeView->itemOld.hItem != NULL)
	{
		// copy the interface into the tempdata
		// get pointer to data
		
		INode *node = (INode*)tree->GetItemData(pNMTreeView->itemOld.hItem); 

		if (!node->IsRootNode())
		{
		

			AppDataChunk *ad = 
				node->GetAppDataChunk(
					JOINTPREFS_SAVE_CLASS_ID, 
					JOINT_SAVE_SUPER_CLASS_ID, 
					TEMP_DATA_ID
				);

			JointPreference *j_pref = (JointPreference *)ad->data;
			SaveControls(j_pref);
		}
		
	}


	// Load this data segment

	INode *node = (INode*)tree->GetItemData(pNMTreeView->itemNew.hItem); 
	
	if (node->IsRootNode())
	{
		ClearControls();
		return;
	}
	
	AppDataChunk *ad = 
		node->GetAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			TEMP_DATA_ID
		);

	if (!ad) 
	{
		// Not found!
		// copy from the other perm data segment...

		AppDataChunk *ad_perm = 
		node->GetAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID
		);
		
		Verify(ad_perm != NULL);

		size_t size = ad_perm->length;
		BYTE *data = new BYTE[size];

		Mem_Copy(data, ad_perm->data, ad_perm->length, size);

		node->AddAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			TEMP_DATA_ID,
			size, data);


		ad = node->GetAppDataChunk(
				JOINTPREFS_SAVE_CLASS_ID, 
				JOINT_SAVE_SUPER_CLASS_ID, 
				TEMP_DATA_ID
			);

	}


	// copy ad into the interface
	ClearControls();

	JointPreference *j_pref = (JointPreference *)ad->data;
	InitControls(j_pref);
	
	*pResult = 0;

}

/////////////////////////////////////////////////////////////////////////////

void JointEditDialog::ClearControls()
{
	
	
	
	// Clear the combos
	m_tranConvertCombo.SetCurSel( -1 );
	m_rotConvertCombo.SetCurSel( -1 );
	m_includeCombo.SetCurSel( -1 );


	m_rotOptCheck = false;
	m_tranOptCheck = false;
	m_rotRangeCheck = false;
	m_tranRangeCheck = false;
	m_rotConvertCheck = false;
	m_tranConvertCheck = false;
	m_encodeVelocityCheck = false;
	m_rotThresholdEdit = 0.0f;
	m_tranThresholdEdit = 0.0f;
	m_rotMaxRange = 0;
	m_rotMinRange = 0;
	m_tranMaxRange = 0;
	m_tranMinRange = 0;

	UpdateData(false);

	// clear out the edits
	CEdit *edit;
	
	edit = (CEdit *)GetDlgItem(IDC_EDIT_ROT_THRESH);
	edit->SetWindowText("");
	edit = (CEdit *)GetDlgItem(IDC_EDIT_TRAN_THRESH);
	edit->SetWindowText("");
	edit = (CEdit *)GetDlgItem(IDC_ROT_MIN_RANGE);
	edit->SetWindowText("");
	edit = (CEdit *)GetDlgItem(IDC_ROT_MAX_RANGE);
	edit->SetWindowText("");
	edit = (CEdit *)GetDlgItem(IDC_TRAN_MIN_RANGE);
	edit->SetWindowText("");
	edit = (CEdit *)GetDlgItem(IDC_TRAN_MAX_RANGE);
	edit->SetWindowText("");

	GetDlgItem(IDC_COMBO_TRAN_CONVERT)->EnableWindow(false);
	GetDlgItem(IDC_TRAN_MIN_RANGE)->EnableWindow(false);
	GetDlgItem(IDC_TRAN_MAX_RANGE)->EnableWindow(false);
	GetDlgItem(IDC_EDIT_TRAN_THRESH)->EnableWindow(false);
	GetDlgItem(IDC_CHECK_TRAN_RANGE)->EnableWindow(false);

	GetDlgItem(IDC_COMBO_ROT_CONVERT)->EnableWindow(false);
	GetDlgItem(IDC_ROT_MIN_RANGE)->EnableWindow(false);
	GetDlgItem(IDC_ROT_MAX_RANGE)->EnableWindow(false);
	GetDlgItem(IDC_EDIT_ROT_THRESH)->EnableWindow(false);
	GetDlgItem(IDC_CHECK_ROT_RANGE)->EnableWindow(false);

	CButton *button;

	button = (CButton *)GetDlgItem(IDC_CHECK_TRAN_RANGE);
	button->SetCheck(0);

	button = (CButton *)GetDlgItem(IDC_CHECK_ROT_RANGE);
	button->SetCheck(0);


}

/////////////////////////////////////////////////////////////////////////////

void JointEditDialog::SaveControls(JointPreference *j_pref)
{
	UpdateData(true);

	j_pref->m_forceExclude = m_forceExclude;
	j_pref->m_forceConvertRotation = m_forceConvertRotation;
	j_pref->m_forceConvertTranslation = m_forceConvertTranslation;


	j_pref->m_excludeJoint = m_includeCombo.GetCurSel();
	j_pref->m_decodeWithVelocity = (m_encodeVelocityCheck)?true:false;
	Verify(j_pref->m_decodeWithVelocity == true || j_pref->m_decodeWithVelocity == false);
	
	//SPEW((0, "SAVE : %d : %d", j_pref->m_decodeWithVelocity, encodeVelocityCheck ));


	j_pref->m_convertRotationJoint = (m_rotConvertCheck)?true:false;;
	if (m_rotConvertCheck)
	{
		j_pref->m_rotationConvertType = m_rotConvertCombo.GetCurSel();
	}

	j_pref->m_convertTranslationJoint = (m_tranConvertCheck)?true:false;;
	if (m_tranConvertCheck)
	{
		j_pref->m_translationConvertType = m_tranConvertCombo.GetCurSel();
	}

	j_pref->m_optimizeRotation = (m_rotOptCheck)?true:false;;
	if (m_rotOptCheck)
	{
		j_pref->m_rotationThreshold = m_rotThresholdEdit;
		j_pref->m_rotationRange = (m_rotRangeCheck)?true:false;;
		if (m_rotRangeCheck)
		{
			j_pref->m_rotationSampleStartFrame = m_rotMinRange;
			j_pref->m_rotationSampleEndFrame = m_rotMaxRange;
		}
	}

	j_pref->m_optimizeTranslation = (m_tranOptCheck)?true:false;;
	if (m_tranOptCheck)
	{
		j_pref->m_translationThreshold = m_tranThresholdEdit;
		j_pref->m_translationRange = (m_tranRangeCheck)?true:false;;
		if (m_tranRangeCheck)
		{
			j_pref->m_translationSampleStartFrame = m_tranMinRange;
			j_pref->m_translationSampleEndFrame = m_tranMaxRange;
		}
	}

}

/////////////////////////////////////////////////////////////////////////////

void JointEditDialog::InitControls(JointPreference *j_pref)
{

	m_forceExclude = j_pref->m_forceExclude;
	m_forceConvertRotation = j_pref->m_forceConvertRotation;
	m_forceConvertTranslation = j_pref->m_forceConvertTranslation;

	m_includeCombo.SetCurSel(j_pref->m_excludeJoint);
	m_encodeVelocityCheck = j_pref->m_decodeWithVelocity;
	Verify(j_pref->m_decodeWithVelocity == true || j_pref->m_decodeWithVelocity == false);
	
	//SPEW((0, "INIT : %d : %d", j_pref->m_decodeWithVelocity, encodeVelocityCheck ));

	m_rotConvertCheck = j_pref->m_convertRotationJoint;
	if (m_rotConvertCheck)
	{
		m_rotConvertCombo.SetCurSel(j_pref->m_rotationConvertType);
	}

	m_tranConvertCheck = j_pref->m_convertTranslationJoint;
	if (m_tranConvertCheck)
	{
		 m_tranConvertCombo.SetCurSel(j_pref->m_translationConvertType);
	}

	m_rotOptCheck = j_pref->m_optimizeRotation;
	if (m_rotOptCheck)
	{
		m_rotThresholdEdit = j_pref->m_rotationThreshold;
		m_rotRangeCheck = j_pref->m_rotationRange;
		if (m_rotRangeCheck)
		{
			m_rotMinRange = j_pref->m_rotationSampleStartFrame;
			m_rotMaxRange = j_pref->m_rotationSampleEndFrame;
		}
	}

	m_tranOptCheck = j_pref->m_optimizeTranslation;
	if (m_tranOptCheck)
	{
		m_tranThresholdEdit = j_pref->m_translationThreshold;
		m_tranRangeCheck = j_pref->m_translationRange;
		if (m_tranRangeCheck)
		{
			m_tranMinRange = j_pref->m_translationSampleStartFrame;
			m_tranMaxRange = j_pref->m_translationSampleEndFrame;
		}
	}

	UpdateData(false);
}

/////////////////////////////////////////////////////////////////////////////
#define APPDATA_TEST_CLASS_ID		0xf6277abd

void JointEditDialog::AddJointPreference(INode* node)
{

	AppDataChunk *ad = 
		node->GetAppDataChunk(
			JOINTPREFS_SAVE_CLASS_ID, 
			JOINT_SAVE_SUPER_CLASS_ID, 
			PERM_DATA_ID
		);

	if (!ad) 
	{
		// Not found!
		// Create and load...
		

		if (!node->IsRootNode())
		{

			JointPreference *joint_preference = (JointPreference *)malloc(sizeof(JointPreference));

			LoadPrefs(node, joint_preference);
	
			node->AddAppDataChunk(
				JOINTPREFS_SAVE_CLASS_ID, 
				JOINT_SAVE_SUPER_CLASS_ID, 
				PERM_DATA_ID,
				(DWORD)sizeof(JointPreference), (void *)joint_preference);
		}
	}


	// For each child of this node, we recurse into ourselves 
	// and increment the counter until no more children are found.
	for (int c = 0; c < node->NumberOfChildren(); c++) 
	{
		AddJointPreference(node->GetChildNode(c));
	}

}

/////////////////////////////////////////////////////////////////////////////


void JointEditDialog::CountNodes(INode* node, int& node_count)
{
	
	node_count++;
	
	// For each child of this node, we recurse into ourselves 
	// and increment the counter until no more children are found.
	for (int c = 0; c < node->NumberOfChildren(); c++) 
	{
		CountNodes(node->GetChildNode(c), node_count);
	}
}


//===========================================================================//

void JointEditDialog::LoadPrefs(INode* node, JointPreference *prefs)
{
	// Right now we are just going to fake it...
	// these routines will be used by the prefrence plugin
	
	// only allow for geom, helpers, bones, etc...NO CAMERAS, LIGHTS, etc...
	if (!KnownNode(node))
	{
		prefs->m_forceExclude = true;
		prefs->m_excludeJoint = JointPreference::ExcludeJoint;
		prefs->m_decodeWithVelocity = false;
	}
	else if (!NodeAnimated(node))
	{
		prefs->m_forceExclude = false;
		prefs->m_excludeJoint = JointPreference::AutoJoint;
		prefs->m_decodeWithVelocity = false;

	}
	else
	{
		prefs->m_forceExclude = false;
		prefs->m_excludeJoint = JointPreference::AutoJoint;


		const char *node_name = node->GetName();

		if (!_strnicmp(node_name, "joint_vel", 9))
		{
			prefs->m_decodeWithVelocity = true;
		}
		else
		{
			prefs->m_decodeWithVelocity = false;
		}


		// if one is diffrent
		// then we can't be sure that it doesn't mess
		// with the other so we just throw out unless we
		// know both controllers!

		if (HasKnownControler(node))
		{
			// this should check each one
			prefs->m_convertRotationJoint = false;
			prefs->m_convertTranslationJoint = false;
			prefs->m_optimizeRotation = false;
			prefs->m_optimizeTranslation = false;

			prefs->m_forceConvertRotation = false;
			prefs->m_forceConvertTranslation = false;

			prefs->m_rotationRange = false;
			prefs->m_translationRange = false;
		}
		else
		{
			prefs->m_forceConvertRotation = true;
			prefs->m_forceConvertTranslation = true;

			Interval total_time = m_max_interface->GetAnimRange();
			int start_frame;
			int end_frame;

			TIME_TO_FRAME(total_time.Start(), start_frame);
			TIME_TO_FRAME(total_time.End(), end_frame);


			prefs->m_convertRotationJoint = true;
			prefs->m_convertTranslationJoint = true;
			prefs->m_rotationConvertType = JointPreference::LinearKeyframeType;
			prefs->m_translationConvertType = JointPreference::LinearKeyframeType;

			prefs->m_optimizeRotation = true;
			prefs->m_rotationThreshold = 0.3f; 
			prefs->m_rotationSampleStartFrame = start_frame;
			prefs->m_rotationSampleEndFrame = end_frame;


			prefs->m_optimizeTranslation = true;
			prefs->m_translationThreshold = 0.05f;
			prefs->m_translationSampleStartFrame = start_frame;
			prefs->m_translationSampleEndFrame = end_frame;

			prefs->m_rotationRange = false;
			prefs->m_translationRange = false;
		}


		// Detect if translation is there

		// Detect if rotation is there


	}

	Verify(prefs->m_decodeWithVelocity == true || prefs->m_decodeWithVelocity == false);

}

//===========================================================================//


bool JointEditDialog::NodeIsRoot(INode* node)
{
	// root node defined as being a child to theworld
	if (m_max_interface->GetRootNode() == node->GetParentNode())
	{
		return true;
	}

	return false;
}
//===========================================================================//

bool JointEditDialog::KnownNode(INode* node)
{
	ObjectState os;
	SClass_ID SCID;
	Class_ID CID;

	os = node->EvalWorldState(m_max_interface->GetTime());
	
	if (os.obj)
	{
		SCID = os.obj->SuperClassID();
		CID = os.obj->ClassID();
		switch (SCID)
		{
			case GEOMOBJECT_CLASS_ID:
				return true;

			case HELPER_CLASS_ID:
				if (CID == Class_ID(DUMMY_CLASS_ID,0) || CID == Class_ID(BONE_CLASS_ID, 0)
					||CID == SITEOBJECT_CLASS_ID)
				{
					return true;
				}
				break;
		}
	}
	
	return false;
	
}                                                                                                                                                                                                                                                                                                                                                                       

//===========================================================================//


bool 
	JointEditDialog::HasKnownControler(INode *node)
{
	Control *c;
	c = node->GetTMController();

	// If known consists of .. is the top a leaf node? if so is it a PRS_CONTROL_CLASS_ID ?
	// If it is a prs, are both the p & r known to me?
	// we ignore scale.


	// This works but...MAN...do we need Euelers now!


	// Check leaf, if it is not a leaf ( leaf is the last node on a branch, imagine )
	// then it must be procedural and wierd.  That would mean that it has one controller
	// for position, rotation and scale
	if (c->IsLeaf())
	{
		return false;
	}

	// Make sure it is a Position Rotation Scale control class, since we don't support hybreeds.
	if (c->ClassID().PartA() != PRS_CONTROL_CLASS_ID)
	{
		return false;
	}



	if (
			IsKnownControlerType(c->GetRotationController()) && 
			IsKnownControlerType(c->GetPositionController())
		)
	{
		return true;
	}


	// We didn't know it so 
	// it is hasta la vista ( ?sp? )

	return false;
}

//===========================================================================//

bool 
	JointEditDialog::IsKnownControlerType(Control *c)
{
	if ( c == NULL )
	{
		return false;
	}
	
	switch(c->ClassID().PartA())
	{
		case LININTERP_POSITION_CLASS_ID:
		case LININTERP_ROTATION_CLASS_ID:
			return true;
	}

	return false;
}


//===========================================================================//

bool JointEditDialog::NodeAnimated(INode* node)
{
	// this does not correctly get bones....
	// only way to tell is to spin through them...


#if 0
	ObjectState os;
	SClass_ID SCID;
	Class_ID CID;

	os = node->EvalWorldState(0);
	
	if (os.obj)
	{
		SCID = os.obj->SuperClassID();
		CID = os.obj->ClassID();
		

		if ((SCID == HELPER_CLASS_ID) && (CID == Class_ID(BONE_CLASS_ID, 0)))
		{

			if (node->IsAnimated())
			{
				return true;
			}

			Interval iv = m_max_interface->GetAnimRange();
			
			TimeValue start = iv.Start();
			TimeValue end = iv.End();
			int delta = GetTicksPerFrame();

			Matrix3 lastTM = node->GetNodeTM(start);

			for (int time_of_key=start; time_of_key<=end; time_of_key+=delta)
			{
				Matrix3 nodeTM;
				nodeTM = node->GetNodeTM(time_of_key);
				

				for (int i = 0; i < 4; ++i)
				{
					Point3 m1 = nodeTM.GetRow(i);
					Point3 m2 = lastTM.GetRow(i);

					if (m1 != m2)
					{
						return true;
					}
				}

				lastTM = nodeTM;
			}
		}
	}


	return (node->IsAnimated())?true:false;

#endif 

	//just evaluate the name

	//cull out sites unless they are animated...
	//cull out anything not joint_

	const char *node_name = node->GetName();

	if (!_stricmp(node_name, "joint_world"))
	{
		return false;
	}


	if (!_stricmp(node_name, "joint_lgunabove"))
	{
		return false;
	}
	if (!_stricmp(node_name, "joint_luarmabove"))
	{
		return false;
	}
	if (!_stricmp(node_name, "joint_rgunabove"))
	{
		return false;
	}
	if (!_stricmp(node_name, "joint_ruarmabove"))
	{
		return false;
	}
	if (!_stricmp(node_name, "joint_torsoabove"))
	{
		return false;
	}
	if (!_stricmp(node_name, "joint_torsobelow"))
	{
		return false;
	}
	if (!_stricmp(node_name, "joint_hipabove"))
	{
		return false;
	}
	if (!_stricmp(node_name, "joint_hipbelow"))
	{
		return false;
	}



	if (!_strnicmp(node_name, "joint_", 6))
	{
		return true;
	}
	
	if (!_strnicmp(node_name, "site_", 5))
	{
		if (node_name)
		{

			ObjectState os;
			os = node->EvalWorldState(0);
			SClass_ID SCID;
			Class_ID CID;

			if (os.obj)
			{
				SCID = os.obj->SuperClassID();
				CID = os.obj->ClassID();
				if (SCID == HELPER_CLASS_ID && CID == SITEOBJECT_CLASS_ID)
				{
					IParamBlock *pb = (IParamBlock*)os.obj->GetParamBlock(); 
					
					return (pb->IsAnimated())?true:false;
				}
			}
		}
		return false;
	}



	//deal with life then move on.

	return false;
}



void JointEditDialog::OnConvertRotCheck() 
{
	CButton *button = (CButton *)GetDlgItem(IDC_CONVERT_ROT_CHECK);
	
	if (button->GetCheck())
	{
		GetDlgItem(IDC_COMBO_ROT_CONVERT)->EnableWindow(true);
		CComboBox *box = (CComboBox *)GetDlgItem(IDC_COMBO_ROT_CONVERT);
		box->SetCurSel( 2 );
	}
	else
	{
		GetDlgItem(IDC_COMBO_ROT_CONVERT)->EnableWindow(false);
		CComboBox *box = (CComboBox *)GetDlgItem(IDC_COMBO_ROT_CONVERT);
		box->SetCurSel( -1 );
	}

}

void JointEditDialog::OnCheckRotOpt() 
{
	CButton *button = (CButton *)GetDlgItem(IDC_CHECK_ROT_OPT);
	if (button->GetCheck())
	{
		GetDlgItem(IDC_EDIT_ROT_THRESH)->EnableWindow(true);
		GetDlgItem(IDC_CHECK_ROT_RANGE)->EnableWindow(true);

		CEdit *edit = (CEdit *)GetDlgItem(IDC_EDIT_ROT_THRESH);
		edit->SetWindowText("0.3");

	}
	else
	{
		GetDlgItem(IDC_EDIT_ROT_THRESH)->EnableWindow(false);
		GetDlgItem(IDC_CHECK_ROT_RANGE)->EnableWindow(false);

		CEdit *edit = (CEdit *)GetDlgItem(IDC_EDIT_ROT_THRESH);
		edit->SetWindowText("");

		CButton *button = (CButton *)GetDlgItem(IDC_CHECK_ROT_RANGE);
	
		if (button->GetCheck())
		{
			button->SetCheck(0);
			GetDlgItem(IDC_ROT_MIN_RANGE)->EnableWindow(false);
			GetDlgItem(IDC_ROT_MAX_RANGE)->EnableWindow(false);
			CEdit *edit;
			edit = (CEdit *)GetDlgItem(IDC_ROT_MIN_RANGE);
			edit->SetWindowText("");
			edit = (CEdit *)GetDlgItem(IDC_ROT_MAX_RANGE);
			edit->SetWindowText("");
		}

	}
}


void JointEditDialog::OnCheckRotRange() 
{

	CButton *button = (CButton *)GetDlgItem(IDC_CHECK_ROT_RANGE);
	
	if (button->GetCheck())
	{
		GetDlgItem(IDC_ROT_MIN_RANGE)->EnableWindow(true);
		GetDlgItem(IDC_ROT_MAX_RANGE)->EnableWindow(true);
		
		Interval total_time = m_max_interface->GetAnimRange();
		int start_frame;
		int end_frame;

		TIME_TO_FRAME(total_time.Start(), start_frame);
		TIME_TO_FRAME(total_time.End(), end_frame);
		
		char buffer[20];
		CEdit *edit;

		sprintf(buffer, "%d", start_frame);
		edit = (CEdit *)GetDlgItem(IDC_ROT_MIN_RANGE);
		edit->SetWindowText(buffer);

		sprintf(buffer, "%d", end_frame);
		edit = (CEdit *)GetDlgItem(IDC_ROT_MAX_RANGE);
		edit->SetWindowText(buffer);

	}
	else
	{
		GetDlgItem(IDC_ROT_MIN_RANGE)->EnableWindow(false);
		GetDlgItem(IDC_ROT_MAX_RANGE)->EnableWindow(false);
		CEdit *edit;
		edit = (CEdit *)GetDlgItem(IDC_ROT_MIN_RANGE);
		edit->SetWindowText("");
		edit = (CEdit *)GetDlgItem(IDC_ROT_MAX_RANGE);
		edit->SetWindowText("");

	}
}

void JointEditDialog::OnConvertTranCheck() 
{
	CButton *button = (CButton *)GetDlgItem(IDC_CONVERT_TRAN_CHECK);
	
	if (button->GetCheck())
	{
		GetDlgItem(IDC_COMBO_TRAN_CONVERT)->EnableWindow(true);
		CComboBox *box = (CComboBox *)GetDlgItem(IDC_COMBO_TRAN_CONVERT);
		box->SetCurSel( 2 );
	}
	else
	{
		GetDlgItem(IDC_COMBO_TRAN_CONVERT)->EnableWindow(false);
		CComboBox *box = (CComboBox *)GetDlgItem(IDC_COMBO_TRAN_CONVERT);
		box->SetCurSel( -1 );
	}
	
}

void JointEditDialog::OnCheckTranOpt() 
{

	CButton *button = (CButton *)GetDlgItem(IDC_CHECK_TRAN_OPT);
	if (button->GetCheck())
	{
		GetDlgItem(IDC_EDIT_TRAN_THRESH)->EnableWindow(true);
		GetDlgItem(IDC_CHECK_TRAN_RANGE)->EnableWindow(true);
		
		CEdit *edit = (CEdit *)GetDlgItem(IDC_EDIT_TRAN_THRESH);
		edit->SetWindowText("0.05");

	}
	else
	{
		GetDlgItem(IDC_EDIT_TRAN_THRESH)->EnableWindow(false);
		GetDlgItem(IDC_CHECK_TRAN_RANGE)->EnableWindow(false);
	

		CEdit *edit = (CEdit *)GetDlgItem(IDC_EDIT_TRAN_THRESH);
		edit->SetWindowText("");

		CButton *button = (CButton *)GetDlgItem(IDC_CHECK_TRAN_RANGE);
	
		if (button->GetCheck())
		{
			button->SetCheck(0);
			GetDlgItem(IDC_TRAN_MIN_RANGE)->EnableWindow(false);
			GetDlgItem(IDC_TRAN_MAX_RANGE)->EnableWindow(false);
			CEdit *edit;
			edit = (CEdit *)GetDlgItem(IDC_TRAN_MIN_RANGE);
			edit->SetWindowText("");
			edit = (CEdit *)GetDlgItem(IDC_TRAN_MAX_RANGE);
			edit->SetWindowText("");
		}
	
	}
}

void JointEditDialog::OnCheckTranRange() 
{

	CButton *button = (CButton *)GetDlgItem(IDC_CHECK_TRAN_RANGE);
	
	if (button->GetCheck())
	{
		GetDlgItem(IDC_TRAN_MIN_RANGE)->EnableWindow(true);
		GetDlgItem(IDC_TRAN_MAX_RANGE)->EnableWindow(true);

		Interval total_time = m_max_interface->GetAnimRange();
		int start_frame;
		int end_frame;

		TIME_TO_FRAME(total_time.Start(), start_frame);
		TIME_TO_FRAME(total_time.End(), end_frame);
		
		char buffer[20];
		CEdit *edit;

		sprintf(buffer, "%d", start_frame);
		edit = (CEdit *)GetDlgItem(IDC_TRAN_MIN_RANGE);
		edit->SetWindowText(buffer);

		sprintf(buffer, "%d", end_frame);
		edit = (CEdit *)GetDlgItem(IDC_TRAN_MAX_RANGE);
		edit->SetWindowText(buffer);

	}
	else
	{
		GetDlgItem(IDC_TRAN_MIN_RANGE)->EnableWindow(false);
		GetDlgItem(IDC_TRAN_MAX_RANGE)->EnableWindow(false);
		CEdit *edit;
		edit = (CEdit *)GetDlgItem(IDC_TRAN_MIN_RANGE);
		edit->SetWindowText("");
		edit = (CEdit *)GetDlgItem(IDC_TRAN_MAX_RANGE);
		edit->SetWindowText("");

	}
}


	

	

////////////////////////////////////////////////////////////////////////////////

int
	JointEditDialog::CountChildren(
		INode *node
	)
{


	// Me
	int total_count = 1;

	// and all my children
	for (int i = 0; i < node->NumberOfChildren(); i++)
	{
		INode *child_node = node->GetChildNode(i);
		assert(child_node != NULL);
		total_count += CountChildren(child_node);
	}

	return total_count;
}

