#ifndef MESSAGES_H
#define MESSAGES_H

#include "entity.h"
#include <d3dx9.h>
#include "llist.h"
#include "stack.h"

enum MessageType{mGroundCollision, mMove, mMoveOK, mNewEntity, mTotal}; //Total is put in so we have a value to look at
											//to see the total number of message types

class Entity;
class PhysicalEntity;

//This define is so that we can limit how many messages can be returned from a
// get message function call, so we don't have to worry about overrunning
// array bounds.  We could do this dynamically, but this is much more efficient as
// far as speed goes.  Also, we may be able to lower this number;  right now,
// the only object that ever sends this many messages at once is the Forest object,
// and that is only if the forest gets very large
#define MAXMESSAGES 300

class Msg
{
public:
	Msg() {Reciever = NULL;}

	Entity* Sender;
	Entity* Reciever;
	MessageType Type;
	//Subclass this for every message type and add message specific data
};

class MessageManager
{
public:
	MessageManager();
	~MessageManager();

	//Adds another message to the list of messages to be processed
	void QueueMessages(Msg** NewMessages, int NumNewMessages);

	//Note that I am making this function responsible for freeing the message
	// memory... the mem is allocated by the sender and freed here.
	void ProcessAllMessages();
	void AddListener(MessageType ListenerMessage, Entity* NewListener);

	void SetEntityList(LList<Entity*>* NewEntityList);

private:
	//We need to store a list of all the listeners, indexed by message type
	//It will be stored as an array of linked lists
	LList<Entity*>* Listeners;
	//Here's where we store all of the messages that have been queued up..
	// actually, the QueueMessages function name is deceptive, b/c we actually
	// store it as a stack.  I had a damn good reason for doing it like this, but
	// I forget at the moment... It somehow solved a problem with a case of infinite 
	// message passing
	Stack<Msg*> MessagesWaiting;

	//This is a pointer to the entitylist over in main;  we need it so
	// we can add new objects to it if the message is of type mNewEntity
	LList<Entity*>* EntityList;
};

class GroundCollisionMsg : public Msg
{
public:
	GroundCollisionMsg() {Type = mGroundCollision;}
	D3DXVECTOR3 Normal; //The normal of the surface that was collided with  
};

class MoveMsg : public Msg
{
public:
	MoveMsg() {Type = mMove;}

	//We are overriding this variable b/c the object must be a
	// physicalentity to send this message
	//PhysicalEntity* Sender;

	//We need to know where the thing is trying to move; This vector shows what
	// its change in position wants to be
	D3DXVECTOR3 MovementAmount;
};

class MoveOKMsg : public Msg
{
public:
	MoveOKMsg() {Type = mMoveOK;}

	//We are overriding this variable b/c the object must be a
	// physicalentity to recieve
	//PhysicalEntity* Reciever;

	//Here we tell the object how much it is ok to move; this may be less than it originally
	// requested if a collision occurred.
	D3DXVECTOR3 MovementAmount;
};

class NewEntityMsg : public Msg
{
public:
	NewEntityMsg() {Type = mNewEntity;}

	//This is the pointer to the new entity to be added to the object list
	Entity* NewEntity;
};

#endif
