#ifndef BOTMENU_H
#define BOTMENU_H

extern char *sAdvancedBotOptionsMenuCommands[];
extern char *sBotTeamMenuNames[];
extern char *sBotClassMenuNames[];
extern char gszDefaultPerso[32];
extern bool gbIsDBMode;

#include<VGUI_Panel.h>
#include<VGUI_TablePanel.h>
#include<VGUI_HeaderPanel.h>
#include<VGUI_TextGrid.h>
#include<VGUI_Label.h>
#include<vgui_grid.h>
#include<vgui_textentry.h>
#include"vgui_scorepanel.h"

#define BUTTON_HEIGHT YRES(24)

#define BUTTON_HEIGHT_SPACE		YRES(2)
#define BUTTON_WIDTH_SPACE		XRES(4)

#define BACKEXIT_BUTTONS_WIDTH	XRES(120)
#define INCDECBUTTON_WIDTH	XRES(40)
#define INCDECBUTTON_HEIGHT	YRES(20)
#define INCDECLABEL_WIDTH	XRES(165)
#define INCDECLABEL_HEIGHT	YRES(24)
#define INCDECLABEL_SPACE	XRES(5)

#define MAINBOTMENU_BUTTONS					6
#define BOTSKILLMENU_BUTTONS				5
#define BOTAGGRESSIONLEVELMENU_BUTTONS		3
#define BOTSETTINGSMENU_BUTTONS				8
#define KICKBOTSMENU_BUTTONS				3
#define BOTPERCENTMENU_BUTTONS				7
#define ADVANCEDBOTMENU_BUTTONS				5
#define ADVANCEDBOTMENU_CHECKBUTTONS		8

#define BOTSETTINGSMENU_SCROLLBARS			8
#define BOTCHATSETTINGSMENU_SCROLLBARS		7

#define MAINBOTMENU_SUBMENUS				4
#define ADVANCEDBOTOPTIONSMENU_SUBMENUS		4

#define PANEL_TRANS 255

#define BOTMENU_X(wide)		(ScreenWidth - wide)/2
#define BOTMENU_Y(height)	(ScreenHeight - height)/2

#define BOTMENU_WIDTH					ScreenWidth/2
#define ADDBOTMENU_WIDTH				XRES(525)
#define ADDSBOTMENU_WIDTH				XRES(510)
#define ADVANCEDOPTIONSBOTMENU_WIDTH	XRES(380)
#define BOTSETTINGSMENU_WIDTH			XRES(490)
#define BOTCHATSETTINGSMENU_WIDTH		XRES(490)
#define BOTMANAGERMENU_WIDTH			XRES(490)
#define BOTMANAGERLIST_WIDTH			XRES(300)
#define EDITBOTMENU_WIDTH				XRES(470)

#define MAINBOTMENU_HEIGHT				((MAINBOTMENU_BUTTONS * (BUTTON_HEIGHT + BUTTON_HEIGHT_SPACE)) + (3 * BUTTON_HEIGHT + BUTTON_HEIGHT_SPACE) + (2 * BUTTON_HEIGHT_SPACE))
#define ADDBOTMENU_HEIGHT				YRES(390)
#define ADDSBOTMENU_HEIGHT				YRES(400)
#define ADVANCEDOPTIONSBOTMENU_HEIGHT	YRES(240)
#define BOTSETTINGSMENU_HEIGHT			YRES(390)
#define BOTCHATSETTINGSMENU_HEIGHT		YRES(352)
#define BOTSKILLMENU_HEIGHT				((BOTSKILLMENU_BUTTONS * (BUTTON_HEIGHT + BUTTON_HEIGHT_SPACE)) + (5 * BUTTON_HEIGHT + BUTTON_HEIGHT_SPACE) + (2 * BUTTON_HEIGHT_SPACE))
#define BOTAGGRESSIONLEVELMENU_HEIGHT	((BOTAGGRESSIONLEVELMENU_BUTTONS * (BUTTON_HEIGHT + BUTTON_HEIGHT_SPACE)) + (5 * BUTTON_HEIGHT + BUTTON_HEIGHT_SPACE) + (2 * BUTTON_HEIGHT_SPACE))
#define BOTMANAGERMENU_HEIGHT			YRES(315)
#define EDITBOTMENU_HEIGHT				YRES(360)

#define APPLYBUTTON_WIDTH		XRES(75)
#define BOTSLIDER_WIDTH			XRES(147)
#define BOTSLIDER_HEIGHT		YRES(10)

