/*	XGViewFactory.cpp
 *
 *		This is the engine for creating views on the fly.
 */

/*  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 <XError.h>
#include <XView.h>
#include <XViewFormat.h>
#include <XDataUtil.h>
#include <XEvent.h>


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

XGSDynArray<XGSFactory> XGViewFactory::gList;

#if OPT_WINOS
extern "C" {
		extern HINSTANCE _GInstance;
}
#endif

/************************************************************************/
/*																		*/
/*	View Construction Support											*/
/*																		*/
/************************************************************************/

/*	@F"XGViewFactory::CreateFromData" @I
 *
 *		Given the data, this scans and creates the view
 */

XGView *XGViewFactory::CreateFromData(const unsigned char *data, XGOwner *parent)
{
	XGSViewHeader h;
	XGSViewHeader *ptr;
	const unsigned char *nptr;
	XGView *nview;
	long i,len;

	XGDispatch *dispatch = XGDispatch::GetCTorDispatch();
	
	/*
	 *	Get and parse the header, initialize the data stream
	 */
	
	h = *((XGSViewHeader *)data);

#if OPT_NATIVEORDER != 1
	h.type     = SwapLong(h.type);
	h.sibling  = SwapLong(h.sibling);
	h.children = SwapLong(h.children);
	h.length   = SwapLong(h.length);
#endif

	ptr = (XGSViewHeader *)data;
	XGArgStream stream((unsigned char *)&(ptr->type),h.length + sizeof(long));
	
	/*
	 *	Now create the view. If not found, this will alert the
	 *	user and will create the generic 'view' instead.
	 */
	
	nview = NULL;
	len = gList.Length();
	for (i = 0; i < len; i++) {
		if (h.type == gList[i].type) {
			nview = (gList[i].proc)(parent,stream);
			break;
		}
	}
	if (nview == NULL) {
		Warning(KXGViewFactoryError,h.type);
		nview = new XGView(parent,stream);
	}
	
	/*
	 *	I have the view. Start looking for the children of this
	 *	thing. (The default view constructor will add the child
	 *	view to the specified parent view, so nothing needs to be
	 *	done here.)
	 */
	
	if (h.children) {
		nptr = data + h.children;

		for (;;) {
			CreateFromData(nptr,nview);
			h = *((XGSViewHeader *)nptr);

#if OPT_NATIVEORDER != 1
			h.sibling = SwapLong(h.sibling);
#endif

			if (!h.sibling) break;
			nptr += h.sibling;
		}
	}
	
	/*
	 *	Done creating me and my children. Return
	 */
	
	XGDispatch::SetCTorDispatch(dispatch);
	return nview;		
}

/*	@F"XGViewFactory::CreateFromResource" @I
 *
 *		This creates the specified view from the resource identifier
 *	provided.
 */

XGView *XGViewFactory::CreateFromResource(short resID, XGOwner *parent)
{
#if OPT_MACOS == 1
	Handle h;
	XGView *v;
	
	h = ::GetResource('VRes',resID);
	Assert(h != NULL);
	
	::HLock(h);
	v = CreateFromData((unsigned char *)(*h),parent);
	::HUnlock(h);
	::ReleaseResource(h);
	return v;
#endif

#if OPT_WINOS == 1
	HRSRC hsrc;
	HGLOBAL h;
	void *data;
	XGView *v;
	
	hsrc = ::FindResource(_GInstance,MAKEINTRESOURCE(resID),"VRes");
	Assert(hsrc != NULL);
	h = LoadResource(_GInstance,hsrc);
	Assert(h != NULL);
	data = LockResource(h);
	
	/*
	 *	Now create the object
	 */
	
	v = CreateFromData((unsigned char *)data,parent);
	
	/*
	 *	Release the resource
	 */
	
	UnlockResource(h);
	FreeResource(h);
	return v;
#endif

#if OPT_XWIN == 1
	void *data;
	
	data = ::GetResourceData('VRes',resID);
	Assert(data != NULL);
	return CreateFromData((unsigned char *)data,parent);
#endif
}

/************************************************************************/
/*																		*/
/*	Construction														*/
/*																		*/
/************************************************************************/

/*	@F"XGViewFactory::Register" @I
 *
 *		register with me the construction proc
 */

void XGViewFactory::Register(long id, XGConstructorProc *proc)
{
	XGSFactory f;
	
	f.type = id;
	f.proc = proc;
	gList += f;
}
