#ifndef _ALARM_H
#define _ALARM_H
static char Alarm_h_id[] = "$Header: Alarm.h,v 1.2 97/03/20 12:32:38 oreilly Exp $";

/*
$Log:	Alarm.h,v $
 * Revision 1.2  97/03/20  12:32:38  12:32:38  oreilly (Thomas C. O'Reilly)
 * *** empty log message ***
 * 
 * Revision 1.1  96/10/28  09:13:09  09:13:09  oreilly (Thomas C. O'Reilly)
 * Initial revision
 * 
*/

#include "DataManager.h"
#include "microdef.h"
#include "gf5vDef.h"
#include "moogdef.h"
#include "array.h"

#define PriorityMnem          "priority"
#define MnemonicMnem          "mnemonic"
#define AckAllMnem            "ackAllChanges"
#define OnePriorityMnem       "onePriority"

/* Non-abstract alarm types */
typedef enum
{
  MotorStatusAlarmType, IbcAlarmType, GfAlarmType, GfTestAlarmType, 
  Gf5vTestAlarmType, BooleanAlarmType, EventAlarmType,

  UnkAlarmType,             // This MUST be last type in enum!

} AlarmType;

#define NAlarmActions 3
#define BeepOnce 01
#define BeepTilAck 02
#define PopupList 04

inline char *alarmActionName(int bit)
{
  switch (bit)
  {
    case 0:
    return "beepOnce";
    
    case 1:
    return "beepTilAck";

    case 2:
    return "popupList";

    default:
    return "UnknownAction";
  }
}

// Number of priority levels (excluding NoPriority) 
#define NPriorityLevels 3

// Priority levels MUST start at 1 (excluding NoPriority)
typedef enum
{
  Priority1 = 1, Priority2 = 2, Priority3 = 3, NoPriority = 999

} Priority;


inline Priority lowestPriority()
{
  return Priority3;
}


inline Priority highestPriority()
{
  return Priority1;
}

inline Priority higherPriority(Priority p1, Priority p2)
{
  return MIN(p1, p2);
}


inline MBool validPriority(int priority)
{
  if (priority >= Priority1 && priority <= Priority3)
    return TRUE;
  else
    return FALSE;
}


inline int priorityIndex(Priority p)
{
  return p - 1;
}


struct ValuePriority
{
  ValuePriority(int v, Priority p)
  {
    value = v;
    priority = p;
  }
  
  short value;
  Priority priority;
};

#define NoAlarmValue -1

/*
class Alarm includes DMObject, alarm priority, states, etc.
*/
class Alarm 
{
  public:

  Alarm();
  ~Alarm();

  char *name()
  {
    return (char *)_dmObject->getName();
  }
  
  // Read DM item and update internal state of alarm
  virtual int update() = 0;

  // Determine if alarm is "active"
  virtual MBool active() = 0;

  virtual MBool wasActive() = 0;

  virtual int value() = 0;
  virtual int okayValue() = 0;
  
  // Determine if alarm has been acknowledged
  MBool acknowledged() {
    return _acknowledged;
  }

  MBool wasAcknowledged()
  {
    return _prevAcknowledged;
  }
  
  // Acknowledge/unacknowledge alarm
  void acknowledge(MBool yesNo = TRUE);
  
  // Return pointer to alarm DmObject
  DmObject *dmObject()
  {
    return _dmObject;
  }

  // Indicates if alarm type is "event"
  virtual MBool eventAlarm() = 0;

  // Return time of last update
  void writeTime(DM_Time *t)
  {
    t->tv_sec = _writeTime.tv_sec;
    t->tv_usec = _writeTime.tv_usec;
  }

  void setItemMnemonic(char *);

  // Return mnemonic for item, or if it doesn't have one, DM item name
  char *itemMnemonic();
  
  // Set default priority
  void setPriority(Priority priority)
  {
    _priority = priority;

    if (_dmForward)
      forward();
  }

  // Set priority for specified alarm value
  virtual void setPriority(int value, Priority priority) = 0;

  // Set whether user must acknowledge all state changes (including
  // change to OK state)    
  virtual void setAckAllChanges(MBool yesNo) = 0;

  // Indicate if user must acknowledge all changes
  virtual MBool ackAllChanges() = 0;
  
  // Return mnemonic for given alarm type
  static char *typeMnemonic(AlarmType type);
  