enum BotVGUIMsgTypes
{
	BOTVGUI_ADDPERSO=0, // Add a new personality to the list
	BOTVGUI_DEFAULTPERSO, // Sets the default personality
	BOTVGUI_BOTSKILL, // Updates skill for a single bot
	BOTVGUI_BOTPERSO, // Updates personality for a single bot
	BOTVGUI_BOTDBROLE, // Updates the bot role for a single bot
	BOTVGUI_DBMODE // Set db mode
};

struct bot_info_s
{
	short sEntIndex; // Entity index of this bot
	short sSkill; // Skill of this bot
	short sDBRole; // The db role of this bot
	char szPersonality[32]; // Personality of this bot
};


// Utility functions
short GetBotIndex(int iEntIndex);
bot_info_s *GetBotPointer(int iEntIndex);
bot_info_s *GetFirstFreeBotSlot(void);


// Button that only works if team play is enabled
class CBotTeamButton : public CommandButton
{
public:
	CBotTeamButton(const char* text,int x,int y,int wide,int tall) : CommandButton(text, x, y, wide, tall) {};
	virtual void setArmed(bool state) { if (gHUD.m_Teamplay) CommandButton::setArmed(state); else CommandButton::setArmed(false); };
	virtual void fireActionSignal(void) { if (gHUD.m_Teamplay) CommandButton::fireActionSignal(); };
};

// Base Bot Menu
class CBaseBotMenu : public CMenuPanel
{
public:
	CBaseBotMenu(int iRemoveMe, int tall) : CMenuPanel(PANEL_TRANS, iRemoveMe, BOTMENU_X(BOTMENU_WIDTH), BOTMENU_Y(tall), BOTMENU_WIDTH, tall),
											m_pPanel(NULL), m_pExitButton(NULL), m_pGoBackButton(NULL),
											m_pTitle(NULL) { SetMenuID(MENU_BOTMENU); };
	// Overloaded for wide
	CBaseBotMenu(int iRemoveMe, int wide, int tall) : CMenuPanel(PANEL_TRANS, iRemoveMe, BOTMENU_X(wide), BOTMENU_Y(tall), wide, tall),
											m_pPanel(NULL), m_pExitButton(NULL), m_pGoBackButton(NULL),
											m_pTitle(NULL) { SetMenuID(MENU_BOTMENU); };
	virtual void DeInit(void) { }; // Get called when the game is shutdown

	virtual void paintBackground(void);
	virtual int KeyInput(int KeyNum) { return 1; };

protected:
	CTransparentPanel	*m_pPanel;
	CommandButton		*m_pExitButton;
	CommandButton		*m_pGoBackButton;
	Label				*m_pTitle;

	void MakeExitButton(int x, int y, int wide, int tall); // Every bot menu has a exit button
	Label *MakeTitle(const char *szText, int x, int y, int wide, int tall);
	Label *MakeLabel(const char *szText, int x, int y, int wide, int tall = YRES(20),
					 vgui::Label::Alignment Al = vgui::Label::a_west, int r = 200, int g = 200,
					 int b = 200, int a = 150);
	Label *MakeIncDecLabel(const char *szText, int x, int y);
	void MakeBackToMainButton(int x, int y, int wide, int tall);
	void MakeCancelButton(int x, int y, int wide, int tall);
	void MakeBackAndExitButtons(int y, int PanelWidth); // Makes both the 'Back to main menu' button and Exit button
	void MakeIncreaseButton(int x, int y, int *pVar, int iDefault, int Min, int Max, Label *pLabel, const char *szHeadText, char **szValTexts = NULL, bool bTeamOnly = false);
	void MakeDecreaseButton(int x, int y, int *pVar, int iDefault, int Min, int Max, Label *pLabel, const char *szHeadText, char **szValTexts = NULL, bool bTeamOnly = false);
	void MakeSettingScrollBar(int x, int y, Label *&pLabel, ScrollBar2 *&pScrollBar, const char *szTitle, const char *szCommand);
};

class CBotTextEntry : public TextEntry
{
	int m_iMaxChars;

	bool CanAddChar(void);

public:
	CBotTextEntry(const char* text,int x,int y,int wide,int tall) : TextEntry(text,x,y,wide,tall),
																	m_iMaxChars(-1) {};
	virtual void doInsertChar(char ch);
	void SetMaxChars(int Max) { m_iMaxChars = Max; };
};

class CBotBoolCheckBox : public CCheckButton2
{
	char m_szCVAR[128];

	void ChangeCVAR(void);

public:

	virtual void internalMousePressed(MouseCode code) { m_bChecked = !m_bChecked; ChangeCVAR(); SetupControls(); };
	void SetCVAR(const char *szCVAR) { strcpy(m_szCVAR, szCVAR); };
};

#define MAX_BOTSETTING_LISTBOXES 150

class CBotSettingListBox : public vgui::CDefaultInputSignal
{
	class CListBoxLabel : public Label
	{
		CBotSettingListBox *m_pOwner;
		int m_iRow;

	public:
		virtual void paintBackground(void);
		virtual void paint(void);
		void SetRow(int Row) { m_iRow = Row; };
		void SetOwner(CBotSettingListBox *pOwner) { m_pOwner = pOwner; };
	};

public:
	struct setting_entry_s
	{
		const char *szListText;
		CGrid SettingGrid;
		CListBoxLabel SettingLabel;
		int iRow;

		setting_entry_s *next;
		setting_entry_s(void) : next(NULL) {};
	};

	friend setting_entry_s;

	setting_entry_s *m_pFirstSettingEntry, *m_pLastSettingEntry;

	CBotSettingListBox(void);
	CBotSettingListBox(int x, int y, int wide, int tall, Panel *pOwner);
	~CBotSettingListBox(void);

	void SetCurrentSelection(int Sel);
	void SetCurrentSelection(const char *szName);
	int GetCurrentSelectionNr(void) { return ((m_pSelectedRow) ? m_pSelectedRow->iRow : -1); };
	const char *GetCurrentSelection(void) { return ((m_pSelectedRow) ? m_pSelectedRow->szListText : NULL); };
	const char *GetRandomSelection(void);
	void Update(void); // This should be called every frame
	void SetVisible(bool Visible) { m_SettingList.setVisible(Visible); };
	void AddEntry(const char *szText);
	void ClearAll(void);

	virtual void setBounds(int x, int y, int wide, int tall) { m_SettingList.setBounds(x, y, wide, tall); m_iWidth = wide; };
	virtual void setParent(Panel *parent) { m_pOwner = parent; m_SettingList.setParent(m_pOwner); };

private:

	class CBotListBox : public CListBox
	{
	public:
		void SetScrollVal(int Val) { if (m_ScrollBar.isVisible()) m_ScrollBar.setValue(Val); };
	};

	friend CListBoxLabel;

	Panel *m_pOwner;
	int m_iRows;
	setting_entry_s *m_pMouseRow;
	setting_entry_s *m_pSelectedRow;
	int m_iWidth;
	CBotListBox	m_SettingList;
	CListBoxLabel *m_pCurrentHighlightLabel;

	virtual void mousePressed(MouseCode code, Panel* panel);
	virtual void cursorMoved(int x, int y, Panel *panel);
	void Init(void) { m_pMouseRow = m_pSelectedRow = NULL; m_pCurrentHighlightLabel = NULL; };
	void MouseOverCell(setting_entry_s *pEntry);
};

// Menu Handlers

// Basic Bot Menu handler, switches to another menu
class CBotMenuHandler : public ActionSignal
{
protected:
	CBaseBotMenu *m_pParent, *m_pNext;

public:
	CBotMenuHandler(CBaseBotMenu *pParent, CBaseBotMenu *pNext) : m_pParent(pParent),
															      m_pNext(pNext) {};

	virtual void actionPerformed(Panel* panel)
	{
		m_pParent->Close();
		if (m_pNext)
		{
			m_pNext->SetActive( true );
			m_pNext->setParent(gViewPort);
			m_pNext->Open();
			m_pNext->Reset();
			m_pNext->SetNextMenu(m_pParent);
			gViewPort->SetCurrentMenu(m_pNext);
		}
//		else
//			gViewPort->ShowVGUIMenu(MENU_BOTMENU);

		gViewPort->UpdateCursorState();
	}
};

// Switches back to the main bot menu
class CGoToPrevMenuHandler : public ActionSignal
{
	CBaseBotMenu *m_pParent;
public:
	CGoToPrevMenuHandler(CBaseBotMenu *pParent) : m_pParent(pParent) {};

	virtual void actionPerformed(Panel* panel)
	{
		gViewPort->HideTopMenu(); // Close current menu
		if (!m_pParent->GetNextMenu())
			gViewPort->ShowVGUIMenu(MENU_BOTMENU);
	}
};

// Closes all (bot) menus
class CCloseAllMenus : public ActionSignal
{
public:
	virtual void actionPerformed(Panel *panel)
	{
		gViewPort->HideVGUIMenu();
	}
};

