/**



*/

#include  "OpenNiDevice.h"

#include  "common++.h"
#include  "xtools++.h"



using namespace jbxl;



#ifndef  DISABLE_OPENNI




COpenNiDevice::COpenNiDevice(void)
{
	context		 = NULL;
	image		 = NULL;
	user		 = NULL;
	depth		 = NULL;
	player		 = NULL;

	imageMD		 = NULL;
	depthMD		 = NULL;
	sceneMD		 = NULL;

	//imageData	 = NULL;
	//depthData	 = NULL;

	m_has_camera = TRUE;
	m_err_mesg	 = make_Buffer(LMESG);		
}



BOOL  COpenNiDevice::init(BOOL use_image)
{
    outputMode.nXRes = OPENNI_DEPTH_XSIZE; 
    outputMode.nYRes = OPENNI_DEPTH_YSIZE; 
    outputMode.nFPS	 = OPENNI_DEPTH_FPS; 

	BOOL ret = create_Context();
	if (ret && use_image) create_Image();
	if (ret) ret = create_Depth();
//	if (ret) ret = create_User();

	return ret;
}



BOOL  COpenNiDevice::init(char* fname, BOOL use_image)
{
	if (fname==NULL) {
		copy_s2Buffer("COpenNiDevice::init ERROR: File name is NULL", &m_err_mesg);
		return FALSE;
	}

	//
	BOOL ret = create_Context(fname);
	if (ret) ret = create_Player(TRUE);
	if (!ret) return FALSE;	
	
	//
	xn::NodeInfoList nodeList;
	player->EnumerateNodes(nodeList);

	for (xn::NodeInfoList::Iterator node=nodeList.Begin(); node!=nodeList.End(); node++) {
		if ((*node).GetDescription().Type==XN_NODE_TYPE_IMAGE) {
			if (use_image) {
				ret = create_Image(TRUE);
				if (!ret) break;
			}
		}
		if ((*node).GetDescription().Type==XN_NODE_TYPE_DEPTH) {
			ret = create_Depth(TRUE);
			if (!ret) break;
		}
	}

	//
	if (image!=NULL && use_image) {
		image->GetMapOutputMode(outputMode);
	}
	else if (depth!=NULL) {
		depth->GetMapOutputMode(outputMode);
	}
	else {
		copy_s2Buffer("COpenNiDevice::init ERROR: No Generators", &m_err_mesg);
		return FALSE;
	}


	return TRUE;
}




void  COpenNiDevice::free(void)
{
	delete_User();
	delete_Depth();
	delete_Image();
	delete_Player();
	delete_Context();

	free_Buffer(&m_err_mesg);

	//if (imageData!=NULL) free(imageData);
	//if (depthData!=NULL) free(depthData);
	//imageData = NULL;
	//depthData = NULL;
}





////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create/Delete Generators

BOOL  COpenNiDevice::create_Context(char* fname)
{
	if (context==NULL) {
		context = new xn::Context();
		if (context==NULL) {
			copy_s2Buffer("COpenNiDevice::create_Context ERROR: context is NULL", &m_err_mesg);
			return FALSE;
		}
	}

	XnStatus rc = context->Init();
	if (rc==XN_STATUS_OK && fname!=NULL) rc = context->OpenFileRecording(fname);

	if (rc!=XN_STATUS_OK) {
		copy_s2Buffer("COpenNiDevice::create_Context ERROR: ", &m_err_mesg);
		cat_s2Buffer (::xnGetStatusString(rc), &m_err_mesg);
		return FALSE;
	}

	return TRUE;
}



BOOL  COpenNiDevice::create_Image(BOOL easy)
{
	if (!m_has_camera) return FALSE;

	if (context==NULL) {
		copy_s2Buffer("COpenNiDevice::create_Image ERROR: context is NULL", &m_err_mesg);
		return FALSE;
	}

	if (image==NULL) {
		image = new xn::ImageGenerator();
		if (image==NULL) {
			copy_s2Buffer("COpenNiDevice::create_Image ERROR: fail to create image generator", &m_err_mesg);
			m_has_camera = FALSE;
			return FALSE;
		}
	}


	XnStatus rc = XN_STATUS_ERROR;
	if (easy) {
		rc = context->FindExistingNode(XN_NODE_TYPE_IMAGE, *image);
	}
	else {
		rc = image->Create(*context);
		if (rc==XN_STATUS_OK) rc = image->StartGenerating();
		if (rc==XN_STATUS_OK) rc = image->SetMapOutputMode(outputMode); 
	}

	if (rc!=XN_STATUS_OK) {
		copy_s2Buffer("COpenNiDevice::create_Image ERROR: ", &m_err_mesg);
		cat_s2Buffer (::xnGetStatusString(rc), &m_err_mesg);
		delete_Image();
		return FALSE;
	}

	imageMD = new xn::ImageMetaData();
	//imageData = (uByte*)malloc(outputMode.nXRes*outputMode.nYRes*3);

	return TRUE;
}




