/*******************************************************************************
 * Copyright (c) 2005, 2009 Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Ramesh Vishwanath,Intel - Initial API and implementation
 *
 * $Id: VariableProvider.cpp,v 1.8 2009/04/14 20:33:26 jwest Exp $ 
 *******************************************************************************/ 



/* Variable Provider Implementation */

#include "tptp/agents/VariableProvider.h"
#include <stdlib.h>


#define BUFSIZE 1024

VariableProvider::VariableProvider(char* name) : BaseAgentImpl(name)
{
	tptp_list_init(&agent_Varlist);
	//TODO: Do we need a destroy function or is adding a destructor for Variable all we need?

}

VariableProvider::~VariableProvider()
{
	#ifndef _SOLARIS
	tptp_list_clear(&agent_Varlist);
	#endif
}


Variable* VariableProvider::getVariable(int varID)
{
	tptp_node_t* listNode = this->agent_Varlist.head;
	tptp_varlist_t* varTemp;

	Variable* tempVar = NULL;

	//Locate Variable
	while (listNode!=0)
	{
		varTemp = (tptp_varlist_t*)listNode->data;

		/* Check if it is a stand alone variable */
		if (varTemp->toggle == VAR){
			if (varTemp->var->getID() == varID){
				// Found Variable
				tempVar = varTemp->var;
				break;
			}	
		}
		/* Check if it is in a variable group */
		else {
//TODO: Why do we always break out of the while loop here?
			tempVar = varTemp->varGroup->getVariable(varID);
			break;
		}
		
		listNode = listNode->next;	
	} // agentvarlist

	return tempVar;
}


VariableGroup* VariableProvider::getVariableGroup(int varGroupID)
{
	tptp_node_t* listNode = this->agent_Varlist.head;
	tptp_varlist_t* varTemp;
	VariableGroup* tempGrp = NULL;
	
	while (listNode!=0)
	{
		varTemp = (tptp_varlist_t*)listNode->data;

		if (varTemp->toggle == VARGRP){
			if (varTemp->varGroup->getID() == varGroupID){
				//Success				
				tempGrp = varTemp->varGroup;
				break;
			}
		}

		listNode = listNode->next;
	}


	return tempGrp;

}



int VariableProvider::setVariable(Variable* varNode)
{
	
	tptp_node_t* listNode = this->agent_Varlist.head;
	tptp_varlist_t* varTemp;
	//char* varBuf = (char *)tptp_malloc(BUFSIZE);
	int i;
	int rc = -1;
	bool foundVar = false;
	
	//Check permissions
	//Not implemented yet
	
	//Locate and Set Value
	while (listNode!=0)
	{
		varTemp = (tptp_varlist_t*)listNode->data;

		if (varTemp->toggle == VAR)
		{
			if (varTemp->var->getID() == varNode->getID())
			{
				// Found Variable
				varTemp->var->setDescription(varNode->getDescription());
				varTemp->var->setName(varNode->getName());
				varTemp->var->setNameSpace(varNode->getNameSpace());
				varTemp->var->setNCName(varNode->getNCName());
				varTemp->var->setReadAccess(varNode->getReadAccess());
				varTemp->var->setType(varNode->getType());
				varTemp->var->setValue(varNode->getValue());
				varTemp->var->setWriteAccess(varNode->getWriteAccess());

				rc=0;
			}	
		}
		else {
			
			i = varTemp->varGroup->setVariable(varNode);
			if (i>0)
			{
				rc = 0;
			}

		}// end toggle
		
		listNode = listNode->next;
		
	} // agentvarlist

	return rc;
	
}

