/* -------------------------------------------------------------------- */
/*	HALLOVL.CPP 				Citadel 								*/
/*			Overlayed hall code for Citadel bulletin board system		*/
/* -------------------------------------------------------------------- */
#include "ctdl.h"
#pragma hdrstop

#include "room.h"
#include "log.h"
#include "hall.h"

/* -------------------------------------------------------------------- */
/*								Contents								*/
/* -------------------------------------------------------------------- */
/*	force() 				sysop special to force access into a hall	*/
/*	listhalls() 			sysop special to list all halls 			*/
/*	accesshall()			returns TRUE if person can access hall		*/
/*	enterhall() 			handles .eh 								*/
/*	gotodefaulthall()		goes to user's default hall                 */
/*	knownhalls()			handles .kh, .kvh							*/
/*	readhalls() 			handles .rh, .rvh							*/
/*	stephall()				handles previous, next hall 				*/
/* -------------------------------------------------------------------- */

/* -------------------------------------------------------------------- */
/*	force() 		sysop special to force access into a hall			*/
/* -------------------------------------------------------------------- */
void force(void)
	{
	label hallname;
	h_slot slot;

	doCR();

	do
		{
		getString(cfg.Lhall_nym, hallname, LABELSIZE, TRUE, ECHO,
				HallData->GetEntry(1)->GetName());

		if (*hallname == '?')
			{
			ListHalls(FALSE);
			}
		} while (*hallname == '?');

	if (!(*hallname))
		{
		return;
		}

	slot = partialhall(hallname);

	if (slot == CERROR)
		{
		CRmPrintfCR(getmsg(157), cfg.Lhall_nym, hallname);
		return;
		}

	TI()thisHall = slot;

	char TrapString[256];
	sprintf(TrapString, getsysmsg(356), cfg.Lhall_nym,
			HallData->GetEntry(TI()thisHall)->GetName());

	CRmPrintfCR(pcts, TrapString);

	sprintf(TrapString, getsysmsg(321),
			HallData->GetEntry(TI()thisHall)->GetName());

	trap(TrapString, T_SYSOP);
	}

/* -------------------------------------------------------------------- */
/*	listhalls() 	list all halls, or just those windowed off of room	*/
/* -------------------------------------------------------------------- */
void ListHalls(Bool WindowedOffRoom)
	{
	CRCRmPrintfCR(getmsg(962), cfg.Uhalls_nym);

	prtList(LIST_START);

	for (h_slot HallSlot = 0; HallSlot < cfg.maxhalls; HallSlot++)
		{
		if (HallData->GetEntry(HallSlot)->IsInuse() &&

				TI()CurrentUser->CanAccessHall(HallSlot) &&

				(!WindowedOffRoom ||
					(HallData->GetEntry(HallSlot)->
					IsWindowedIntoHall(TI()thisRoom) ||
					cfg.subhubs == 4)
				)
			)
			{
			prtList(HallData->GetEntry(HallSlot)->GetName());
			}
		}

	prtList(LIST_END);
	}

/* -------------------------------------------------------------------- */
/*	accesshall() returns true if hall can be accessed from current room */
/* -------------------------------------------------------------------- */
Bool accesshall(h_slot slot)
	{
	return (	// always list this hall
			(slot == TI()thisHall) ||

			// if not this hall, check to see if it is in use
			(HallData->GetEntry(slot)->IsInuse() &&

			// and this room is windowed into the hall
			(HallData->GetEntry(slot)->IsWindowedIntoHall(TI()thisRoom) ||
			cfg.subhubs == 4) &&

			// and we have group-access to the hall
			TI()CurrentUser->CanAccessHall(slot)));
	}

/* -------------------------------------------------------------------- */
/*	enterhall() 		handles .eh 									*/
/* -------------------------------------------------------------------- */
void enterhall(void)
	{
	label hallname;
	h_slot slot;
	int accessible;

	SetDoWhat(ENTERHALL);

	do
		{
		getString(cfg.Lhall_nym, hallname, LABELSIZE, TRUE, ECHO, ns);

		if (*hallname == '?')
			{
			ListHalls(TRUE);
			}
		} while (*hallname == '?');

	if (!*hallname)
		{
		return;
		}

	slot = partialhall(hallname);

	if (slot != CERROR)
		{
		accessible = accesshall(slot);
		}

	if ((slot == CERROR) || !(*hallname) || !accessible)
		{
		CRmPrintfCR(getmsg(611), cfg.Lhall_nym);
		return;
		}
	else
		{
		TI()thisHall = slot;
		}
	}

/* -------------------------------------------------------------------- */
/*	gotodefaulthall()		goes to user's default hall                 */
/* -------------------------------------------------------------------- */
void gotodefaulthall(void)
	{
	h_slot i;

	if (*TI()CurrentUser->GetDefaultHall())
		{
		for (i = 1; i < cfg.maxhalls; ++i)
			{
			if (HallData->GetEntry(i)->IsInuse() &&
					SameString(HallData->GetEntry(i)->GetName(),
					TI()CurrentUser->GetDefaultHall()))
				{
				if (TI()CurrentUser->CanAccessHall(i))
					{
					TI()thisHall = i;
					}
				}
			}
		}
	}

/* -------------------------------------------------------------------- */
/*	knownhalls()		handles .kh .kvh								*/
/* -------------------------------------------------------------------- */
void knownhalls(void)
	{
	SetDoWhat(KNOWNHALLS);

	CRmPrintfCR(getmsg(1001), cfg.Uhalls_nym);

	prtList(LIST_START);

	for (h_slot i = 0; i < cfg.maxhalls; i++)
		{
		if (accesshall(i))
			{
			prtList(HallData->GetEntry(i)->GetName());
			}
		}

	prtList(LIST_END);
	}

