// AnimScriptDoc.cpp : implementation of the CAnimScriptDoc class
//

#include "stdafx.h"
#include "AnimScript.h"
#include "AnimScriptDoc.h"
#include "AnimNode.h"

#include "mw4headers.hpp"
#include "Vehicle.hpp"
#include "MechAnimationState.hpp"
#include "stuff\NotationFile.hpp"

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

extern CString g_strRoot;

CObList CAnimScriptDoc::m_listParamNodes;

/////////////////////////////////////////////////////////////////////////////
// CAnimScriptDoc

IMPLEMENT_DYNCREATE(CAnimScriptDoc, CDocument)

BEGIN_MESSAGE_MAP(CAnimScriptDoc, CDocument)
	//{{AFX_MSG_MAP(CAnimScriptDoc)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CAnimScriptDoc construction/destruction

char g_szStateNames[][40] = 
{
	// see Mw4/Code/Mw4/MechAnimationState.hpp
	"StandState",
	"StandHalfState",

	"Stand_1_8_thState",
	"Stand_2_8_thState",
	"Stand_3_8_thState",
	"Stand_5_8_thState",
	"Stand_6_8_thState",
	"Stand_7_8_thState",
	
	"ForwardState",
	"BackwardState",

	"TurnLeftState",
	"TurnRightState",

	"LGimpTurnRightState",
	"RGimpTurnRightState",
	"LGimpTurnLeftState",
	"RGimpTurnLeftState",

	"GimpStandLeftState",
	"GimpForwardLeftState",
	"GimpStandRightState",
	"GimpForwardRightState",

	"FallForwardState",
	"FallBackwardState",
	"FallLeftState",
	"FallRightState",
	"FallCataclysmicState",

	"PowerDownState",
	"PowerDownCataclysmicState",

	"CrouchState",
	"FlyState",
};

//#define STATENAME_COUNT 22

CAnimScriptDoc::CAnimScriptDoc()
{
	this->m_pSelectedNode = NULL;

	// Create all of the state nodes
	for (int x=MechWarrior4::AnimationStateEngine::StateCount;x<(MechWarrior4::MechAnimationStateEngine::StateCount);x++)
	//for (int x=0;x<MechWarrior4::MechAnimationStateEngine::DefaultData->GetStateCount();x++)
	{
		int i = x-MechWarrior4::AnimationStateEngine::StateCount;
		CAnimStateNode *pNode = new CAnimStateNode(g_szStateNames[i]);
		this->m_listStates.AddHead(pNode);
	}

	// Create all of the transition nodes (fully connected)
	POSITION posx = m_listStates.GetHeadPosition();
	while (posx)
	{
		CObject *pObj = m_listStates.GetNext(posx);
		CAnimStateNode *pAnimNodeX = (CAnimStateNode *)pObj;
	
		// Create one sided Transition states to and from this state
		CTransStateNode *pNode = new CTransStateNode(pAnimNodeX,NULL);
		m_listTransitions.AddHead(pNode);
		pNode = new CTransStateNode(NULL,pAnimNodeX);
		m_listTransitions.AddHead(pNode);

		POSITION posy = m_listStates.GetHeadPosition();
		while (posy)
		{
			pObj = m_listStates.GetNext(posy);
			CAnimStateNode *pAnimNodeY = (CAnimStateNode *)pObj;

			if (pAnimNodeX != pAnimNodeY)
			{
				pNode = new CTransStateNode(pAnimNodeX,pAnimNodeY);
				m_listTransitions.AddHead(pNode);
			}
		}
	}

	for (x=1;x<(MechWarrior4::AnimationStateEngine::AnimTypeCount);x++)
	{
		CAnimTypeNode *pNode = new CAnimTypeNode(x);
		m_listAnimTypes.AddHead(pNode);
	}
}