int VariableProvider::setVariableGroup(VariableGroup* varGrp)
{
	
	tptp_node_t* listNode = this->agent_Varlist.head;
	tptp_varlist_t* varTemp;
	tptp_node_t* tempNode;
	tptp_list_t* tempList;
	VariableGroup* tempGrp;
	int rc = -1;
		
	//Check permissions
	//Not implemented yet
	
	//Locate and Set Value
	while (listNode!=0)
	{

		varTemp = (tptp_varlist_t*)listNode->data;

		if (varTemp->toggle == VARGRP){

			if (varTemp->varGroup->getID() == varGrp->getID()){

				//Success : set attributes
				varTemp->varGroup->setDescription(varGrp->getDescription());
				varTemp->varGroup->setName(varGrp->getName());
				varTemp->varGroup->setSubGroupList(varGrp->getSubGroups());
				varTemp->varGroup->setVariableList(varGrp->getVariableList());
				rc = 0;
				break;
			}

			//Check Sub Groups
			tempList = varTemp->varGroup->getSubGroups();
			tempNode = tempList->head;
			while (tempNode != 0){
				tempGrp = (VariableGroup *)tempNode->data;
				if (tempGrp->getID() == varGrp->getID()){

					//Success : set attributes
					tempGrp->setDescription(varGrp->getDescription());
					tempGrp->setName(varGrp->getName());
					tempGrp->setSubGroupList(varGrp->getSubGroups());
					tempGrp->setVariableList(varGrp->getVariableList());
					rc = 0;
					break;
				}
				tempNode=tempNode->next;
			}

		}//End toggle

	}//End list


	return rc;
}


int VariableProvider::addVariable(Variable* varNode)
{
	
	tptp_node_t* listNode = this->agent_Varlist.head;

	int rc = -1;
	bool foundVar = false;
		
	
	rc = tptp_list_add(&agent_Varlist, varNode);

	return rc;
}

int VariableProvider::addVariableGroup(VariableGroup* varGrp)
{
	
	tptp_node_t* listNode = this->agent_Varlist.head;
	int rc = -1;
		
	rc = tptp_list_add(&agent_Varlist, varGrp);

	return rc;
}



int VariableProvider::listVariables(CmdBlock* cmdBlock){
	
	tptp_node_t* listNode;
	tptp_varlist_t* varTemp;
	char *varBuf = (char *)tptp_malloc(BUFSIZE);
	char *temp   = (char *)tptp_malloc(BUFSIZE); 
	char *sendCmd = (char *)tptp_malloc(BUFSIZE);
	int mem_count=0;
	
	//Not implemented
	//Check read permissions here
	
	listNode = agent_Varlist.head;
	while (listNode !=0 ){

		varTemp = (tptp_varlist_t *)listNode->data;

		//check if variable
		if (varTemp->toggle == VAR){

			temp = Variable::createVariableString(varTemp->var);
			memcpy(varBuf+mem_count, temp, strlen(temp));
			mem_count+=strlen(temp);
		
			// Should clear temp here. 
		}
		
		listNode = listNode->next;
	}

	varBuf[mem_count]='\0';

	//Send the list back
	sprintf(sendCmd,"<Cmd src=\"%d\" dest=\"%d\" ctxt=\"%d\"><VariableList iid=\"org.eclipse.tptp.Client\">%s</VariableList></Cmd>",
		cmdBlock->getDestID(), cmdBlock->getSourceID(), cmdBlock->getContextID(), varBuf);		
	sendCommand(sendCmd);
		
	// Clean Mess 
	tptp_free(varBuf);
	tptp_free(temp);
	tptp_free(sendCmd);
	
	//Success
	return 0;
}

