/* -------------------------------------------------------------------- */
/*	HALL.H						Citadel 								*/
/*				Data and structures for the hall subsystem. 			*/
/* -------------------------------------------------------------------- */

#include "bitbag.h"
#include "boolexpr.h"

/* -------------------------------------------------------------------- */
/*	This is almost all of the information we know about halls. This is	*/
/*	stored in HALL.DAT. Like groups, we keep this whole buffer in		*/
/*	memory at a time. There is nothing that can really be taken out to	*/
/*	make a table out of it. But, why is it only "almost" all of the     */
/*	information? This is because we also keep track of which rooms are	*/
/*	in a hall, and which rooms are windowed into a hall. We cannot put	*/
/*	this data into the structure, because the number of rooms varies.	*/
/*	To keep track of that data, we have another hall file: HALL2.DAT.	*/
/*	This file is very simple: for each hall, we first write out which	*/
/*	rooms are in the hall, then which rooms are windowed into the hall. */
/*	Each room gets a single bit in each list, set if the room is in or	*/
/*	windowed into the hall, cleared if it is not.						*/
/* -------------------------------------------------------------------- */
class HallEntry1
	{
	label	Name;				// Name of our hall

	uchar	GroupNumber;		// owning group's #
								// Would prefer a g_slot... someday

	Bool	Inuse		: 1;	// Is hall in use?
	Bool	Owned		: 1;	// Is this hall owned?
	Bool	Described	: 1;	// described?
	Bool	UNUSED1 	: 1;	// default maintenance (not)
	Bool	EnterRoom	: 1;	// Can users enter rooms here?
	Bool	BoolGroup	: 1;	// If GroupExpression...

	uint	UNUSED2 	: 10;

	uchar	UNUSED3;			// hall default mainencance hall (not)
	char	DescriptionFile[13];// Hall description

	BoolExpr GroupExpression;	// If BoolGroup

public:
	HallEntry1(void)
		{
		assert(this);
		Clear();
		}

	void Clear(void)
		{
		assert(this);
		VerifyHeap();
		memset(this, 0, sizeof(*this));
		VerifyHeap();
		}

	HallEntry1& operator =(const HallEntry1 &Original)
		{
		assert(this);
		VerifyHeap();
		memcpy(this, &Original, sizeof(HallEntry1));
		VerifyHeap();
		return (*this);
		}

	void Verify(void)
		{
		assert(this);
		/* Make sure no strings are too long */
		Name[LABELSIZE] = 0;
		DescriptionFile[12] = 0;

		/* Fill unused areas with nothingness */
		UNUSED1 = 0;
		UNUSED2 = 0;
		UNUSED3 = 0;

		/* Don't overindex the group buffer */
		if (GroupNumber >= cfg.maxgroups)
			{
			GroupNumber = 0;
			}
		}

	const char *GetName(void) const
		{
		assert(this);
		return (Name);
		}

	void SetName(const char *New)
		{
		assert(this);
		assert(New);

		CopyStringToBuffer(Name, New, LABELSIZE);
		}

	const char *GetDescriptionFile(void) const
		{
		assert(this);
		return (DescriptionFile);
		}

	void SetDescriptionFile(const char *New)
		{
		assert(this);
		assert(New);

		CopyStringToBuffer(DescriptionFile, New, sizeof(DescriptionFile) - 1);
		}

	g_slot GetGroupNumber(void) const
		{
		assert(this);
		assert(Owned);
		assert(!BoolGroup);

		return (GroupNumber);
		}

	void SetGroupNumber(g_slot New)
		{
		assert(this);
		assert(Owned);
		assert(!BoolGroup);

		GroupNumber = (uchar) New;
		}

	Bool IsOwned(void) const
		{
		assert(this);
		return (Owned);
		}

	void SetOwned(Bool New)
		{
		assert(this);
		Owned = !!New;
		}

	Bool IsDescribed(void) const
		{
		assert(this);
		return (Described);
		}

	void SetDescribed(Bool New)
		{
		assert(this);
		Described = !!New;
		}

	Bool IsInuse(void) const
		{
		assert(this);
		return (Inuse);
		}

	void SetInuse(Bool New)
		{
		assert(this);
		Inuse = !!New;
		}

	Bool IsEnterRoom(void) const
		{
		assert(this);
		return (EnterRoom);
		}

	void SetEnterRoom(Bool New)
		{
		assert(this);
		EnterRoom = !!New;
		}

	Bool IsBoolGroup(void) const
		{
		assert(this);
		return (BoolGroup);
		}

	void SetBoolGroup(Bool New)
		{
		assert(this);
		BoolGroup = !!New;
		}

	const uint *GetGroupExpression(void) const
		{
		assert(this);
		assert(Owned);
		assert(BoolGroup);

		return (GroupExpression);
		}

	void SetGroupExpression(BoolExpr New)
		{
		assert(this);
		assert(Owned);
		assert(BoolGroup);
		assert(IsBooleanExpressionValid(New));

		memcpy(GroupExpression, New, sizeof(BoolExpr));
		}

	Bool Load(h_slot Slot, FILE *File);
	Bool Save(h_slot Slot, FILE *File) const;
	};

