/* 
Copyright (c) 1991-2000 UserLand Software, Inc. 

Permission is hereby granted, free of charge, to any person obtaining a 
copy of this software and associated documentation files (the 
"Software"), to deal in the Software without restriction, including 
without limitation the rights to use, copy, modify, merge, publish, 
distribute, sublicense, and/or sell copies of the Software, and to 
permit persons to whom the Software is furnished to do so, subject to the 
following conditions: 

The above copyright notice and this permission notice shall be 
included in all copies or substantial portions of the Software. 

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
*/ 


#include "iowacore.h"
#include <applet.h>
#include "iowaobject.h"
#include "iowapack.h"


#define currentheaderversion 4


typedef struct typackglobals {

	short minh, minv;
	} typackglobals;
	
typackglobals pack = {0, 0};


static boolean packhandle (Handle hpacked, Handle h) {
	
	boolean fl;
	
	if (h == nil) /*nil handles take no space on disk*/
		return (true);
		
	lockhandle (h);
	
	fl = enlargehandle (hpacked, GetHandleSize (h), *h);
	
	unlockhandle (h);
	
	return (fl);
	} /*packhandle*/
	

boolean packobject (Handle hpacked, hdlobject h, boolean lastinlist) {
	
	tydiskobject info;
	Handle packedobjectdata;
	bigstring bs;
	
	if (!callpackdata (h, &packedobjectdata)) 
		return (false);
		
	clearbytes (&info, longsizeof (info));
	
	info.versionnumber = 3;
	
	info.objecttype = (**h).objecttype;
	
	info.objectrect = (**h).objectrect;
	
	OffsetRect (&info.objectrect, -pack.minh, -pack.minv);
	
	GetFontName ((**h).objectfont, bs);
	
	if (stringlength (bs) > 31)
		setstringlength (bs, 31);
		
	copystring (bs, info.objectfont);
	
	info.objectfontsize = (**h).objectfontsize;
	
	info.objectstyle = (**h).objectstyle;
	
	info.objectjustification = (short) (**h).objectjustification;
	
	info.objectfillcolor = (**h).objectfillcolor;
	
	info.objecttextcolor = (**h).objecttextcolor;
	
	info.objectframecolor = (**h).objectframecolor;
	
	info.objecthasframe = (**h).objecthasframe;
	
	info.objectdropshadowdepth = (**h).objectdropshadowdepth;
	
	info.objectlinespacing = (**h).objectlinespacing;
	
	info.objectindentation = (**h).objectindentation;

	info.lenname = GetHandleSize ((**h).objectname);
	
	info.lenvalue = GetHandleSize ((**h).objectvalue);
	
	info.lenscript = GetHandleSize ((**h).objectscript);
	
	info.lendata = GetHandleSize (packedobjectdata);
	
	info.lastinlist = lastinlist;
	
	info.objectflag = (**h).objectflag;
	
	info.objectinvisible = !(**h).objectvisible;
	
	info.objectdisabled = !(**h).objectenabled;
	
	info.objecttransparent = (**h).objecttransparent;
	
	info.objectlanguage = (**h).objectlanguage;
	
	info.objectrecalcstatus = (**h).objectrecalcstatus;
	
	info.objectrecalcperiod = (**h).objectrecalcperiod;
	
	info.lenrecalcscript = GetHandleSize ((**h).objectrecalcscript);
	
	if (!enlargehandle (hpacked, longsizeof (info), (ptrchar) &info))
		return (false);
		
	if (!packhandle (hpacked, (**h).objectname))
		return (false);
	
	if (!packhandle (hpacked, (**h).objectvalue))
		return (false);
	
	if (!packhandle (hpacked, (**h).objectscript))
		return (false);
	
	if (!packhandle (hpacked, (**h).objectrecalcscript))
		return (false);
	
	/*new in 1.0b15 -- we let the object pack the objectdata handle*/ {
		
		if (!packhandle (hpacked, packedobjectdata))
			return (false);
			
		disposehandle (packedobjectdata);
		}
	
	if ((**h).objecttype == grouptype) 
		return (packlist ((**h).childobjectlist, hpacked));
	
	return (true);
	} /*packobject*/
	
	
static boolean packlist (hdlobject firstobject, Handle hpacked) {
	
	hdlobject nomad = firstobject;
	hdlobject nextnomad;
	
	while (nomad != nil) {
		
		nextnomad = (**nomad).nextobject;
		
		if (!packobject (hpacked, nomad, nextnomad == nil)) 
			return (false);
		
		nomad = nextnomad;
		} /*while*/
	
	return (true);
	} /*packlist*/
	
	
static void getminposition (short *minh, short *minv) {
	
	short h = infinity, v = infinity;
	hdlobject x = (**iowadata).selectionlist;
	Rect r;
	
	while (x != nil) {
		
		r = (**x).objectrect;
		
		if (r.left < h)
			h = r.left;
		
		if (r.top < v)
			v = r.top;
			
		x = (**x).nextselectedobject;
		} /*while*/
	
	*minh = h;
	
	*minv = v;
	} /*getminposition*/
		
		
