/*
 *    SCCS ID: %Z%%M% %I% %E% SST 
 *
 *    Copyright (c) 1992-1993 Mark Soloway.  All rights reserved.
 *    See SST_LEGAL_NOTICE file for terms of the license.
 */

#include "PollFD.h"

PollFD::PollFD ()
{
  setPollFDDefaults (); 
}

PollFD::PollFD (int fd, short events)
{
  setPollFDDefaults (); 

  pollfd *poll_fd = new pollfd;
  poll_fd->fd = fd;
  poll_fd->events = events;

  fdsToPoll.addItem ((TTGeneric *) poll_fd);
}

PollFD::PollFD (const PollFD &poll_fd)
{
  copy (poll_fd);
}

PollFD &PollFD::operator= (const PollFD &poll_fd)
{
  if (this != &poll_fd) {
    destroy ();
    copy (poll_fd);
  }

  return *this;
}

void PollFD::setPollFDDefaults ()
{
  data = (void *)NULL;
  events = 0;
  timeOut = -1;
}

PollFD::~PollFD ()
{
  destroy ();
}

int PollFD::waitForActiveFD ()
{
  if (activeFDs.getSize ())  {
    pollfd *poll_fd = (pollfd *)activeFDs.removeItem (0);
    int     fd = poll_fd->fd;

    events = poll_fd->revents;

    DataEntry *data_entry = getDataEntry (fd);
    if (data_entry) {
      data = data_entry->data;

      if (data_entry->handler)
        (*data_entry->handler) (fd, events, data);
    }
    
    delete poll_fd;
    return fd;
  }

  int num_fds_to_poll = fdsToPoll.getSize ();
  if (num_fds_to_poll) {
    pollfd *poll_fd = new pollfd [num_fds_to_poll];
    for (int i=0; i < num_fds_to_poll; i++) {
      poll_fd [i].fd = ((pollfd *)fdsToPoll [i])->fd;
      poll_fd [i].events = ((pollfd *)fdsToPoll [i])->events;
      poll_fd [i].revents = 0;
    }

    int result = poll (poll_fd, num_fds_to_poll, timeOut);
    if (result < 1) {
      delete poll_fd;
      return -1;
    }

    for (i=0; i < num_fds_to_poll; i++) {
      if (poll_fd [i].revents) {
        pollfd *active_fd = new pollfd;
        active_fd->fd = poll_fd [i].fd;
        active_fd->revents = poll_fd [i].revents;

	activeFDs.addItem ((TTGeneric *)active_fd);
      }
    }

    delete poll_fd;
    if (activeFDs.getSize ())
      return waitForActiveFD ();
  }

  return -1;
}

void *PollFD::getData () const
{
  return data;
}

short PollFD::getEvents () const
{
  return events;
}

void PollFD::addFD (int            fd,
		    short          events,
		    void          *data,
		    PollFDHandler  handler)
{
  pollfd *poll_fd = new pollfd; 
  poll_fd->fd = fd;
  poll_fd->events = events; 

  DataEntry *data_entry = new DataEntry (data, handler);
  addDataEntry (fd, data_entry);
 
  fdsToPoll.addItem ((TTGeneric *)poll_fd); 
}

void *PollFD::removeFD (int fd)
{
  int num_fds_to_poll = fdsToPoll.getSize ();
  for (int i=0; i < num_fds_to_poll; i++) {
    if (((pollfd *)fdsToPoll [i])->fd == fd) {
      delete ((pollfd *)fdsToPoll.removeItem (i));

      DataEntry *data_entry = removeDataEntry (fd);
      if (data_entry) {
        void *data = data_entry->data;

        delete data_entry;
        return data;
      }
    }
  }
}

void PollFD::setTimeOut (int timeout)
{
  timeOut = timeout;
}

void PollFD::addDataEntry (int fd, DataEntry *data)
{
  char string [12];
  sprintf (string, "%d", fd);
  dataTable.addItem (string, (TTGeneric *)data);
}

PollFD::DataEntry *PollFD::removeDataEntry (int fd)
{
  char string [12];
  sprintf (string, "%d", fd);
  return (DataEntry *)dataTable.removeItem (string);
}

PollFD::DataEntry *PollFD::getDataEntry (int fd) const
{
  char string [12];
  sprintf (string, "%d", fd);
  return (DataEntry *)dataTable.getItem (string);
}

void PollFD::copy (const PollFD &poll_fd)
{
  setPollFDDefaults (); 

  dataTable = poll_fd.dataTable;
  fdsToPoll = poll_fd.fdsToPoll;
  timeOut = poll_fd.timeOut;
}

void PollFD::destroy ()
{
  int num_active_fds = activeFDs.getSize ();
  for (int i=0; i < num_active_fds; i++)
    delete ((pollfd *)activeFDs [i]);
  activeFDs.dropItems ();

  int num_fds_to_poll = fdsToPoll.getSize ();
  for (i=0; i < num_fds_to_poll; i++)
    delete ((pollfd *)fdsToPoll [i]);
  fdsToPoll.dropItems ();
}