// Increases a int and displays the right text for the given label
class CIncreaseIntMenuHandler : public ActionSignal
{
	int *m_pVarToChange;
	int m_iMin, m_iMax;
	const char *m_szHeadText;
	char **m_szValTexts;
	Label *m_pLabel;

public:
	CIncreaseIntMenuHandler(int *pVarToChange, int iDefault, int Min, int Max, Label *pLabel, const char *szHeadText, char **szValTexts) : m_pVarToChange(pVarToChange), m_iMin(Min), m_iMax(Max), m_pLabel(pLabel), m_szHeadText(szHeadText), m_szValTexts(szValTexts) { *pVarToChange = iDefault; };
	virtual void actionPerformed(Panel* panel)
	{
		if (*m_pVarToChange < m_iMin)
			*m_pVarToChange = m_iMin;

		if (*m_pVarToChange < m_iMax)
			(*m_pVarToChange)++;
		else
			*m_pVarToChange = m_iMin;

		char szNewText[256];
		if (m_szValTexts) // Custom texts are given?
			sprintf(szNewText, "%s %s", m_szHeadText, m_szValTexts[*m_pVarToChange - 1]);
		else // else just use the current int value
			sprintf(szNewText, "%s %d", m_szHeadText, *m_pVarToChange);

		m_pLabel->setText(szNewText);
	}
};

// Decreases a int and displays the right text for the given label
class CDecreaseIntMenuHandler : public ActionSignal
{
	int *m_pVarToChange;
	int m_iMin, m_iMax;
	const char *m_szHeadText;
	char **m_szValTexts;
	Label *m_pLabel;

public:
	CDecreaseIntMenuHandler(int *pVarToChange, int iDefault, int Min, int Max, Label *pLabel, const char *szHeadText, char **szValTexts) : m_pVarToChange(pVarToChange), m_iMin(Min), m_iMax(Max), m_pLabel(pLabel), m_szHeadText(szHeadText), m_szValTexts(szValTexts) { *pVarToChange = iDefault; };
	virtual void actionPerformed(Panel* panel)
	{
		if (*m_pVarToChange > m_iMax)
			*m_pVarToChange = m_iMax;

		if (*m_pVarToChange > m_iMin)
			(*m_pVarToChange)--;
		else
			*m_pVarToChange = m_iMax;

		char szNewText[256];
		if (m_szValTexts) // Custom texts are given?
			sprintf(szNewText, "%s %s", m_szHeadText, m_szValTexts[*m_pVarToChange - 1]);
		else // else just use the current int value
			sprintf(szNewText, "%s %d", m_szHeadText, *m_pVarToChange);

		m_pLabel->setText(szNewText);
	}
};

// Executes a console command and switches back to the main bot menu
class CExecuteBotCommandMenuHandler : public ActionSignal
{
	char m_szConsoleCommand[128];

public:
	CExecuteBotCommandMenuHandler(const char *szConsoleCommand) { strcpy(m_szConsoleCommand, szConsoleCommand); };
	virtual void actionPerformed(Panel* panel)
	{
		gEngfuncs.pfnClientCmd(m_szConsoleCommand);
		gViewPort->HideTopMenu(); // Close current menu
		gViewPort->ShowVGUIMenu(MENU_BOTMENU);
	}
};

// Executes a console command with the value of an scrollbar as parameter 
class CBotSettingApplyButtonHandler : public ActionSignal
{
	char m_szConsoleCommand[128];
	ScrollBar2 *m_pScrollBar;

public:
	CBotSettingApplyButtonHandler(const char *szConsoleCommand, ScrollBar2 *pScrollBar) : m_pScrollBar(pScrollBar) { strcpy(m_szConsoleCommand, szConsoleCommand); };
	virtual void actionPerformed(Panel* panel)
	{
		char szCommand[128];
		sprintf(szCommand, "%s %d", m_szConsoleCommand, m_pScrollBar->getValue());
		gEngfuncs.pfnClientCmd(szCommand);
	}
};

// end menu handlers

// Main Bot menu
class CBotMenuPanel : public CBaseBotMenu
{
public:

	CBotMenuPanel(void);
	virtual void DeInit(void);

private:
	CommandButton		*m_pBotButton[MAINBOTMENU_BUTTONS];

	// sub menus
	CBaseBotMenu *m_pSubMenus[MAINBOTMENU_SUBMENUS];
};

// Add a fully Customized Bot menu
class CAddBotMenuPanel : public CBaseBotMenu
{
public:

