// --------------------------------------------------------------------------
// Citadel: DoRmHall.CPP
//
// Room and Hall commands

#include "ctdl.h"
#pragma hdrstop

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

// --------------------------------------------------------------------------
// Contents
//
// exclude()		handles X>clude room, toggles the bit
// doGoto() 		handles G(oto) command
// doGotoMail() 	handles .M(ail scan) command
// doKnown()		handles K(nown rooms) command
// doNext() 		handles '+' next room
// doPrevious() 	handles '-' previous room
// doNextHall() 	handles '>' next room
// doPreviousHall() handles '<' previous room
// doPersonal() 	handles .P(ersonal hall) command


// --------------------------------------------------------------------------
// exclude(): Handles X>clude room, toggles the bit.

void exclude(void)
	{
	SetDoWhat(DOEXCLUDE);

	if ((TI()thisRoom == LOBBY || !IsCurrentRoomExcludable()) &&
			!TI()CurrentUser->IsRoomExcluded(TI()thisRoom))
		{
		CRCRmPrintfCR(getmsg(256), cfg.Lroom_nym);
		}
	else if (!TI()CurrentUser->IsRoomExcluded(TI()thisRoom))
		{
		if (!TI()CurrentUser->IsExpert())
			{
			char Prompt[128];

			doCR();
			sprintf(Prompt, getmsg(257), cfg.Lroom_nym);
			if (!getYesNo(Prompt, 1))
				{
				return;
				}
			}
		else
			{
			doCR();
			}

		CRmPrintfCR(getmsg(258), cfg.Uroom_nym);
		TI()CurrentUser->SetRoomExcluded(TI()thisRoom, TRUE);
		}
	else
		{
		CRCRmPrintfCR(getmsg(259), cfg.Uroom_nym);
		TI()CurrentUser->SetRoomExcluded(TI()thisRoom, FALSE);
		}
	}


// --------------------------------------------------------------------------
// doGoto(): Handles G(oto) command.

void doGoto(Bool expand, char skip)
	{
	if (!skip)
		{
		mPrintf(getmsg(260));
		SetDoWhat(DOGOTO);
		}
	else
		{
		mPrintf(getmsg(261));
		SetDoWhat(DOBYPASS);
		}

	if (!expand)
		{
		gotoRoom(ns, skip, TRUE, FALSE);
		}
	else
		{
		label roomName;
		roomName[0] = 0;

		do
			{
			char Prompt[128];

			sprintf(Prompt, roomName[0] == '?' ? getmsg(262) : ns,
					cfg.Lroom_nym);

			if (!getString(Prompt, roomName, LABELSIZE, TRUE, ECHO, ns))
				{
				return;
				}

			normalizeString(roomName);

			if (roomName[0] == '?')
				{
				TI()MRO.Verbose = FALSE;
				listRooms(0);
				}
			} while (roomName[0] == '?');

		gotoRoom(roomName, skip, TRUE, FALSE);
		}
	}


// --------------------------------------------------------------------------
// doGotoMail(): Handles .M(ail Scan) command.

void doGotoMail(void)
	{
	mPrintf(getmsg(900), cfg.Lroom_nym);
	SetDoWhat(DOGOTOMAIL);

	gotoRoom(ns, FALSE, TRUE, TRUE);
	}


// --------------------------------------------------------------------------
// doKnown(): Handles K(nown rooms) command.

