#ifndef _DMSTATUS_H
#define _DMSTATUS_H

#include <array.h>
#include <Vk/VkComponent.h>
#include "DataManager.h"
#include "SList.h"

class DmLogWindow;

/*
CLASS 
DmPeer

DESCRIPTION
Contains state of a DataManager peer node, pointer to 
log file, etc

AUTHOR
Tom O'Reilly
*/
class DmPeer {

 public:

  enum State {
    Error = DMP_ERROR,
    NotConnected = DMP_NOTCONN,
    Booting = DMP_BOOT,
    Init = DMP_INIT,
    Init2 = DMP_INIT2,
    InitSent = DMP_INIT_SENT,
    InitRcvd = DMP_INIT_RCVD,
    Connected = DMP_CONN,
    IsHost,
    Unknown
  };

  ///////////////////////////////////////////////////////////////////
  // Constructor
  // [input] inetAddr: Internet address
  // [input] logFile: log file
  // [input] isHost: True if this peer is the host, else False
  DmPeer(InAddr inetAddr, const char *logFile, Boolean isHost = False);

  ~DmPeer();

  ///////////////////////////////////////////////////////////////////
  // Name of peer at specified Internet address
  static const char *name(InAddr addr);

  ///////////////////////////////////////////////////////////////////
  // Name of this DmPeer
  const char *name() {
    return _name;
  }

  ///////////////////////////////////////////////////////////////////
  // Name of log file
  const char *logFile() {
    return _logFile;
  }

  ///////////////////////////////////////////////////////////////////
  // Internet address 
  const InAddr address() {
    return _peerAddr;
  }

  ///////////////////////////////////////////////////////////////////
  // Current peer State
  State state() {
    return _state;
  }

  ///////////////////////////////////////////////////////////////////
  // Set peer State
  void setState(State state) {
    if (_state == IsHost)
      // Can't change state of host
      return;

    _state = state;
  }

  ///////////////////////////////////////////////////////////////////
  // Number of warning/critical messages associated with peer
  int msgCount() {
    return _msgCount;
  }

  ///////////////////////////////////////////////////////////////////
  // Set number of warning/critical messages associated with peer
  void setMsgCount(int count) {
    _msgCount = count;
  }

  ///////////////////////////////////////////////////////////////////
  // Mnemonic of current peer State
  const char *stateMnem();

  ///////////////////////////////////////////////////////////////////
  // Peer's LogWindow
  DmLogWindow *logWindow;

 protected:

  int _msgCount;
  InAddr _peerAddr;
  const char *_name;
  const char *_logFile;
  State _state;
};



/*
CLASS 
AlarmMgr

DESCRIPTION
Manages alarm displays (including sound) for DmStatus/DmLog objects

AUTHOR
Tom O'Reilly
*/
class AlarmMgr {

public:

  enum AlarmLevel {
    Okay, Warning, Critical
  };

  ///////////////////////////////////////////////////////////////////
  // Constructor
  AlarmMgr(Widget matrixWidget, 
	   int updateMillisec,
	   const char *configDir,
	   Pixel okayForeground,
	   Pixel okayBackground,
	   Pixel warningForeground, 
	   Pixel warningBackground,
	   Pixel criticalForeground, 
	   Pixel criticalBackground);

  ~AlarmMgr();

  ///////////////////////////////////////////////////////////////////
  // Add cell to list of alarmed cells
  void addCell(int row, int column, AlarmLevel level);

  ///////////////////////////////////////////////////////////////////
  // Cell is no longer in alarm; remove from list
  int removeCell(int row, int column);

  ///////////////////////////////////////////////////////////////////
  // Set AlarmLevel of cell (must already be in list)
  int setCellLevel(int row, int column, AlarmLevel level);

  ///////////////////////////////////////////////////////////////////
  // Raise alarm(s); initiate actions (flashing, sounds, etc)
  void raise();

  ///////////////////////////////////////////////////////////////////
  // Acknowledge new alarms
  void acknowledge();

  ///////////////////////////////////////////////////////////////////
  // Flash newly alarmed cells, generate sounds, etc
  void doActions();

  ///////////////////////////////////////////////////////////////////
  // Return True if alarm(s) has been raised, else False
  Boolean alarmRaised();

  ///////////////////////////////////////////////////////////////////
  // Foreground color for specified AlarmLevel
  Pixel foreground(AlarmLevel level);

  ///////////////////////////////////////////////////////////////////
  // Background color for specified AlarmLevel
  Pixel background(AlarmLevel level);

protected:

  XtIntervalId _timer;
  int _updatePeriod;

  int _actionPhase;

  Boolean _alarmRaised;

  Widget _matrixWidget;

  Pixel _okayForeground;
  Pixel _okayBackground;
  Pixel _warningForeground;
  Pixel _warningBackground;
  Pixel _criticalForeground;
  Pixel _criticalBackground;

