/*****************************************************************************
 * File:  sys_evpool.c
 *
 *
 * Notice:
 *   (C) Copyright 1999, 2000 ROX Software, Inc.
 *   All rights reserved.
 *
 * Model Compiler:  MC3020 V1.3.0
 *
 * Warnings:
 *   !!! THIS IS AN AUTO-GENERATED FILE. PLEASE DO NOT EDIT. !!!
 ****************************************************************************/

#include <stdlib.h>

#include "sys_init.h"
#include "e_mechs.h"
#include "e_events.h"
#include "e_objset.h"
#include "sys_user_co.h"
/* Include header(s) of domain level events union. */
#include "A_events.h"
#include "EXP_events.h"

/*****************************************************************************
 * Structure: SystemOoaEvents_u
 * 'Super-union' of all OOA events in the system. For translation patterns
 * which can not accept dynamic memory allocation for OOA events, this union
 * is used to predetermine the maximum size of any OOA event in the system.
 ****************************************************************************/
union SystemOoaEvents_u
{
  OoaEvent_t mc_event_base;
  A_DomainEvents_u mc_events_in_domain_A;
  EXP_DomainEvents_u mc_events_in_domain_EXP;
};
typedef union SystemOoaEvents_u SystemOoaEvents_u;

/*****************************************************************************
 * Provide anchor declaration for front and back of list of events.
 ****************************************************************************/
typedef struct OoaEventQueue_s OoaEventQueue_s;
struct OoaEventQueue_s
{
  OoaEvent_t * head, * tail;
};

/*****************************************************************************
 * Pre-allocated memory pool for OOA events.
 ****************************************************************************/
static SystemOoaEvents_u aSG_ooa_event_pool[ SYS_MAX_OOA_EVENTS ];
static OoaEvent_t * pSG_free_event_list = (OoaEvent_t *) 0;

/*****************************************************************************
 * Link the event skeleton nodes together on the free list ready
 * for allocation.
 ****************************************************************************/
void
InitializeOoaEventPool()
{
  unsigned int i;
  /* String events together into a singly linked list. */
  pSG_free_event_list = (OoaEvent_t *) &aSG_ooa_event_pool[ 0 ];
  for ( i = 0; i < SYS_MAX_OOA_EVENTS; i++ )
  {
    aSG_ooa_event_pool[ i ].mc_event_base.next = (OoaEvent_t *) &(aSG_ooa_event_pool[ i + 1 ]);
    aSG_ooa_event_pool[ i ].mc_event_base.prev = (OoaEvent_t *) 0;
  }
  aSG_ooa_event_pool[ SYS_MAX_OOA_EVENTS - 1 ].mc_event_base.next = (OoaEvent_t *) 0;
}

/*****************************************************************************
 * Escher_AllocateOoaEvent
 * Note:  event_size unused, reserved for future use, eliminated for now.
 ****************************************************************************/
OoaEvent_t *
Escher_AllocateOoaEvent()
{
  OoaEvent_t * event;
  if ( ! pSG_free_event_list )
  {
    UserEventFreeListEmptyCallout(); /* Bad news!  No more events.         */
  }
  else
  {
    event = pSG_free_event_list;       /* Grab front of the free list.     */
    pSG_free_event_list = event->next; /* Unlink from front of free list.  */
    ClearOoaEventFlags( event );
  }
  return event;
}

/*****************************************************************************
 * Escher_NewOoaEvent
 * Allocate the event and initialize the base attributes.
 ****************************************************************************/
OoaEvent_t *
Escher_NewOoaEvent( const void * const destination,
                            const OoaEventConstant_t * const event_info )
{
  OoaEvent_t * event = Escher_AllocateOoaEvent();
  SetEventTargetInstance( event, destination );
  SetEventDestDomainNumber( event, event_info->destination_domain_number );
  SetEventDestObjectNumber( event, event_info->destination_object_number );
  SetOoaEventNumber( event, event_info->event_number );
  SetOoaEventFlags( event, event_info->event_flags );
  SetOoaEventPriority( event, event_info->priority );
  return event;
}

/*****************************************************************************
 * Escher_DeleteOoaEvent
 ****************************************************************************/
void
Escher_DeleteOoaEvent( void * event )
{
  if ( event != 0 )
  {
    ((OoaEvent_t *) event)->next = pSG_free_event_list;
    pSG_free_event_list = (OoaEvent_t *) event;
  }
}


static OoaEventQueue_s sSG_non_self_event_queue;

/*****************************************************************************
 * Zero the anchor points for the non- self-directed event queue.
 ****************************************************************************/
void
InitializeOoaNonSelfEventQueue()
{
  sSG_non_self_event_queue.head = (OoaEvent_t *) 0;
  sSG_non_self_event_queue.tail = (OoaEvent_t *) 0;
}

/*****************************************************************************
 * Send an event to the instance queue.  Use priority where applicable.
 *
 * The following table summarizes the construction of events as
 * expected in Escher.  For each type of object (or pseudo-object)
 * that may be the source or target of an event, the expected
 * value of the source and destination handles in the event are
 * given.
 *
 *   object type | as event source     | as destination
 *   ------------+---------------------+----------------------
 *   instance    | handle              | handle
 *   assigner    | manufactured handle | 0
 *   creator     | manufactured handle | 0
 *   init        | manufactured handle | cannot be destination
 *   FBO         | manufactured handle | cannot be destination
 *
 ****************************************************************************/
