#include "TemplateWindow.h"

/*** CREATOR ***/
TemplateWindow::TemplateWindow( WindowRef newWindow )
{
	// clear all instance bytes
	BlockZero( this, sizeof(TemplateWindow) );
	
	// set the window to the one just created
	window = newWindow;
}

/*** DESTRUCTOR ***/
TemplateWindow::~TemplateWindow( void )
{
	ReadControls();
}

/*** USE TEMPLATE ***/
OSStatus TemplateWindow::UseTemplate( Handle newTmpl )
{
	tmpl = newTmpl;
	return noErr;
}

/*** PARSE DATA ***/
OSStatus TemplateWindow::ParseData( Handle data )
{
	#pragma unused( data )
	OSStatus error = noErr;
	error = ParseTemplate();
	error = CreateControls();
	return error;
}

/*** PARSE TEMPLATE ***/
OSStatus TemplateWindow::ParseTemplate( void )
{
	SInt32 size = GetHandleSize( tmpl );
	SInt8 state = HGetState( tmpl );
	HLock( tmpl );
	ElementPtr current = elements = new Element;
	elementCount++;
	unsigned long position = 0;			// start parsing at offset zero (unsurprisingly)
	while( position < size )
	{
		// fill in element data
		short labelSize = *(*tmpl + position);
		BlockMoveData( *tmpl + position, &current->label, labelSize +1 );
		position += labelSize +1;		// don't forget length byte!
		BlockMoveData( *tmpl + position, &current->type, sizeof(ResType) );
		position += sizeof(ResType);	// but restype is always 4 bytes :)
		
		// create new element
		if( position < size )
		{
			elementCount++;
			current->next = new Element;
			current = current->next;
		}
	}
	
	// clean up
	HSetState( tmpl, state );
	return noErr;
}

