/*
 * MMCDEventQueue.java
 *
 * Created on 02 May�s 2005 Pazartesi, 22:55
 */

package com.isoft.mmcd.application.events ;

import com.isoft.mmcd.exceptions.* ;

import java.util.* ;

/**
 *
 * @author Fatih
 */
public class MMCDEventQueue implements java.io.Serializable
{
    // note: Using vectors for this operation is slow, since we remove data at position 0, it always shifts all
    // elements. Maybe a better solution would be implementing our own queue. But, we hope this queues will never
    // get such large
    protected Vector[ ] queues = new Vector[ 5 ] ;

    protected Object mutex = new Object( ) ;

    protected int iswaiting = 0 ;

    /** Creates a new instance of MMCDEventQueue */
    public MMCDEventQueue( )
    {
        for( int i = 0; i < queues.length; ++i )
            queues[ i ] = new Vector( ) ;
    }

    public synchronized EventQueueElement dequeueEventFromQueue( int priority )
    {
        synchronized( mutex )
        {
            if( queues[ priority ].size( ) > 0 )
                return ( EventQueueElement )queues[ priority ].remove( 0 ) ;
        }
        return null ;
    }

    public EventQueueElement lookEventFromQueue( int priority )
    {
        return ( EventQueueElement )queues[ priority ].elementAt( 0 ) ;
    }

    public void addEventToQueue( EventQueueElement event, int priority )
    {
        addEventToQueue( event, priority, true ) ;
    }

    public synchronized int getEventCount( )
    {
        return queues[ 0 ].size( ) + queues[ 1 ].size( ) + queues[ 2 ].size( ) + queues[ 3 ].size( ) + queues[ 4 ].size( ) ;
    }

    public void addEventToQueue( EventQueueElement event, int priority, boolean isMultipleAllowed )
    {
        synchronized( mutex )
        {
            // System.out.println( "Adding event:" + event.name ) ;
            if( !isMultipleAllowed )
            {
                for( int j = queues[ priority ].size( ) - 1; j >= 0; --j )
                {
                    // NOTE: Here we use == to compare, since we use a common eventPool. If this is not the case,
                    // then MMCDEvent should declare an equals method and we should use it instead
                    if( ( ( EventQueueElement )queues[ priority ].elementAt( j ) ).name.equals( event.name ) )
                        queues[ priority ].remove( j ) ;
                }
            }
            queues[ priority ].add( event ) ;
            if( iswaiting > 0 )
            {
                mutex.notify( ) ;
            }
        }
    }

    public void insertUrgentEvent( EventQueueElement event, int priority )
    {
        insertUrgentEvent( event, priority, true ) ;
    }

    // adds an event to the front end of the queue    
    public void insertUrgentEvent( EventQueueElement event, int priority, boolean isMultipleAllowed )
    {
        synchronized( mutex )
        {
            if( !isMultipleAllowed )
            {
                for( int j = queues[ priority ].size( ) - 1; j >= 0; --j )
                {
                    // NOTE: Here we use == to compare, since we use a common eventPool. If this is not the case,
                    // then MMCDEvent should declare an equals method and we should use it instead
                    if( ( ( EventQueueElement )queues[ priority ].elementAt( j ) ).name.equals( event.name ) )
                        queues[ priority ].remove( j ) ;
                }
            }
            queues[ priority ].insertElementAt( event, 0 ) ;
            System.err.println( "------ Wait count:" + iswaiting ) ;
            if( iswaiting > 0 )
            {
                mutex.notify( ) ;
            }
            System.err.println( "           Wait count:" + iswaiting ) ;
        }
    }

    public void unlockMutexAll( )
    {
        synchronized( mutex )
        {
            this.mutex.notifyAll( ) ;
        }
    }

    public EventQueueElement getNextEventQueueElementBlocked( ) throws MMCDException
    {
        int excnt = 0 ;
        int exlimit = 1 ;
        while( excnt < exlimit )
        {
            try
            {
                synchronized( mutex )
                {
                    for( int i = queues.length - 1; i >= 0; --i )
                    {
                        if( queues[ i ].size( ) > 0 )
                            return dequeueEventFromQueue( i ) ;
                    }
                    ++iswaiting ;
                    mutex.wait( ) ;
                    --iswaiting ;
                }
            }
            catch( InterruptedException e )
            {
                System.err.println( "Waiting interrupted, ignored for " + excnt + " times.." ) ;
                excnt++ ;
            }
            catch( Exception ex )
            {
                System.err.println( "An error occured during waiting next event" ) ;
                ex.printStackTrace( ) ;
                throw new MMCDException( ex ) ;
            }
        }
        return null ;
    }

    private synchronized EventQueueElement getNextEventQueueElementNonBlocked( ) throws MMCDException
    {
        try
        {
            for( int i = queues.length - 1; i >= 0; --i )
            {
                if( queues[ i ].size( ) > 0 )
                    return dequeueEventFromQueue( i ) ;
            }
        }
        catch( Exception ex )
        {
            System.err.println( "An error occured during waiting next event" ) ;
            ex.printStackTrace( ) ;
            throw new MMCDException( ex ) ;
        }
        return null ;
    }

    public EventQueueElement getNextEventBlocked( EventPool eventpool ) throws MMCDException
    {
        EventQueueElement eqe = getNextEventQueueElementBlocked( ) ;
        if( eqe != null )
            eqe.event = eventpool.getEvent( eqe.name ) ;
        return eqe ;
    }

    public EventQueueElement getNextEventNonBlocked( EventPool eventpool ) throws MMCDException
    {
        EventQueueElement eqe = getNextEventQueueElementNonBlocked( ) ;
        if( eqe != null )
            eqe.event = eventpool.getEvent( eqe.name ) ;
        return eqe ;
    }

    public void freeAllResources( )
    {
        synchronized( mutex )
        {
            queues = new Vector[ 5 ] ;
            mutex.notifyAll( ) ;
        }
    }
}