  // Return AlarmType corresponding to specified mnemonic
  static AlarmType mnemonicType(char *mnemonic);

  // Return internal value corresponding to specified type and mnemonic
  static int mnemonicValue(AlarmType type, char *mnemonic);

  // Return mnemonic corresponding to specified type and value
  static char *valueMnemonic(AlarmType type, int value);
  
  // Return type of alarm
  virtual AlarmType type() = 0;

  static const char *const UnkValueMnem;
  static const char *const MotorStatusTypeMnem;
  static const char *const IbcTypeMnem;
  static const char *const GfTypeMnem;
  static const char *const GfTestTypeMnem;
  static const char *const Gf5vTestTypeMnem;
  static const char *const BooleanTypeMnem;
  static const char *const EventTypeMnem;

  // Determine priority
  virtual Priority priority(int value)
  {
    return _priority;
  }

  // Set name of associated item
  void setAssociatedItem(char *itemName)
  { 
    _associatedItem = strdup(itemName);
  }

  // Return name of associated data manager item
  char *associatedItem()
  {
    return _associatedItem;
  }

  // Determine whether to forward alarm info via datamanager
  int setForwarding(MBool forward);

  protected:

  // _dmObject points to DmObject of appropriate type
  DmObject *_dmObject;

  // _dmForward is used to communicate alarm ack status (and priority) to
  // other processes (e.g. video overlay)
  DmNat16Object *_dmForward;

  MBool _acknowledged;
  MBool _prevAcknowledged;

  // Time DM_Item was last written
  DM_Time _writeTime;

  // DM item mnemonic
  char *_itemMnemonic;

  Priority _priority;

  char *_associatedItem;
 
  // Forward information
  int forward();
};


/* An EventAlarm is "valueless"; i.e. this alarm just indicates that
"something" happened, but the event has no value associated with it.
*/
class EventAlarm : public Alarm
{
  public:
  EventAlarm(const char *name);
  ~EventAlarm();

  AlarmType type()
  {
    return EventAlarmType;
  }
  
  // This function should only be called if update has actually 
  // occurred
  int update();

  // EventAlarm is NEVER active
  virtual MBool active()
  {  
    return FALSE;
  }
  
  virtual MBool wasActive()
  {
    return FALSE;
  }
  
  // Set priority for specified alarm value;
  // Does nothing for EventAlarm, since EventAlarm has no associated value
  virtual void setPriority(int value, Priority priority)
  {
    return;
  }

  MBool eventAlarm()
  {
    return TRUE;
  }

  // Set whether user must acknowledge all state changes (including
  // change to OK state)
  // This function does nothing for EventAlarm
  void setAckAllChanges(
			MBool yesNo
			)
  {
    return;
  }

  MBool ackAllChanges()
  {
    return TRUE;
  }
  
  // EventAlarm is valueless
  int value() 
  {
    return NoAlarmValue;
  }
  
  // EventAlarm is valueless
  int okayValue()
  {
    return NoAlarmValue;
  }
  
  protected:
  DmEmptyObject *_dmEmptyObject;
};


/* 
ValueAlarm has a set of associated values 
*/
class ValueAlarm : public Alarm
{
  public:

  ValueAlarm();
  ~ValueAlarm();
  

  // Return current alarm state
  virtual MBool active()
  {
    if (_value != okayValue())
      return TRUE;
    else
      return FALSE;
  }

  virtual MBool wasActive()
  {
    if (_prevValue != okayValue())
      return TRUE;
    else
      return FALSE;
  }
  

  // Indicate if this class is an event alarm      
  MBool eventAlarm()
  {
    return FALSE;
  }

  // Set whether user must acknowledge all state changes (including
  // change to OK state)
  void setAckAllChanges(
			MBool yesNo
			)
  {
    _ackAllChanges = yesNo;
  }
  
  MBool ackAllChanges()
  {
    return _ackAllChanges;
  }
  
  // Return current internal value
  int value() 
  {
    return _value;
  }
  
  // Set priority for specified alarm value;
  virtual void setPriority(int value, Priority priority);
  
  // Return priority for specified value
  Priority priority(int value);

  // Return highest set priority
  Priority highestSetPriority();
  
  protected:
  int _value;
  int _prevValue;
  
  MBool _active;
  MBool _ackAllChanges;

  DynArray<ValuePriority *> _valuePriority;  
};