	CAddBotMenuPanel(void);
	virtual void DeInit(void);
	virtual void paintBackground(void);
	virtual int KeyInput(int KeyNum) { return (!m_pBotTextEntry->hasFocus()); };
	virtual void Open(void);

private:
	int m_iBotCount;
	char m_szBotName[33];
	CBotSettingListBox m_SkillListBox;
	CBotSettingListBox m_TeamListBox;
	CBotSettingListBox m_ClassListBox;
	CBotSettingListBox m_DBTypeListBox;
	CBotSettingListBox m_PersoListBox;
	CBotTextEntry *m_pBotTextEntry;
	Label *m_pTeamLabel;
	Label *m_pDBTypeLabel;

	class CAddBotMenuHandler : public ActionSignal
	{
		CAddBotMenuPanel *m_pParent;

	public:
		CAddBotMenuHandler(CAddBotMenuPanel *pParent) : m_pParent(pParent) {};
		virtual void actionPerformed(Panel* panel)
		{
			short Skill = m_pParent->m_SkillListBox.GetCurrentSelectionNr() + 1;
			short Team = m_pParent->m_TeamListBox.GetCurrentSelectionNr() + 1;
			short Class = m_pParent->m_ClassListBox.GetCurrentSelectionNr() + 1;
			short DBType = m_pParent->m_DBTypeListBox.GetCurrentSelectionNr() + 1;
			char szPerso[32];
			
			// Random perso selected?
			if (m_pParent->m_PersoListBox.GetCurrentSelectionNr() == 0)
			{
				strcpy(szPerso, "random_perso");
			}
			else if (m_pParent->m_PersoListBox.GetCurrentSelection())
			{
				const char *szSelection = m_pParent->m_PersoListBox.GetCurrentSelection();
				// Default personality selected?
				if ((gszDefaultPerso[0]) && (!strcmp(szSelection, "Default Personality")))
					strcpy(szPerso, gszDefaultPerso);
				else
					strcpy(szPerso, m_pParent->m_PersoListBox.GetCurrentSelection());
			}
			else
				szPerso[0] = 0;

			// Default skill selected?
			if (Skill == 6)
				Skill = CVAR_GET_FLOAT("sv_botskill") + 1;

			char szBotName[33];
			m_pParent->m_pBotTextEntry->getText(0, szBotName, 32);
			szBotName[32] = 0;

			if (szPerso[0] == 0)
				strcpy(szPerso, "*"); // stars indicates that it should skip this arg
			if (szBotName[0] == 0)
				strcpy(szBotName, "*"); // stars indicates that it should skip this arg

			char szCommand[128];
			sprintf(szCommand, "addbot %d %d \"%s\" %d \"%s\" %d %d", Team, Class, szBotName,
					Skill, szPerso, m_pParent->m_iBotCount, DBType);
			gEngfuncs.pfnClientCmd(szCommand);
		}
	};

	friend CAddBotMenuHandler;
};

// Add a Super Bot menu
class CAddSuperBotMenuPanel : public CBaseBotMenu
{
public:

	CAddSuperBotMenuPanel(void);
	virtual void DeInit(void);
	virtual void paintBackground(void);
	virtual int KeyInput(int KeyNum) { return (!m_pBotTextEntry->hasFocus()); };
	virtual void Open(void);

private:
	int m_iSBotCount;
	char m_szBotName[33];
	CBotSettingListBox m_SBotTypeListBox;
	CBotSettingListBox m_ClassListBox;
	CBotSettingListBox m_PersoListBox;
	CBotSettingListBox m_DBRoleListBox;
	CBotTextEntry *m_pBotTextEntry;
	Label *m_pDBRoleLabel;

	class CAddSuperBotMenuHandler : public ActionSignal
	{
		CAddSuperBotMenuPanel *m_pParent;