/*** CREATE CONTROLS ***/
OSStatus TemplateWindow::CreateControls( void )
{
	OSStatus error = noErr;
	ControlRef root, label, secondaryLabel, group, radio, checkbox, edit, listcount;
	CreateRootControl( window, &root );
	
	Rect windowBounds, rect, secondaryLabelRect;
	GetWindowPortBounds( window, &windowBounds );
	
	// get resource data (the really tedious way - I ought to make this easier)
	Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
	if( plugWindow == null ) DebugStr("\pplugWindow == null");
	Plug_ResourceRef resource = Host_GetTargetResource( plugWindow );
	if( resource == null ) DebugStr("\presource == null");
	Handle data = Host_GetResourceData( resource );
	SInt32 size = GetHandleSize( data );
	SInt8 state = HGetState( data );
	HLock( data );
	
	// set control font style
	ControlID id;
	ControlFontStyleRec fontStyle, rectLabelStyle;
	fontStyle.flags = kControlUseFontMask + kControlUseJustMask;
	fontStyle.font = kControlFontSmallSystemFont;
	fontStyle.just = teJustLeft;
	
	rectLabelStyle.flags = kControlUseFontMask + kControlUseJustMask;
	rectLabelStyle.font = kControlFontSmallSystemFont;
	rectLabelStyle.just = teJustRight;
	
	// set up bounds for first control
	bounds.top = bounds.bottom = windowBounds.top;	// bounds.top is ignored, bounds.bottom is the bottom of the previous control
	bounds.left = windowBounds.left +110 + 8;		// bounds.left and .right are the sides of the controls excluding the label
	bounds.right = windowBounds.right - 8;
	
	// declare variables
	CFStringRef text = null;
	signed long position = 0;			// offset of data currently being processed
	unsigned char boolBit = 0;
	ElementPtr current = elements;
	ElementPtr recursionOrigin = null;	// bug: only handles one level of recursion
	signed long recursionTotal = 0;
	unsigned long recursionIndex = 0, recursionCount = 0;
	unsigned long m = 0, n = 0;			// counters, one is always unique, the other is an element index
	for( ; m < elementCount; m++ )
	{
		n++;	// advance unique counter
		
		// create controls
		switch( current->type )
		{
			case 'BOOL':	// BOOL is two bytes long, false == 0x0000, true == 0x0100
			{	Boolean valid = false;
				if( size > position ) valid = (Boolean) ((unsigned short) *(*data + position)) > 0;
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom + 2*16 +12 );
				CreateRadioGroupControl( window, &rect, &group );
				SetRect( &rect, rect.left, rect.top, rect.right, rect.top +16 );
				error = CreateRadioButtonControl( window, &rect, CFSTR("False"), !valid, true, &radio );	// false is embedded at index zreo
				error = EmbedControl( radio, group );
				OffsetRect( &rect, 0, 16 +4 );
				error = CreateRadioButtonControl( window, &rect, CFSTR("True"), valid, true, &radio );		// true is embedded at index one
				error = EmbedControl( radio, group );
				SetControlValue( group, valid +1 );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom + 2*16 +12 );
				rect.bottom += 4;
				position += 2;
				
				// set control ID
				id.id = n;
				id.signature = kBooleanGroupSignature;
				SetControlID( group, &id );
			}	break;
			
			case 'BBIT':
			case 'FBIT':
				if( boolBit == 0 )
				{
					// greate group box
					SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom + 20*8 +32 );
					CreateGroupBoxControl( window, &rect, CFSTR("Some bits to click"), true, &group );
					bounds.bottom += 24;
					
					// set control ID
					id.id = n;
					id.signature = kBooleanGroupSignature;
					SetControlID( group, &id );
				}
				else
				{
					id.id = n - boolBit;
					id.signature = kBooleanGroupSignature;
					GetControlByID( window, &id, &group );
				}
				
				// create checkbox
			{	SInt32 content = 0x00000000;
				if( size > position && current->type == 'BBIT' )
					content = ((*(char*)(*data + position) << boolBit) & 0x80)? 1:0;
				SetRect( &rect, bounds.left +8, bounds.bottom +4, bounds.right -8, bounds.bottom +20 );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), current->label, kCFStringEncodingMacRoman );
				CreateCheckBoxControl( window, &rect, text, content, true, &checkbox );
				EmbedControl( checkbox, group );	// checkboxes are embedded from 0 to 7, in direct bit order
				if( current->type == 'FBIT' )
					HiliteControl( checkbox, kControlDisabledPart );	// kControlInactivePart might work too
				//	DisableControl( checkbox );
				//	DeactivateControl( checkbox );
				//	HideControl( checkbox );
				
				// advance BBIT counter
				boolBit += 1;
				if( boolBit == 8 )
				{
					boolBit = 0;
					position += 1;
					rect.bottom += 12;
				}
			}	break;
			
			case 'DBYT':
			{	Str255 number;
				SInt8 content = 0x00;
				if( size > position ) content = *((char*)(*data + position));
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position += 1;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'DWRD':
			{	Str255 number;
				SInt16 content = 0x0000;
				if( size > position +1 ) content = *((short*)(*data + position));
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position += 2;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'DLNG':
			{	Str255 number;
				SInt32 content = 0x00000000;
				if( size > position +3 ) content = *((long*)(*data + position));
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'HBYT':
			{	Str255 number;
				SInt8 content = 0x00;
				if( size > position ) content = *((char*)(*data + position));
				NumToString( (long) content, number );
				// convert to hex here
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position += 1;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
				
				// add dollar denoting hex
				SetRect( &secondaryLabelRect, bounds.left -24, bounds.bottom +9, bounds.left -6, bounds.bottom +22 );
				CreateStaticTextControl( window, &secondaryLabelRect, CFSTR("$"), &rectLabelStyle, &secondaryLabel );
			}	break;
			
			case 'HWRD':
			{	Str255 number;
				SInt16 content = 0x0000;
				if( size > position +1 ) content = *((short*)(*data + position));
				NumToString( (long) content, number );
				// convert to hex here
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +21 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position += 2;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
				
				// add dollar denoting hex
				SetRect( &secondaryLabelRect, bounds.left -24, bounds.bottom +9, bounds.left -6, bounds.bottom +22 );
				CreateStaticTextControl( window, &secondaryLabelRect, CFSTR("$"), &rectLabelStyle, &secondaryLabel );
			}	break;
			
			case 'HLNG':
			{	Str255 number;
				SInt32 content = 0x00000000;
				if( size > position +3 ) content = *((long*)(*data + position));
				NumToString( (long) content, number );
				// convert to hex here
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +21 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
				
				// add dollar denoting hex
				SetRect( &secondaryLabelRect, bounds.left -24, bounds.bottom +9, bounds.left -6, bounds.bottom +22 );
				CreateStaticTextControl( window, &secondaryLabelRect, CFSTR("$"), &rectLabelStyle, &secondaryLabel );
			}	break;
			
			case 'FBYT':
				position += 1;
				break;
			
			case 'FWRD':
				position += 2;
				break;
			
			case 'FLNG':
				position += 4;
				break;
			
			case 'AWRD':
				position += position % 2;
				break;
			
			case 'ALNG':
				position += position % 4;
				break;
			
			case 'CHAR':	// one byte
			{	UInt8 content = 0x00;
				if( size > position ) content = *((unsigned char*)(*data + position));
				text = CFStringCreateWithBytes( CFAllocatorGetDefault(), (unsigned char *) &content, 1, kCFStringEncodingMacRoman, false );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position += 1;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'TNAM':	// four bytes
			{	UInt32 content = 0x00000000;
				if( size > position +3 ) content = *((unsigned long*)(*data + position));
				text = CFStringCreateWithBytes( CFAllocatorGetDefault(), (unsigned char *) &content, 4, kCFStringEncodingMacRoman, false );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'CSTR':	// one to 32,768 bytes?
			{	SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position )	// bug: if the bytes do not end in a 0x00, the function just keeps on reading!
					text = CFStringCreateWithCString( CFAllocatorGetDefault(), (char *) (*data + position), kCFStringEncodingMacRoman );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				position += CFStringGetLength(text) +1;
				rect.bottom += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'ECST':	// one to 32,768 bytes?
			{	SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position )
					text = CFStringCreateWithCString( CFAllocatorGetDefault(), (char *) (*data + position), kCFStringEncodingMacRoman );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				position += CFStringGetLength(text) +1;					// null byte
				position += (CFStringGetLength(text) % 2 == 0)? 1:0;	// to pad or not to pad?
				rect.bottom += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'OCST':	// one to 32,768 bytes?
			{	SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position )
					text = CFStringCreateWithCString( CFAllocatorGetDefault(), (char *) (*data + position), kCFStringEncodingMacRoman );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				position += CFStringGetLength(text) +1;					// null byte
				position += (CFStringGetLength(text) % 2 == 1)? 1:0;	// to pad or not to pad?
				rect.bottom += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'PSTR':	// one to 256 bytes
			{	unsigned char length = 0;
				if( size > position ) length = *(*data + position);
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position )
					text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), (unsigned char *) (*data + position), kCFStringEncodingMacRoman );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				position += length +1;
				rect.bottom += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'ESTR':	// one to 256 bytes
			{	unsigned char length = 0;
				if( size > position ) length = *(*data + position);
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position )
					text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), (unsigned char *) (*data + position), kCFStringEncodingMacRoman );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				position += length +1;
				position += (length % 2 == 0)? 1:0;
				rect.bottom += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'OSTR':	// one to 256 bytes
			{	unsigned char length = 0;
				if( size > position ) length = *(*data + position);
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position )
					text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), (unsigned char *) (*data + position), kCFStringEncodingMacRoman );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				position += length +1;
				position += (length % 2 == 1)? 1:0;
				rect.bottom += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'WSTR':	// one to 65,536 bytes
			{	unsigned short length = 0;
				if( size > position +1 ) BlockMoveData( *data + position, &length, 2 );		// length = *((unsigned short*) *data + position);
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position +1 )
					text = CFStringCreateWithBytes( CFAllocatorGetDefault(), (unsigned char *) (*data + position +2), (CFIndex) length, kCFStringEncodingMacRoman, false );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				position += length +2;
				rect.bottom += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'LSTR':	// one to 4,294,967,296 bytes
			{	unsigned long length = 0;
				if( size > position +3 ) BlockMoveData( *data + position, &length, 4 );		// length = *((unsigned long*) *data + position);
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position +3 )
					text = CFStringCreateWithBytes( CFAllocatorGetDefault(), (unsigned char *) (*data + position +4), (CFIndex) length, kCFStringEncodingMacRoman, false );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				position += length +4;
				rect.bottom += 4;
				
				// set control ID
				id.id = n;
				id.signature = kEditFieldSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'HEXD':	// bug: should display in hex - wait until hex is implemented  :-)	// infinetly long (limited only by CFString)
			{	SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( size > position )
					text = CFStringCreateWithBytes( CFAllocatorGetDefault(), (unsigned char *) (*data + position), size - position, kCFStringEncodingMacRoman, false );
				else text = CFSTR("");
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				rect.bottom += 4;
				position = size;	// bug: should ensure termination of parsing
				
				// set control ID
				id.id = n;
				id.signature = kHexDumpSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'RECT':	// four SInt16s: top, left, bottom, right
			{	// greate group box
				SInt16 menuID = 2001;	// bug: make into a constant
				SInt16 titleWidth = 0;
				SInt16 titleJustification = teJustLeft;
				Style titleStyle = normal;
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom + 26*4 +40 );
				error = CreatePopupGroupBoxControl( window, &rect, CFSTR("A Rectangle"), true, menuID, true, titleWidth, titleJustification, titleStyle, &group );
				
				// set control ID
				id.id = n;
				id.signature = kRectGroupSignature;
				SetControlID( group, &id );
				
				// create top
			{	Str255 number;
				SInt16 content = 0x0000;
				if( size > position +1 ) content = *((short*)(*data + position));
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left + (bounds.right - bounds.left -32) /2 +8, bounds.bottom +40, bounds.right -12, bounds.bottom +54 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				EmbedControl( edit, group );	// embed order: top, label, left, label, bottom, label, right, label
			
				SetRect( &secondaryLabelRect, bounds.left +12, bounds.bottom +40, bounds.left + (bounds.right - bounds.left -32) /2 -8, bounds.bottom +54 );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), "\pTop", kCFStringEncodingMacRoman );
				CreateStaticTextControl( window, &secondaryLabelRect, text, &rectLabelStyle, &secondaryLabel );
				EmbedControl( secondaryLabel, group );
			}	position += 2;

				// create left
			{	Str255 number;
				SInt16 content = 0x0000;
				if( size > position +1 ) content = *((short*)(*data + position));
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				OffsetRect( &rect, 0, 26 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				EmbedControl( edit, group );	// embed order: top, label, left, label, bottom, label, right, label
			
				OffsetRect( &secondaryLabelRect, 0, 26 );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), "\pLeft", kCFStringEncodingMacRoman );
				CreateStaticTextControl( window, &secondaryLabelRect, text, &rectLabelStyle, &secondaryLabel );
				EmbedControl( secondaryLabel, group );
			}	position += 2;

				// create bottom
			{	Str255 number;
				SInt16 content = 0x0000;
				if( size > position +1 ) content = *((short*)(*data + position));
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				OffsetRect( &rect, 0, 26 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				EmbedControl( edit, group );	// embed order: top, label, left, label, bottom, label, right, label
			
				OffsetRect( &secondaryLabelRect, 0, 26 );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), "\pBottom", kCFStringEncodingMacRoman );
				CreateStaticTextControl( window, &secondaryLabelRect, text, &rectLabelStyle, &secondaryLabel );
				EmbedControl( secondaryLabel, group );
			}	position += 2;

				// create right
			{	Str255 number;
				SInt16 content = 0x0000;
				if( size > position +1 ) content = *((short*)(*data + position));
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				OffsetRect( &rect, 0, 26 );
				CreateEditTextControl( window, &rect, text, false, true, &fontStyle, &edit );
				EmbedControl( edit, group );	// embed order: top, label, left, label, bottom, label, right, label
			
				OffsetRect( &secondaryLabelRect, 0, 26 );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), "\pRight", kCFStringEncodingMacRoman );
				CreateStaticTextControl( window, &secondaryLabelRect, text, &rectLabelStyle, &secondaryLabel );
				EmbedControl( secondaryLabel, group );
			}	position += 2;
				
				rect.top =  bounds.bottom +14;
				rect.bottom += 18;
			}	break;
			
			case 'ZCNT':
			{	Str255 number;
				SInt16 content = 0x0000;
				if( size > position +1 ) content = *((short*)(*data + position)) +1;	// add one for zero-based count
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				CreateStaticTextControl( window, &rect, text, &fontStyle, &listcount );
				rect.bottom += 4;
				position += 2;
				
				// set recursion total (number of times to repeat)
				recursionTotal = content;
				
				// set control ID
				id.id = n;
				id.signature = kListCountSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'OCNT':
			{	Str255 number;
				SInt16 content = 0x0000;
				if( size > position +1 ) content = *((short*)(*data + position));
				NumToString( (long) content, number );
				text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), number, kCFStringEncodingMacRoman );
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				CreateStaticTextControl( window, &rect, text, &fontStyle, &listcount );
				rect.bottom += 4;
				position += 2;
				
				// set recursion total (number of times to repeat)
				recursionTotal = content;
				
				// set control ID
				id.id = n;
				id.signature = kListCountSignature;
				SetControlID( edit, &id );
			}	break;
			
			case 'LSTB':	// repeats to end of resource
			{	recursionTotal = -1;
				recursionIndex = m;
				recursionOrigin = current;
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				rect.bottom += 4;
			}	break;
			
			case 'LSTC':	// repeats recursionTotal times
			{	recursionIndex = m;
				recursionOrigin = current;
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				rect.bottom += 4;
			}	break;
			
			case 'LSTZ':	// repeats until 0x00 is encountered as first byte of next block
			{	recursionTotal = -2;
				recursionIndex = m;
				recursionOrigin = current;
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				rect.bottom += 4;
			}	break;
			
			case 'LSTE':
			{	recursionCount++;
				if( recursionTotal == -2 )
				{
					UInt8 content = 0x00;
					if( size > position ) content = *((unsigned char*)(*data + position));
					if( content != 0x00 )
					{
						// set current parser back to where recursion began from
						m = recursionIndex;
						current = recursionOrigin;
					}
				}
				else if( recursionTotal == -1 )
				{
					if( size > position )
					{
						// set current parser back to where recursion began from
						m = recursionIndex;
						current = recursionOrigin;
					}
				}
				else if( recursionCount < recursionTotal )
				{
					// set current parser back to where recursion began from
					m = recursionIndex;
					current = recursionOrigin;
				}
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				rect.bottom += 4;
			}	break;
			
