// Provide classes for simulating a mouse moving in a maze
//
// Copyright 2007 John L Baker. All rights reserved.
//
// This software is provided AS IS under the terms of the Open Source
// MIT License. See http://www.opensource.org/licenses/mit-license.php.
//
// File: subject_baker_2003.h
//
// Release:		1.0.0
// Author:		John Baker
// Updated:		14 July 2006
//
// Description:
//
// This header provides a framework for defining an anmimal moving in such an
// environment such as a Morris Water Maze. The definition here is abstract
// and concrete implementation involves extension of the MazeSubject class.
//
// A basic movement policy is provided in which the animal moves about the
// maze at random without attempting to seek a goal or explicitly explore
// unfamiliar regions of the maze.
//
// References:
//
// Dudek G, Jenkin M (2000) Computational principles of mobile robotics.
// New York: Cambridge University Press.
//
// Nakazawa K, Quick MC, Chitwood RA, Watanabe M, Yeckel MF, Sun LD, 
// Kata A, Carr CA, Johnston D, Wilson MA, Tonegawa S (2002) Requirement
// for hippocampal CA3 NMDA receptors in associative memory recall.
// Science 297: 211-218.


// --------------------------------------------------------------------
// Only include the definitions in this header once
// --------------------------------------------------------------------

#ifndef __SUBJECT_BAKER_2003_H_
#define __SUBJECT_BAKER_2003_H_


// --------------------------------------------------------------------
// MICROSOFT SPECIFIC DECLARATIONS
// --------------------------------------------------------------------
#ifdef WIN32

// Disable warning C4786: symbol greater than 255 character,
#pragma warning( disable: 4786)

#endif
// --------------------------------------------------------------------
// END OF MICROSOFT SPECIFIC DECLARATIONS
// --------------------------------------------------------------------


#include "bnsf.h"
#include "maze_baker_2003.h"

using namespace std;
using namespace BNSF;


// Declare a namespace so that different models
// can be intermixed in the same simulation

namespace BAKER_2003 {

	// ----------------------------------------------------------------
	// Prototype declarations to allow forward references.
	// See below for descriptions of the individual classes.
	// ----------------------------------------------------------------

	class MazeSubject;

	class MovementPolicy;
		class RandomWalk;
		class WallFollower;


	// ----------------------------------------------------------------
	// CLASS:	MazeSubject
	// EXTENDS:	ModelComponent
	// DESC:	Abstract class for defining subjects for maze
	//			experiments. .
	// RESP:
	//		1.	Store relationship with maze.
	//		2.	Know current position and heading.
	//		3.	Allocate private model and solver if none provided
	//		4.	Compute angular relationship between current position
	//			and all visible landmarks.
	//		5.	Know current novelty region	
	//
	// NOTES:	For now all landmarks are assumed to be visible.
	//			Because a clock solver is used, subclasses must
	//			provide motion in terms of discrete change in location
	//			with each time step.
	//
	//			Subclass must establish any behaviors associated with
	//			being within the novelty region, including possibly
	//			passing the region to affected place cell layers.
	// ----------------------------------------------------------------

	class MazeSubject : public ModelComponent {

	public:

		// Constructors and destructor
		MazeSubject(Maze* m=NULL);
		virtual ~MazeSubject();

		// Accessors
		inline  Maze*			maze() { return _maze; }
		virtual void			maze(Maze* m);

		inline  SpatialRegion*	noveltyRegion() { return _noveltyRegion; }
		virtual void			noveltyRegion(SpatialRegion* nr) { _noveltyRegion=nr; }

		inline  MovementPolicy* movementPolicy() { return _movementPolicy; }
		virtual void			movementPolicy(MovementPolicy* policy);

		inline  Number			speed() { return _speed; }
		virtual void			speed(Number v);

		inline	Number			locX() { return _locX; }
		virtual void			locX(Number x);

		inline  Number			locY() { return _locY; }
		virtual void			locY(Number y);

