static char AlarmList_id[] = "$Header: /usr/tiburon/unix/gui/tmacs/RCS/AlarmList.cc,v 1.7 1997/10/03 09:24:09 oreilly Exp $";


/*
$Log: AlarmList.cc,v $
Revision 1.7  1997/10/03 09:24:09  oreilly
Use local SList iterator

Revision 1.6  97/08/12  14:14:59  14:14:59  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.5  97/05/30  15:43:49  15:43:49  oreilly (Thomas C. O'Reilly)
added sort()

Revision 1.4  97/04/30  19:24:28  19:24:28  oreilly (Thomas C. O'Reilly)
Attach bottom of list widget to baseWidget

Revision 1.3  97/03/20  12:28:32  12:28:32  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.2  96/10/28  09:11:36  09:11:36  oreilly (Thomas C. O'Reilly)
*** empty log message ***

Revision 1.1  96/07/22  10:41:27  10:41:27  oreilly (Thomas C. O'Reilly)
First external release

*/
#include <stdlib.h>
#include <time.h>
#include <Xm/Form.h>
#include <Xm/List.h>
#include <Xm/PushB.h>
#include <Xm/Text.h>
#include <Xm/Label.h>
#include "AlarmList.h"

AlarmList::AlarmList(const char *name, Widget parent, Priority priority)
  : VkComponent(name)
{
  _baseWidget = XtCreateWidget(_name, xmFormWidgetClass, parent, NULL, 0);
  installDestroyHandler();

  Arg args[10];
  int nArgs = 0;
  XtSetArg(args[nArgs], XmNlistSizePolicy, XmRESIZE_IF_POSSIBLE);
  
  nArgs++;
  /* Set scrollBarDisplayPolicy to xmAS_NEEDED, because if it's xmSTATIC
     then updating the list doesn't seem to properly update the scrollbar */
  XtSetArg(args[nArgs], XmNscrollBarDisplayPolicy, XmAS_NEEDED);
  
  nArgs++;
  XtSetArg(args[nArgs], XmNselectionPolicy, XmSINGLE_SELECT);
  nArgs++;

  _listWidget = 
    XmCreateScrolledList(_baseWidget, "alarmListWidget", args, nArgs);

  XtVaSetValues(XtParent(_listWidget), 
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);
  
  XtAddCallback(_listWidget, XmNsingleSelectionCallback, 
		&AlarmList::listSelectCallback, (XtPointer )this);


  _selectedItem = 
    XtVaCreateManagedWidget(" ", xmLabelWidgetClass, 
			    _baseWidget, 
			    XmNleftAttachment, XmATTACH_FORM,
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNbottomAttachment, XmATTACH_FORM,
			    NULL);

  XtVaSetValues(XtParent(_listWidget),
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, _selectedItem,
		NULL);

  XtManageChild(_listWidget);

  XtManageChild(_baseWidget);
  _priority = priority;
}


void AlarmList::clear()
{
  XmListDeleteAllItems(_listWidget);
  SListIter<Alarm *> alarms(_alarmList);
  alarms.reset();
  Alarm **alarmp;
  while (alarmp = alarms.next())
    alarms.remove();

  // Blank-out label
  XmString xmstr = XmStringCreateSimple(" ");
  XtVaSetValues(_selectedItem, XmNlabelString, xmstr, NULL);  
  XmStringFree(xmstr);
}


int AlarmList::itemCount()
{
  int count;
  XtVaGetValues(_listWidget, XmNitemCount, &count, NULL);
  return count;
}



int AlarmList::entryPosition(Alarm *alarm)
{
  SListIter<Alarm *> alarms(_alarmList);

  alarms.reset();
  Alarm **alarmp;
  for (int i = 0; alarmp = alarms.next(); i++)
  {
    if (*alarmp == alarm)
      return i;
  }
  return EndOfList;
}

void AlarmList::update(Alarm *alarm)
{
  SListIter<Alarm *> alarms(_alarmList);

  alarms.reset();
  Alarm **alarmp;
  for (int i = 0; alarmp = alarms.next(); i++)
  {
    if (*alarmp == alarm)
    {
      XmString xmstr;
      XmStringTable items;
      int nItems;
      XtVaGetValues(_listWidget, XmNitems, &items, XmNitemCount, &nItems, 
		    NULL);

      xmstr = makeListString(alarm);

      if (!XmStringCompare(xmstr, items[i]))
	XmListReplaceItemsPos(_listWidget, &xmstr, 1, i + 1);

      XmStringFree(xmstr);
      return;
    }
  }
  
  // Alarm not yet in list; append it
  append(alarm);
  return;
}


void AlarmList::append(Alarm *alarm)
{
  _alarmList.append(alarm);
  XmString xmstr = makeListString(alarm);
  XmListAddItem(_listWidget, xmstr, 0);
  XmStringFree(xmstr);
  return;
}


int AlarmList::remove(Alarm *alarm)
{
  SListIter<Alarm *> alarms(_alarmList);
  alarms.reset();
  Alarm **alarmp;
  for (int i = 0; alarmp = alarms.next(); i++)
  {
    if (*alarmp == alarm)
    {
      alarms.remove();
      XmListDeletePos(_listWidget, i + 1);
      return 0;
    }
  }
  // Specified item not found
  return -1;
}