void doKnown(Bool moreYet, char first)
	{
	Bool done = FALSE;
	ulong kWhat = K_NEW | K_OLD;

	SetDoWhat(DOKNOWN);

	TI()MRO.Verbose = FALSE;
	TI()MRO.Reverse = FALSE;

	if (moreYet)
		{
		first = '\0';
		}

	mPrintf(getmsg(265));

	int OptionCounter = 0;

	do
		{
		int ich;
		const int letter = toupper(first ? (int) first : (ich = iCharNE()));

		if (++OptionCounter == 69)
			{
			mPrintf(getmsg(69));
			mPrintf(spc);
			OptionCounter = 0;
			}

		switch (letter)
			{
			case '0':
				{
				mPrintf(getmsg(1272));
				kWhat |= K_NOMSGS;
				break;
				}

			case 'A':
				{
				mPrintf(getmsg(266));
				kWhat |= K_APPLIC;
				break;
				}

			case 'B':
				{
				mPrintf(getmsg(1211));
				kWhat |= K_BIO;
				break;
				}

			case 'D':
				{
				mPrintf(getmsg(269));
				kWhat |= K_DIR;
				break;
				}

			case 'G':
				{
				mPrintf(getmsg(236), cfg.Ugroup_nym);
				kWhat |= K_GROUP;
				break;
				}

			case 'H':
				{
				mPrintfCR(pcts, cfg.Uhalls_nym);
				knownhalls();
				done = TRUE;
				break;
				}

			case 'I':
				{
				mPrintfCR(getmsg(277), cfg.Uroom_nym);
				ShowRoomStatus();
				done = TRUE;
				break;
				}

			case 'K':
				{
				mPrintf(getmsg(297));
				kWhat |= K_KEYWORD;
				break;
				}

			case 'L':
				{
				mPrintf(getmsg(272));
				kWhat |= K_LOCAL;
				kWhat &= ~K_SHARED;
				break;
				}

			case 'M':
			case 'E':
				{
				mPrintf(getmsg(275), cfg.Lmsg_nym);
				kWhat |= K_MAIL;
				break;
				}

			case 'N':
				{
				mPrintf(getmsg(273));
				kWhat |= K_NEW;
				kWhat &= ~K_OLD;
				break;
				}

			case 'O':
				{
				mPrintf(getmsg(274));
				kWhat |= K_OLD;
				kWhat &= ~K_NEW;
				break;
				}

			case 'P':
				{
				mPrintf(getmsg(268));
				kWhat |= K_PERM;
				break;
				}

			case '\r':
			case '\n':
			case 'R':
				{
				mPrintfCR(pcts, cfg.Urooms_nym);
				listRooms(kWhat);
				done = TRUE;
				break;
				}

			case 'S':
				{
				mPrintf(getmsg(276));
				kWhat |= K_SHARED;
				kWhat &= ~K_LOCAL;
				break;
				}

			case 'T':
				{
				mPrintf(getmsg(280), cfg.Lhall_nym);
				kWhat |= K_THALL;
				break;
				}

			case 'V':
				{
				mPrintf(getmsg(279));
				TI()MRO.Verbose = TRUE;
				break;
				}

			case 'W':
				{
				mPrintf(getmsg(281));

				if (cfg.subhubs == 4)
					{
					CRCRmPrintfCR(getmsg(282));
					return;
					}

				kWhat |= K_WINDOWS;
				break;
				}

			case 'X':
				{
				mPrintf(getmsg(283));
				kWhat |= K_EXCLUDE;
				kWhat &= ~K_NEW & ~K_OLD;
				break;
				}

			case 'Y':
				{
				mPrintf(getmsg(267));
				kWhat |= K_ANON;
				break;
				}

			case ')':
				{
				mPrintf(getmsg(517));
				kWhat |= K_HIDDEN;
				break;
				}

			case '#':
				{
				mPrintf(getmsg(284), cfg.Lmsgs_nym);
				kWhat |= K_NUM;
				break;
				}

			case ESC:
				{
				done = TRUE;
				break;
				}

			default:
				{
				oChar(ich);
				mPrintf(sqst);
				done = TRUE;
				if (TI()CurrentUser->IsExpert())
					{
					break;
					}
				}

			case '?':
				{
				if (letter == '?')
					{
					oChar('?');
					}

				SetDoWhat(KNOWNMENU);

				showMenu(M_KNOWN);
				done = TRUE;
				break;
				}
			}
		} while (!done && moreYet);
	}