		inline  Number			headingX() { return _headingX; }
		virtual void			headingX(Number x) { _headingX = x; }

		inline  Number			headingY() { return _headingY; }
		virtual void			headingY(Number y) { _headingY = y; }

		virtual Number			headingAngle();
		virtual void			headingAngle(Number angle);

		virtual ModelComponentVector* subscribers() { return &_subscribers; }

		// Provide access to the previous maze, but only while switching over.
		inline  Maze*			previousMaze() { return _previousMaze; }

		// Interface for updating location and heading in one function call.
		// This reduces the overhead of multiple change notifications.
		virtual void			setLocationAndHeading(
			Number				x,			// location x coord
			Number				y,			// location y coord
			Number				hx,			// heading vector x coord
			Number				hy);		// heading vector y coord

		// Set heading to a uniformly distributed random direction
		virtual void			randomizeHeading();

		// Access sensory information available from the current location.
		// For now all landmarks are assumed to be fully visible at all locations.
		virtual LandmarkVector&	landmarks() { return maze()->landmarks(); }
		virtual NumberArray		landmarkAngles() { return _landmarkAngles; }

		// Interface for various sources of random numbers ------------

		inline  UniformRandom*	networkRandomizer()		{ return _networkRandomizer; }
		inline  UniformRandom*	locationRandomizer()	{ return _locationRandomizer; }
		inline  UniformRandom*	movementRandomizer()	{ return _movementRandomizer; }
		inline  UniformRandom*	pcSpikeRandomizer()		{ return _pcSpikeRandomizer; }
		inline  UniformRandom*	inSpikeRandomizer()		{ return _inSpikeRandomizer; }
		inline  UniformRandom*	synapticRandomizer()	{ return _synapticRandomizer; }

		// Interface with Clock Solver --------------------------------

		inline  SimTime			timeStep() { return model()->solver()->timeStep(); }
		virtual void			timeStep(SimTime h) { model()->solver()->timeStep(h); }

		virtual void			timeStepEnded();

		// Accessors for probing state values -------------------------

		virtual int				numStateVar() { return 0; }
		virtual int				numInternalStateVar() { return 4; }
		virtual Number			internalStateValue(int n);

		virtual const char*		componentName() { return "MazeSubject"; }
		virtual const char**	stateLabels() {
			static const char* sl[]={"locX","locY","headingX","heandingY"}; 
			return sl; }

		virtual Number*			unitsOfMeasure() {
			static Number um[] = {UOM::cm, UOM::cm, 1.0, 1.0 }; return &(um[0]); }

	protected:

		ModelComponentVector	_subscribers;	// subscribers to be informed of state changes
		MovementPolicy*			_movementPolicy; // Policy object implementing movements

		// Different random number streams, each of which can be
		// separately controlled, including setting of seeds for
		// reproducible results. The subject instance owns these
		// object and is responsible for creating and deleting them.
		UniformRandom*			_networkRandomizer;		// for establishing the network
		UniformRandom*			_locationRandomizer;	// for setting place cell locations
		UniformRandom*			_movementRandomizer;	// for for generating movements
		UniformRandom*			_pcSpikeRandomizer;		// for place cell spike trains
		UniformRandom*			_inSpikeRandomizer;		// for interneuron spike trains
		UniformRandom*			_synapticRandomizer;	// for random events in synapses

		// Parameters
		Maze*					_maze;			// current maze environment or NULL
		Maze*					_previousMaze;	// old maze before changing to a new one
		SpatialRegion*			_noveltyRegion;	// novelty region or NULL
		Number					_speed;			// walk/swim speed

		// State variables
		Number					_locX;			// current location X coord
		Number					_locY;			// current location Y coord
		Number					_headingX;		// current heading vector X coord
		Number					_headingY;		// current heading vector Y coord

		// Derived information
		NumberArray				_landmarkAngles; // angle to each landmark from current location

		// Compute angles to landmarks from current location.
		virtual	void			updateLandmarkAngles();
	};

