#ifndef AGENT_H
#define AGENT_H

#include<iostream>
#include "Globals.h"

#include <string>
#include <vector>

//*************************
//***
//*** Created by Clauda Ephrem		Date Jan 3, 2008
//*** 
//*** Edited by Vivian Jreig		Date April 3, 2008
//*** void Agent::getState () 
//***
//*** Edited by Vivian Jreig		Date April 10, 2008
//*** added string getszId() and int Agent::getScore();
//***
//*** Edited by WFN	on 15-May-2008
//*** changed name and arguments of printState (used to be getState and wite to cout
//***
//*************************

using namespace std;
class Patch;
class Controller;
class Agent 
{

private:

	long int iID; // A number with N significant figures to identify the current agent
	int iN; // The significant figures of the ID used to denote the generation
	Patch *phCurrentLocation; //Pointer to the grid patch on which the agent currently is standing
	Agent * agCurrentPartner; // Pointer to current partner
	long int iPastPartnerId; // Id of the past partner
	int iCurrentScore; //Current Score of the Agent
	int iNumTurns; // Number of interactions so far with the current partner
	vector<string> CurrentOpponentMemory;//Vector implementing memory array storing the moves
	//of the agent in positions 0&1 and the moves of the opponent in positions 2&3
	unsigned int LengthOfMemory; //Variable storing the length of the memory array
	string* StrategyArray; //Pointer to the strategy array for the specific species
	Strategy CurrentStrategy; //represents the strategy of the agent
	Controller* Control;
	
	int CastMemArrayToInt(vector<string> Mem); 

public:
	int IndexLocation;
	void Move();
//  Move: Queries the controller for mobility (m), calls 
//  the grid to obtain a new patch, (m) distance from
//  current position, and in a random direction. Sets the
//  current location to this new location. Raises error if
//  called while self.partner is not NULL.

	void Meet();
//  Meet : Queries the patch, checks for over-capacity,
//  looks for un-partnered agents on that patch. If found,
//  stores past opponent ID if need be, and sets the
//  partner pointer, calls partner.associate, sets
//  self.num_turns to zero. If patch is over capacity or
//  has no available partners, call self.move.

	void Reproduce();
//  Reproduce : If self.score is above
//  controller.threshold , call the constructor to create a
//  new instance of the same subclass with half of
//  self.score, with ID derived from self.ID by adding one
//  more significant binary figure and setting it to "1", 
//  location = self.location.  Set self.score to half of
//  self.score (rounding up if score is odd)and self.N to
//  self.N+1 (making zero the highest bit of self.ID).

	void Die();
//  Die: If self.score is zero or below, call
//  partner.disassociate and call self.destructor.

	void Dissociate(Agent* agPartner);
//  public dissociate(p_partner): if the current partner
//  sends this message with its correct pointer, the agent
//  saves the partner ID, sets the self.current_partner to
//  null, and calls self.move. Raise an error message if
//  the message is sent from another agent. (i.e. if
//  p_partner != self.partner).

	void Associate(Agent* agPartner);
//  public associate(p_partner): if current partner is 
//  null, sets sets self.num_turns to zero and self.partner
//  to p_partner.

	void Decide();
//  Decide: if self.partner != NULL, Selects the next move
//  based on its subclass, opponent and history (It might 
//  be easier for you to just implement the strategy tables
//  as described in the spreadsheet I gave you right now
//  instead of re-designing all the strategies as separate
//  functions.)  Calls parter.respond with the move.
//  Updates own score, num_truns and history string based
//  on the result. If response is "Walk away" or num_turns
//  is greater than controller.num_play, call 
//  partner.dissociate and self.move.

	string Respond(Agent* agPartner, string Move);
//  public function Respond(p_partner, move) returns move:
//  This is tricky since the responding agent must generate
//  its move before learning of the partner's move (encoded 
//  in the parameter passed), but then must set its own
//  score and history etc. based on both own move and
//  partner move.  Returns own move so that partner can do
//  the same.  Raises an error message if p_partner != 
//  self.partner.

	void NewMemoryArray (string PartnerMove, string selfMove);
//  Function to update the Memory Array
//  To trim to N past moves we could either discard the last move
//  or AND or OR it withtheone before it

	void UpdateScore (string PartnerMove, string selfMove);
//Function to update self.score given opponent.move;

	Agent(long int iId, int iN, Patch* phPatch, int lenOfMem , int strategyOfAgent, Controller* Cont, int Score);
	Agent(long int iId, int iN, Patch* phPatch, int lenOfMem , Strategy strategyOfAgent, Controller* Cont, int Score);
	~Agent();
	Agent();

	Agent(int i);

	void CopyStrategyArray (Agent* child);

	Agent* getCurrentPartner();
	Strategy getCurrentStrategy();

	Patch* getphCurrentLocation();

	int getIndexLocation();

	void SetIndexLocation(int a );

	void printState (ofstream& outfile);
	//Tries to find out the states of the agent: Its strategy, score 
	//and current position, so that we can later store these values for each agent


	//***** Functions added in May 2008 for state dump
	string getszId();
	//int getiId();
	//int getScore();

};



#endif;