/*******************************************************************************
 * Copyright (c) 2005-2008 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:
 *    Vishnu K Naikawadi,Intel - Initial API and implementation
 *
 * $Id: BaseAgentImpl.h,v 1.30 2009/09/24 21:02:05 jwest Exp $ 
 *******************************************************************************/ 

#ifndef __BASEAGENTIMPL_H__
#define __BASEAGENTIMPL_H__

#include "tptp/TPTPExport.h"
#include "tptp/agents/IBaseAgent.h"
#include "tptp/TransportSupport.h"
#include "tptp/TPTPSupportTypes.h"
#include "tptp/TPTPUtils.h"
#include "tptp/TPTPConfigBinding.h"

class TPTP_CLASS_EXPORT MsgBlock
{
	private:
		unsigned int _magicNumber;
		unsigned int _flags;
		unsigned int _payLoadLength;
		unsigned char* _pMsg;
		

	public:
		MsgBlock();
		~MsgBlock();
		void setMagicNumber(unsigned int magNum);
		void setFlags(unsigned int flags);
		void setPayLoadLength(unsigned int length);
		void setMsg(unsigned char* pMsg, int count);
		unsigned int getMagicNumber() {return _magicNumber;}
		unsigned int getFlags() {return _flags;}
		unsigned int getPayLoadLength() {return _payLoadLength;}
		unsigned char* getMsg() {return _pMsg;}
};

class TPTP_CLASS_EXPORT CmdBlock
{
	private:
		int _sourceID;
		int _destID;
		int _contextID;
		char* _iid;
		char* _commandName;
		tptp_list_t _paramList;

	public:
		CmdBlock();
		~CmdBlock();
		void setSourceID(int srcID);
		void setDestID(int destID);
		void setContextID(int contextID);
		void setIID(char* iid);
		void setCommandName(char* commandName);
		void setParamList(tptp_list_t* paramList);
		int getSourceID();
		int getDestID();
		int getContextID();
		char* getIID();
		char* getCommandName();
		tptp_list_t* getParamList();
};



class TPTP_CLASS_EXPORT BaseAgentImpl: public IBaseAgent
{
	private:
		char* agentName;		// agent's identifying name string
		bool agentConnected;	// indicates if agent recv'd connection reply from AC
		bool agentRegistered;	// indicates if agent recv'd  register reply from AC
		int agentID;			// contains the connection ID given it by the AC
		char* agentPipeName;	// name of pipe through which AC sends cmds to agent
		TPTP_HANDLE agentNamedPipeHandle; // handle of pipe thru which AC sends cmds to agent
		long contextValue;		// holds a value the agent can use as the "context" in cmds it sends
		TPTP_HANDLE msgHandlerThreadHandle; //handle of the thread that gets incoming msgs from the AC
		TID msgHandlerThreadID;	// Id of the thread that gets incoming msgs from the AC
		char* configFile;
		agent_config_t agentConfig;
		Semaphore_t registerAgentConnectedSem;	// indicates when the agentConnected bool has been set
		Semaphore_t registerAgentCompletedSem;	// indicates when the agentRegistered bool has been set
		Semaphore_t terminateSemaphore;			// indicates the AC sent a msg that the agent should terminate itself

		tptp_loggingFormat  loggingFormat;
		tptp_int32          loggingLevel;

		tptp_list_t controllerList;
		tptp_list_t observerList;
		Lock_t      clientListsLock;

		/* one lock per process */  //TODO:???This gives a lock per Agent, is that what is meant by "process"?
		Lock_t   cmdPipeLock; 
		Lock_t   logPipeLock; 

		int sendCONNECTCommand(char *pUniqueId);
		int sendLogCommand(char *pMessage);

	public:
		typedef enum
		{
			TPTP_OBSERVER_CAL = 0,
			TPTP_CONTROLLER_CAL = 1,
		} tptp_clientAccessLevel;

