/*	XGDispatch.cpp
 *
 *		This is the dispatch object, the root of all message receiving
 *	classes in my application.
 */

/*  YAAF - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#include <XConfig.h>			// must be first to optimize compile on MSVC++
#include <XEvent.h>

/************************************************************************/
/*																		*/
/*	Globals																*/
/*																		*/
/************************************************************************/

XGDispatch *XGDispatch::gParent = NULL;

/************************************************************************/
/*																		*/
/*	Construction/Destruction											*/
/*																		*/
/************************************************************************/

// @G"Construction/Destruction"

/*	@F"XGDispatch::XGDispatch" @I
 *
 *		Construct me. This constructs my dispatch object by 
 *	constructing me with the last constructed object as my parent.
 */

XGDispatch::XGDispatch(bool root)
{
	/*
	 *	Use the parent specified in 'gParent'
	 */
	
	fParent = root ? NULL : gParent;
	if (fParent != NULL) {
		fFocus = fParent->fFocus;
	} else {
		fFocus = NULL;
	}
	
	/*
	 *	Now make me the default parent.
	 */
	
	gParent = this;
}

/*	@F"XGDispatch::~XGDispatch" @I
 *
 *		If I have the focus, clear it
 */

XGDispatch::~XGDispatch()
{
	if (HasFocus()) {
		fFocus->_ClearFocus();
	}
	
	while (fSend.Length()) {
		fSend[0]->RemoveReceiver(this);
	}
	
	if (gParent == this) gParent = NULL;		// prevent random bombs
}

/************************************************************************/
/*																		*/
/*	Focus Routines														*/
/*																		*/
/************************************************************************/

// @G"Focus Manipulation"

/*	@F"XGDispatch::SetFocus" @I
 *
 *		Set the current focus
 */

bool XGDispatch::SetFocus()
{
	XGDispatch *old;
	
	if (fFocus == NULL) return false;
	
	/*
	 *	See if I can even switch focus
	 */
	
	if (!CanGainFocus()) return false;			// can't gain focus
	old = fFocus->GetFocus();
	if (old == this) return true;				// I already have the focus
	if (!(old->CanLoseFocus())) return false;	// can't switch focus
	
	/*
	 *	I can switch focus. Send the appropriate messages
	 */
	
	old->LoseFocus();
	fFocus->_SetFocus(this);
	GainFocus();
	return true;
}

/*	@F"XGDispatch::HasFocus" @I
 *
 *		Do I have focus?
 */

bool XGDispatch::HasFocus()
{
	if (fFocus == NULL) return false;
	if (fFocus->GetFocus() == this) return true;
	return false;
}


/*	@F"XGDispatch::CanGainFocus" @I
 *
 *		Can I gain focus? Default true
 */

bool XGDispatch::CanGainFocus()
{
	return true;
}

/*	@F"XGDispatch::CanLoseFocus" @I
 *
 *		Can i lose focus? Default true
 */

bool XGDispatch::CanLoseFocus()
{
	return true;
}

/*	@F"XGDispatch::GainFocus" @I
 *
 *		Called right after I gain focus. Default does nothing
 */

void XGDispatch::GainFocus()
{
}

/*	@F"XGDispatch::LoseFocus" @I
 *
 *		Called right before I lose focus. Default does nothing
 */

void XGDispatch::LoseFocus()
{
}


/************************************************************************/
/*																		*/
/*	Dispatch Stuff														*/
/*																		*/
/************************************************************************/

// @G"Message dispatch"

/*	@F"XGDispatch::DoDispatch" @I
 *
 *		Do dispatch of message. This scans the various dispatch tables
 *	to determine what's going on
 */

long XGDispatch::DoDispatch(long msg, long arg, void *parg, bool par)
{
	_DispatchData *dptr;
	XGDispatch *pThis;
	long i;
	long ret;
	
	/*
	 *	Run through the dispatch table built by my macros
	 */
	
	ret = -1;
	pThis = this;
	for (;;) {
		/*
		 *	Find the top level table for this instance
		 */
			
		dptr = pThis->_GetDispatchTable();
		for (;;) {
			/*
			 *	Send it to the 'dispatch' procedure if it exists.
			 *	This is a catchall which allows redirection of
			 *	events that make it up to here
			 */
			
			if (dptr->dispatch) {
				ret = (pThis->*(dptr->dispatch))(msg,arg,parg);
				if (ret != -1) return ret;
			}
			
			/*
			 *	Scan the table to dispatch to specific procedures
			 */
			
			for (i = 0; (dptr->table)[i].msg != -1; i++) {
				if ((dptr->table)[i].msg == msg) {
					ret = (pThis->*(dptr->table)[i].proc)(arg,parg);
					if (ret != -1) return ret;
					break;
				}
			}
			
			/*
			 *	Find the class parent's table
			 */
		
			dptr = dptr->base;
			if (dptr == NULL) break;
		}
		
		/*
		 *	Now go to my parent if the 'par' flag is true.
		 */
		
		if (!par) break;
		pThis = pThis->fParent;
		if (!pThis) break;
	}
	
	return ret;
}


/************************************************************************/
/*																		*/
/*	Root dispatch tables												*/
/*																		*/
/************************************************************************/

/*	XGDispatch::_GetDispatchTable
 *
 *		Default has an empty table
 */

_DispatchData *XGDispatch::_GetDispatchTable()
{
	return &_TableData;
}

/*	XGDispatch::_TableData
 *
 *		This is the dispatch table data.
 */

_DispatchData XGDispatch::_TableData = {
	NULL,
	XGDispatch::_Dispatch
};

/*	XGDispatch::_Dispatch
 *
 *		The table contents
 */

_DispatchTable XGDispatch::_Dispatch[] = {
	{ -1, NULL }
};
