//----------------------------BEGIN LICENSE----------------------------
/* 
 * Willow : the Open Source WorkFlow Project
 * Distributable under GNU LGPL license by gun.org
 *
 * Copyright (C) 2004-2010 huihoo.org 
 * Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com> 
 * 
 * ====================================================================
 * Project Homepage : http://www.huihoo.org/willow
 * Source Forge     : http://sourceforge.net/projects/huihoo
 * Mailing list     : willow@lists.sourceforge.net 
 */
//----------------------------END  LICENSE----------------------------

package org.huihoo.workflow.event;

import java.awt.ActiveEvent;

import org.huihoo.workflow.WorkflowComponent;

public class EventDispatchThread extends Thread implements WorkflowComponent
{
	private EventQueue theQueue;
	private boolean doDispatch = true;
	private static final int ANY_EVENT = -1;

	EventDispatchThread(ThreadGroup group, String name, EventQueue queue)
	{
		super(group, name);
		theQueue = queue;
	}

	void stopDispatchingImpl(boolean wait)
	{
		// Note: We stop dispatching via a flag rather than using
		// Thread.interrupt() because we can't guarantee that the wait()
		// we interrupt will be EventQueue.getNextEvent()'s.  -fredx 8-11-98

		doDispatch = false;

		// wait for the dispatcher to complete
		if (Thread.currentThread() != this)
		{
			// Post an empty event to ensure getNextEvent is unblocked
			//
			// We have to use postEventPrivate instead of postEvent because
			// EventQueue.pop calls EventDispatchThread.stopDispatching.
			// Calling SunToolkit.flushPendingEvents in this case could
			// lead to deadlock.
			theQueue.postEventPrivate(new EmptyEvent());

			if (wait)
			{
				try
				{
					join();
				}
				catch (InterruptedException e)
				{
				}
			}
		}
	}

	public void stopDispatching()
	{
		stopDispatchingImpl(true);
	}

	public void stopDispatchingLater()
	{
		stopDispatchingImpl(false);
	}

	class EmptyEvent extends WorkflowEvent implements ActiveEvent
	{
		public EmptyEvent()
		{
			super(EventDispatchThread.this, 0);
		}

		public void dispatch()
		{
		}
	}

	public void run()
	{
		try
		{
			pumpEvents(new Conditional()
			{
				public boolean evaluate()
				{
					return true;
				}
			});
		}
		finally
		{
			/*
			 * This synchronized block is to secure that the event dispatch 
			 * thread won't die in the middle of posting a new event to the
			 * associated event queue. It is important because we notify
			 * that the event dispatch thread is busy after posting a new event
			 * to its queue, so the EventQueue.dispatchThread reference must
			 * be valid at that point.
			 */
			synchronized (theQueue)
			{
				theQueue.detachDispatchThread();
				/*
				 * Event dispatch thread dies in case of an uncaught exception. 
				 * A new event dispatch thread for this queue will be started
				 * only if a new event is posted to it. In case if no more
				 * events are posted after this thread died all events that 
				 * currently are in the queue will never be dispatched.
				 */
				if (theQueue.peekEvent() != null)
				{
					theQueue.initDispatchThread();
				}
				EventAutoShutdown.getInstance().notifyThreadFree(this);
			}
		}
	}

	void pumpEvents(Conditional cond)
	{
		pumpEvents(ANY_EVENT, cond);
	}

	void pumpEventsForHierarchy(Conditional cond, WorkflowComponent modalComponent)
	{
		pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
	}

	void pumpEvents(int id, Conditional cond)
	{
		pumpEventsForHierarchy(id, cond, null);
	}

	void pumpEventsForHierarchy(int id, Conditional cond, WorkflowComponent modalComponent)
	{
		while (doDispatch && cond.evaluate())
		{
			if (isInterrupted() || !pumpOneEventForHierarchy(id, modalComponent))
			{
				doDispatch = false;
			}
		}
	}

	boolean pumpOneEventForHierarchy(int id, WorkflowComponent modalComponent)
	{
		try
		{
			WorkflowEvent event = (id == ANY_EVENT) ? theQueue.getNextEvent() : theQueue.getNextEvent(id);
			
			theQueue.dispatchEvent(event);

			return true;
		}
		catch (ThreadDeath death)
		{
			return false;

		}
		catch (InterruptedException interruptedException)
		{
			return false;
			// Can get and throw only unchecked exceptions
		}
		catch (RuntimeException e)
		{
		}
		catch (Error e)
		{
		}
		return true;
	}
}