CAnimScriptDoc::~CAnimScriptDoc()
{
	POSITION pos = m_listStates.GetHeadPosition();
	while (pos)
	{
		CObject *pObj = m_listStates.GetNext(pos);
		CAnimStateNode *pNode = (CAnimStateNode *)pObj;
		delete pNode;
	}

	pos = m_listTransitions.GetHeadPosition();
	while (pos)
	{
		CObject *pObj = m_listTransitions.GetNext(pos);
		CTransStateNode *pNode = (CTransStateNode *)pObj;
		delete pNode;
	}
	m_listTransitions.RemoveAll();

	pos = m_listAnimTypes.GetHeadPosition();
	while (pos)
	{
		CObject *pObj = m_listAnimTypes.GetNext(pos);
		CAnimTypeNode *pNode = (CAnimTypeNode *)pObj;
		delete pNode;
	}
	m_listAnimTypes.RemoveAll();

	pos = m_listParamNodes.GetHeadPosition();
	while (pos)
	{
		CObject *pObj = m_listParamNodes.GetNext(pos);
		CParamNode*pNode = (CParamNode *)pObj;
		delete pNode;
	}
	m_listParamNodes.RemoveAll();
}

BOOL CAnimScriptDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CAnimScriptDoc serialization

void CAnimScriptDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}

/////////////////////////////////////////////////////////////////////////////
// CAnimScriptDoc diagnostics

#ifdef _DEBUG
void CAnimScriptDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CAnimScriptDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CAnimScriptDoc commands

extern char g_szParamKeyName[][40];