void
Escher_SendEvent( OoaEvent_t * event )
{
  /* Insert event into empty event queue.  */
  if ( sSG_non_self_event_queue.tail == (OoaEvent_t *) 0 )
  {
    sSG_non_self_event_queue.head = event;    /* first in queue */
    sSG_non_self_event_queue.tail = event;    /* last in queue */
    event->next = (OoaEvent_t *) 0;
    event->prev = (OoaEvent_t *) 0;
  }
  else
  /* No priority, append to end of queue.  */
  if ( event->priority == 0 )
  {
    event->next = (OoaEvent_t *) 0;           /* input at tail end */
    event->prev = sSG_non_self_event_queue.tail;
    sSG_non_self_event_queue.tail->next = event; /* non empty */
    sSG_non_self_event_queue.tail = event;    /* tail points to last */
  }
  else
  /* Priority event, insert at proper position.  */
  {
    OoaEvent_t * e = sSG_non_self_event_queue.tail;
    /* Find slot before which to insert our new arrival.     */
    /* Break from the loop before the event we must follow.  */
    while ( e != (OoaEvent_t *) 0 )
    {
      if ( event->priority <= e->priority )
        break;
      if ( GetEventTargetInstance( event ) == GetEventTargetInstance(e) ) {
        if ( GetEventSendingInstance( event ) == GetEventSendingInstance(e) ) {
          if ( GetEventTargetInstance( event ) != 0 )
            break;
          else
            /* Creator or assigner with no target instance handle.  */
            /* We must interrogate the object and domain numbers.   */
            if ( GetEventDestObjectNumber( event ) == GetEventDestObjectNumber( e ) )
              if ( GetEventDestDomainNumber( event ) == GetEventDestDomainNumber( e ) )
                break;
        }
      }
      e = e->prev;
    }
    if ( e == (OoaEvent_t *) 0 )
    {
      /* Slot not found, insert after head.  */
      e = sSG_non_self_event_queue.head;
      event->prev = (OoaEvent_t *) 0;
      event->next = e;
      e->prev = event;
      sSG_non_self_event_queue.head = event;
    }
    else
    {
      /* Slot found, insert before.  */
      event->prev = e;
      event->next = e->next;
      e->next = event;
      if ( event->next != (OoaEvent_t *) 0 )
        event->next->prev = event;
      if ( sSG_non_self_event_queue.tail == e )
        sSG_non_self_event_queue.tail = event;
    }
  }
}

/*****************************************************************************
 * Drag an event from the instance directed queue if there is one.  This
 * routine also serves as the IsQueueEmpty routine.  A null return code 
 * indicates that the queue is empty.  Otherwise the handle to the
 * event will be returned.
 ****************************************************************************/
OoaEvent_t *
DequeueOoaNonSelfEvent()
{
  OoaEvent_t * event;
  /* Assign the event from the head of the queue.  */
  event = sSG_non_self_event_queue.head;
  /* If the list is not empty, bump the head.  */
  if ( event != (OoaEvent_t *) 0 )
  {
    sSG_non_self_event_queue.head = event->next;
    /* If empty, nullify tail.  Link prev pointers.  */
    if ( sSG_non_self_event_queue.head == (OoaEvent_t *) 0 )
      sSG_non_self_event_queue.tail = (OoaEvent_t *) 0;
    else
      sSG_non_self_event_queue.head->prev = (OoaEvent_t *) 0;
  }
  return event;
}


/*****************************************************************************
 ****************************************************************************/
static OoaEventQueue_s sSG_self_event_queue;

/*****************************************************************************
 * Zero the anchor points for the self-directed event queue.
 ****************************************************************************/
void
InitializeOoaSelfEventQueue()
{
  sSG_self_event_queue.head = (OoaEvent_t *) 0;
  sSG_self_event_queue.tail = (OoaEvent_t *) 0;
}

/*****************************************************************************
 * Send an event to the self queue.  No prioritization occurs on
 * this queue.
 ****************************************************************************/
void
Escher_SendSelfEvent( OoaEvent_t * event )
{
  event->next = (OoaEvent_t *) 0;
  /* Append the event to the tail end of the queue.  */
  /* No need to maintain prev pointers for self directed events.  */
  if ( sSG_self_event_queue.tail == (OoaEvent_t *) 0 )
    sSG_self_event_queue.head = event;
  else
    sSG_self_event_queue.tail->next = event;
  sSG_self_event_queue.tail = event;
}

/*****************************************************************************
 * Drag an event from the self queue if there is one.  This routine
 * also serves as the IsQueueEmpty routine.  A null return code 
 * indicates that the queue is empty.  Otherwise the handle to the
 * event will be returned.
 ****************************************************************************/
OoaEvent_t *
DequeueOoaSelfEvent()
{
  OoaEvent_t * event;
  /* Assign the event from the head of the queue.  */
  event = sSG_self_event_queue.head;
  /* If the list is not empty, bump the head.  */
  if ( event != (OoaEvent_t *) 0 )
  {
    sSG_self_event_queue.head = event->next;               /* bump */
    /* If empty, nullify tail.  No need to maintain prev pointers
       for the self queue.  They are not used.  */
    if ( sSG_self_event_queue.head == (OoaEvent_t *) 0 )
      sSG_self_event_queue.tail = (OoaEvent_t *) 0;
  }
  return event;
}