	public:
		CAddSuperBotMenuHandler(CAddSuperBotMenuPanel *pParent) : m_pParent(pParent) {};
		virtual void actionPerformed(Panel* panel)
		{
			short Type = m_pParent->m_SBotTypeListBox.GetCurrentSelectionNr() + 1;
			short Class = m_pParent->m_ClassListBox.GetCurrentSelectionNr() + 1;
			short DBType = m_pParent->m_DBRoleListBox.GetCurrentSelectionNr() + 1;
			char szPerso[32];
			
			// Random perso selected?
			if (m_pParent->m_PersoListBox.GetCurrentSelectionNr() == 0)
			{
				strcpy(szPerso, "random_perso");
			}
			else if (m_pParent->m_PersoListBox.GetCurrentSelection())
			{
				const char *szSelection = m_pParent->m_PersoListBox.GetCurrentSelection();
				// Default personality selected?
				if ((gszDefaultPerso[0]) && (!strcmp(szSelection, "Default Personality")))
					strcpy(szPerso, gszDefaultPerso);
				else
					strcpy(szPerso, m_pParent->m_PersoListBox.GetCurrentSelection());
			}
			else
				szPerso[0] = 0;
	
			char szBotName[33];
			m_pParent->m_pBotTextEntry->getText(0, szBotName, 26);
			szBotName[32] = 0;

			if (szPerso[0] == 0)
				strcpy(szPerso, "*"); // stars indicates that it should skip this arg
			if (szBotName[0] == 0)
				strcpy(szBotName, "*"); // stars indicates that it should skip this arg

			char szCommand[128];
			sprintf(szCommand, "addsbot %d %d \"%s\" %d %d \"%s\"", Type, Class, szPerso,
				    DBType, m_pParent->m_iSBotCount, szBotName);
			gEngfuncs.pfnClientCmd(szCommand);
		}
	};

	friend CAddSuperBotMenuHandler;
};

// Advanced bot menus

// Main advanced menu
class CAdvancedBotOptionsMenuPanel : public CBaseBotMenu
{
public:
	
	CAdvancedBotOptionsMenuPanel(void);
	virtual void DeInit(void);

private:
	// sub menus
	CBaseBotMenu *m_pSubMenus[ADVANCEDBOTOPTIONSMENU_SUBMENUS];
 
	void AddCheckBox(int x, int y, const char *szTitle, const char *szCVAR);
};

class CBotChatSettingsMenuPanel : public CBaseBotMenu
{
	ScrollBar2 *m_pScrollBars[BOTCHATSETTINGSMENU_SCROLLBARS];
	Label *m_pScrollLabels[BOTCHATSETTINGSMENU_SCROLLBARS];

public:

	CBotChatSettingsMenuPanel(void);
	virtual void paintBackground(void);
};

// Change bot skill menu
class CBotSkillMenuPanel : public CBaseBotMenu
{
public:

	CBotSkillMenuPanel(void);

private:
	CommandButton		*m_pBotButton[BOTSKILLMENU_BUTTONS];
};

// Change bot aggressionlevel menu
class CBotAggressionLevelMenuPanel : public CBaseBotMenu
{
public:

	CBotAggressionLevelMenuPanel(void);

private:
	CommandButton		*m_pBotButton[BOTAGGRESSIONLEVELMENU_BUTTONS];
};

// Change bot settings menu
class CBotSettingsMenuPanel : public CBaseBotMenu
{
public:

	CBotSettingsMenuPanel(void);
	virtual void paintBackground(void);

private:

	class CApplyMenuHandler : public ActionSignal
	{
		CBotSettingsMenuPanel *m_pParent;

	public:

		CApplyMenuHandler(CBotSettingsMenuPanel *pParent) : m_pParent(pParent) {};

		virtual void actionPerformed(Panel *panel)
		{
			char szCommand[32];
			for (int n=0;n<BOTSETTINGSMENU_SCROLLBARS;n++)
			{
				sprintf(szCommand, "%s %d", sAdvancedBotOptionsMenuCommands[n], m_pParent->m_pScrollBars[n]->getValue());
				gEngfuncs.pfnClientCmd(szCommand);
			}
		}
	};

	friend CApplyMenuHandler;
	ScrollBar2 *m_pScrollBars[BOTSETTINGSMENU_SCROLLBARS];
	Label *m_pScrollLabels[BOTSETTINGSMENU_SCROLLBARS];
};

// end advanced menus

// Kick multiple bots menu
class CKickBotsMenuPanel : public CBaseBotMenu
{
public:

	CKickBotsMenuPanel(void);

private:
	CommandButton		*m_pBotButton[KICKBOTSMENU_BUTTONS];
};

class CBotManager : public CBaseBotMenu, public vgui::CDefaultInputSignal
{
	class CBotManagerLabel : public Label
	{
		CBotManager *m_pOwner;
		int m_iRow;

	public:
		//CBotManagerLabel(CBotManager *pOwner, int Row) : m_pOwner(pOwner), m_iRow(Row) {};
		virtual void paintBackground(void);
		virtual void paint(void);
		void SetRow(int Row) { m_iRow = Row; };
		void SetOwner(CBotManager *pOwner) { m_pOwner = pOwner; };
	};

	class CKillBotHandler : public ActionSignal
	{
		CBotManager *m_pOwner;

	public:
		CKillBotHandler(CBotManager *pOwner) { m_pOwner = pOwner; };