		BaseAgentImpl(char* name);
		virtual ~BaseAgentImpl();
		int registerAgent();
		int asyncRegisterAgent();
		int deRegisterAgent();
		int initialize();
		virtual int preRegisterInitialization();
		void waitForTermination();
		static THREAD_USER_FUNC_RET_TYPE registerFunc(void* arg);
		static THREAD_USER_FUNC_RET_TYPE handleMessages(void* args);
		int processRecdMessages(char* buffer, int bytesRead);
		int processOneMessage(char* buffer);

		char* getAgentName();
		int getAgentID();
		int getAgentControllerID();
		int getNextContext();
		TPTP_HANDLE getMsgHandlerThreadHandle() {return msgHandlerThreadHandle;}
		TID getMsgHandlerThreadID() {return msgHandlerThreadID;}

		char* getConfigValue(char* name);

		// Provides the handling code for commands that come as flags.
		// Typically, these are exchanged with the TransportLayer which
		// does not do XML parsing.
		virtual int processFlagCommand(MsgBlock* msg);

		//TPTP AGENT API - Terminates the Agent (TODO:Not implemented in the prototype)
		virtual int terminate();

		/*
		* TPTP AGENT API - Provides the handling code for the base commands
		* Agent or developer should provide their own implementation for the 
		* commands that are not handled
		* The CmdBlock is a class defined above and contains information about
		* Command (sourceID, destID, contextID, Command Name and Command Parameters)
		*/
		virtual int processCommand(CmdBlock* cmd);

		/*
		* TPTP AGENT API - This function is called by the base command handler when the
		* Agent Controller sends a notifyReference command. The base implementation of 
		* this method adds the client ID to a list of either controllers or observers.
		* The accessLevel parameter will be either TPTP_CONTROLLER_CAL or 
		* TPTP_OBSERVER_CAL. The Agent Controller will have already checked agent 
		* availability and granted before this notification is sent.
		*/
		virtual void addClient(tptp_int32 clientID, tptp_clientAccessLevel accessLevel);

		/*
		* TPTP AGENT API - This function is called by the base command handler when the
		* Agent Controller sends a notifyDereference command. The base implementation of 
		* this method removes the client ID from the lists of controllers and observers.
		* The accessLevel parameter can be either TPTP_CONTROLLER_CAL or 
		* TPTP_OBSERVER_CAL.
		*/
		virtual void removeClient(tptp_int32 clientID);

		/*
		* TPTP AGENT API - This function may be called by to determine whether a given
		* client has been granted access to this agent.  The Agent Controller manages
		* granting or rejecting controller or observer access, but because it does not
		* know the relationship of individual commands to this access level.  Therefore,
		* the Agent Controller does not validate access on individual messages.  The 
		* agent itself may call this function to verify access and do its own enforcement.
		* The default implementation of this method uses the lists created by the base
		* implementation of addClient to determine access levels.
		*/
		virtual bool checkClientAccess(int clientID, tptp_clientAccessLevel accessLevel);


		//TPTP AGENT API - Sends a command through the AC's general communication channel.
		int sendCommand(char *pMessage);

		//This form sends flag-based commands, which do not have an XML-formatted body.
		int sendCommand(char *pMessage, int msgLength, unsigned int flags);

		int sendErrorCommand(const int destID, const int ctxt,
							 const int tptpErrCode, char *errInfo);

		virtual void processCommandLine(int argc, char* argv[]);
		int initializeAgentConfiguration(char *configDir);
		void setServiceConfigFile(int argc, char* argv[]);
		char *getServiceConfigFile();

		// This will log to the Agent Controller through the named pipe
		tptp_int32 logEvent(tptp_string* subcomponent,
		                    tptp_uint32  instanceId,
		                    tptp_string* filename, 
		                    tptp_int32   lineNum, 
		                    tptp_int32   severity, 
		                    tptp_string* event );
		int getAgentRegistrationStatus();

#ifdef MVS
		Semaphore_t * getTerminationSemaphore() { return &terminateSemaphore;}
#endif

	protected:
		char* _serviceConfigFile;
		char* _raMasterAddress;
		char* _raShmBufNameRoot;
		int registrationStatus;
};

#endif /* __BASEAGENTIMPL_H__ */