/*
BooleanAlarm has two values, True and False
*/
class BooleanAlarm : public ValueAlarm
{
  public:
  
  BooleanAlarm(const char *name);
  ~BooleanAlarm();
  
  AlarmType type()
  {
    return BooleanAlarmType;
  }

  int update();

  int okayValue()
  {
    return 0;
  }
  
  // Return mnemonic string for specified value
  static char *valueMnemonic(int value);

  // Return internal value of specified mnemonic string
  static int mnemonicValue(char *mnemonic);

  static const char *const TrueMnem;
  static const char *const FalseMnem;

  protected:

  Priority _priority;
  DmBooleanObject *_dmBooleanObject;
};


/*
EnumAlarm has two or more "enum" values 
*/
class EnumAlarm : public ValueAlarm
{
  public:
  EnumAlarm(const char *name);
  ~EnumAlarm();
  
  virtual int update();

  protected:

  DmEnumObject *_dmEnumObject;
};


class GfTestAlarm : public EnumAlarm 
{
  public:
  GfTestAlarm(const char *name);
  
  AlarmType type()
  {
    return GfTestAlarmType;
  }
  
  static const char *const OkMnem;
  static const char *const FailOnMnem;
  static const char *const FailOffMnem;

  // Return mnemonic string for specified value
  static char *valueMnemonic(int value);

  // Return internal value of specified mnemonic string
  static int mnemonicValue(char *mnemonic);

  int okayValue()
  {
    return GF_TEST_OK;
  }
};


class Gf5vTestAlarm : public EnumAlarm
{
  public:
  Gf5vTestAlarm(const char *name);
  
  AlarmType type()
  {
    return Gf5vTestAlarmType;
  }

  static const char *const NotRunMnem;
  static const char *const AtodFailedMnem;
  static const char *const SelfTestFailedMnem;
  static const char *const SelfTestPassedMnem;

  // Return mnemonic string for specified value
  static char *valueMnemonic(int value);

  // Return internal value of specified mnemonic string
  static int mnemonicValue(char *mnemonic);

  int okayValue()
  {
    return GF_SELFTEST_PASSED;
  }
};


class MotorStatusAlarm : public EnumAlarm
{
  public:
  MotorStatusAlarm(const char *name);

  AlarmType type()
  {
    return MotorStatusAlarmType;
  }

  static const char *const UnkStatusMnem;
  static const char *const NoFaultMnem;
  static const char *const ControlVoltMnem;
  static const char *const ControlTempMnem;
  static const char *const StallMnem;
  static const char *const ResolverMnem;
  static const char *const OverCurrMnem;
  static const char *const FaultMnem;
  
  // Return mnemonic string for specified value
  static char *valueMnemonic(int value);

  // Return internal value of specified mnemonic string
  static int mnemonicValue(char *mnemonic);

  int okayValue()
  {
    return MOTOR_NO_FAULT;
  }
};


/*
GraduatedAlarm has values which indicate progressively more
severe or dangerous states
*/
class GraduatedAlarm : public EnumAlarm
{
  public:
  GraduatedAlarm(const char *name);
};


class IbcAlarm : public GraduatedAlarm
{
  public:
  IbcAlarm(const char *name);
  
  AlarmType type()
  {
    return IbcAlarmType;
  }
  
  static const char *const AlarmMnem;
  static const char *const WarningMnem;
  static const char *const OkMnem;

  // Return mnemonic string for specified value
  static char *valueMnemonic(int value);

  // Return internal value of specified mnemonic string
  static int mnemonicValue(char *mnemonic);

  int okayValue()
  {
    return MICRO_ALARM_OK;
  }
};


class GfAlarm : public GraduatedAlarm 
{
  public:
  GfAlarm(const char *name);
  
  AlarmType type()
  {
    return GfAlarmType;
  }
  
  static const char *const NormalMnem;
  static const char *const AdvisoryMnem;
  static const char *const WarningMnem;
  static const char *const CriticalMnem;

  // Return mnemonic string for specified value
  static char *valueMnemonic(int value);

  // Return internal value of specified mnemonic string
  static int mnemonicValue(char *mnemonic);

  int okayValue()
  {
    return GF_NORMAL;
  }
  
};


inline double tval2sec(DM_Time *t)
{
  return t->tv_sec + 0.000001 * (double )t->tv_usec;
}


/* Prototypes */
int alarmFileLineNo();

#endif


