static char SystemAlarms_id[] = "$Header: SystemAlarms.cc,v 1.6 97/10/03 09:33:18 oreilly Exp $";


/*
$Log:	SystemAlarms.cc,v $
Revision 1.6  97/10/03  09:33:18  09:33:18  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.5  97/06/16  15:59:52  15:59:52  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.4  97/04/09  14:36:49  14:36:49  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.3  97/03/20  12:30:56  12:30:56  oreilly (Thomas C. O'Reilly)
..

Revision 1.2  96/07/22  10:42:10  10:42:10  oreilly (Thomas C. O'Reilly)
First external release

*/
#include <stdlib.h>
#include <string.h>
#include "SystemAlarms.h"

#define dprintf if (debug) fprintf

#define CommentChar '#'


SystemAlarms::SystemAlarms(const char *fileName)
{
  _fileName = NULL;
  alarmList.clear();

  load(fileName);
}


SystemAlarms::~SystemAlarms()
{
  if (_fileName) free(_fileName);
}


Alarm *SystemAlarms::find(const char *name)
{
  SListIter<Alarm *> list(alarmList);
  list.reset();
  Alarm **alarm;
  while (alarm = list.next())
  {
    if (!strcmp(name, (*alarm)->name()))
      return *alarm;
  }

  // Specified alarm not found
  return NULL;
}


int SystemAlarms::save(const char *fileName)
{
  char buf[512];
  
  FILE *fp;
  if ((fp = fopen(fileName, "w")) == NULL)
  {
    sprintf(buf, "Couldn't open file \"%s\" for write", fileName); 
    setError(buf);
    return -1;
  }

  if (_fileName) free(_fileName);
  
  _fileName = strdup(fileName);

  SListIter<Alarm *> list(alarmList);

  list.reset();
  Alarm **alarm;
  while (alarm = list.next())
  {
    fprintf(fp, "%s %s {\n", 
	    Alarm::typeMnemonic((*alarm)->type()),
	    (*alarm)->name());
  
    // Write mnemonic if it differs from name
    if (strcmp((*alarm)->name(), (*alarm)->itemMnemonic()))
      fprintf(fp, "  mnemonic = %s\n", (*alarm)->itemMnemonic());

    // Write default priority
    fprintf(fp, "  priority = %d\n", (*alarm)->priority(NoAlarmValue));

    AlarmType type = (*alarm)->type();
    
    if ((*alarm)->multiValued())
    {
      // Write priority for each alarm level
      for (int value = 0;; value++)
      {	
	if (value == (*alarm)->okayValue())
	  continue;
	
	char *mnem = Alarm::valueMnemonic((*alarm)->type(), value);
	
	if (!strcmp(mnem, Alarm::UnkValueMnem))
	  // Done
          break;

	fprintf(fp, "  %s priority = %d\n",
		mnem, (*alarm)->priority(value));
      }
    }

    if ((*alarm)->ackAllChanges())
      fprintf(fp, "  ackAll\n");      

    if ((*alarm)->forwarding())
      fprintf(fp, "  forward\n");
    
    fprintf(fp, "}\n\n");
  }
  
  fclose(fp);
  return 0;
}



int SystemAlarms::load(const char *fileName)
{
  FILE *fp;
  char buf[512];
  MBool debug = FALSE;
  
  fprintf(stderr, "Reading System Alarm file %s...\n", fileName);
  
  /* Each line in file specifies alarm's DM item name, and alarm type */
  if ((fp = fopen(fileName, "r")) == NULL)
  {
    sprintf(buf, "Couldn't open file \"%s\"", fileName);
    setError(buf);
    return -1;
  }

  // Directory of this alarm file
  char directory[256];
  char *ptr;
  if ((ptr = strrchr(fileName, '/')) != 0) {
    strncpy(directory, fileName, ptr - fileName);
    directory[ptr - fileName] = '\0';
  }
  else {
    strcpy(directory, "");
  }

  const char *includeFile;

  // Process any "#include" directives
  while (fgets(buf, sizeof(buf), fp) != 0) {
    if ((includeFile = includeDirective(directory, buf)) != 0) {
      // Include file specified; load it
      if (load(includeFile) == -1) {
	fclose(fp);
	return -1;
      }
    }
  }

  rewind(fp);

  if (_fileName) free(_fileName);
  
  _fileName = strdup(fileName);
  
  MBool error;
  char errorBuf[512];

  int nCreated = 0;

  while (TRUE)
  {
    Alarm *alarm;
    if ((alarm = parseAlarm(fp, &error, errorBuf)) == NULL)
    {
      if (error)
      {
	sprintf(buf, "Error parsing alarms in file \"%s\":\n%s", 
		fileName, errorBuf);

	setError(buf);
	fclose(fp);
	return -1;
      }
      
      break;
    }

    alarmList.append(alarm);
    nCreated++;
  }

  fprintf(stderr, "Created %d alarm objects\n", nCreated);
  fclose(fp);
  
  return 0;
}


const char *SystemAlarms::includeDirective(char *directory, char *buf)
{
  static char filename[256];

  char *ptr;
  for (ptr = buf; *ptr != 0; ptr++) {

    if (*ptr == ' ' || *ptr == '\t')
      continue;

    if (*ptr != '#')
      return 0;

    break;
  }
  // Point to character after '#'
  ptr++;

  char *token;
  int nTokens = 0;
  while ((token = strtok(ptr, " \t\n")) != 0) {
    ptr = 0;
    switch (nTokens) {

    case 0:
      if (strcmp(token, "include"))
	// Not #include directive
	return 0;
      break;

    case 1:
      // Filename
      char *tokenPtr = token;

      if ((token[0] == '"' && token[strlen(token)-1] == '"') ||
	  (token[0] == '<' && token[strlen(token)-1] == '>')) {
	token[strlen(token)-1] = '\0';
	tokenPtr++;
      }

      if (tokenPtr[0] == '/') {
	// Absolute pathname
	strcpy(filename, tokenPtr);
      }
      else {
	// Relative pathname
	sprintf(filename, "%s/%s", directory, tokenPtr);
      }

    }
    nTokens++;
  }

  if (nTokens != 2)
    return 0;

  return (const char *)filename;
}