int VariableProvider::listVariableGroups(CmdBlock* cmdBlock){
	
	tptp_node_t* listNode;
	tptp_varlist_t* varTemp;
	char *varBuf = (char *)tptp_malloc(BUFSIZE);
	char *temp   = (char *)tptp_malloc(BUFSIZE); 
	char *sendCmd = (char *)tptp_malloc(BUFSIZE);
	int mem_count=0;
	
	//Not implemented
	//Check read permissions here
	
	listNode = agent_Varlist.head;
	while (listNode != 0){

		varTemp = (tptp_varlist_t *)listNode->data;

		//check if variable group
		if (varTemp->toggle == VARGRP){
			temp = VariableGroup::createVarGroupString(varTemp->varGroup);
			memcpy(varBuf+mem_count, temp, strlen(temp));
			mem_count+=strlen(temp);
		
			// Should clear temp here. 
		}
		listNode = listNode->next;
	}

	varBuf[mem_count]='\0';

	//Send the list back
	
	sprintf(sendCmd,"<Cmd src=\"%d\" dest=\"%d\" ctxt=\"%d\"><VariableGroupList iid=\"org.eclipse.tptp.Client\">%s</VariableGroupList></Cmd>",
		cmdBlock->getDestID(), cmdBlock->getSourceID(), cmdBlock->getContextID(), varBuf);		
	sendCommand(sendCmd);
		
	// Clean Mess 
	tptp_free(varBuf);
	tptp_free(temp);
	tptp_free(sendCmd);
	
	//Success
	return 0;
}


	
int VariableProvider::getVariable(int varID, CmdBlock* cmdBlock)
{
	
	char* varBuf = (char *)tptp_malloc(BUFSIZE);
	Variable* tempVar = 0;
	
	//Check Permissions before returning
	//Not implemented currently

	tempVar = this->getVariable(varID);
	// Found Variable
	if (tempVar != 0)
	{
		sprintf(varBuf,"<Cmd src=\"%d\" dest=\"%d\" ctxt=\"%d\"><VariableList iid=\"org.eclipse.tptp.Client\">%s</VariableList></Cmd>", cmdBlock->getDestID(), cmdBlock->getSourceID(), cmdBlock->getContextID(), Variable::createVariableString(tempVar));
	}
	else
	{
		sprintf(varBuf,"<Cmd src=\"%d\" dest=\"%d\" ctxt=\"%d\"><getVariableFailed iid=\"org.eclipse.tptp.Client\"></getVariableFailed></Cmd>", cmdBlock->getDestID(), cmdBlock->getSourceID(), cmdBlock->getContextID());		
	}

	sendCommand(varBuf);

	
	//Clean Mess
	tptp_free(varBuf);
	
	
	//Couldn't find variable
	return 0;
}


int VariableProvider::getVariableGroup(int varGroupID, CmdBlock* cmdBlock){

	VariableGroup* tempGrp;
	char* varBuf = (char *)tptp_malloc(BUFSIZE);
	
	//Check Permissions
	//Currently not implemented
	
	tempGrp = this->getVariableGroup(varGroupID);

	if (tempGrp != 0)
	{
		//Success				
		sprintf(varBuf,"<Cmd src=\"%d\" dest=\"%d\" ctxt=\"%d\"><VariableGroupList iid=\"org.eclipse.tptp.Client\">%s</VariableGroupList></Cmd>", cmdBlock->getDestID(), cmdBlock->getSourceID(), cmdBlock->getContextID(), VariableGroup::createVarGroupString(tempGrp));
	}
	else
	{
		//Success				
		sprintf(varBuf,"<Cmd src=\"%d\" dest=\"%d\" ctxt=\"%d\"><getVariableGroupFailed iid=\"org.eclipse.tptp.Client\"></getVariableGroupFailed></Cmd>", cmdBlock->getDestID(), cmdBlock->getSourceID(), cmdBlock->getContextID());
	}

	sendCommand(varBuf);

	//Clean Mess
	tptp_free(varBuf);
	
	//Couldn't find variable group
	return -1;
		
}

int VariableProvider::setVariable(Variable* varNode, CmdBlock* cmdBlock)
{
	
	int rc = -1;
	
	//Check permissions
	//Not implemented yet
	
	//Locate and Set Value
	rc = this->setVariable(varNode);

	//Send the Response to the Client
	char   command[BUFSIZE];
	if (rc == 0)
	{
		char   commandFormat[] = "<Cmd src=\"%ld\" dest=\"%ld\" ctxt=\"%ld\"><setVariableSuccess iid=\"org.eclipse.tptp.Client\"></setVariableSuccess></Cmd>";	
		sprintf( command, commandFormat, getAgentID(), cmdBlock->getSourceID(), cmdBlock->getContextID());
	}
	else
	{
		char   commandFormat[] = "<Cmd src=\"%ld\" dest=\"%ld\" ctxt=\"%ld\"><setVariableFailed iid=\"org.eclipse.tptp.Client\"><reason>%d</reason></setVariableFailed></Cmd>";	
		sprintf( command, commandFormat, getAgentID(), cmdBlock->getSourceID(), cmdBlock->getContextID(), rc);
	}
	sendCommand(command);

	return rc;
	
}