BOOL  COpenNiDevice::create_Depth(BOOL easy)
{
	if (context==NULL) {
		copy_s2Buffer("COpenNiDevice::create_Depth ERROR: context is NULL", &m_err_mesg);
		return FALSE;
	}

	if (depth==NULL) {
		depth = new xn::DepthGenerator();
		if (depth==NULL) {
			copy_s2Buffer("COpenNiDevice::create_Depth ERROR: fail to create depth generator", &m_err_mesg);
			return FALSE;
		}
	}

	XnStatus rc = XN_STATUS_ERROR;
	if (easy) {
		rc = context->FindExistingNode(XN_NODE_TYPE_DEPTH, *depth);
	}
	else {
		rc = depth->Create(*context);
		if (rc==XN_STATUS_OK) rc = depth->StartGenerating();
		if (rc==XN_STATUS_OK) rc = depth->SetMapOutputMode(outputMode);
		if (rc==XN_STATUS_OK && image!=NULL) {
			rc = depth->GetAlternativeViewPointCap().SetViewPoint(*image);
			/*if (rc==XN_STATUS_OK && depth->IsCapabilitySupported(XN_CAPABILITY_FRAME_SYNC)) {
				if (depth->GetFrameSyncCap().CanFrameSyncWith(*image)) {
					rc = depth->GetFrameSyncCap().FrameSyncWith(*image);
				}
			}*/
		}
	}
	
	if (rc!=XN_STATUS_OK) {
		copy_s2Buffer("COpenNiDevice::create_Depth ERROR: ", &m_err_mesg);
		cat_s2Buffer (::xnGetStatusString(rc), &m_err_mesg);
		delete_Depth();
		return FALSE;
	}

	depthMD = new xn::DepthMetaData();
	//depthData = (XnLabel*)malloc(outputMode.nXRes*outputMode.nYRes*sizeof(XnLabel));

	return TRUE;
}



BOOL  COpenNiDevice::create_User(BOOL easy)
{
	if (context==NULL) {
		copy_s2Buffer("COpenNiDevice::create_User ERROR: context is NULL", &m_err_mesg);
		return FALSE;
	}

	if (user==NULL) {
		user = new xn::UserGenerator();
		if (user==NULL) {
			copy_s2Buffer("COpenNiDevice::create_User ERROR: fail to create user generator", &m_err_mesg);
			return FALSE;
		}
	}

	XnStatus rc = XN_STATUS_ERROR;
	if (easy) {
		rc = context->FindExistingNode(XN_NODE_TYPE_USER, *user);
	}
	else {
		rc = user->Create(*context);
		if (rc==XN_STATUS_OK) rc = user->StartGenerating();
	}

	if (rc!=XN_STATUS_OK) {
		copy_s2Buffer("COpenNiDevice::create_User ERROR: ", &m_err_mesg);
		cat_s2Buffer (::xnGetStatusString(rc), &m_err_mesg);
		delete_User();
		return FALSE;
	}

	sceneMD = new xn::SceneMetaData();
	return TRUE;
}



BOOL  COpenNiDevice::create_Player(BOOL easy)
{
	if (context==NULL) {
		copy_s2Buffer("COpenNiDevice::create_Player ERROR: context is NULL", &m_err_mesg);
		return FALSE;
	}	

	if (player==NULL) {
		player = new xn::Player();
		if (player==NULL) {
			copy_s2Buffer("COpenNiDevice::create_Player ERROR: fail to create player generator", &m_err_mesg);
			return FALSE;
		}
	}

	XnStatus rc = XN_STATUS_ERROR;
	if (easy) {
		rc = context->FindExistingNode(XN_NODE_TYPE_PLAYER, *player);
	}
	else {
		rc = player->Create(*context, "oni");
	}
	
	if (rc!=XN_STATUS_OK) {
		copy_s2Buffer("COpenNiDevice::create_Player EROR: ", &m_err_mesg);
		cat_s2Buffer (::xnGetStatusString(rc), &m_err_mesg);
		delete_Player();
		return FALSE;
	}

	return TRUE;
}




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Delete Generators

void  COpenNiDevice::delete_Context(void)
{
	if (context!=NULL) {
		context->Release();
		delete(context);
	}
	context = NULL;
}



void  COpenNiDevice::delete_Image(void)
{
	if (image!=NULL) {
		if (image->IsValid()) {
			if (image->IsGenerating()) image->StopGenerating();
		}
		image->Release();
		delete(image);
	}
	if (imageMD!=NULL) delete(imageMD);

	image   = NULL;
	imageMD = NULL;
}



void  COpenNiDevice::delete_Depth(void)
{
	if (depth!=NULL) {
		if (depth->IsValid()) {
			if (depth->IsGenerating()) depth->StopGenerating();
		}
		depth->Release();
		delete(depth);
	}
	if (depthMD!=NULL) delete(depthMD);

	depth   = NULL;
	depthMD = NULL;
}



void  COpenNiDevice::delete_User(void)
{
	if (user!=NULL) {
		if (user->IsValid()) {
			if (user->IsGenerating()) user->StopGenerating();
		}
		user->Release();
		delete(user);
	}
	if (sceneMD!=NULL) delete(sceneMD);

	user    = NULL;
	sceneMD = NULL;
}



void	COpenNiDevice::delete_Player(void)
{
	if (player!=NULL) {
		player->Release();
		delete(player);
		player = NULL;	
	}	
}






#endif		// ifndef DISABLE_OPENNI