class HallEntry2 : public BitBag
	{
	char FileName[13];

public:
	void SetFileName(const char *NewName)
		{
		assert(this);

		CopyStringToBuffer(FileName, NewName, sizeof(FileName) - 1);
		}

	void ResetFileName(void)
		{
		SetFileName(hall2Dat);
		}

	HallEntry2(r_slot NumRooms = 0) :
		BitBag(NumRooms)
		{
		ResetFileName();
		VerifyHeap();
		}

	Bool Load(h_slot Index, FILE *HallFile);
	Bool Save(h_slot Index, FILE *HallFile) const;

	Bool IsRoomInHall(r_slot RoomSlot) const
		{
		return (BitTest(RoomSlot));
		}

	void SetRoomInHall(r_slot RoomSlot, Bool RoomInHall)
		{
		BitSet(RoomSlot, RoomInHall);
		}
	};

class HallEntry3 : public BitBag
	{
	char FileName[13];

public:
	void SetFileName(const char *NewName)
		{
		assert(this);

		CopyStringToBuffer(FileName, NewName, sizeof(FileName) - 1);
		}

	void ResetFileName(void)
		{
		SetFileName(hall2Dat);
		}

	HallEntry3(r_slot NumRooms = 0) :
		BitBag(NumRooms)
		{
		ResetFileName();
		VerifyHeap();
		}

	Bool Load(h_slot Index, FILE *HallFile);
	Bool Save(h_slot Index, FILE *HallFile) const;

	Bool IsWindowedIntoHall(r_slot RoomSlot) const
		{
		return (BitTest(RoomSlot));
		}

	void SetWindowedIntoHall(r_slot RoomSlot, Bool Windowed)
		{
		BitSet(RoomSlot, Windowed);
		}
	};

class HallEntry : public HallEntry1, public HallEntry2, public HallEntry3
	{
public:
	HallEntry(void);
	HallEntry(r_slot Rooms);
	HallEntry(const LogEntry &Original);

	HallEntry& HallEntry::operator = (const HallEntry &Original)
		{
		assert(this);
		VerifyHeap();
		HallEntry1::operator =(Original);
		HallEntry2::operator =(Original);
		HallEntry3::operator =(Original);
		VerifyHeap();
		return (*this);
		}

	void Resize(r_slot Rooms)
		{
		assert(this);
		HallEntry2::Resize(Rooms);
		HallEntry3::Resize(Rooms);
		}

	void Clear(void);

	Bool IsValid(void) const;

	Bool Load(h_slot HallSlot, FILE *HallFile1, FILE *HallFile2);
	Bool Save(h_slot HallSlot, FILE *HallFile1, FILE *HallFile2) const;
	};

class HallBuffer
	{
	h_slot NumHalls;
	HallEntry *Halls;

public:
	void Clear(void);

	HallBuffer(h_slot NumberOfHalls, r_slot NumberOfRooms);
	void Resize(h_slot NewNumberOfHalls, r_slot NumberOfRooms);

	~HallBuffer(void)
		{
		assert(this);
		VerifyHeap();
		delete [] Halls;
		VerifyHeap();
		}

	Bool IsValid(void) const
		{
		assert(this);
		return (Halls != NULL);
		}

	HallEntry *GetEntry(h_slot HallSlot) const
		{
		assert(this);
		assert(HallSlot >= 0);
		assert(HallSlot < NumHalls);

		if (IsValid())
			{
			return (&Halls[HallSlot]);
			}
		else
			{
			return (NULL);
			}
		}

	Bool Load(const char *Name = hallDat);
	Bool Save(const char *Name = hallDat) const;

	const HallEntry *GetPointer(void) const
		{
		assert(this);
		return (Halls);
		}
	};

extern HallBuffer	*HallData;			// Hall data goes here

/* HALL.CPP */
extern Bool accesshall(int slot);
extern void enterhall(void);
extern void gotodefaulthall(void);
extern h_slot hallexists(const char *hallname);
extern Bool iswindow(r_slot roomslot);
extern void knownhalls(void);
extern h_slot partialhall(const char *hallname);
extern void readhalls(void);
extern int roominhall(r_slot roomslot, h_slot hallslot);
extern int roomonlyinthishall(int roomslot);
extern void stephall(int direction);


/* HALLEDIT.CPP */
void force(void);
void globalhall(void);
void hallfunc(void);
Bool killhall(const char *hn);
void ListHalls(Bool WindowedOffRoom);
Bool newhall(const char *name, const char *group, r_slot room);
Bool renamehall(void);
void windowfunc(void);
Bool moveHall(int offset, h_slot hall, Bool disp);
