
#include  "WinBaseLib.h"
#include  "NiFileTool.h"
#include  "MFCio.h"




using namespace jbxl;
using namespace jbxwl;





CNiFileTool::~CNiFileTool(void)
{ 
	close_wfile(); 
	close_rfile();

	clearFrameData();
	
	if (JTXT_Tool!=NULL) delete(JTXT_Tool);
	if (VMD_Tool!=NULL)   delete(VMD_Tool);
	if (BVH_Tool!=NULL)   delete(BVH_Tool);
}





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

void  CNiFileTool::clear_data(void)
{
	m_enable_wfile	= FALSE;
	m_wfp			= NULL;
	m_rfp			= NULL;
	m_lib			= NiSDK_None;

	frame_data		= NULL;
	frame_start		= 0;
	frame_num		= 0;
	frame_ptr		= 0;

	frame_timer		= 0;
	lap_timer		= 0;
	play_time		= 0.0f;
	time_scale		= 1.0f;

	clearStartPosition();
	clearJointsData();

	JTXT_Tool		= NULL;
	VMD_Tool		= NULL;
	BVH_Tool		= NULL;
}



void  CNiFileTool::init(NiSDK_Lib lib)
{
	//
	m_lib = lib;
	
	//
	JTXT_Tool = new CJTextTool();
	VMD_Tool  = new CVMDTool();
	BVH_Tool  = new CBVHTool();
	
	frameTool = NULL;
}




BOOL  CNiFileTool::open_wfile(LPCTSTR fname)
{
	if (m_enable_wfile) return TRUE;

	if (m_wfp!=NULL) return FALSE;
	m_wfp = tfopen(fname, _T("wb"));
	if (m_wfp==NULL) return FALSE;

	//
	JTXT_Tool->writeHeader(m_wfp);

	m_enable_wfile = TRUE;
	return TRUE;
}



BOOL  CNiFileTool::open_rfile(LPCTSTR fname)
{
	if (m_rfp!=NULL) return FALSE;
	m_rfp = tfopen(fname, _T("rb"));
	if (m_rfp==NULL) return FALSE;

	return TRUE;
}



void  CNiFileTool::close_wfile(void)
{
	if (m_wfp!=NULL) {
		fclose(m_wfp);
		m_wfp = NULL;
		m_enable_wfile = FALSE;
	}
}



void  CNiFileTool::close_rfile(void)
{
	if (m_rfp!=NULL) {
		fclose(m_rfp);
		m_rfp = NULL;
	}
}





///////////////////////////////////////////////////////////////////////////////////////////////////
//
// I/O
//

int  CNiFileTool::readJointsTextFile(LPCTSTR fname)
{
	if (fname==NULL) return -1;
	clearFrameData();
	if (JTXT_Tool==NULL) JTXT_Tool = new CJTextTool();

	BOOL ret = open_rfile(fname);
	if (!ret) return -2;

	ret = JTXT_Tool->readFile(m_rfp);
	close_rfile();
	if (!ret) return -3;

	frame_data = JTXT_Tool->getJointsFrame();
	if (frame_data==NULL) return -4;
	frame_num = JTXT_Tool->getFrameNumber();
	frameTool = JTXT_Tool;

	play_time = (frame_data[frame_num-1].msec - frame_data[0].msec)/1000.f;
	return frame_num;
}



void  CNiFileTool::writeJointsText(Vector<double>* pos, Quaternion* rot, BOOL mirror)
{
	if (m_wfp==NULL) return;

	JTXT_Tool->setPosVect(pos, m_lib, mirror);
	JTXT_Tool->setRotQuat(rot, m_lib, mirror);
	JTXT_Tool->writeData(m_wfp, GetMsecondsTimer());	

	return;
}




BOOL  CNiFileTool::saveAsJointsText(LPCTSTR fname, LPCTSTR backup)
{
	return copyFileWithCounter(fname, backup);
}





///////////////////////////////////////////////////////////////////////////////////////////////////
//
// BVH
//

int  CNiFileTool::readBVHFile(LPCTSTR fname)
{
	if (fname==NULL) return -1;
	clearFrameData();
	if (BVH_Tool==NULL) BVH_Tool = new CBVHTool();

	BOOL ret = open_rfile(fname);
	if (!ret) return -2;

	ret = BVH_Tool->readFile(m_rfp);
	close_rfile();
	if (!ret) return -3;

	frame_data = BVH_Tool->getJointsFrame();
	if (frame_data==NULL) return -4;
	frame_num = BVH_Tool->getFrameNumber();
	frameTool = BVH_Tool;

	play_time = (frame_data[frame_num-1].msec - frame_data[0].msec)/1000.f;
	return frame_num;
}




BOOL  CNiFileTool::saveAsBVH(LPCTSTR fname, LPCTSTR backup)
{

	return TRUE;
}