		virtual void actionPerformed(Panel *panel)
		{
			if (m_pOwner->m_iSelectedRow == -1)
				return;

			char szCommand[128];
			sprintf(szCommand, "killbot \"%s\"\n", g_PlayerInfoList[m_pOwner->m_iPlayers[m_pOwner->m_iSelectedRow]].name);
			gEngfuncs.pfnServerCmd(szCommand);
		}
	};

	class CKickBotHandler : public ActionSignal
	{
		CBotManager *m_pOwner;

	public:
		CKickBotHandler(CBotManager *pOwner) { m_pOwner = pOwner; };

		virtual void actionPerformed(Panel *panel)
		{
			if (m_pOwner->m_iSelectedRow == -1)
				return;

			char szCommand[128];
			sprintf(szCommand, "kick \"%s\"\n", g_PlayerInfoList[m_pOwner->m_iPlayers[m_pOwner->m_iSelectedRow]].name);
			gEngfuncs.pfnServerCmd(szCommand);
		}
	};

	class CEditBotPanel : public CBaseBotMenu
	{
		char m_szBotName[33];
		CBotSettingListBox m_SkillListBox;
		CBotSettingListBox m_TeamListBox;
		CBotSettingListBox m_ClassListBox;
		CBotSettingListBox m_DBRoleListBox;
		CBotSettingListBox m_PersoListBox;
		CBotTextEntry *m_pBotTextEntry;
		Label *m_pTitleLabel, *m_pTeamLabel, *m_pDBRoleLabel;

		class CEditButtonHandler : public ActionSignal
		{
			CEditBotPanel *m_pOwner;

		public:

			CEditButtonHandler(CEditBotPanel *pOwner) : m_pOwner(pOwner) { };
			virtual void actionPerformed(Panel *panel)
			{
				char szCommand[128];
				short BotIndex = -1;

				// Search the bot ent index
				for (int i=1;i<=32;i++)
				{
					if (!strcmp(g_PlayerInfoList[i].name, m_pOwner->m_szBotName))
					{
						BotIndex = i;
						break;
					}
				}
				
				if (BotIndex == -1)
					return; // Shouldn't happen

				bot_info_s *pBot = GetBotPointer(BotIndex);

				if (!pBot)
					return;

				short Skill = m_pOwner->m_SkillListBox.GetCurrentSelectionNr() + 1;
				// Skill selected?
				if ((Skill != 0) && (pBot->sSkill != Skill))
				{
					// Default skill selected?
					if (Skill == 6)
						Skill = CVAR_GET_FLOAT("sv_botskill") + 1;

					sprintf(szCommand, "botskill \"%s\" %d", m_pOwner->m_szBotName, Skill);
					gEngfuncs.pfnClientCmd(szCommand);
				}

				if (gHUD.m_Teamplay)
				{
					short Team = m_pOwner->m_TeamListBox.GetCurrentSelectionNr() + 1;

					// New team selected?
					if ((Team != 0) &&	(g_PlayerExtraInfo[BotIndex].teamnumber != Team))
					{
						char *szTeam = NULL;
						switch(Team)
						{
						case 1: szTeam = "good"; break;
						case 2: szTeam = "evil"; break;
						}
						sprintf(szCommand, "botteam \"%s\" \"%s\"", m_pOwner->m_szBotName, szTeam);
						gEngfuncs.pfnClientCmd(szCommand);
					}
				}

				short Class = m_pOwner->m_ClassListBox.GetCurrentSelectionNr() + 1;

				// New class selected?
				if ((Class != 0) && (g_PlayerExtraInfo[BotIndex].playerclass != Class))
				{
					char *szClass = NULL;
					switch(Class)
					{
					case 1: szClass = "buu"; break;
					case 2: szClass = "goku"; break;
					case 3: szClass = "gohan"; break;
					case 4: szClass = "krillin"; break;
					case 5: szClass = "frieza"; break;
					case 6: szClass = "piccolo"; break;
					case 7: szClass = "trunks"; break;
					case 8: szClass = "vegeta"; break;
					case 9: szClass = "cell"; break;
					}
					sprintf(szCommand, "botclass \"%s\" \"%s\"", m_pOwner->m_szBotName, szClass);
					gEngfuncs.pfnClientCmd(szCommand);
				}

				if (gbIsDBMode)
				{
					short DBRole = m_pOwner->m_DBRoleListBox.GetCurrentSelectionNr() + 1;

					// New DB Role selected?
					if ((DBRole != 0) && (pBot->sDBRole != DBRole))
					{
						sprintf(szCommand, "botdbrole \"%s\" %d", m_pOwner->m_szBotName, DBRole);
						gEngfuncs.pfnClientCmd(szCommand);
					}
				}

				// Personality Selected?
				if (m_pOwner->m_PersoListBox.GetCurrentSelection())
				{
					sprintf(szCommand, "botperso \"%s\" \"%s\"", m_pOwner->m_szBotName, m_pOwner->m_PersoListBox.GetCurrentSelection());
					gEngfuncs.pfnClientCmd(szCommand);
				}

				char szBuffer[33];
				m_pOwner->m_pBotTextEntry->getText(0, szBuffer, 32);
				szBuffer[32] = 0;

				// New bot name typed?
				if ((*szBuffer) && (strcmp(m_pOwner->m_szBotName, szBuffer) != 0))
				{
					sprintf(szCommand, "botname \"%s\" \"%s\"", m_pOwner->m_szBotName, szBuffer);
					gEngfuncs.pfnClientCmd(szCommand);
				}

				gViewPort->HideTopMenu(); // Close current menu
				if (!m_pOwner->GetNextMenu())
					gViewPort->ShowVGUIMenu(MENU_BOTMENU);
			}
		};

