/*	XGWindowFactory.cpp
 *
 *		This is exactly like the view factory, but for constructing
 *	windows instead.
 */

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

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

XGSDynArray<XGSWFactory> XGWindowFactory::gList;

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

/*	@F"XGWindowFactory::CreateFromData" @I
 *
 *		Given the data, this scans and creates the window. Note that
 *	I use the same header information for the window as the view
 *	(the XGSViewHeader record), even though this is a separate
 *	collection of routines.
 */

XGWindow *XGWindowFactory::CreateFromData(const unsigned char *data, XGDocument *doc, XGForm *form)
{
	XGSViewHeader h;
	const unsigned char *nptr;
	XGWindow *nwindow;
	long i,len;
	XGView *view;
	XGSViewHeader *ptr;
	XGOwner *owner;

	if (doc) XGDispatch::SetCTorDispatch(doc);
	else XGDispatch::SetCTorDispatch(XGAppCore::GetApplication());
	
	/*
	 *	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 window. If not found, this will alert the
	 *	user and will create the generic 'window' instead.
	 */
	
	nwindow = NULL;
	len = gList.Length();
	for (i = 0; i < len; i++) {
		if (h.type == gList[i].type) {
			nwindow = (gList[i].proc)(stream,doc,form);
			break;
		}
	}
	if (nwindow == NULL) {
		Warning(KXGWindowFactoryError,h.type);
		nwindow = new XGWindow(stream,doc,form);
	}
	
	/*
	 *	I have the window. This will only have one child, the view
	 *	object which is to be contained in this window. Scan for
	 *	the child object and construct.
	 */
	
	owner = nwindow->GetView();
	if (owner == NULL) {
		owner = nwindow;
		if (h.children) {
			nptr = data + h.children;
			view = XGViewFactory::CreateFromData(nptr,owner);
		}
		nwindow->SetWindowView(view);
	} else {
		if (h.children) {
			nptr = data + h.children;
			for (;;) {
				view = XGViewFactory::CreateFromData(nptr,owner);
				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
	 */
	
	return nwindow;		
}

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

XGWindow *XGWindowFactory::CreateFromResource(short resID, XGDocument *doc, XGForm *form)
{
#if OPT_MACOS == 1
	Handle h;
	XGWindow *w;
	
	h = ::GetResource('VRes',resID);
	Assert(h != NULL);
	
	::HLock(h);
	w = CreateFromData((unsigned char *)(*h),doc,form);
	::HUnlock(h);
	::ReleaseResource(h);
	return w;
#endif

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

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

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

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

void XGWindowFactory::Register(long id, XGWConstructorProc *proc)
{
	XGSWFactory f;
	
	f.type = id;
	f.proc = proc;
	gList += f;
}