///////////////////////////////////////////////////////////////////////////////////////////////////
//
// MMD VMD
//

int  CNiFileTool::readVMDFile(LPCTSTR fname)
{
	if (fname==NULL) return -1;	
	clearFrameData();
	if (VMD_Tool==NULL) VMD_Tool = new CVMDTool();

	BOOL ret = open_rfile(fname);
	if (!ret) return -2;

	ret = VMD_Tool->readFile(m_rfp);
	close_rfile();
	if (!ret) return -3;

	//
	frame_data = VMD_Tool->getJointsFrame();
	if (frame_data==NULL) return -4;
	frame_num = VMD_Tool->getFrameNumber();
	frameTool = VMD_Tool;

	play_time = (frame_data[frame_num-1].msec - frame_data[0].msec)/1000.f;
	return frame_num;
}





///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Frame
//

void  CNiFileTool::setFrame(int frame) 
{ 
	frame_start = 0;
	if (frame_num!=0) {
		frame_start = frame%frame_num;
	}

	frame_ptr = frame_start;
}




//
// Start 位置の設定とフレームデータの準備
//
BOOL  CNiFileTool::startFrame(int start)
{
	if (frame_num==0 || start<0 || start>=frame_num) return FALSE;

	lap_timer	= GetMsecondsTimer();
	frame_timer	= (int)(frame_data[start].msec*time_scale);
	setFrame(start);

	return TRUE;
}




//
// 次のフレームデータの準備
//
BOOL  CNiFileTool::nextFrame(BOOL next)		// next==TRUE フレームを進める
{
	if (next) {
		frame_ptr++;
		if (frame_ptr>frame_num) {
			// not reachable
			DEBUG_ERR("CNiFileTool::nextFrame: frame ptr = %d, frame num = %d", frame_ptr, frame_num); 
			return FALSE;
		}
	}

	//
	int msec = 0;
	if (frame_ptr==frame_num) {
		if (frame_num!=1) {
			msec = (int)((2*frame_data[frame_ptr-1].msec - frame_data[frame_ptr-2].msec)*time_scale);
		}
	}
	else {
		msec = (int)(frame_data[frame_ptr].msec*time_scale);
	}

	//
	unsigned short ctime;
	frame_timer += GetMsecondsLapTimer(lap_timer, &ctime);
	lap_timer = ctime;
	
	if (frame_timer>=msec) {
		return TRUE;
	}
	else if (msec>frame_timer+5000) {
		DEBUG_ERR("CNiFileTool::nextFrame: next frame = %d, current frame = %d", msec, frame_timer);
		return FALSE;	// 5sec 進?
	}
	
	// Wait
	do {
		::DisPatcher();
		int slptm = Min(msec-frame_timer, 100);
		if (slptm>0) ::Sleep(slptm);
		frame_timer += GetMsecondsLapTimer(lap_timer, &ctime);
		lap_timer = ctime;
	} while (msec>frame_timer);
	
	return TRUE;
}





///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Frame Data
//

void  CNiFileTool::clearFrameData(void)
{
	//
	frame_data = NULL;
	frame_num  = 0;
	frame_ptr  = 0;

	if (JTXT_Tool!=NULL) JTXT_Tool->clearData();
	if (BVH_Tool!=NULL)   BVH_Tool->clearData();
	if (VMD_Tool!=NULL)   VMD_Tool->clearData();

	frameTool  = NULL;

	return;
}





///////////////////////////////////////////////////////////////////////////////////////////////////
//
// joints
//

void  CNiFileTool::clearJointsData(void)
{
	for (int i=0; i<NI_JOINT_NUM; i++) {
		rotQuat[i].init(-1.0);
		posVect[i].init(-1.0);
	}
}




void  CNiFileTool::getFrameData(BOOL mirror, int frame)
{
	if (frame>=0) setFrame(frame);

	NiJointData* joint_data = frame_data[frame_ptr].jdat;
	int			 joint_num  = frame_data[frame_ptr].jnum;

	if (joint_data==NULL) {
		if (frameTool!=NULL) {
			joint_data = frameTool->getFrameData(frame_ptr);
			//joint_num  = frameTool->getJointNum(frame_ptr);
		}
	}
	if (joint_data==NULL) return;

	//
	for (int j=0; j<joint_num; j++) {
		int n = joint_data[j].joint;
		//
		if (n>=0 && n<NI_JOINT_NUM) {
			if (mirror) n = NiMirrorJointNum(n);
			posVect[n] = joint_data[j].vect;
			rotQuat[n] = joint_data[j].quat;
			posVect[n].c = 1.0;
			rotQuat[n].c = 1.0;
			//			
			if (mirror) {
				posVect[n].y = - posVect[n].y;
				rotQuat[n].x = - rotQuat[n].x;
				rotQuat[n].z = - rotQuat[n].z;
			}
		}
	}
	return;
}