/*			default:
				SetRect( &rect, bounds.left, bounds.bottom +8, bounds.right, bounds.bottom +22 );
				if( current->type & 0xFF000000 == 'P' << 24 )
				{
					// do Pxxx string
					SInt32 length;
					Str255 number;
					number[0] = 3;
					number[1] = (char) current->type << 8;
					number[2] = (char) current->type << 16;
					number[3] = (char) current->type << 24;
					StringToNum( number, &length );
					if( size > position ) 
						text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), (unsigned char *) (*data + position), kCFStringEncodingMacRoman );
					else text = CFSTR("");
					CreateStaticTextControl( window, &rect, text, &fontStyle, &edit );
					position += length + 1;
					
					// set control ID
					id.id = n;
					id.signature = kEditFieldSignature;
					SetControlID( edit, &id );
				}
				else if( current->type & 0xFF000000 == 'C' << 24 )
				{
					// do Cxxx string
					SInt32 length;
					Str255 number;
					number[0] = 3;
					number[1] = (char) current->type << 8;
					number[2] = (char) current->type << 16;
					number[3] = (char) current->type << 24;
					StringToNum( number, &length );
					if( size > position ) 
						text = CFStringCreateWithCString( CFAllocatorGetDefault(), *data + position, kCFStringEncodingMacRoman );
					else text = CFSTR("");
					CreateStaticTextControl( window, &rect, text, &fontStyle, &edit );
					position += length + 1;
					
					// set control ID
					id.id = n;
					id.signature = kEditFieldSignature;
					SetControlID( edit, &id );
				}
				else if( current->type & 0xFF000000 == 'H' << 24 )
				{
					// do Hxxx string
				}
			//	else I don't know what it is.
				rect.bottom += 4;
				break;
*/		}
		
		// create label
		if( (current->type != 'AWRD') && (current->type != 'ALNG') && ((current->type & 0xFF000000) != ('F' << 24)) )	// skip aligns and fillers
		{
			SetRect( &rect, windowBounds.left +8, rect.top, windowBounds.left +100, rect.bottom );
			text = CFStringCreateWithPascalString( CFAllocatorGetDefault(), current->label, kCFStringEncodingMacRoman );
//			Host_DebugError( current->label, rect.top );
			CreateStaticTextControl( window, &rect, text, &fontStyle, &label );
			id.id = n;
			id.signature = kLabelSignature;
			SetControlID( label, &id );
		}
		
		// save rect for next element to use
		bounds.top = bounds.bottom = rect.bottom;
		
		// advance current element
		current = current->next;
	}
	
	if( current != null ) Host_DebugError( "\pLast elementÕs 'next' parameter != 0", (long) current );	// last element should have null as it's "next" param
	HSetState( data, state );
	return error;
}

