// MAXSDK.cpp: implementation of the MAXSDK class.
//
//////////////////////////////////////////////////////////////////////

#include "MAXSDK.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

TCHAR* GetString(int nId)
{
	static TCHAR szBuffer[256];

	if (hInstance)
		return LoadString(hInstance, nId, szBuffer, sizeof(szBuffer)) ? szBuffer : NULL;

	return NULL;
}

void MESSAGE(const char* lpszText)
{
	// Tell user that exporting is finished (it can take a while with no feedback)
	char szMessage[300];

	sprintf(szMessage, "MSG: %s", lpszText);
	MessageBox(GetActiveWindow(), szMessage, "Status", MB_OK);
}

//========================================================================
// Utility functions for getting/setting the personal "node index" property.
// NOTE: I'm storing a string-property because I hit a 3DSMax bug in v1.2 when I
// NOTE: tried using an integer property.
// FURTHER NOTE: those properties seem to change randomly sometimes, so I'm
// implementing my own.

Modifier* FindPhysiqueModifier(INode* lpNode)
{
	INode* pNode = lpNode; // Hungarian

	// Get object from node. Abort if no object.
	Object* pObject = pNode->GetObjectRef();
	if (!pObject) 
		return NULL;

	// Is derived object ?
	if (pObject->SuperClassID() == GEN_DERIVOB_CLASS_ID)
	{
		// Yes -> Cast.
		IDerivedObject *pDerivedObject = static_cast<IDerivedObject*> (pObject);

		// Iterate over all entries of the modifier stack.
		int nModStackIndex = 0;
		while (nModStackIndex < pDerivedObject->NumModifiers())
		{
			// Get current modifier.
			Modifier *pModifier = pDerivedObject->GetModifier(nModStackIndex);

			// Is this Physique ?
			if (pModifier->ClassID() == Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B))
			{
				// Yes -> Exit.
				return pModifier;
			}
			
			// Next modifier stack entry.
			nModStackIndex++;
		}
	}

	// Not found.
	return NULL;
}

//=============================================================
// Returns TRUE if a node should be ignored during tree traversal.
//
BOOL FUndesirableNode(INode* lpNode)
{
	// Get Node's underlying object, and object class name
	Object* pObject = lpNode->GetObjectRef();

/*
	if (lpNode->IsHidden())
		return TRUE;
*/
	if (lpNode->IsFrozen())
		return TRUE;

	// Actually, if it's not selected, pretend it doesn't exist!
	//if (!lpNode->Selected())
	//	return TRUE;

	// Don't care about lights, dummies, and cameras
	if (pObject->SuperClassID() == CAMERA_CLASS_ID)
		return TRUE;

	if (pObject->SuperClassID() == LIGHT_CLASS_ID)
		return TRUE;

	return FALSE;
}


/*

*/

static int			nINodeIndexCounts;
static LPINODEINDEX	pINodeIndexList;

void CreateINodeIndex()
{
	nINodeIndexCounts = 0;
	pINodeIndexList = NULL;
}

void ReleaseINodeIndex()
{
	if (pINodeIndexList)
	{
		free(pINodeIndexList);
		pINodeIndexList = NULL;
	}

	nINodeIndexCounts = 0;
}

int GetIndexOfINode(INode* lpNode, BOOL bAssertPropExists)
{
	LPINODEINDEX pINodeIndex = pINodeIndexList;

	TSTR strNodeName(lpNode->GetName());
	for (int i=0; i<nINodeIndexCounts; i++)
	{
		if (!strcmp(pINodeIndex->szNodeName, (char*) strNodeName))
			return pINodeIndex->nIndex;

		pINodeIndex ++;
	}
	
	if (bAssertPropExists)
		return FALSE;

	return UNDESIRABLE_NODE_MARKER;
}
	
void SetIndexOfINode(INode* lpNode, int nIndex)
{
	int			 nINodeIndex = -1;
	LPINODEINDEX pINodeIndex = pINodeIndexList;

	TSTR strNodeName(lpNode->GetName());
	for (int i=0; i<nINodeIndexCounts; i++)
	{
		if (!strcmp(pINodeIndex->szNodeName, (char*) strNodeName))
		{
			nINodeIndex = i;
			break;
		}

		pINodeIndex ++;
	}

	if (nINodeIndex == -1)
	{
		nINodeIndex = nINodeIndexCounts;
		nINodeIndexCounts ++;

		pINodeIndexList = (LPINODEINDEX) realloc(pINodeIndexList, 
			                                     sizeof(INODEINDEX) * nINodeIndexCounts);
		if (!pINodeIndexList)
			return;

		pINodeIndex = pINodeIndexList + nINodeIndex;
		strcpy(pINodeIndex->szNodeName, (char*) strNodeName);
	}

	pINodeIndex->nIndex = nIndex;
}


//=============================================================
// Returns TRUE if a node has been marked as skippable
//
BOOL FNodeMarkedToSkip(INode* lpNode)
{
	return (::GetIndexOfINode(lpNode) == UNDESIRABLE_NODE_MARKER);
}

	
//=============================================================
// Reduces a rotation to within the -2PI..2PI range.
//
float FlReduceRotation(float fl)
{
	while (fl >= TWOPI)
		fl -= TWOPI;

	while (fl <= -TWOPI)
		fl += TWOPI;

	return fl;
}



