// Local chat registration and mission scope. RPC transport stays on the controller.
class ERR_ChatClient
{
 protected SCR_PlayerController m_Controller;
 protected ERR_GameMode m_Mode;
 protected ChatCommandInvoker m_Command;
 protected int m_Attempts;
 protected int m_Token = 1;
 protected bool m_Stopped;
 void ERR_ChatClient(SCR_PlayerController controller)
 {
  m_Controller = controller;
  m_Mode = ERR_GameMode.Get();
  Register();
  GetGame().GetCallqueue().CallLater(Poll, 1000, true);
 }
 protected void Register()
 {
  if (m_Stopped || m_Command || m_Attempts++ >= 40 || !GetGame() || m_Controller != GetGame().GetPlayerController()) return;
  SCR_ChatPanelManager manager = SCR_ChatPanelManager.GetInstance();
  if (manager) m_Command = manager.GetCommandInvoker("esc");
  if (m_Command) m_Command.Insert(OnCommand);
  else GetGame().GetCallqueue().CallLater(Register, 250, false);
 }
 protected void Poll()
 {
  if (!GetGame() || m_Controller != GetGame().GetPlayerController()) { Stop(); return; }
  Scope();
 }
 int Scope()
 {
  ERR_GameMode mode = ERR_GameMode.Get();
  if (mode != m_Mode)
  {
   m_Mode = mode;
   m_Token++;
   ERR_AdminMenu menu = ERR_AdminMenu.GetOpenMenu();
   if (menu) menu.Close();
  }
  return m_Token;
 }
 bool Accept(int token) { return !m_Stopped && GetGame() && m_Controller == GetGame().GetPlayerController() && ERR_GameMode.Get() && token == Scope(); }
 protected void OnCommand(SCR_ChatPanel panel, string arguments) { m_Controller.ERR_AdminSubmit(arguments); }
 void Stop()
 {
  if (m_Stopped) return;
  m_Stopped = true;
  if (GetGame()) { GetGame().GetCallqueue().Remove(Register); GetGame().GetCallqueue().Remove(Poll); }
  if (m_Command) m_Command.Remove(OnCommand);
  m_Command = null;
  ERR_AdminMenu menu = ERR_AdminMenu.GetOpenMenu();
  // A retained former controller must not close the current owner's panel.
  if (menu && GetGame() && m_Controller == GetGame().GetPlayerController()) menu.Close();
 }
}
