/*====================================================================
 * event.c
 *
 * Copyright 1993, Silicon Graphics, Inc.
 * All Rights Reserved.
 *
 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
 * Inc.; the contents of this file may not be disclosed to third
 * parties, copied or duplicated in any form, in whole or in part,
 * without the prior written permission of Silicon Graphics, Inc.
 *
 * RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to
 * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
 * in Technical Data and Computer Software clause at DFARS
 * 252.227-7013, and/or in similar or successor clauses in the FAR,
 * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
 * Copyright Laws of the United States.
 *====================================================================*/

#include <libaudio.h>
#include <os_internal.h>
#include <ultraerror.h>


void alEvtqNew(ALEventQueue *evtq, ALEventListItem *items, s32 itemCount)
{
    s32 i;
    
    evtq->eventCount     = 0;
    evtq->allocList.next = 0;
    evtq->allocList.prev = 0;
    evtq->freeList.next  = 0;
    evtq->freeList.prev  = 0;

    for (i = 0; i < itemCount; i++) {
        alLink((ALLink *)&items[i], &evtq->freeList);
    }
}

ALMicroTime alEvtqNextEvent(ALEventQueue *evtq, ALEvent *evt) 
{
    ALEventListItem *item;
    ALMicroTime delta;
    OSIntMask mask;

    mask = osSetIntMask(OS_IM_NONE);
    
    item = (ALEventListItem *)evtq->allocList.next;

    if (item)
    {
        alUnlink((ALLink *)item);
        alCopy(&item->evt, evt, sizeof(*evt));
        alLink((ALLink *)item, &evtq->freeList);
	delta = item->delta;
    }
    else
    {
        /* sct 11/28/95 - If we get here, most like we overflowed the event queue */
	/* with non-self-perpetuating events.  Eg. if we filled the evtq with volume */
	/* events, then when the seqp is told to play it will handle all the events */
	/* at once completely emptying out the queue.  At this point this problem */
	/* must be treated as an out of resource error and the evtq should be increased. */
	evt->type = -1;
	delta = 0;	    
    }

    osSetIntMask(mask);
    
    return delta;
}

void alEvtqPostEvent(ALEventQueue *evtq, ALEvent *evt, ALMicroTime delta)
{
    ALEventListItem     *item;
    ALEventListItem     *nextItem;
    ALLink              *node;
    s32                 postAtEnd=0;
    OSIntMask           mask;

    mask = osSetIntMask(OS_IM_NONE);

    item = (ALEventListItem *)evtq->freeList.next;
    if (!item) {
        osSetIntMask(mask);
#ifdef _DEBUG
        __osError(ERR_ALEVENTNOFREE, 0);
#endif        
        return;
    }
    
    alUnlink((ALLink *)item);
    alCopy(evt, &item->evt, sizeof(*evt));

    if (delta == AL_EVTQ_END)
        postAtEnd = -1;
    
    for (node = &evtq->allocList; node != 0; node = node->next) {
        if (!node->next) { /* end of the list */
            if (postAtEnd)
                item->delta = 0;
            else
                item->delta = delta;
            alLink((ALLink *)item, node);
            break;
        } else {
            nextItem = (ALEventListItem *)node->next;

            if (delta < nextItem->delta) {
                item->delta = delta;
                nextItem->delta -= delta;
                    
                alLink((ALLink *)item, node);
                break;
            }
                
            delta -= nextItem->delta;

        }
    }

    osSetIntMask(mask);
    
}

void alEvtqFlush(ALEventQueue *evtq)
{
    ALLink      *thisNode;
    ALLink      *nextNode;
    OSIntMask   mask;

    mask = osSetIntMask(OS_IM_NONE);

    thisNode = evtq->allocList.next;
    while( thisNode != 0 ) {
	nextNode = thisNode->next;
	alUnlink(thisNode);
	alLink(thisNode, &evtq->freeList);
	thisNode = nextNode;
    }
    
    osSetIntMask(mask);
}


/*
  This routine flushes events according their type.
*/
void alEvtqFlushType(ALEventQueue *evtq, s16 type)
{
    ALLink      	*thisNode;
    ALLink      	*nextNode;
    ALEventListItem     *thisItem, *nextItem;
    OSIntMask   	mask;

    mask = osSetIntMask(OS_IM_NONE);

    thisNode = evtq->allocList.next;
    while( thisNode != 0 )
    {
	nextNode = thisNode->next;
	thisItem = (ALEventListItem *)thisNode;
	nextItem = (ALEventListItem *)nextNode;
	if (thisItem->evt.type == type)
	{
	    if (nextItem)
		nextItem->delta += thisItem->delta;
	    alUnlink(thisNode);
	    alLink(thisNode, &evtq->freeList);
	}
	thisNode = nextNode;
    }

    osSetIntMask(mask);
}


#ifdef _DEBUG_INTERNAL
void alEvtqPrintEvtQueue(ALEventQueue *evtq) 
{
    s32 count1 = 0;
    s32 count2 = 0;
    ALLink *node;
    ALEventListItem *item;
    
    /* count free events */
    for (node = evtq->freeList.next; node != 0; node= node->next) {
        count1++;
    }

    PRINTF("----- Allocated Events -----\n");
    for (node = evtq->allocList.next; node != 0; node= node->next) {
        item = (ALEventListItem *)node;
        
        PRINTF("\tdelta: %d\ttype %d\n", item->delta, item->evt.type);
        count2++;
    }
    PRINTF("\n");

    PRINTF("free  events\t %d\n", count1);
    PRINTF("alloc events\t %d\n", count2);
    PRINTF("total events\t %d\n", count1 + count2);
}

char *MidiStatus2Str (char status, char *str);

void
alEvtqPrintAllocEvts(ALEventQueue *evtq) 
{
    ALLink *node;
    ALEventListItem *item;
    ALMicroTime itemTime = 0;
    char str[32];

    PRINTF("----- Allocated Events -----\n");
    for (node = evtq->allocList.next; node != 0; node= node->next)
    {
        item = (ALEventListItem *)node;
        itemTime += item->delta;

        PRINTF("\tdelta: %d\tabs: %d\t", item->delta, itemTime);

	switch (item->evt.type)
	{
	    case AL_NOTE_END_EVT:
	        PRINTF("NOTE_END\tvox: %x\n", item->evt.msg.note.voice);
	    break;

	    case AL_SEQP_MIDI_EVT:
		PRINTF("SEQP_MIDI\t%s\n", MidiStatus2Str(item->evt.msg.midi.status & AL_MIDI_StatusMask, str));
	    break;

	    case AL_SEQP_PRIORITY_EVT:
		PRINTF("SEQP_PRIORITY\n");
	    break;

	    default:
	        PRINTF("type: %d\n", item->evt.type);
	    break;
	}

    }
    PRINTF("\n");

}

char *
MidiStatus2Str (char status, char *str)
{
    switch (status)
    {
        case AL_MIDI_NoteOn:
	    sprintf(str, "note on");
	break;

        case AL_MIDI_NoteOff:
	    sprintf(str, "note off");
	break;

        default:
	    sprintf(str, "status:%d", status);
	break;
    }

    return str;
}

#endif /* _DEBUG_INTERNAL */