/*** READ CONTROLS ***/
OSStatus TemplateWindow::ReadControls( void )
{
	OSStatus error = noErr;
	
	// get resource ref
	Plug_WindowRef plugWindow = Host_GetPlugWindowFromWindowRef( window );
	if( plugWindow == null ) DebugStr("\pplugWindow == null");
	Plug_ResourceRef resource = Host_GetTargetResource( plugWindow );
	if( resource == null ) DebugStr("\presource == null");
	
	// create blank resource
	UInt32 size = 0;
	Handle data = NewHandle(0);
	
	// cycle through each element of the template
	ControlID id;
	ControlRef control, group;
	ElementPtr current = elements;
	ElementPtr recursionOrigin = null;	// bug: only handles one level of recursion
	signed long recursionTotal = 0;
	unsigned long recursionIndex = 0, recursionCount = 0;
	unsigned long m = 0, n = 0;			// counters, one is always unique, the other is an element index
	for( ; m < elementCount; m++ )
	{
		n++;	// advance unique counter
		
		// read controls
		switch( current->type )
		{
			case 'BOOL':	// BOOL is two bytes long, false == 0x0000, true == 0x0100
			{	UInt16 value = 0;
				
				// get control value
				id.id = n;
				id.signature = kBooleanGroupSignature;
				error = GetControlByID( window, &id, &control );
				if( !error ) value = GetControlValue( control ) -1;	// false gives 1, true gives 2
				value <<= 8;
				
				// append correct data to handle
				SInt8 state = HGetState( data );
				SetHandleSize( data, size +2 );
				if( !MemError() )
				{
					HLock( data );	// lock handle after increasing it's size
					BlockMoveData( &value, *data + size, 2 );
					HSetState( data, state );
				}
				size += 2;
			}	break;
			
			case 'BBIT':
			case 'FBIT':
			{	// read all eight bits in simultaneously
				//	nb. re. filler bits - the control exists but is disabled/hidden. reading it gives value of 0
				id.id = n;
				id.signature = kBooleanGroupSignature;
				error = GetControlByID( window, &id, &group );
				if( !error )
				{
					// read checkboxs
					UInt8 value = 0x00;
					GetIndexedSubControl( group, 1, &control );
					value += (GetControlValue( control ) & 0x01) << 7;
					GetIndexedSubControl( group, 2, &control );
					value += (GetControlValue( control ) & 0x01) << 6;
					GetIndexedSubControl( group, 3, &control );
					value += (GetControlValue( control ) & 0x01) << 5;
					GetIndexedSubControl( group, 4, &control );
					value += (GetControlValue( control ) & 0x01) << 4;
					GetIndexedSubControl( group, 5, &control );
					value += (GetControlValue( control ) & 0x01) << 3;
					GetIndexedSubControl( group, 6, &control );
					value += (GetControlValue( control ) & 0x01) << 2;
					GetIndexedSubControl( group, 7, &control );
					value += (GetControlValue( control ) & 0x01) << 1;
					GetIndexedSubControl( group, 8, &control );
					value += (GetControlValue( control ) & 0x01) << 0;
					
					// append correct data to handle
					SInt8 state = HGetState( data );
					SetHandleSize( data, size +1 );
					if( !MemError() )
					{
						HLock( data );	// lock handle after increasing it's size
						BlockMoveData( &value, *data + size, 1 );
						HSetState( data, state );
					}
				}
				
				// update size & advance element counter
				size += 1;
				n += 7;
			}	break;
			
			case 'DBYT':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// convert buffer into desired format
							SInt8 value;
							SInt32 number;
							Str255 string;
							string[0] = actualSize;
							BlockMoveData( buffer, &string[1], actualSize );
							StringToNum( string, &number );
							value = (char) number;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( &value, *data + size, 1 );
								HSetState( data, state );
							}
							size += 1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
		
			case 'DWRD':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// convert buffer into desired format
							SInt16 value;
							SInt32 number;
							Str255 string;
							string[0] = actualSize;
							BlockMoveData( buffer, &string[1], actualSize );
							StringToNum( string, &number );
							value = (short) number;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +2 );
							error = MemError();
							if( !error )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( &value, *data + size, 2 );
								Host_DebugError( "\pvalue", value );
								HSetState( data, state );
							}
							else Host_DebugError( "\pMemError() occoured", error );
							size += 2;
						}
						else Host_DebugError( "\pGetControlData() failed", error );
						DisposePtr( buffer );
					}
					else Host_DebugError( "\pGetControlDataSize() failed", error );
				}
				else Host_DebugError( "\pCould not get EditText control", error );
			}	break;
		
			case 'DLNG':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// convert buffer into desired format
							SInt32 value;
							Str255 string;
							string[0] = actualSize;
							BlockMoveData( buffer, &string[1], actualSize );
							StringToNum( string, &value );
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +4 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( &value, *data + size, 4 );
								HSetState( data, state );
							}
							size += 4;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
		
			case 'HBYT':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// convert buffer into desired format
							SInt8 value;
							SInt32 number;
							Str255 string;
							string[0] = actualSize;
							BlockMoveData( buffer, &string[1], actualSize );
							StringToNum( string, &number );
							value = (char) number;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( &value, *data + size, 1 );
								HSetState( data, state );
							}
							size += 1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
		
			case 'HWRD':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// convert buffer into desired format
							SInt16 value;
							SInt32 number;
							Str255 string;
							string[0] = actualSize;
							BlockMoveData( buffer, &string[1], actualSize );
							StringToNum( string, &number );
							value = (short) number;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +2 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( &value, *data + size, 2 );
								HSetState( data, state );
							}
							size += 2;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
		
			case 'HLNG':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// convert buffer into desired format
							SInt32 value;
							Str255 string;
							string[0] = actualSize;
							BlockMoveData( buffer, &string[1], actualSize );
							StringToNum( string, &value );
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +4 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( &value, *data + size, 4 );
								HSetState( data, state );
							}
							size += 4;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
		
			case 'FBYT':
			{	SInt8 state = HGetState( data );
				SetHandleSize( data, size +1 );
				if( !MemError() )
				{
					HLock( data );	// lock handle after increasing it's size
					*((char *) *data + size) = 0x00;
					HSetState( data, state );
				}
				size += 1;
			}	break;
			
			case 'FWRD':
			{	SInt16 value = 0;
				SInt8 state = HGetState( data );
				SetHandleSize( data, size +2 );
				if( !MemError() )
				{
					HLock( data );	// lock handle after increasing it's size
					BlockMoveData( &value, *data + size, 2 );
//					*((short *) *data + size) = 0x0000;
					HSetState( data, state );
				}
				size += 2;
			}	break;
			
			case 'FLNG':
			{	SInt32 value = 0;
				SInt8 state = HGetState( data );
				SetHandleSize( data, size +4 );
				if( !MemError() )
				{
					HLock( data );	// lock handle after increasing it's size
					BlockMoveData( &value, *data + size, 4 );
//					*((long *) *data + size) = 0x00000000;
					HSetState( data, state );
				}
				size += 4;
			}	break;
			
			case 'AWRD':
			{	SInt8 state = HGetState( data );
				SetHandleSize( data, size + size % 2 );
				if( !MemError() )
				{
					HLock( data );	// lock handle after increasing it's size
					while( size % 2 )
					{
						*((char *) *data + size) = 0x00;
						size++;
					}
					HSetState( data, state );
				}
			}	break;
			
			case 'ALNG':
			{	SInt8 state = HGetState( data );
				SetHandleSize( data, size + size % 4 );
				if( !MemError() )
				{
					HLock( data );	// lock handle after increasing it's size
					while( size % 4 )
					{
						*((char *) *data + size) = 0x00;
						size++;
					}
					HSetState( data, state );
				}
			}	break;
			
			case 'CHAR':	// one byte
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( (bufferSize > 1)? bufferSize:1 );		// ensures minimum buffer of one byte
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// put zero into buffer if actualSize == 0
							if( actualSize < 1 ) *((char *) buffer) = 0x00;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( buffer, *data + size, 1 );
								HSetState( data, state );
							}
							size += 1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'TNAM':	// four bytes
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( (bufferSize > 4)? bufferSize:4 );		// ensures minimum buffer of four bytes
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						Str255 text;
						text[0] = 4;
						BlockMoveData( buffer, &text[1], 4 );
						Host_DebugError( text, bufferSize );
						if( !error )
						{
							// put zero into buffer if actualSize == 0
							if( actualSize < 4 ) *((long *) buffer) = 0x00000000;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +4 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( buffer, *data + size, 4 );
								HSetState( data, state );
							}
							size += 4;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'CSTR':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( buffer, *data + size, actualSize );
								*((char *)(*data + size + actualSize)) = 0x00;	// add zero byte
								HSetState( data, state );
							}
							size += actualSize +1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'ECST':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// decide if I need a padding byte or not
							Boolean pad = (actualSize % 2 == 0)? true:false;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize + (pad? 1:0) +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( buffer, *data + size, actualSize );
											*((char *)(*data + size + actualSize)) = 0x00;		// add zero byte
								if( pad )	*((char *)(*data + size + actualSize +1)) = 0x00;	// add pad byte
								HSetState( data, state );
							}
							size += actualSize + (pad? 1:0) +1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'OCST':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// decide if I need a padding byte or not
							Boolean pad = (actualSize % 2 == 1)? true:false;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize + (pad? 1:0) +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( buffer, *data + size, actualSize );
											*((char *)(*data + size + actualSize)) = 0x00;		// add zero byte
								if( pad )	*((char *)(*data + size + actualSize +1)) = 0x00;	// add pad byte
								HSetState( data, state );
							}
							size += actualSize + (pad? 1:0) +1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'PSTR':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								*((char *)(*data + size)) = (char) actualSize;	// add length byte
								BlockMoveData( buffer, *data + size +1, actualSize );
								HSetState( data, state );
							}
							size += actualSize +1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'ESTR':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// decide if I need a padding byte or not
							Boolean pad = (actualSize % 2 == 0)? true:false;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize + (pad? 1:0) +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								*((char *)(*data + size)) = (char) actualSize;	// add length byte
								BlockMoveData( buffer, *data + size +1, actualSize );
								if( pad )	*((char *)(*data + size + actualSize +1)) = 0x00;	// add pad byte
								HSetState( data, state );
							}
							size += actualSize + (pad? 1:0) +1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'OSTR':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// decide if I need a padding byte or not
							Boolean pad = (actualSize % 2 == 1)? true:false;
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize + (pad? 1:0) +1 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								*((char *)(*data + size)) = (char) actualSize;	// add length byte
								BlockMoveData( buffer, *data + size +1, actualSize );
								if( pad )	*((char *)(*data + size + actualSize +1)) = 0x00;	// add pad byte
								HSetState( data, state );
							}
							size += actualSize + (pad? 1:0) +1;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'WSTR':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize +2 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								*((short *)(*data + size)) = (short) actualSize;	// add length bytes
								BlockMoveData( buffer, *data + size +2, actualSize );
								HSetState( data, state );
							}
							size += actualSize +2;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'LSTR':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize +4 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								*((long *)(*data + size)) = (long) actualSize;	// add length bytes
								BlockMoveData( buffer, *data + size +4, actualSize );
								HSetState( data, state );
							}
							size += actualSize +4;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'HEXD':
			{	id.id = n;
				id.signature = kEditFieldSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size + actualSize );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( buffer, *data + size, actualSize );
								HSetState( data, state );
							}
							size += actualSize;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'RECT':
			{	id.id = n;
				id.signature = kRectGroupSignature;
				error = GetControlByID( window, &id, &group );
				if( !error )
				{
					// read checkboxs
					Rect value;
					error = GetIndexedSubControl( group, 2, &control );
					if( !error )
					{
						// find out how much text has been typed
						Size bufferSize, actualSize;
						error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
						if( !error )
						{
							// allocate buffer and read data
							Ptr buffer = NewPtrClear( bufferSize );
							error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
							if( !error )
							{
								// convert buffer into desired format
								SInt32 number;
								Str255 string;
								string[0] = actualSize;
								BlockMoveData( buffer, &string[1], actualSize );
								StringToNum( string, &number );
								value.top = (short) number;
							}
							DisposePtr( buffer );
						}
					}
					else value.top = 0;
						
					error = GetIndexedSubControl( group, 4, &control );
					if( !error )
					{
						// find out how much text has been typed
						Size bufferSize, actualSize;
						error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
						if( !error )
						{
							// allocate buffer and read data
							Ptr buffer = NewPtrClear( bufferSize );
							error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
							if( !error )
							{
								// convert buffer into desired format
								SInt32 number;
								Str255 string;
								string[0] = actualSize;
								BlockMoveData( buffer, &string[1], actualSize );
								StringToNum( string, &number );
								value.left = (short) number;
							}
							DisposePtr( buffer );
						}
					}
					else value.left = 0;
					
					error = GetIndexedSubControl( group, 6, &control );
					if( !error )
					{
						// find out how much text has been typed
						Size bufferSize, actualSize;
						error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
						if( !error )
						{
							// allocate buffer and read data
							Ptr buffer = NewPtrClear( bufferSize );
							error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
							if( !error )
							{
								// convert buffer into desired format
								SInt32 number;
								Str255 string;
								string[0] = actualSize;
								BlockMoveData( buffer, &string[1], actualSize );
								StringToNum( string, &number );
								value.bottom = (short) number;
							}
							DisposePtr( buffer );
						}
					}
					else value.bottom = 0;
					
					error = GetIndexedSubControl( group, 8, &control );
					if( !error )
					{
						// find out how much text has been typed
						Size bufferSize, actualSize;
						error = GetControlDataSize( control, kControlEditTextPart, kControlEditTextTextTag, &bufferSize );
						if( !error )
						{
							// allocate buffer and read data
							Ptr buffer = NewPtrClear( bufferSize );
							error = GetControlData( control, kControlEditTextPart, kControlEditTextTextTag, bufferSize, buffer, &actualSize );
							if( !error )
							{
								// convert buffer into desired format
								SInt32 number;
								Str255 string;
								string[0] = actualSize;
								BlockMoveData( buffer, &string[1], actualSize );
								StringToNum( string, &number );
								value.right = (short) number;
							}
							DisposePtr( buffer );
						}
					}
					else value.right = 0;
					
					// append correct data to handle
					SInt8 state = HGetState( data );
					SetHandleSize( data, size +8 );
					if( !MemError() )
					{
						HLock( data );	// lock handle after increasing it's size
						BlockMoveData( &value, *data + size, 8 );
						HSetState( data, state );
					}
					size += 8;
				}
			}	break;
			
			case 'ZCNT':
			case 'OCNT':
			{	id.id = n;
				id.signature = kListCountSignature;
				error = GetControlByID( window, &id, &control );
				if( !error )
				{
					// find out how much text has been typed
					Size bufferSize, actualSize;
					error = GetControlDataSize( control, kControlLabelPart, kControlStaticTextTextTag, &bufferSize );
					if( !error )
					{
						// allocate buffer and read data
						Ptr buffer = NewPtrClear( bufferSize );
						error = GetControlData( control, kControlLabelPart, kControlStaticTextTextTag, bufferSize, buffer, &actualSize );
						if( !error )
						{
							// convert buffer into desired format
							SInt16 value;
							SInt32 number;
							Str255 string;
							string[0] = actualSize;
							BlockMoveData( buffer, &string[1], actualSize );
							StringToNum( string, &number );
							value = (short) number;
							
							// set recursion total (number of times to repeat)
							recursionTotal = value;	// actually, this value is ignored :)  --  I count occourences of LSTE instead
							
							// append correct data to handle
							SInt8 state = HGetState( data );
							SetHandleSize( data, size +2 );
							if( !MemError() )
							{
								HLock( data );	// lock handle after increasing it's size
								BlockMoveData( &value, *data + size, 2 );
								HSetState( data, state );
							}
							size += 2;
						}
						DisposePtr( buffer );
					}
				}
			}	break;
			
			case 'LSTB':	// repeats to end of resource
			{	recursionTotal = -1;
				recursionIndex = m;
				recursionOrigin = current;
			}	break;
			
			case 'LSTC':	// repeats recursionTotal times
			{	recursionIndex = m;
				recursionOrigin = current;
			}	break;
			
			case 'LSTZ':	// repeats until 0x00 is encountered as first byte of next block
			{	recursionTotal = -2;
				recursionIndex = m;
				recursionOrigin = current;
			}	break;
			
			case 'LSTE':
			{	recursionCount++;
/*				if( recursionTotal == -2 )
				{
					UInt8 content = 0x00;
					if( size > position ) content = *((unsigned char*)(*data + position));
					if( content != 0x00 )
					{
						// set current parser back to where recursion began from
						m = recursionIndex;
						current = recursionOrigin;
					}
				}
				else if( recursionTotal == -1 )
				{
					if( size > position )
					{
						// set current parser back to where recursion began from
						m = recursionIndex;
						current = recursionOrigin;
					}
				}
				else if( recursionCount < recursionTotal )
				{
					// set current parser back to where recursion began from
					m = recursionIndex;
					current = recursionOrigin;
				}
*/			}	break;
			
			default:
				break;
		}
		
		// advance current element
		current = current->next;
	}
	
	// save any changes
	if( !error )
	{
		Handle original = Host_GetResourceData( resource );
		Host_DebugError( "\ptesting if handles matchÉ", 0 );
		if( !HandlesMatch( original, data ) )	// only save if data changed
		{
			Host_DebugError( "\pthey don't, saving changesÉ", 0 );
			SInt8 state = HGetState( original );
			HLock( original );
			SetHandleSize( original, size );
			BlockMoveData( *data, *original, size );
			HSetState( original, state );
			Host_SetResourceDirty( resource, true );
		}
		else Host_DebugError( "\pthey do match, don't save changes", 0 );
		Host_ReleaseResourceData( resource );
	}
	else Host_DebugError( "\pan error occoured somewhere, don't save any changes", error );
	
	// clean up and leave
	DisposeHandle( data );
	return error;
}

/*** HANDLES MATCH ***/
Boolean HandlesMatch( const Handle one, const Handle two )
{
	Size sizeOne = GetHandleSize( one );
	Size sizeTwo = GetHandleSize( two );
	if( sizeOne != sizeTwo ) return false;
	else
	{
		SInt8 stateOne = HGetState( one );
		SInt8 stateTwo = HGetState( two );
		HLock( one );
		HLock( two );
		char *a = *one;
		char *b = *two;
		for( unsigned short i = 0; i < sizeOne; i++ )
			if( *a++ != *b++ ) return false;
		HSetState( one, stateOne );
		HSetState( two, stateTwo );
		return true;
	}
}