/**********************************************************************************
* AUTHOR		: Deepu V.
* DATE			: 22-AUG-2005
* NAME			: recognize
* DESCRIPTION	: This is the recognize call
*               : The results of the recognition is set on the Recognition context
*               : object.  In case of BATCH_MODE recognition recognition of every
*               : character is performed.  otherwise the recognizer updates the outputs
*               : with the recognized results
* ARGUMENTS		: rc - The recognition context for the current recognition
* RETURNS		: SUCCESS/FAILURE
* NOTES			:
* CHANGE HISTROY
* Author			Date				Description of
*************************************************************************************/
int BoxedFieldRecognizer::recognize (LTKRecognitionContext& rc)
{
	LOG(LTKLogger::LTK_LOGLEVEL_DEBUG)
	    <<"Entering: BoxedFieldRecognizer::recognize"
	    <<endl;

	string 	tempStr = REC_UNIT_INFO;  //temp string required to pass the arguments to set/get Flags

	int tempFlagValue = 0; //temp int to hold flag values

	int errorCode = 0;

	vector <LTKWordRecoResult>::iterator resultIter,resultEnd;  //iterates through decoded recognition results

	int numWordRecoResults ; //Number of results required by the application

	int resultIndex ; //index to iterate through the results

	vector<unsigned short> resultString; //result

	float normConf; //normalized confidence

	//Returning FAILURE if the recognition context
	//is not segmented into characters

	if((errorCode=rc.getFlag(tempStr,tempFlagValue))!=SUCCESS)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
            <<"Error: BoxedFieldRecognizer::recognize"<<endl;

		LTKReturnError(errorCode);
	}

	if( tempFlagValue != REC_UNIT_CHAR)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
		    <<"Error : "<< EINVALID_SEGMENT <<":"<< getErrorMessage(EINVALID_SEGMENT)
            <<" BoxedFieldRecognizer::recognize" <<endl;

		LTKReturnError(EINVALID_SEGMENT);
	}

	tempStr =REC_MODE;

	if((errorCode=rc.getFlag(tempStr,tempFlagValue))!=SUCCESS)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
            <<"Error: BoxedFieldRecognizer::recognize"<<endl;

		LTKReturnError(errorCode);
	}

	if(tempFlagValue == REC_MODE_BATCH)
	{
		//clear all the recognizer state
		clearRecognizerState();
		recognizeTraces(rc);
	}
	else if (tempFlagValue == REC_MODE_STREAMING)
	{
		recognizeTraces(rc);
	}
	else
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
		    <<"Error : "<< EINVALID_REC_MODE <<":"<< getErrorMessage(EINVALID_REC_MODE)
            <<" BoxedFieldRecognizer::recognize" <<endl;

		LTKReturnError(EINVALID_REC_MODE);
	}

	/* Now all the recognized results are in
	 * m_decodedResults.
	 */

	resultEnd =	m_decodedResults.end();

	for(resultIter = m_decodedResults.begin(); resultIter != resultEnd ; ++resultIter)
	{
		normConf = (*resultIter).getResultConfidence();

		normConf /= ((*resultIter).getResultWord()).size();

		(*resultIter).setResultConfidence(normConf);

	}

	//number of requested results
	numWordRecoResults =  rc.getNumResults();

	//checking with existing recognition results' size
	if(numWordRecoResults > m_decodedResults.size())
	{
		LOG(LTKLogger::LTK_LOGLEVEL_INFO)
			<< "Don't have enough results to populate. Num of results available = "
			<< m_decodedResults.size() <<", however, results asked for ="
			<< numWordRecoResults <<endl;
	}

	resultEnd = m_decodedResults.end();
	for(resultIndex =0,resultIter = m_decodedResults.begin();(resultIndex <numWordRecoResults)&&(resultIter != resultEnd); ++resultIndex,++resultIter)
	{
		//map the shape ids to unicode IDs
		if((errorCode = LTKStrEncoding::shapeStrToUnicode(m_boxedShapeProject,(*resultIter).getResultWord(),resultString)) != SUCCESS)
		{
			LOG(LTKLogger::LTK_LOGLEVEL_ERR)
            	<<"Error: BoxedFieldRecognizer::recognize"<<endl;

			LTKReturnError(errorCode);
		}

		//adding the recognition result to recognition context
		 rc.addRecognitionResult(LTKWordRecoResult(resultString,
												   (*resultIter).getResultConfidence()));

		resultString.clear();

	}

	//clearing state of the recognizer
	clearRecognizerState();


	LOG(LTKLogger::LTK_LOGLEVEL_DEBUG)
		<<"Exiting: BoxedFieldRecognizer::recognize"
	    <<endl;

	return SUCCESS;
}
/**********************************************************************************
* AUTHOR		: Deepu V.
* DATE			: 22-AUG-2005
* NAME			: recognizeTraces
* DESCRIPTION	: performs the recognition of the new strokes added to rc
*               : pre condition - markers are present in this vector
*               :               - m_numTracesProcessed  and m_numCharsProcessed
*               :                 set to proper value
* ARGUMENTS		: rc - The recognitino context
* RETURNS		:
* NOTES			:
* CHANGE HISTROY
* Author			Date				Description of
*************************************************************************************/
int BoxedFieldRecognizer::recognizeTraces(LTKRecognitionContext& rc )
{
	LOG(LTKLogger::LTK_LOGLEVEL_DEBUG)
	    <<"Entering: BoxedFieldRecognizer::recognizeTraces"
	    <<endl;

	vector<LTKTrace>::const_iterator traceIter,traceEnd,traceBegin;
	                 //iterator for the traces

	int errorCode = FAILURE;

	int recUnit;     //unit for recognition (should be char)

	LTKTraceGroup emptyChar;
	                 //TraceGroup object that buffers
	                 //all ink corresponding to a character

	vector<int> subSet;
	                 //passing a null arguement for shape subset

	vector<LTKShapeRecoResult> shapeRecoResults;
	                 //The object to hold the output from shape recognizer

	LTKScreenContext screenContext = rc.getScreenContext();
	                 //retrieving the screen context

	LTKCaptureDevice captureDevice = rc.getDeviceContext();
	                 //retrieving the device context

	const LTKTraceVector & traces = rc.getAllInk();
	                //retrieving the traces from recognition context

	string tempStr;  //temporary string object


	if(m_shapeRecognizer == NULL)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR) <<"Shape recognizer not initialized" <<endl;

		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
		    <<"Error : "<< ENULL_POINTER <<":"<< getErrorMessage(ENULL_POINTER)
            <<" BoxedFieldRecognizer::recognizeTraces" <<endl;

		LTKReturnError(ENULL_POINTER);

	}
	else if( (errorCode = m_shapeRecognizer->setDeviceContext(captureDevice)) != SUCCESS)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR) << "Unable to set device context in shape rec : " << getErrorMessage(errorCode) <<endl;

		 LOG(LTKLogger::LTK_LOGLEVEL_ERR)
             <<"Error: BoxedFieldRecognizer::recognizeTraces"<<endl;

		LTKReturnError(errorCode);
	}

	shapeRecoResults.reserve(m_numShapeRecoResults+1);//reserving memory


	if(m_numTracesProcessed > traces.size())
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR) << "Invalid number of traces processed. "
		    << "Traces processed = " << m_numTracesProcessed
            <<  " > total number of traces" << traces.size() <<endl;

        LOG(LTKLogger::LTK_LOGLEVEL_ERR)
		             <<"Error : "<< EINVALID_NUM_OF_TRACES <<":"<< getErrorMessage(EINVALID_NUM_OF_TRACES)
             <<" BoxedFieldRecognizer::recognizeTraces" <<endl;

		LTKReturnError(EINVALID_NUM_OF_TRACES);
	}
	//Start processing from the number of traces processed.
	traceBegin = traces.begin() + m_numTracesProcessed;
	traceEnd = traces.end();int r=0;

	for(traceIter = traceBegin; traceIter != traceEnd; ++traceIter)
	{
		/* Marker strokes are inserted to detect
		 * end of segment.  The marker strokes are
		 * identified by 9number of channels == 0)
         */
		if((*traceIter).getNumberOfPoints() == 0)
		{
			tempStr = REC_UNIT_INFO;
			if((errorCode = rc.getFlag(tempStr,recUnit)) != SUCCESS)
			{
				LOG(LTKLogger::LTK_LOGLEVEL_ERR)
            		<<"Error: BoxedFieldRecognizer::recognizeTraces"<<endl;

				LTKReturnError(errorCode);
			}
			switch(recUnit)
			{

			/* The segment is character
			 * This algorithm recognizes
			 * only character segments
			 */
			case REC_UNIT_CHAR:
				shapeRecoResults.clear();
				//calling the shape recognizer's recognize method.

				if(m_boxedChar.getNumTraces() == 0)
				{
					LTKShapeRecoResult T;
					T.setShapeId(SHRT_MAX);
					T.setConfidence(1.0);
					shapeRecoResults.push_back(T);
				}
				else if( (errorCode =	m_shapeRecognizer->recognize(m_boxedChar,screenContext,subSet,
					m_shapeRecoMinConfidence, m_numShapeRecoResults, shapeRecoResults ))!= SUCCESS )
				{
					LOG(LTKLogger::LTK_LOGLEVEL_ERR) << "Shape recognition failed : " << getErrorMessage(errorCode) <<endl;

					LOG(LTKLogger::LTK_LOGLEVEL_ERR)
            			<<"Error: BoxedFieldRecognizer::recognizeTraces"<<endl;

					LTKReturnError(errorCode);
				}


				//This updates the recognition results using
				//current shape recognition results

				if((errorCode = updateRecognitionResults(shapeRecoResults,rc)) != SUCCESS)
				{
					LOG(LTKLogger::LTK_LOGLEVEL_ERR)
            			<<"Error: BoxedFieldRecognizer::recognizeTraces"<<endl;

					LTKReturnError(errorCode);
				}

				for(r=0;r<shapeRecoResults.size();++r)
				{
					LTKShapeRecoResult& tempResult=shapeRecoResults[r];

				}

				m_boxedChar = emptyChar;//making the trace group empty again
				break;

			default:
				LOG(LTKLogger::LTK_LOGLEVEL_ERR) << "Unsupported reccognizer mode by Box Field" <<endl;

				LOG(LTKLogger::LTK_LOGLEVEL_ERR)
				    <<"Error : "<< EINVALID_RECOGNITION_MODE <<":"<< getErrorMessage(EINVALID_RECOGNITION_MODE)
             		<<" BoxedFieldRecognizer::recognizeTraces" <<endl;

				LTKReturnError(EINVALID_RECOGNITION_MODE);

			}
			++m_numCharsProcessed;      //incrementing number of characters processed
		}
		else
		{
			m_boxedChar.addTrace(*traceIter); //buffering the trace to the temp TraceGroup for recognition
		}
		++m_numTracesProcessed;         //incrementing the number of traces processed
	}


	LOG(LTKLogger::LTK_LOGLEVEL_DEBUG)
		<<"Exiting: BoxedFieldRecognizer::recognizeTraces"
		<<endl;

	return SUCCESS;
}
/*****************************************************************************
* AUTHOR		: Deepu V.
* DATE			: 22-AUG-2005
* NAME			: processInk
* DESCRIPTION	: This method is called from recognition context whenever new traces
*               : are added to it.  The Recognizer need to process the new traces
*               : in this methods and updates the internal state.
* ARGUMENTS		: rc - The recognition context for the current recognition
* RETURNS		: SUCCESS/FAILURE
* NOTES			:
* CHANGE HISTROY
* Author			Date				Description of
******************************************************************************/
int BoxedFieldRecognizer::processInk (LTKRecognitionContext& rc)
{
	LOG(LTKLogger::LTK_LOGLEVEL_DEBUG)
	    <<"Entering: BoxedFieldRecognizer::processInk"
	    <<endl;

	string tempStr = REC_UNIT_INFO;

	int tempFlagValue=0;

	int errorCode=0;

	if((errorCode=rc.getFlag(tempStr,tempFlagValue))!=SUCCESS)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
            <<"Error: BoxedFieldRecognizer::processInk"<<endl;

		LTKReturnError(errorCode);
	}

	//give an error if the Ink is not segmented into characters
	if(tempFlagValue != REC_UNIT_CHAR)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
		    <<"Error : "<< EINVALID_SEGMENT <<":"<< getErrorMessage(EINVALID_SEGMENT)
            <<" BoxedFieldRecognizer::processInk" <<endl;

		LTKReturnError(EINVALID_SEGMENT);
	}

	tempStr = REC_MODE;


	if((errorCode=rc.getFlag(tempStr,tempFlagValue))!=SUCCESS)
	{
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
            <<"Error: BoxedFieldRecognizer::processInk"<<endl;

		LTKReturnError(errorCode);
	}

	//if the recognizer mode is correct
	if (tempFlagValue == REC_MODE_STREAMING)
	{
		//recognize the newly added strokes
		recognizeTraces(rc);
	}
	else
	{
		//give an error otherwise
		LOG(LTKLogger::LTK_LOGLEVEL_ERR)
			<<"Error : "<< EINVALID_REC_MODE <<":"<< getErrorMessage(EINVALID_REC_MODE)
            <<" BoxedFieldRecognizer::processInk" <<endl;


		LTKReturnError(EINVALID_REC_MODE);
	}

	LOG(LTKLogger::LTK_LOGLEVEL_DEBUG)
		<<"Exiting: BoxedFieldRecognizer::processInk"
	    <<endl;

	return SUCCESS;
}