XmString AlarmList::makeListString(Alarm *alarm)
{
  char buf[512];
  memcpy((void *)buf, (void *)' ', sizeof(buf) - 1);
  buf[sizeof(buf)-1] = '\0';
  
  char *ptr = buf;
  if (!alarm->acknowledged())
    sprintf(ptr, "* ");
  else
    sprintf(ptr, "  ");
  
  ptr += strlen(ptr);
  
  sprintf(ptr, "%-32s", alarm->itemMnemonic());
  ptr[31] = ' ';
  ptr += 32;

  if (!alarm->eventAlarm())
    sprintf(ptr, "%-10s", Alarm::valueMnemonic(alarm->type(), alarm->value()));
  else
    // EventAlarm has no associated value
    sprintf(ptr, "%-10s", "(Event)");

  // Pad end of value and time column with blanks
  ptr += strlen(ptr);
  while (ptr - buf < TimeColumn)
  {
    *ptr = ' ';
    ptr++;
  }
  
  ptr = buf + TimeColumn;
  
  ptr += strlen(ptr);
  DM_Time dmTime;
  alarm->writeTime(&dmTime);
  struct tm *timePtr = gmtime((const time_t *)&dmTime.tv_sec);
  strftime(ptr, sizeof(buf) - (ptr - buf) - 1, "%j:%H:%M:%S UTC", timePtr);

  return XmStringCreateSimple(buf);
}


void AlarmList::listSelectCallback(Widget w, XtPointer clientData, 
				   XtPointer callData)
{
  AlarmList *obj = (AlarmList *)clientData;
  
  XmListCallbackStruct *cb = (XmListCallbackStruct *)callData;
  if (!cb->selected_item_count)
  {
    // Blank-out label
    XmString xmstr = XmStringCreateSimple(" ");
    XtVaSetValues(obj->_selectedItem, XmNlabelString, xmstr, NULL);  
    XmStringFree(xmstr);
    return;
  }
  
  // Display info for selected alarm
  obj->displaySelectedItem(cb->item_position - 1);
}



void AlarmList::displaySelectedItem(int index)
{
  SListIter<Alarm *> alarms(_alarmList);

  alarms.reset();
  Alarm **alarm;
  for (int i = 0; i <= index; i++)
  {
    alarm = alarms.next();
  }

  char buf[100];
  sprintf(buf, "DM Item: %s  Type: %s", 
	  (*alarm)->name(), Alarm::typeMnemonic((*alarm)->type()));

  XmString xmstr = XmStringCreateSimple(buf);
  XtVaSetValues(_selectedItem, XmNlabelString, xmstr, NULL);
  XmStringFree(xmstr);
  return;
}


Alarm *AlarmList::selectedItem()
{
  int nSelected;
  int *selected;
  
  if (!XmListGetSelectedPos(_listWidget, &selected, &nSelected))
    return NULL;

  int pos = selected[0];
  XtFree((char *)selected);

  Alarm **alarm;
  SListIter<Alarm *> alarms(_alarmList);
  alarms.reset();
  for (int i = 0; i < pos; i++)
    alarm = alarms.next();
  
  return *alarm;
}


Alarm *AlarmList::alarm(int index)
{
  SListIter<Alarm *> alarms(_alarmList);

  alarms.reset();
  Alarm **alarmp;

  for (int i = 0; alarmp = alarms.next(); i++)
  {
    if (i == index)
      return *alarmp;
  }

  return NULL;
}


void AlarmList::sort()
{
  XmStringTable items;
  int nItems;
  XtVaGetValues(_listWidget, XmNitems, &items, XmNitemCount, &nItems, 
		NULL);

  ListEntry *entries = (ListEntry *)malloc(nItems * sizeof(ListEntry));
  
  if (entries == NULL)
  {
    fprintf(stderr, "AlarmList::sort() - malloc() failed for %d items\n",
	    nItems);
    return;
  }

  SListIter<Alarm *> alarms(_alarmList);

  alarms.reset();
  Alarm **alarm;
  
  for (int i = 0; i < nItems; i++)
  {
    char *text;
    XmStringGetLtoR(items[i], XmSTRING_DEFAULT_CHARSET, &text);
    entries[i].entryString = text;

    alarm = alarms.next();
    entries[i].alarm = *alarm;
  }

  qsort((void *)entries, nItems, sizeof(ListEntry), AlarmList::timeCompare);

  XmListDeleteAllItems(_listWidget);

  // Clear alarm object list
  alarms.reset();
  while (alarm = alarms.next())
    alarms.remove();

  alarms.reset();
  
  // Re-build GUI list and alarm object list
  for (i = 0; i < nItems; i++)
  {
    XmString xmstr = XmStringCreateSimple(entries[i].entryString);
    XmListAddItem(_listWidget, xmstr, 0);
    XmStringFree(xmstr);
    XtFree(entries[i].entryString);
    _alarmList.append(entries[i].alarm);
  }

  free(entries);
}


int AlarmList::timeCompare(const void *p1, const void *p2)
{
  ListEntry *entry1 = (ListEntry *)p1;
  ListEntry *entry2 = (ListEntry *)p2;
  
  char *timeStr1 = entry1->entryString + TimeColumn;
  char *timeStr2 = entry2->entryString + TimeColumn;

  return strcmp((const char *)timeStr1, (const char *)timeStr2);
}







