#pragma once

#include "other.h"
#include "user.h"
#include "libraries.h"
#include "messages.h"

#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include "sys-wait.h" // was a bug in file on athena.

// =================================
//
// class Library_Collection  represents the concept of having
// a set of libraries to which one can be connected,
// and potentially having one of them as the "current_library".
//

class Library_Collection
{
  Library   *crnt_libr =NULL;

  Library*   list[10];

 public:
  Library_Collection();

  Barton     Lbarton;
  BU_Library Lbu;
  CARL       Lcarl;
  Harvard    Lharvard;
  UC_MELVYL  Lmelvyl;

  Library&   current_library();
  char*      current_library_name();

  bool       LibraryHasStopped ();
  bool       aLibraryIsOpen    ()    { return (bool) crnt_libr; };
  
  void Set_current_library   (Library&, bool use_vt100 =0);
  void Close_current_library ();

  void Close_all_libraries();
};


// =================================
// class Parser  and  class Command
//
// parse user input looking for commands.
//

enum Command {
  _no_immediate_command,
  _emptyLine,
  _redraw,
  _quit,
  _help,
  _menu,
  _close,
  _user_has_VT100,
  _user_hasnt_VT100,
  _toggle_BartonVTHack,
  _1, _2, _3, _4, _5
};

class Parser
{
  bool Cmd_Mode =0;
  char pending_cmd_char =NULL;
  void PushbackCommandChar(char c) { pending_cmd_char = c; };

  enum { _NotIn, _HavePrefix, _HaveIdChar } cmd_state;
  char cmd_id_char =NULL;

  bool last_char_was_newline =1;

 public:

  Parser () : cmd_state(_NotIn) {};
  Command found_command;
  void   new_char(char, bool in_cmd_mode);
  bool   obtained_command() { return (found_command!=_no_immediate_command); };
  int    command_body_length();
};


// =================================
// class Interface  contains the user interface code.
//
//  Library_Collection should be private, but am encountering bug
//    I dont understand when that is the case.

class Interface : public Library_Collection
{

  User  *usr             =NULL;
  void   w(char*msg) { usr->write(msg); };

  Parser parse;
  bool invalid_command_given(char c);

  void do_intro();
  void do_prompt();
  void do_help();
  void do_menu();
  void show_menu(), sm_hlpr(Library&);

  void WaitForInput  ();
  char WaitForUserKey();

  bool in_cmd_only_mode =0;
  bool ok_to_write_library () { return !in_cmd_only_mode; };
  bool ok_to_read_library  () { return !in_cmd_only_mode; };

  void Use_Library(Library &, int silent =0);
  void Use_Library_announce(bool new_libp);
  void Close_Library();
  bool first_barton__pretend_is_new =0;

  void execute_command (Command cmd);
  void handle_stopped_library();

 public:
  ~Interface() { termination_cleanup(); };

  void termination_cleanup() { Close_all_libraries(); };
  void Service (User& u);

};
