// KINEExportClass.cpp: implementation of the CKINEExportClass class.
//
//////////////////////////////////////////////////////////////////////

#include "KINEExportClass.h"

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

#include "KINECollectNodesTEP.h"
#include "KINEDumpNodesTEP.h"
#include "KINEDumpFrameRotationsTEP.h"

#include "..\CountNodesTEP.h"
#include "..\MaxKernel.h"

#define DEFAULT_EXT _T("KNX")

CKINEExportClass::CKINEExportClass()
{
	m_pKeyFrame = NULL;
}

CKINEExportClass::~CKINEExportClass()
{
	Destroy();
}

void CKINEExportClass::Destroy()
{
	CMaxKernel::Destroy();

	ReleaseINodeIndex();
	if (m_pKeyFrame)
	{
		delete m_pKeyFrame;
		m_pKeyFrame = NULL;
	}
}

int CKINEExportClass::ExtCount()
{
	//TODO: Returns the number of file name extensions supported by the plug-in.
	return 1;
}

const TCHAR* CKINEExportClass::Ext(int n)
{
	//TODO: Return the 'i-th' file name extension (i.e. "3DS").
	return DEFAULT_EXT;
}

const TCHAR* CKINEExportClass::LongDesc()
{
	//TODO: Return long ASCII description (i.e. "Targa 2.0 Image File")
	return _T("Kniematices File Export");
}

const TCHAR* CKINEExportClass::ShortDesc()
{
	//TODO: Return short ASCII description (i.e. "Targa")
	return _T("Kniematices Export");
}

// ================================================== dummyFn()
// used by 3DS progress bar
DWORD WINAPI dummyFn(LPVOID arg)
{
    return 0;
}

int CKINEExportClass::DoExport(const TCHAR* lpszFileName, ExpInterface* lpEI, Interface* lpI, BOOL bSuppressPrompts, DWORD dwOptions)
{
	//TODO: Implement the actual file Export here and 
	//		return TRUE If the file is exported properly

	ExpInterface*	pExpInterface = lpEI;	// Hungarian
	Interface*		pInterface = lpI;		// Hungarian

    BOOL bSaveSelection = (dwOptions & SCENE_EXPORT_SELECTED);

	   // return failure if no filename provided
    if (lpszFileName == NULL)
        return FALSE;

	// Break up filename, re-assemble longer versions
	TSTR strPath, strFile, strExt;
	SplitFilename(TSTR(lpszFileName), &strPath, &strFile, &strExt);

	TCHAR szFile[MAX_PATH];
	sprintf(szFile, "%s\\%s.%s", (char*) strPath, (char*) strFile, DEFAULT_EXT);

	m_pKeyFrame = new CMaxKeyFrame;
	if (!m_pKeyFrame)
		return FALSE;

    // Extract scene information
    pInterface->ProgressStart(_T("Extracting skinning data"), TRUE, dummyFn, NULL);
    pInterface->ProgressUpdate(0);

//////////////////////////////////////////////////////////////////////
// Start Exporting
//////////////////////////////////////////////////////////////////////

	// Get animation metrics
	m_IntervalOfAnimation = pInterface->GetAnimRange();

	m_tvStart = m_IntervalOfAnimation.Start();
	m_tvEnd   = m_IntervalOfAnimation.End();

	m_pKeyFrame->SetTicksPerFrame(::GetTicksPerFrame());
	m_pKeyFrame->SetNumFrames((m_tvEnd - m_tvStart) / m_pKeyFrame->GetTicksPerFrame() + 1);

	// Reset the name-map property manager
	CreateINodeIndex();

	// Count nodes, label them, collect into array
	if (!CollectNodes(pExpInterface))
		return FALSE;

    pInterface->ProgressStart(_T("Exporting data"), TRUE, dummyFn, NULL);
    pInterface->ProgressUpdate(25);

	// Output nodes
	if (!DumpNodes(pExpInterface))
		return FALSE;

	// Output bone rotations, for each frame. Do only first frame if this is the reference frame MAX file
	DumpRotations(pExpInterface);

    pInterface->ProgressUpdate(50);

    pInterface->ProgressStart(_T("Saving data to file"), TRUE, dummyFn, NULL);
    pInterface->ProgressUpdate(75);

	m_pKeyFrame->Save(szFile);

	Destroy();

//////////////////////////////////////////////////////////////////////
// End Exporting
//////////////////////////////////////////////////////////////////////
    pInterface->ProgressUpdate(100);
    pInterface->ProgressEnd();

	return TRUE;
}

BOOL CKINEExportClass::CollectNodes(ExpInterface *lpExpInterface)
{
	// Count total nodes in the model, so I can alloc array
	// Also "brands" each node with node index, or with "skip me" marker.
	CCountNodesTEP procCountNodes;
	procCountNodes.m_nNodeCounts = 0;
	lpExpInterface->theScene->EnumTree(&procCountNodes);

	int nNumNodes = procCountNodes.m_nNodeCounts;
	if (nNumNodes == 0)
		return FALSE;

	if (!m_pKeyFrame->CreateKeys(nNumNodes))
		return FALSE;

	CMaxNodeKey* pNodeKey = (CMaxNodeKey*) m_pKeyFrame->GetNodeKeys();
	for (int i=0; i<nNumNodes; i++)
	{
		if (!pNodeKey->CreateFrames(m_pKeyFrame->GetNumFrames()))
			return FALSE;

		pNodeKey ++;
	}

	CKINECollectNodesTEP procCollectNodes;
	procCollectNodes.m_pExportClass = this;
	lpExpInterface->theScene->EnumTree(&procCollectNodes);

	return TRUE;
}

BOOL CKINEExportClass::DumpNodes(ExpInterface *lpExpInterface)
{
	// Dump node names
	CKINEDumpNodesTEP procDumpNodes;
	procDumpNodes.m_pExportClass = this;

	lpExpInterface->theScene->EnumTree(&procDumpNodes);

	return TRUE;
}

BOOL CKINEExportClass::DumpRotations(ExpInterface *lpExpInterface)
{
	// Dump bone-rotation info, for each frame
	// Also dumps root-node translation info (the model's world-position at each frame)
	CKINEDumpFrameRotationsTEP procDumpFrameRotations;
	procDumpFrameRotations.m_pExportClass = this;
	procDumpFrameRotations.m_dwTicksPerFrame = m_pKeyFrame->GetTicksPerFrame();

	for (TimeValue tv = m_tvStart; tv <= m_tvEnd; tv += m_pKeyFrame->GetTicksPerFrame())
	{
		procDumpFrameRotations.m_tvToDump = tv;
		lpExpInterface->theScene->EnumTree(&procDumpFrameRotations);
	}

	return TRUE;
}