static boolean packselectionlist (Handle hpacked) {
	
	/*
	12/4/92 DW: determine the smallest h and v in the selection and offset
	the rectangles of all packed objects by that amount. makes it easy for
	clones to derive their position from the rectangle of the clone object.
	*/
	
	hdlcard hc = iowadata;
	hdlobject nomad = (**hc).selectionlist;
	hdlobject nextnomad;
	boolean fl = false;
	
	getminposition (&pack.minh, &pack.minv);
	
	while (nomad != nil) {
		
		nextnomad = (**nomad).nextselectedobject;
		
		if (!packobject (hpacked, nomad, nextnomad == nil)) 
			goto exit;
		
		nomad = nextnomad;
		} /*while*/
		
	fl = true;
	
	exit:
	
	pack.minh = pack.minv = 0;
	
	return (fl);
	} /*packselectionlist*/
	
	
boolean iowapack (Handle *hpacked) {
	
	hdlcard hc = iowadata;
	Handle h;
	tydiskheader header;
	Handle htable, hwindowtitle;
	
	htable = (**hc).embeddedtable;
	
	hwindowtitle = (**iowadata).windowtitle;
	
	if (!newclearhandle ((long) 0, hpacked))
		return (false);
		
	h = *hpacked; /*copy into register*/
	
	clearbytes (&header, longsizeof (header));
	
	header.versionnumber = currentheaderversion;
	
	header.backcolor = (**hc).backcolor;
	
	header.flgrid = (**hc).flgrid;
	
	header.flinvisiblegrid = (**hc).flinvisiblegrid;
	
	header.gridunits = (**hc).gridunits;
	
	header.rightborder = (**hc).rightborder;
	
	header.bottomborder = (**hc).bottomborder;
	
	header.floater = (**hc).floater;
	
	header.idwindow = (**hc).idwindow;
	
	header.lenembeddedtable = gethandlesize (htable);
	
	header.lenwindowtitle = gethandlesize (hwindowtitle);
	
	if (!enlargehandle (h, longsizeof (header), (ptrchar) &header))
		goto error;
		
	if (!packhandle (h, htable))
		goto error;
	
	if (!packhandle (h, hwindowtitle))
		goto error;
	
	if (!packlist ((**hc).objectlist, h)) 
		goto error;
		
	return (true); /*loop terminated, it worked*/
	
	error:
	
	disposehandle (h);
	
	*hpacked = nil;
	
	return (false);
	} /*iowapack*/
	
	
boolean packselectedobjects (Handle *hpacked) {

	hdlcard hc = iowadata;
	Handle h;
	tydiskheader header;
	
	if (!newclearhandle ((long) 0, hpacked))
		return (false);
		
	h = *hpacked; /*copy into register*/
	
	header.versionnumber = currentheaderversion;
	
	header.flselection = true; /*indicates color, grid not set*/
	
	if (!enlargehandle (h, longsizeof (header), (ptrchar) &header))
		goto error;
		
	if (!packselectionlist (h)) 
		goto error;
		
	return (true); /*loop terminated, it worked*/
	
	error:
	
	disposehandle (h);
	
	*hpacked = nil;
	
	return (false);
	} /*packselectedobjects*/
	
	
boolean packfirstselectedobject (Handle *hpacked) {
		
	hdlcard hc = iowadata;
	hdlobject hobject = (**hc).selectionlist;
	
	*hpacked = nil;		/*1/22/96 dmb: was ==
	
	if (hobject == nil) /*nothing selected*/
		return (false);
		
	if (!newclearhandle ((long) 0, hpacked))
		return (false);
		
	if (!packobject (*hpacked, hobject, true))
		goto error;
		
	return (true);
	
	error:
	
	disposehandle (*hpacked);
	
	*hpacked = nil;
	
	return (false);
	} /*packfirstselectedobject*/
	
	
boolean iowacopy (Handle *hpacked) {

	hdleditrecord hedit;
	
	hedit = getanyactiveeditrecord ();
	
	if (hedit != nil)
		return (false);
	
	return (packselectedobjects (hpacked));
	} /*iowacopy*/
	
	
static boolean afterpastevisit (hdlobject h) {
	
	if ((**h).objecttmpbit) {
		
		addtoselection (h);
		
		madechanges ();
		
		(**h).objecttmpbit = false;
		}
	
	return (true);
	} /*afterpastevisit*/
	
	
boolean iowapaste (Handle hpacked) {
	
	hdlcard hc = iowadata;
	hdleditinfo he = (hdleditinfo) (**hc).refcon;
	hdleditrecord hedit;
	boolean fl;
	
	hedit = getanyactiveeditrecord ();
	
	if (hedit != nil) 
		return (false);
	
	unpack.hoffset = (**he).lastclickpoint.h;
	
	unpack.voffset = (**he).lastclickpoint.v;
	
	fl = iowaunpack (hpacked);
	
	makeselectionempty ();
		
	visittoplevelobjects ((**hc).objectlist, &afterpastevisit);
	
	clearalltmpbits ();
		
	unpack.hoffset = 0;
	
	unpack.voffset = 0;
	
	return (fl);
	} /*iowapaste*/
	
	
boolean copycardrecord (hdlcard hsource, hdlcard *hdest) {

	hdlcard x = iowadata;
	Handle hpackedcard = nil;
	boolean fl = false;
	
	iowadata = hsource;
	
	if (!iowapack (&hpackedcard))
		goto exit;
		
	if (!newclearhandle (longsizeof (tycard), (Handle *) &iowadata))
		goto exit;
		
	fl = iowaunpack (hpackedcard);
	
	exit:
	
	disposehandle (hpackedcard);
	
	*hdest = iowadata;
	
	iowadata = x;
	
	return (fl);
	} /*copycardrecord*/