		class CBotNameHandler : public ActionSignal
		{
			CEditBotPanel *m_pEditPanel;

		public:
			CBotNameHandler(CEditBotPanel *pEditPanel) : m_pEditPanel(pEditPanel) {};
			virtual void actionPerformed(Panel *panel)
			{
			};
		};

		friend CEditButtonHandler;
		friend CBotNameHandler;

		void MakeEditButton(int x, int y, int wide, int tall);

	public:

		CEditBotPanel(void);
		virtual void DeInit(void);
		virtual void paintBackground(void);
		virtual int KeyInput(int KeyNum) { return (!m_pBotTextEntry->hasFocus()); };
		virtual void Open(void);
		void SetBotName(const char *szName) { strcpy(m_szBotName, szName); };
	};

	class CEditBotButtonHandler : public ActionSignal
	{
		CBotManager *m_pOwner;

	public:

		CEditBotButtonHandler(CBotManager *pOwner) : m_pOwner(pOwner) {};
		virtual void actionPerformed(Panel *panel)
		{
			if (m_pOwner->m_iSelectedRow == -1)
				return;

			m_pOwner->Close();

			CEditBotPanel *pEditBotPanel = m_pOwner->m_pEditBotPanel;
			pEditBotPanel->SetBotName(g_PlayerInfoList[m_pOwner->m_iPlayers[m_pOwner->m_iSelectedRow]].name);
			pEditBotPanel->SetActive( true );
			pEditBotPanel->setParent(gViewPort);
			pEditBotPanel->Open();
			pEditBotPanel->Reset();
			pEditBotPanel->SetNextMenu(m_pOwner);

			gViewPort->SetCurrentMenu(pEditBotPanel);

			gViewPort->UpdateCursorState();			
		}
	};

	friend CBotManagerLabel;
	friend CKillBotHandler;
	friend CKickBotHandler;
	friend CEditBotButtonHandler;

	vgui::CListBox	m_PlayerList;
	CGrid			m_PlayerGrids[32];
	CBotManagerLabel	m_PlayerEntries[32];	// Labels for the grid entries.
	int m_iRows;
	int m_iSelectedRow;
	int m_iMouseRow;
	int m_iPlayers[32];
	CBotManagerLabel *m_pCurrentHighlightLabel;
	CEditBotPanel *m_pEditBotPanel;

	void Update(void);
	void FillGrid(void);
	void MouseOverCell(int row);
	void GetPlayers(void);
	void MakeKillBotButton(int x, int y, int wide, int tall);
	void MakeKickBotButton(int x, int y, int wide, int tall);
	void MakeEditBotButton(int x, int y, int wide, int tall);
	virtual void mousePressed(MouseCode code, Panel* panel);
	virtual void cursorMoved(int x, int y, Panel *panel);
	virtual void Open(void) { Update(); m_iMouseRow = m_iSelectedRow = -1; CBaseBotMenu::Open(); };
	virtual void paintBackground(void) { Update(); CBaseBotMenu::paintBackground(); };

public:

	CBotManager(void);
	virtual void DeInit(void) { m_pEditBotPanel->DeInit(); };
};

inline void DeInitBotMenus(void) { if(gViewPort && gViewPort->m_pBotMenu) gViewPort->m_pBotMenu->DeInit(); };

#endif