#include <cdevTagMap.h>

// *****************************************************************************
// * cdevTagMap::cdevTagMap :
// *	This is the constructor for the cdevTagMap class.
// *****************************************************************************
cdevTagMap::cdevTagMap ( void )
	: cnt(0),
	  maximum(0),
	  local(NULL),
	  remote(NULL)
	{
	}


// *****************************************************************************
// * cdevTagMap::cdevTagMap :
// *	This is the destructor for the cdevTagMap class.
// *****************************************************************************
cdevTagMap::~cdevTagMap ( void )
	{
	if(local !=NULL) free(local);
	if(remote!=NULL) free(remote);
	}
	
// *****************************************************************************
// * cdevTagMap::updateTagMap :
// *	This method will read the names and integers from a cdevData object and
// *	will then pass these values to the updateTagMap method for processing.
// *
// *	For standardization the tag integers are placed in tag 1, and the
// *	tag strings are placed in tag 2...
// *****************************************************************************
void cdevTagMap::updateTagMap ( cdevData & data )
	{
	char ** names;
	int  *  tags;
	size_t  nameCnt=0, tagCnt=0;
	
	if(data.getElems(1, &tagCnt)==CDEV_SUCCESS &&
	   data.getElems(2, &nameCnt)==CDEV_SUCCESS &&
	   tagCnt>0 && tagCnt==nameCnt)
	   	{
		names = new char *[nameCnt];
		tags  = new int [tagCnt];
		memset(names, 0, sizeof(char *)*nameCnt);
		data.get(1, tags);
		data.get(2, names);
		updateTagMap(names, tags, nameCnt);
		while(nameCnt>0)
			{
			--nameCnt;
			delete names[nameCnt];
			}
		delete names;
		delete tags;
		}
	}

// *****************************************************************************
// * cdevTagMap::updateTagMap :
// *	This method will create a mapping of the differences between the tags
// *	specified in the user provided array and the tags that are stored 
// *	within cdevData.
// *****************************************************************************
void cdevTagMap::updateTagMap ( char ** names, int * tags, int count )
	{
	// *********************************************************************
	// * Process each item in the names array from last to first.
	// *********************************************************************
	while((--count)>=0)
		{
		int localTag = -1;
		
		// *************************************************************
		// * Determine if a tag that is identified by the names[count]
		// * string exists in the cdevData Global Tag Table.  If it 
		// * does, copy its integer representation into the localTag 
		// * variable.
		// *************************************************************
		if(cdevData::tagC2I(names[count], &localTag)!=CDEV_SUCCESS)
			{
			// *****************************************************
			// * If the string does not already exist in the 
			// * cdevData Global Tag Table, then attempt to add it.
			// *
			// * If the specified integer is in use locally by
			// * another cdevData tag - then the value will be 
			// * incremented until an open slot is found.
			// *****************************************************
			char * s;
			localTag = tags[count];
			while(cdevData::tagI2C(localTag, s)==CDEV_SUCCESS)
				{
				localTag++;
				}
			cdevData::insertTag(localTag, names[count]);
			}
		
		// *************************************************************
		// * If the local integer tag value differs from the remote
		// * integer tag value, then this tag must be added to the 
		// * list.
		// *************************************************************
		if(localTag != tags[count])
			{
			int idx;
			
			// *****************************************************
			// * Walk through the list and determine if the tag 
			// * has already been added to the list...
			// *****************************************************
			for(idx=0; idx<cnt && remote[idx]!=tags[count]; idx++);

			// *****************************************************
			// * If the tag does not already exist in the list,
			// * then do the following.
			// *****************************************************
			if(idx>=cnt)
				{
				// *********************************************
				// * If the internal arrays have not yet been 
				// * allocated, then allocate a default number 
				// * of entries (64).
				// *********************************************
				if(maximum==0)
					{
					maximum=64;
					local  = (int *)malloc(maximum*sizeof(int));
					remote = (int *)malloc(maximum*sizeof(int));
					}
				// *********************************************
				// * If the internal arrays are already filled 
				// * by the existing entries, then double the
				// * size of the arrays.
				// *********************************************
				else if(idx>=maximum) 
					{
					maximum*=2;
					local  = (int *)realloc(local, maximum*sizeof(int));
					remote = (int *)realloc(remote, maximum*sizeof(int));
					}

				// *********************************************
				// * Populate the new entry with the mismatch
				// * data and increment the total number of 
				// * mismatches.
				// *********************************************
				local [idx] = localTag;
				remote[idx] = tags[count];
				cnt         = idx+1;
				}
			}
		}
	}


// *****************************************************************************
// * cdevTagMap::swapTags :
// *	This method is used to swap between two sets of tags...  If a tag 
// *	listed in the outTags array is used in the cdevData item, its tag will
// *	be converted to the corresponding value in the inTags array.
// *****************************************************************************
void cdevTagMap::swapTags ( cdevData & data, int *inTags, int *outTags, int count)
	{
	int tag;
	int changeCount = 0;
	cdevDataIterator iter(&data);
	
	iter.init();
	do	{
		int idx;
		for(idx=0, tag=iter.tag(); idx<count && tag!=outTags[idx]; idx++);
		if(idx<count)	
			{
			data.changeTag(tag, -1*inTags[idx]);
			changeCount++;
			}
		} while(++iter != 0);

	if(changeCount)
		{
		iter.init();
		do
			{
			if((tag=iter.tag())<0) data.changeTag(tag, -1*tag);
			} while(++iter!=0);
		}
	}
	

// *****************************************************************************
// * cdevTagMap::asciiDump :
// *	This mechanism is used to perform an ascii dump of the contents of a 
// *	cdevtagMap structure.
// *****************************************************************************
void cdevTagMap::asciiDump (FILE * fp )
	{
	fprintf(fp, "----------------------------------------------------------\n");
	fprintf(fp, "             Diagnostic Dump of CDEV Tag Map\n");
	fprintf(fp, "----------------------------------------------------------\n\n");
	fprintf(fp, "Number of Mismatches           : %i\n", cnt);
	fprintf(fp, "Allocated Maximum Mismatches   : %i\n", maximum);
	if(cnt) {
		fprintf(fp, "\nMismatch Table:\n\n");
		fprintf(fp, "\tTag Name                  Local ID     Remote ID\n");
		fprintf(fp, "\t--------------------------------------------------\n");
		for(int i=0; i<cnt; i++)
			{
			char * s;
			cdevData::tagI2C(local[i], s);
			fprintf(fp, "\t%-26.26s%-13i%i\n", s, local[i], remote[i]);
			}
		fprintf(fp, "\t--------------------------------------------------\n\n");
		}
	fprintf(fp, "----------------------------------------------------------\n");
	fprintf(fp, "            End of Diagnostic Dump of CDEV Tag Map\n");
	fprintf(fp, "----------------------------------------------------------\n\n");
	fflush(fp);
	}