  Boolean _audio;
  char _audioPlayer[256];
  char _audioFile[256];


  ///////////////////////////////////////////////////////////////////
  // Generate sounds appropriate to highest current alarm level
  void doAudio();

  ///////////////////////////////////////////////////////////////////
  // Level of highest current unacknowledged alarm
  AlarmLevel highestNewLevel();

  ///////////////////////////////////////////////////////////////////
  // Called when timer expires; invokes alarm action execution 
  // (sound, flashing, etc)
  static void timerCallback(XtPointer clientData, XtIntervalId *id);

  ///////////////////////////////////////////////////////////////////
  // Specifies cell that is currently in alarm condition
  struct AlarmedCell {

    AlarmedCell(int nrow, int ncolumn, AlarmLevel nlevel) {
      row = nrow;
      column = ncolumn;
      newAlarm = True;
      level = nlevel;
    }

    ///////////////////////////////////////////////////////////////////
    // Level of alarm
    AlarmLevel level;

    ///////////////////////////////////////////////////////////////////
    // Cell row
    int row;

    ///////////////////////////////////////////////////////////////////
    // Cell column
    int column;

    ///////////////////////////////////////////////////////////////////
    // Alarm has not been acknowledged yet
    Boolean newAlarm;
  };

  ///////////////////////////////////////////////////////////////////
  // List of AlarmedCell objects
  SList<AlarmedCell *> _alarmedCellList;

};


/*
CLASS 
DmStatus

DESCRIPTION
Displays status of DataManager system, including peer status, error 
messages from DataManager log file, etc. Display consists of a "matrix"
of cells; each peer occupies a row of the matrix, and peer name, state,
and message counts are displayed in the columns.

AUTHOR
Tom O'Reilly
*/

class DmStatus : public VkComponent {

 public:

  ///////////////////////////////////////////////////////////////////
  // Constructor
  DmStatus(const char *name, 
	   Widget parent, 
	   const char *configDir,
	   const char *logFileDir);

  ~DmStatus();

  virtual const char *className() {
    return "DmStatus";
  }

  ///////////////////////////////////////////////////////////////////
  // Update status display
  virtual void periodicUpdate();

  ///////////////////////////////////////////////////////////////////
  // Add to peer list, based on results of dm_peer_status() call
  virtual void updatePeerList(DmPeerSts *visiblePeer, int nPeers);

  ///////////////////////////////////////////////////////////////////
  // Update peer list display
  virtual void updatePeerListDisplay();

  ///////////////////////////////////////////////////////////////////
  // Add new peers to displayed list
  void displayNewPeers();

  ///////////////////////////////////////////////////////////////////
  // Update state of displayed peers
  void updateState();

  ///////////////////////////////////////////////////////////////////
  // Update log message counts of displayed peers
  void updateMsgCounts();

 protected:

  AlarmMgr *_alarmMgr;
  Boolean _alarmRaised;

  ///////////////////////////////////////////////////////////////////
  // Default name of log file associated with specified peer
  const char *defaultLogFile(const char *peerName);

  ///////////////////////////////////////////////////////////////////
  // Widget for peer matrix display
  Widget _peerListWidget;

  ///////////////////////////////////////////////////////////////////
  // Alarm-acknowledgement button
  Widget _ackButton;

  Pixel _criticalBackground, _criticalForeground;
  Pixel _warningBackground, _warningForeground;
  Pixel _okayBackground, _okayForeground;

  Int32 _peerSeqNo;
  Boolean _stateChanged;

  DynArray<DmPeer *> _peers;

  ///////////////////////////////////////////////////////////////////
  // Number of rows in matrix display
  int _rowsFilled;

  ///////////////////////////////////////////////////////////////////
  // Read list of peers/logfiles from file
  int loadPeers(const char *peerFileName);

  ///////////////////////////////////////////////////////////////////
  // Specify period for display update
  void setStatusUpdatePeriod(int millisec);

  ///////////////////////////////////////////////////////////////////
  // Show DmLogWindow for peer at specified index
  void showPeerDetail(int index);

  XtIntervalId _updateTimer;
  int _updatePeriod;

  const char *_configDir;
  const char *_logFileDir;

  ///////////////////////////////////////////////////////////////////
  // Called when update period expires
  static void updateTimerCallback(XtPointer clientData, XtIntervalId *id);

  ///////////////////////////////////////////////////////////////////
  // Called when _ackButton is pushed
  static void alarmAckCallback(Widget w, 
			       XtPointer clientData, XtPointer callData);

  ///////////////////////////////////////////////////////////////////
  // Called when user clicks in cell
  static void enterCellCallback(Widget w,
				XtPointer clientData,
				XtPointer callData);

  ///////////////////////////////////////////////////////////////////
  // Called when user double-clicks in cell
  static void selectCallback(Widget w,
			     XtPointer clientData,
			     XtPointer callData);

  static XtResource _resources[];
};

#endif