	// ----------------------------------------------------------------
	// CLASS:	MovementPolicy
	// EXTENDS:	none
	// DESC:	Abstract class for maze subject movement policies.
	// RESP:
	//		1.	Know maze subject
	//		2.	Provide interface for movement
	//
	// ----------------------------------------------------------------

	class MovementPolicy {

	public:

		// Constructors and destructor
		MovementPolicy(MazeSubject* sub=NULL);
		virtual ~MovementPolicy();

		// Accessors
		inline  MazeSubject*	subject() { return _subject; }
		virtual void			subject(MazeSubject* sub) { _subject = sub; }

		inline  Maze*			maze() { return subject()->maze(); }

		inline  Number			locX() { return subject()->locX(); }
		inline  Number			locY() { return subject()->locY(); }

		inline  Number			headingX() { return subject()->headingX(); }
		inline  Number			headingY() { return subject()->headingY(); }

		inline  Number			speed() { return subject()->speed(); }

		// Pass updates of state on to subject
		virtual void			setLocationAndHeading(
			Number				x,				// location x coord
			Number				y,				// location y coord
			Number				hx,				// heading vector x coord
			Number				hy);			// heading vector y coord

		// Update the maze subject state to take the next movement
		virtual void			takeNextStep()=0;	// subclass responsibility

	protected:
		MazeSubject*			_subject;		// subject using this policy
	};

	// ----------------------------------------------------------------
	// CLASS:	RandomWalk
	// EXTENDS:	MovementPolicy
	// DESC:	Defines movements that wanders at random in a
	//			Maze. Path is a random walk combining monentum,
	//			noisey changes in direction, and random reset
	//			of direction upon encountering a maze wall.
	// RESP:
	//		1.	Know parameters for random walk.
	//		2.	Determine next change in location for a time step.
	//
	// NOTES:	Parameter defaults are intended to create a space-
	//			filling random walk with somewhat mouse-like aspects,
	//			there is no attempt to statistically model specific
	//			observed mouse data. To avoid excessive time spent
	//			bouncing off walks, randomness in the walk is
	//			temporarily set to zero and recovers with a time
	//			constant specified through wanderTau.
	// ----------------------------------------------------------------

	class RandomWalk : public MovementPolicy {

	public:

		// Constructors and destructor
		RandomWalk(MazeSubject* sub=NULL, 
			Number wrate=1/UOM::sec,			// wander rate value
			Number wtau=1*UOM::sec);			// wander tau value
		virtual ~RandomWalk();

		// Accessors
		inline  Number			wanderRate() { return _wanderRate; }
		virtual void			wanderRate(Number wr) { _wanderRate=_currentWanderRate=wr; }

		inline  Number			wanderTau() { return _wanderTau; }
		virtual void			wanderTau(Number tm) { _wanderTau = tm; }

		// Take the next step
		virtual void			takeNextStep();

	protected:
		Number					_wanderRate;		// Initial rate of random direction changes
		Number					_wanderTau;			// Time constant for recovering randomness
		Number					_currentWanderRate;	// Wander rate as of the present
	};

	// ----------------------------------------------------------------
	// CLASS:	WallFollower
	// EXTENDS:	MovementPolicy
	// DESC:	Defines movements that wanders while staying near
	//			a boundary. Movements are somewhat irregular but
	//			at each step there is an objective of staying
	//			a given distance from a boundary.
	// RESP:
	//		1.	Know desired boundary distance.
	//		2.	Determine next change in location for a time step.
	// ----------------------------------------------------------------

	class WallFollower : public MovementPolicy {

	public:

		// Constructors and destructor
		WallFollower(MazeSubject* sub=NULL, Number wd=2*UOM::cm);
		virtual ~WallFollower();

		// Accessors
		inline  Number			wallDistance() { return _wallDistance; }
		virtual void			wallDistance(Number d) { _wallDistance = d; }

		// Take the next step
		virtual void			takeNextStep();

	protected:
		Number					_wallDistance;
	};
};

#endif // #ifndef