int VariableProvider::setVariableGroup(VariableGroup* varGrp, CmdBlock* cmdBlock)
{
	int rc = -1;
		
	//Check permissions
	//Not implemented yet
	
	//Locate and Set Value
	rc = this->setVariableGroup(varGrp);


	//Send the Response to the Client
	char   command[BUFSIZE];
	if (rc == 0)
	{
		char   commandFormat[] = "<Cmd src=\"%ld\" dest=\"%ld\" ctxt=\"%ld\"><setVariableGroupSuccess iid=\"org.eclipse.tptp.Client\"></setVariableGroupSuccess></Cmd>";	
		sprintf( command, commandFormat, getAgentID(), cmdBlock->getSourceID(), cmdBlock->getContextID());
	}
	else
	{
		char   commandFormat[] = "<Cmd src=\"%ld\" dest=\"%ld\" ctxt=\"%ld\"><setVariableGroupFailed iid=\"org.eclipse.tptp.Client\"><reason>%d</reason></setVariableGroupFailed></Cmd>";	
		sprintf( command, commandFormat, getAgentID(), cmdBlock->getSourceID(), cmdBlock->getContextID(), rc);
	}
	sendCommand(command);

	return rc;
}


int VariableProvider::processVariableProviderCommands(CmdBlock* cmd){

	char* cmdName = cmd->getCommandName();

	if (isEqualString(cmdName,"listVariables"))
	{
		listVariables(cmd);
	}

	if (isEqualString(cmdName,"listVariableGroups"))
	{
		listVariableGroups(cmd);
	}

	if (isEqualString(cmdName,"getVariable"))
	{
		int varID;
		if (0 != getIntegerParam( "variableID", cmd->getParamList(), &varID ) )
		{
			//TODO: Error missing required parameter
			return -1;
		}
		getVariable(varID, cmd);
	}

	if (isEqualString(cmdName,"getVariableGroup"))
	{
		int varGroupID;
		if (0 != getIntegerParam( "variableGroupID", cmd->getParamList(), &varGroupID ) )
		{	
			//TODO: Error missing required parameter
			return -1;
		}
		getVariableGroup(varGroupID, cmd);
	}

	if (isEqualString(cmdName,"setVariable"))
	{
		Variable* varObj = new Variable();
		char * strValue=NULL;
		int intValue=0;

		// A Name parameter is required, but the other parameters can be
		// ommitted.
		if (0 != getStringParam( "Name", cmd->getParamList(), &strValue ) )
		{	
			//TODO: Report Error - missing required parameter
			return -1;
		}
		varObj->setName(strValue);

		if (0 == getStringParam("Value", cmd->getParamList(), &strValue ) )
		{
			varObj->setValue(strValue);
		}
		
		if (0 == getIntegerParam("ID", cmd->getParamList(), &intValue ) )
		{
			varObj->setID(intValue);
		}

		if (0 == getStringParam("Description", cmd->getParamList(), &strValue ) )
		{
			varObj->setDescription(strValue);
		}

		if (0 == getIntegerParam("Type", cmd->getParamList(), &intValue ) )
		{
			varObj->setType(intValue);
		}

		setVariable(varObj, cmd);
	}

	if (isEqualString(cmdName,"setVariableGroup"))
	{
		/* TODO Change the parsing logic to retrieve the XML tags properly */
//TODO: The parameter list is a tptp_list_t and can't be cast to VariableGroup.
//		setVariableGroup((VariableGroup *)cmd->getParamList().parms[0].value, cmd);
	}
	return 0;

}