// --------------------------------------------------------------------------
// doNext(): Handles the '+' for next room.

void doNext()
	{
	mPrintf(getmsg(321), cfg.Lroom_nym);
	stepRoom(1);
	}


// --------------------------------------------------------------------------
// doPrevious(): Handles the '-' for previous room.

void doPrevious()
	{
	mPrintf(getmsg(322), cfg.Lroom_nym);
	stepRoom(0);
	}


// --------------------------------------------------------------------------
// doNextHall(): Handles the '>' for next hall.

void doNextHall()
	{
	mPrintf(getmsg(321), cfg.Lhall_nym);
	stephall(1);
	}


// --------------------------------------------------------------------------
// doPreviousHall(): Handles the '<' for previous hall.

void doPreviousHall()
	{
	mPrintf(getmsg(322), cfg.Lhall_nym);
	stephall(0);
	}


// --------------------------------------------------------------------------
// doPersonal(): Handles .P(ersonal hall) command.

static void ListRoomsNotInPersonalHall(void)
	{
	Bool *AccessArray = new Bool[cfg.maxrooms];

	if (AccessArray)
		{
		theOtherAlgorithm(AccessArray, TI()thisHall, FALSE);
		}
	else
		{
		mPrintf(getmsg(188), getmsg(1307));
		return;
		}

	CRmPrintfCR(getmsg(791), cfg.Urooms_nym, cfg.Lhall_nym);

	prtList(LIST_START);

	for (r_slot RoomSlot = 0; RoomSlot < cfg.maxrooms; RoomSlot++)
		{
		if (AccessArray[RoomPosTableToRoom(RoomSlot)] &&
				TI()CurrentUser->CanAccessRoom(RoomPosTableToRoom(RoomSlot), FALSE, FALSE) &&
				!TI()CurrentUser->IsRoomInPersonalHall(RoomPosTableToRoom(RoomSlot)))
			{
			prtList(GetRoomName(RoomPosTableToRoom(RoomSlot)));
			}
		}

	prtList(LIST_END);

	delete [] AccessArray;
	}

static void ListRoomsInPersonalHall(void)
	{
	CRmPrintfCR(getmsg(792), cfg.Urooms_nym, cfg.Lhall_nym);

	prtList(LIST_START);

	for (r_slot RoomSlot = 0; RoomSlot < cfg.maxrooms; RoomSlot++)
		{
		if (TI()CurrentUser->CanAccessRoom(RoomPosTableToRoom(RoomSlot), FALSE, FALSE) &&
				TI()CurrentUser->IsRoomInPersonalHall(RoomPosTableToRoom(RoomSlot)))
			{
			prtList(GetRoomName(RoomPosTableToRoom(RoomSlot)));
			}
		}

	prtList(LIST_END);
	}