/* -------------------------------------------------------------------- */
/*	readhalls() 		handles .rh .rvh								*/
/* -------------------------------------------------------------------- */
void readhalls(void)
	{
	int i;
	char str[LABELSIZE + LABELSIZE];

	SetDoWhat(READHALLS);

	CRmPrintfCR(getmsg(1002), cfg.Uroom_nym, MakeRoomName(TI()thisRoom, str));

	prtList(LIST_START);

	for (i = 0; i < cfg.maxhalls; i++)
		{
		if (	HallData->GetEntry(i)->IsInuse() &&
				HallData->GetEntry(i)->IsRoomInHall(TI()thisRoom) &&
				TI()CurrentUser->CanAccessHall(i))
			{
			prtList(HallData->GetEntry(i)->GetName());
			}
		}

	prtList(LIST_END);
	}

/* -------------------------------------------------------------------- */
/*	roomonlyinthishall()	returns TRUE if room# is in hall and no 	*/
/*							others										*/
/* -------------------------------------------------------------------- */
int roomonlyinthishall(r_slot roomslot)
	{
	h_slot hall;

	if (!roominhall(roomslot, TI()thisHall))
		{
		return (FALSE);
		}

	for (hall = 0; hall < cfg.maxhalls; hall++)
		{
		if ((hall != TI()thisHall) &&
				HallData->GetEntry(hall)->IsRoomInHall(roomslot))
			{
			return (FALSE);
			}
		}

	return (TRUE);
	}

/* -------------------------------------------------------------------- */
/*	stephall()		handles previous, next hall 						*/
/* -------------------------------------------------------------------- */
void stephall(int direction)
	{
	if (TI()CurrentUser->IsUsePersonalHall())
		{
		CRCRmPrintfCR(getmsg(477), cfg.Lhall_nym);
		return;
		}

	h_slot i;
	int done = FALSE;

	i = TI()thisHall;

	do
		{
		/* step */
		if (direction == 1)
			{
			if (++i == cfg.maxhalls)
				{
				i = 0;
				}
			}
		else
			{
			if (--i == -1)
				{
				i = cfg.maxhalls - 1;
				}
			}

		/* keep from looping endlessly */
		if (i == TI()thisHall)
			{
			CRCRmPrintfCR(getmsg(1003), cfg.Lroom_nym);
			return;
			}

		if (HallData->GetEntry(i)->IsInuse())
			{
			/* is this room a window in hall we're checking */
			if (HallData->GetEntry(i)->IsWindowedIntoHall(TI()thisRoom) ||
					cfg.subhubs == 4)
				{
				// can group see this hall
				if (TI()CurrentUser->CanAccessHall(i))
					{
					mPrintf(pctss, HallData->GetEntry(i)->GetName());
					TI()thisHall = i;
					done = TRUE;
					}
				}
			}
		} while (!done);

	if (HallData->GetEntry(TI()thisHall)->IsDescribed() &&
			TI()CurrentUser->IsViewHallDescription())
		{
		if (!changedir(cfg.roompath))
			{
			return;
			}

		if (!IsFilenameLegal(HallData->GetEntry(TI()thisHall)->
				GetDescriptionFile(), FALSE))
			{
			changedir(cfg.homepath);
			return;
			}

		doCR();

		if (!filexists(HallData->GetEntry(TI()thisHall)->GetDescriptionFile()))
			{
			CRmPrintfCR(getmsg(1004), cfg.Lhall_nym,
					HallData->GetEntry(TI()thisHall)->GetDescriptionFile());
			changedir(cfg.homepath);
			return;
			}

		if (!TI()CurrentUser->IsExpert())
			{
			CRmPrintfCR(getmsg(1005));
			}

		dumpf(HallData->GetEntry(TI()thisHall)->GetDescriptionFile(), 1, FALSE);

		changedir(cfg.homepath);

		TI()UserControl.SetOutFlag(OUTOK);
		}
	else
		{
		doCR();
		}
	}

void HallEntry::Clear(void)
	{
	HallEntry1::Clear();
	HallEntry2::Clear();
	HallEntry3::Clear();
	}

void HallBuffer::Clear(void)
	{
	VerifyHeap();

	if (IsValid())
		{
		for (h_slot HS = 0; HS < NumHalls; HS++)
			{
			Halls[HS].Clear();
			}

		VerifyHeap();
		}
	}

HallBuffer::HallBuffer(h_slot NumberOfHalls, r_slot NumberOfRooms)
	{
	VerifyHeap();
	assert (NumberOfHalls <= (65532u / sizeof(HallEntry)));

	NumHalls = NumberOfHalls;

	Halls = new HallEntry[NumHalls];

	if (Halls)
		{
		for (h_slot HS = 0; HS < NumHalls; HS++)
			{
			Halls[HS].Resize(NumberOfRooms);
			}
		}

	Clear();
	VerifyHeap();
	}

void HallBuffer::Resize(h_slot NewNumberOfHalls, r_slot NumberOfRooms)
	{
	VerifyHeap();
	assert (NewNumberOfHalls <= (65532u / sizeof(HallEntry)));

	if (IsValid())
		{
		delete [] Halls;
		}

	NumHalls = NewNumberOfHalls;

	Halls = new HallEntry[NumHalls];

	if (Halls)
		{
		for (h_slot HS = 0; HS < NumHalls; HS++)
			{
			Halls[HS].Resize(NumberOfRooms);
			}
		}

	Clear();
	VerifyHeap();
	}


HallEntry::HallEntry(void) :
		HallEntry1(),
		HallEntry2(0),
		HallEntry3(0)
		{
		}


HallEntry::HallEntry(r_slot Rooms) :
		HallEntry1(),
		HallEntry2(Rooms),
		HallEntry3(Rooms)
		{
		}
