// TODO: check this is working and use it with ONI recordings??
void ofxOpenNIContext::enableLogging() {
	
	XnStatus result = xnLogSetConsoleOutput(true);
	SHOW_RC(result, "Set console output");
	
	result = xnLogSetSeverityFilter(XN_LOG_ERROR);	// TODO: set different log levels with code; enable and disable functionality
	SHOW_RC(result, "Set log level");

	xnLogSetMaskState(XN_LOG_MASK_ALL, TRUE);
	
}
// we need to programmatically add a license when playing back a recording
// file otherwise the skeleton tracker will throw an error and not work
void ofxOpenNIContext::addLicense(std::string sVendor, std::string sKey) {
	
	XnLicense license = {0};
	XnStatus status = XN_STATUS_OK;
	
	status = xnOSStrNCopy(license.strVendor, sVendor.c_str(),sVendor.size(), sizeof(license.strVendor));
	if(status != XN_STATUS_OK) {
		printf("ofxOpenNIContext error creating license (vendor)\n");
		return;
	}
	
	status = xnOSStrNCopy(license.strKey, sKey.c_str(), sKey.size(), sizeof(license.strKey));
	if(status != XN_STATUS_OK) {
		printf("ofxOpenNIContext error creating license (key)\n");
		return;
	}	
	
	status = context.AddLicense(license);
	SHOW_RC(status, "AddLicense");
	
	xnPrintRegisteredLicenses();
	
}
//----------------------------------------
bool ofxOpenNITracker::setup(ofxOpenNI & _openNI){
	openNI = &_openNI;

	if (!openNI->getDepthGenerator().IsValid()){
		ofLogError(LOG_NAME) << "no depth generator present";
		return false;
	}

	XnStatus result = XN_STATUS_OK;

	// get map_mode so we can setup width and height vars from depth gen size
	XnMapOutputMode map_mode;
	openNI->getDepthGenerator().GetMapOutputMode(map_mode);

	width = map_mode.nXRes;
	height = map_mode.nYRes;

	// set update mask pixels default to false
	//useMaskPixels = false;

	// setup mask pixels array TODO: clean this up on closing or dtor
	//including 0 as all users
	//for (int user = 0; user <= MAX_NUMBER_USERS; user++) {
	//	maskPixels[user] = new unsigned char[width * height];
	//}

	// set update cloud points default to false
	/*cloudPoints.resize(MAX_NUMBER_USERS);

	// setup cloud points array TODO: clean this up on closing or dtor
	// including 0 as all users
	for (int user = 0; user <= MAX_NUMBER_USERS; user++) {
		cloudPoints[user].getVertices().resize(width * height);
		cloudPoints[user].getColors().resize(width * height);
		cloudPoints[user].setMode(OF_PRIMITIVE_POINTS);
	}*/

	// if one doesn't exist then create user generator.
	result = user_generator.Create(openNI->getXnContext());
	SHOW_RC(result, "Create user generator");

	if (result != XN_STATUS_OK) return false;

	// register user callbacks
	XnCallbackHandle user_cb_handle;
	user_generator.RegisterUserCallbacks(
		 User_NewUser
		,User_LostUser
		,this
		,user_cb_handle
	);

	XnCallbackHandle calibration_cb_handle;
	/*user_generator.GetSkeletonCap().RegisterToCalibrationStart(
		 UserCalibration_CalibrationStart
		,this
		,calibration_cb_handle
	);

	user_generator.GetSkeletonCap().RegisterToCalibrationComplete(
			UserCalibration_CalibrationEnd
			,this
			,calibration_cb_handle
	);*/

	// check if we need to pose for calibration
	if(user_generator.GetSkeletonCap().NeedPoseForCalibration()) {

		needs_pose = true;

		if(!user_generator.IsCapabilitySupported(XN_CAPABILITY_POSE_DETECTION)) {
			ofLogError(LOG_NAME) << "Pose required, but not supported";
			return false;
		}

		XnCallbackHandle user_pose_cb_handle;

/*user_generator.GetPoseDetectionCap().RegisterToPoseDetected(
			 UserPose_PoseDetected
			,this
			,user_pose_cb_handle
		);*/

		user_generator.GetSkeletonCap().GetCalibrationPose(calibration_pose);

	}

	user_generator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_ALL);

	// needs this to allow skeleton tracking when using pre-recorded .oni or nodes init'd by code (as opposed to xml)
	// as otherwise the image/depth nodes play but are not generating callbacks
	//if (context->isUsingRecording()) {
	result = openNI->getXnContext().StartGeneratingAll();
	SHOW_RC(result, "StartGenerating");
	if (result != XN_STATUS_OK) return false;

	return true;
}
// Setup the user generator.
//----------------------------------------
bool ofxUserGenerator::setup( ofxOpenNIContext* pContext) {

    // store context and generator references
    context	= pContext;
    context->getDepthGenerator(&depth_generator);
    context->getImageGenerator(&image_generator);

    XnStatus result = XN_STATUS_OK;

    // get map_mode so we can setup width and height vars from depth gen size
    XnMapOutputMode map_mode;
    depth_generator.GetMapOutputMode(map_mode);

    width = map_mode.nXRes;
    height = map_mode.nYRes;

    // set update mask pixels default to false
    useMaskPixels = false;

    // setup mask pixels array TODO: clean this up on closing or dtor
    for (int user = 0; user < MAX_NUMBER_USERS; user++) {
        maskPixels[user] = new unsigned char[width * height];
    }

    // set update cloud points default to false
    useCloudPoints = false;

    // setup cloud points array TODO: clean this up on closing or dtor
    for (int user = 0; user < MAX_NUMBER_USERS; user++) {
        cloudPoints[user] = new ofPoint[width * height];
        cloudColors[user] = new ofColor[width * height];
    }

    // check if the USER generator exists.
    if(!context->getUserGenerator(&user_generator)) {

        // if one doesn't exist then create user generator.
        result = user_generator.Create(context->getXnContext());
        SHOW_RC(result, "Create user generator");

        if(result != XN_STATUS_OK) {
            return false;
        }
    }

    // register user callbacks
    XnCallbackHandle user_cb_handle;
    user_generator.RegisterUserCallbacks(
        User_NewUser
        ,User_LostUser
        ,this
        ,user_cb_handle
    );

    XnCallbackHandle calibration_cb_handle;
    user_generator.GetSkeletonCap().RegisterCalibrationCallbacks(
        UserCalibration_CalibrationStart
        ,UserCalibration_CalibrationEnd
        ,this
        ,calibration_cb_handle
    );

    // check if we need to pose for calibration
    if(user_generator.GetSkeletonCap().NeedPoseForCalibration()) {

        needs_pose = true;

        if(!user_generator.IsCapabilitySupported(XN_CAPABILITY_POSE_DETECTION)) {
            printf("Pose required, but not supported!\n");
            return false;
        }

        XnCallbackHandle user_pose_cb_handle;

        user_generator.GetPoseDetectionCap().RegisterToPoseCallbacks(
            UserPose_PoseDetected
            ,NULL
            ,this
            ,user_pose_cb_handle
        );

        user_generator.GetSkeletonCap().GetCalibrationPose(calibration_pose);

    }

    user_generator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_ALL);

    // needs this to allow skeleton tracking when using pre-recorded .oni or nodes init'd by code (as opposed to xml)
    // as otherwise the image/depth nodes play but are not generating callbacks
    //if (context->isUsingRecording()) {
    result = context->getXnContext().StartGeneratingAll();
    CHECK_RC(result, "StartGenerating");

    // pre-generate the tracked users.
    for(int i = 0; i < MAX_NUMBER_USERS; ++i) {
        printf("Creting user: %i\n", i+1);
        ofxTrackedUser* tracked_user = new ofxTrackedUser(context);
        tracked_users[i] = tracked_user;
    }

    return true;
}