void doPersonal(void)
	{
	SetDoWhat(DOPERSONAL);

	TI()MRO.Reverse = FALSE;

	mPrintf(getmsg(903), cfg.Lhall_nym);

	if (!cfg.PersonalHallOK)
		{
		CRCRmPrintfCR(getmsg(621), cfg.Lhalls_nym);
		return;
		}

	int letter, ich;
	letter = toupper(ich = iCharNE());

	switch (letter)
		{
		case 'A':
			{
			mPrintf(getmsg(902));

			SetDoWhat(PERSONALADD);

			letter = toupper(ich = iCharNE());

			switch (letter)
				{
				case 'A':
					{
					Bool add = FALSE;

					mPrintfCR(getmsg(292));
					doCR();

					SetDoWhat(PERSONALADDALL);

					char Prompt[128];
					sprintf(Prompt, getmsg(622), cfg.Lrooms_nym,
							cfg.Lhall_nym);
					if (getYesNo(Prompt, 0))
						{
						for (r_slot rm = 0; rm < cfg.maxrooms; rm++)
							{
							if (theAlgorithm(RoomPosTableToRoom(rm),
									TI()thisHall, FALSE) &&
									!TI()CurrentUser->IsRoomInPersonalHall(RoomPosTableToRoom(rm)))
								{
								char string[LABELSIZE+LABELSIZE];

								if (!add)
									{
									mPrintf(getmsg(857), cfg.Lrooms_nym);
									prtList(LIST_START);
									}

								MakeRoomName(RoomPosTableToRoom(rm), string);
								prtList(string);
								add = TRUE;
								TI()CurrentUser->SetRoomInPersonalHall(RoomPosTableToRoom(rm),
										TRUE);
								}
							}

						if (add)
							{
							prtList(LIST_END);
							}
						else
							{
							mPrintfCR(getmsg(855), getmsg(856),
									cfg.Lrooms_nym, cfg.Lhall_nym);
							}
						}

					break;
					}

				case 'L':
					{
					Bool add = FALSE;

					mPrintfCR(getmsg(272));
					doCR();

					SetDoWhat(PERSONALADDLOCAL);

					char Prompt[128];
					sprintf(Prompt, getmsg(623), cfg.Lrooms_nym,
							cfg.Lhall_nym);

					if (getYesNo(Prompt, 0))
						{
						for (r_slot rm = 0; rm < cfg.maxrooms; rm++)
							{
							if (theAlgorithm(RoomPosTableToRoom(rm), TI()thisHall, FALSE) &&
									!TI()CurrentUser->IsRoomInPersonalHall(RoomPosTableToRoom(rm)) &&
									!IsRoomShared(RoomPosTableToRoom(rm)))
								{
								char string[LABELSIZE + LABELSIZE];

								if (!add)
									{
									mPrintf(getmsg(1348));
									prtList(LIST_START);
									}

								MakeRoomName(RoomPosTableToRoom(rm), string);
								prtList(string);
								add = TRUE;
								TI()CurrentUser->SetRoomInPersonalHall(RoomPosTableToRoom(rm),
										TRUE);
								}
							}

						if (add)
							{
							prtList(LIST_END);
							}
						else
							{
							mPrintfCR(getmsg(855), ns, cfg.Lrooms_nym,
									cfg.Lhall_nym);
							}
						}

					break;
					}

				case '\r':
				case '\n':
				case 'R':
					{
					label roomname;

					mPrintfCR(pcts, cfg.Uroom_nym);

					SetDoWhat(PERSONALADDROOM);

					do
						{
						getString(getmsg(1279), roomname, LABELSIZE, TRUE,
								ECHO, GetRoomName(TI()thisRoom));

						if (*roomname == '?')
							{
							ListRoomsNotInPersonalHall();
							}
						} while (*roomname == '?');

					r_slot rm = RoomExists(roomname);

					if (rm == CERROR)
						{
						rm = PartialRoomExists(roomname, 0, TRUE);
						}

					if (rm == CERROR || !(*roomname) ||
								!theAlgorithm(rm, TI()thisHall, FALSE))
						{
						CRmPrintfCR(getmsg(1066), cfg.Lroom_nym, roomname);
						return;
						}

					if (!TI()CurrentUser->IsRoomInPersonalHall(rm))
						{
						TI()CurrentUser->SetRoomInPersonalHall(rm, TRUE);
						CRmPrintfCR(getmsg(862), cfg.Uroom_nym,
								GetRoomName(rm), cfg.Lhall_nym);
						}
					else
						{
						CRmPrintfCR(getmsg(861), cfg.Uroom_nym,
								GetRoomName(rm), cfg.Lhall_nym);
						}

					break;
					}

				case ESC:
					{
					break;
					}

				default:
					{
					oChar((char) ich);
					mPrintf(sqst);
					if (TI()CurrentUser->IsExpert())
						{
						break;
						}
					}

				case '?':
					{
					if (letter == '?')
						{
						oChar('?');
						}

					SetDoWhat(PERSONALADDMENU);

					showMenu(M_PERSONALADD);
					break;
					}
				}

			break;
			}

		case 'C':
			{
			char Prompt[128];

			mPrintfCR(getmsg(854));

			SetDoWhat(PERSONALCLEAR);

			sprintf(Prompt, getmsg(853), cfg.Lrooms_nym, cfg.Lhall_nym);
			if (getYesNo(Prompt, 0))
				{
				for (r_slot rm = 0; rm < cfg.maxrooms; rm++)
					{
					TI()CurrentUser->SetRoomInPersonalHall(rm, FALSE);
					}
				}

			break;
			}

		case 'L':
			{
			Bool rooms = FALSE;

			SetDoWhat(PERSONALLST);

			mPrintfCR(getmsg(870), cfg.Lrooms_nym);
			doCR();

			TI()UserControl.SetOutFlag(OUTOK);

			for (r_slot rm = 0; rm < cfg.maxrooms; rm++)
				{
				if (TI()CurrentUser->IsRoomInPersonalHall(RoomPosTableToRoom(rm)))
					{
					if (TI()CurrentUser->CanAccessRoom(RoomPosTableToRoom(rm), FALSE, FALSE))
						{
						char string[LABELSIZE+LABELSIZE];

						if (!rooms)
							{
							mPrintfCR(getmsg(865), cfg.Urooms_nym,
									cfg.Lhall_nym);
							prtList(LIST_START);
							}

						MakeRoomName(RoomPosTableToRoom(rm), string);
						prtList(string);
						rooms = TRUE;
						}
					}
				}

			if (rooms)
				{
				prtList(LIST_END);
				}
			else
				{
				mPrintfCR(getmsg(860), cfg.Lrooms_nym, cfg.Lhall_nym);
				}

			break;
			}

		case 'R':
			{
			label roomname;

			SetDoWhat(PERSONALRMV);

			mPrintfCR(getmsg(871), cfg.Lroom_nym);

			do
				{
				getString(getmsg(1279), roomname, LABELSIZE, TRUE, ECHO,
						GetRoomName(TI()thisRoom));

				if (*roomname == '?')
					{
					ListRoomsInPersonalHall();
					}
				} while (*roomname == '?');

			r_slot rm = RoomExists(roomname);

			if (rm == CERROR)
				{
				rm = PartialRoomExists(roomname, 0, TRUE);
				}

			if (rm == CERROR || !(*roomname) ||
						!theAlgorithm(rm, TI()thisHall, FALSE))
				{
				CRmPrintfCR(getmsg(1066), cfg.Lroom_nym, roomname);
				return;
				}

			if (TI()CurrentUser->IsRoomInPersonalHall(rm))
				{
				TI()CurrentUser->SetRoomInPersonalHall(rm, FALSE);
				CRmPrintfCR(getmsg(864), cfg.Uroom_nym,
						GetRoomName(rm), cfg.Lhall_nym);
				}
			else
				{
				CRmPrintfCR(getmsg(863), cfg.Lroom_nym,
						GetRoomName(rm), cfg.Lhall_nym);
				}

			break;
			}

		case 'U':
			{
			SetDoWhat(PERSONALUSE);

			mPrintfCR(getmsg(869));

			TI()CurrentUser->SetUsePersonalHall(!TI()CurrentUser->IsUsePersonalHall());

			if (TI()CurrentUser->IsUsePersonalHall())
				{
				CRmPrintfCR(getmsg(867), cfg.Lhall_nym);
				}
			else
				{
				CRmPrintfCR(getmsg(866), cfg.Lhall_nym);
				}

			break;
			}

		case ESC:
			{
			break;
			}

		default:
			{
			oChar((char) ich);
			mPrintf(sqst);
			if (TI()CurrentUser->IsExpert())
				{
				break;
				}
			}

		case '?':
			{
			if (letter == '?')
				{
				oChar('?');
				}

			SetDoWhat(PERSONALMENU);

			showMenu(M_PERSONAL);
			break;
			}
		}
	}