BOOL CAnimScriptDoc::OnOpenDocument(LPCTSTR lpszPathName) 
{
	// Be sure that all of the states are invalid
	{
		POSITION pos = m_listStates.GetHeadPosition();
		while (pos)
		{
			CAnimNode *pAnimNode = (CAnimNode *)m_listStates.GetNext(pos);
			pAnimNode->m_bValid = false;
		}
	}
	{
		POSITION pos = this->m_listTransitions.GetHeadPosition();
		while (pos)
		{
			CAnimNode *pAnimNode = (CAnimNode *)m_listTransitions.GetNext(pos);
			pAnimNode->m_bValid = false;
		}
	}
	//if (!CDocument::OnOpenDocument(lpszPathName))
	//	return FALSE;

	CString root = g_strRoot;
	CString path(lpszPathName);
	if (path.GetLength()>root.GetLength())
		path.Delete(0,root.GetLength()+1);
	SetCurrentDirectory(root);


	NotationFile *notefile = new NotationFile(lpszPathName);
	Register_Object(notefile);

	NotationFile::PageIterator *pages = notefile->MakePageIterator();
	Check_Object(pages);

	pages->First();
	Page *page = NULL;
	while (page = pages->ReadAndNext())
	{
		Check_Object(page);
		const char* anim_state_name = page->GetName();
		Check_Pointer(anim_state_name);

		
		CAnimNode *pNode = NULL;
		if (strstr(anim_state_name, "::") == NULL)
		{
			// Find the state
			POSITION pos = m_listStates.GetHeadPosition();
			while (pos)
			{
				CAnimNode *pAnimNode = (CAnimNode *)m_listStates.GetNext(pos);
				if (0==strcmpi(pAnimNode->GetName(),anim_state_name)) // (0==strncmp(pAnimNode->GetName(),anim_state_name,strlen(anim_state_name)))
				{
					pNode = pAnimNode;
					break;
				}
			}
			
			if (NULL == pNode)
				STOP(("CAnimScriptDoc::OnOpenDocument: FILE FORMAT - "+CString(anim_state_name)+" is not a valid animation state."));
		}
		else if (strstr(anim_state_name, "::") != NULL) // load the transitions
		{
			// Find the state
			POSITION pos = this->m_listTransitions.GetHeadPosition();
			while (pos)
			{
				CAnimNode *pAnimNode = (CAnimNode *)m_listTransitions.GetNext(pos);
				if (0==strcmpi(pAnimNode->GetName(),anim_state_name)) // (0==strncmp(pAnimNode->GetName(),anim_state_name,strlen(anim_state_name)))
				{
					pNode = pAnimNode;
					break;
				}
			}

			if (NULL == pNode)
				STOP(("CAnimScriptDoc::OnOpenDocument: FILE FORMAT - "+CString(anim_state_name)+" is not a valid transition state."));

			// load the transition based off of type (anim, transition or expression)			
/*			TransitionState *new_anim_state = new TransitionState(this);
			Check_Object(new_anim_state);

			new_anim_state->PreLoad(script_notefile, anim_state_name);
			anim_holder_count += new_anim_state->GetAnimHolderCount(script_notefile, anim_state_name);
			total_curve_count += new_anim_state->GetCurveCount(script_notefile, anim_state_name);

			transitionsLoaded.Add(new_anim_state);
*/
		}
		else
		{
			STOP(("CAnimScriptDoc::OnOpenDocument: INVALID CODE - SHOULD NEVER REACH HERE"));
		}

		assert(pNode);
		pNode->m_bValid = true;

//		NameList *entry_pages = notefile->MakeEntryList(anim_state_name);
//		Check_Object(entry_pages);
//		NameList::Entry *entry_page = entry_pages->FindEntry(g_szParamKeyName[PARAM_ANIMTYPE]);

		// find the CAnimTypeNode with the same name
		CAnimTypeNode *pAnimType = NULL;
		POSITION pos = m_listAnimTypes.GetHeadPosition();
		const char *pName=NULL;
		const char *pData=NULL;
		if (page->GetEntry(pName = g_szParamKeyName[PARAM_ANIMTYPE],&pData))
		{
			while (pos)
			{
				pAnimType = (CAnimTypeNode *)m_listAnimTypes.GetNext(pos);
				//pName = (char *)entry_page->GetName();
				//pData = (char *)entry_page->GetData();
				if (0 == strcmpi(pAnimType->m_strName,pData)) // (0 == strncmp(pAnimType->m_strName,pData,strlen(pData)))
				{
					// found the right Animation Type
					pNode->SetParam(PARAM_ANIMTYPE,pAnimType);
					break;
				}
			}
		}
		if (pAnimType)
			pNode->LoadState(page);
		else
			STOP(("AnimScriptDoc::OnOpenDocument: File Error" + CString(anim_state_name)+"|"+CString(pName)+"|" + pData+CString(" missing AnimType parameter")));
		//Check_Object(entry_pages);
		//delete entry_pages;
		//page = page->GetNextEntry();
	}

	Check_Object(pages);
	delete pages;

	Check_Object(notefile);
	delete notefile;
		
	return TRUE;
}


BOOL CAnimScriptDoc::OnSaveDocument(LPCTSTR lpszPathName) 
{
	NotationFile notefile;

	// Save all of the states
	{
		POSITION pos = m_listStates.GetHeadPosition();
		while (pos)
		{
			CAnimNode *pAnimNode = (CAnimNode *)m_listStates.GetNext(pos);
			pAnimNode->SaveState(&notefile);
		}
	}
	{
		POSITION pos = this->m_listTransitions.GetHeadPosition();
		while (pos)
		{
			CAnimNode *pAnimNode = (CAnimNode *)m_listTransitions.GetNext(pos);
			pAnimNode->SaveState(&notefile);
		}
	}
	notefile.SaveAs(lpszPathName);
	/*
	Check_Object(FileStreamManager::Instance);
	FileStream *file = FileStream::MakeFileStream();
	Check_Object(file);
	file->Open(lpszPathName, FileStream::WriteOnly);
	notefile->Write(file);
	file->Close();
	Check_Object(notefile);
	delete notefile;

	Check_Object(file);
	delete file;*/
	return true;
	//return CDocument::OnSaveDocument(lpszPathName);
}
