/*  Shrine mentions possibly using two FIFOs
    (in our case, Queues) for pending and
    empty frames. If logical to implement,
    perhaps Zeal NetQueue code should
    do something similar to that idea.

    Each Ethernet Frame will be represented
    as an entry in a CQueue. */

class CNetQueueEntry:CQueue
{
    I64 packet_length;
    U8  frame[ETHERNET_FRAME_SIZE];
};


/*  global variable, holds pointer of Ethernet Queue.
    This acts as the Head of the Queue, Entries act
    as the Tail of the Queue. 
    Upon QueueInit, ->next and ->last are set to
    itself, the Head. */

CQueue *net_queue; // no QueueRemove the Head! only Entries!

U0 NetQueueInit()
{
    net_queue = CAlloc(sizeof(CQueue));
    QueueInit(net_queue);
}

CNetQueueEntry *NetQueuePull()
{/* Returns a pointer to a CNetQueueEntry,
    or NULL pointer if Net Queue is empty. */

    CNetQueueEntry *entry;

    if (net_queue->next != net_queue)
    {
        entry = net_queue->next;

        NetLog("NETQUEUE PULL: Removing entry from queue.");
        QueueRemove(entry);
    }
    else // Queue is empty if head->next is head itself.
    {
        entry = NULL;
    }

    return entry;
}

U0 NetQueuePush(U8 *data, I64 length)
{/* Pushes a copy of the packet data and length
    into the Net Queue. The NetQueueEntry is inserted
    after the last entry of net_queue to keep new
    items in the back of the Queue, old in front. */ 

    CNetQueueEntry *entry = CAlloc(sizeof(CNetQueueEntry));

    entry->packet_length = length;

    MemCopy(entry->frame, data, length);

    QueueInsert(entry, net_queue->last);

    // Generate Net Handler interrupt.
    NetLog("NETQUEUE PUSH COPY: Generating NetHandler interrupt.");
    MPInt(I_NETHANDLER, INT_DEST_CPU);
}


NetQueueInit;