//	Zinc Application Framework - Z_GMGR2.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <z_gmgr.hpp>

// ----- ZafAttachment ------------------------------------------------------

ZafAttachment::ZafAttachment(ZafWindowObject *zObject, ZafAttachmentType zType) :
	ZafConstraint(zObject), reference(ZAF_NULLP(ZafWindowObject)),
	refNumberID(-1),
	offset(-1), type(zType), stretch(false), oppositeSide(false)
{
}

ZafAttachment::ZafAttachment(const ZafAttachment &copy) :
	ZafConstraint(copy), reference(ZAF_NULLP(ZafWindowObject)),
	refNumberID(copy.refNumberID),
	offset(copy.offset), type(copy.type), stretch(copy.stretch),
	oppositeSide(copy.oppositeSide)
{
}

ZafAttachment::~ZafAttachment(void)
{
}

ZafConstraint *ZafAttachment::Duplicate(void)
{
	// Initialize ZafConstraint stuff.
	ZafConstraint::Duplicate();

	// Initialize refNumberID, since reference object may not have had its 
	// numberID assigned before.
	if (reference)
		refNumberID = reference->NumberID();

	return (new ZafAttachment(*this));
}

ZafEventType ZafAttachment::Event(const ZafEventStruct &event)
{
	// Check for zinc events.
	ZafEventType ccode = event.type;
	if (ccode == S_INITIALIZE)
	{
		ZafConstraint::Event(event);
		if (!reference && refNumberID >= 0)
			reference = DynamicPtrCast(parent->parent, ZafWindow)->GetObject(refNumberID);
		return (ccode);
	}
	else if (ccode != S_COMPUTE_SIZE || !object || !object->display)
		return (S_ERROR);

	// Determine support variables.
	ZafRegionStruct objectRegion = object->Region();
	int width = objectRegion.Width();
	int height = objectRegion.Height();

	// Get the reference region.
	ZafDisplay *display = object->display;
	ZafRegionStruct refRegion;
	if (reference)
		refRegion = reference->Region();
	else if (object->parent)
	{
		// Use the parent client region.
//		refRegion = object->parent->MaxRegion(parent);
		refRegion = object->parent->MaxRegion(object->parent);
		refRegion.right -= refRegion.left;
		refRegion.bottom -= refRegion.top;
		refRegion.left = refRegion.top = 0;
	}
	else
	{
		// Use the screen coordinates.
		refRegion.Assign(0, 0, display->columns, display->lines, ZAF_PIXEL);
	}

	// Flip the coordinates if opposite.
	if (oppositeSide)
	{
		int left = refRegion.left; refRegion.left = refRegion.right; refRegion.right = left;
		int top = refRegion.top; refRegion.top = refRegion.bottom; refRegion.bottom = top;
	}

	// Determine the object region based on the type of connection.
	ZafRegionStruct newRegion = objectRegion;
	if (type == ZAF_ATCF_LEFT)
	{
		newRegion.left = refRegion.left;
		if (object->CoordinateType() == ZAF_CELL)
			newRegion.left += (int)((unsigned long)offset * display->cellWidth);
		else if (object->CoordinateType() == ZAF_MINICELL)
			newRegion.left += (int)((unsigned long)offset * display->cellWidth * display->miniNumeratorX / display->miniDenominatorX);
		else
			newRegion.left += offset;
		if (!stretch)
			newRegion.right = newRegion.left + width - 1;
	}
	else if (type == ZAF_ATCF_TOP)
	{
		newRegion.top = refRegion.top;
		if (object->CoordinateType() == ZAF_CELL)
			newRegion.top += (int)((unsigned long)offset * display->cellHeight);
		else if (object->CoordinateType() == ZAF_MINICELL)
			newRegion.top += (int)((unsigned long)offset * display->cellHeight * display->miniNumeratorY / display->miniDenominatorY);
		else
			newRegion.top += offset;
		if (!stretch)
			newRegion.bottom = newRegion.top + height - 1;
	}
	else if (type == ZAF_ATCF_RIGHT)
	{
		newRegion.right = refRegion.right;
		if (object->CoordinateType() == ZAF_CELL)
			newRegion.right -= (int)((unsigned long)offset * display->cellWidth);
		else if (object->CoordinateType() == ZAF_MINICELL)
			newRegion.right -= (int)((unsigned long)offset * display->cellWidth * display->miniNumeratorX / display->miniDenominatorX);
		else
			newRegion.right -= offset;
		if (!stretch)
			newRegion.left = newRegion.right - width + 1;
	}
	else if (type == ZAF_ATCF_BOTTOM)
	{
		newRegion.bottom = refRegion.bottom;
		if (object->CoordinateType() == ZAF_CELL)
			newRegion.bottom -= (int)((unsigned long)offset * display->cellHeight);
		else if (object->CoordinateType() == ZAF_MINICELL)
			newRegion.bottom -= (int)((unsigned long)offset * display->cellHeight * display->miniNumeratorY / display->miniDenominatorY);
		else
			newRegion.bottom -= offset;
		if (!stretch)
			newRegion.top = newRegion.bottom - height + 1;
	}
	object->SetRegion(newRegion);

	// Return the control code.
	return (ccode);
}

bool ZafAttachment::IsA(ZafClassID compareID) const
{
	return ((compareID == classID) ? true : ZafConstraint::IsA(compareID));
}

bool ZafAttachment::IsA(ZafClassName compareName) const
{
	return (!strcmp(className, className) ? true : ZafConstraint::IsA(compareName));
}

// ----- Attributes ---------------------------------------------------------

ZafError ZafAttachment::SetReference(ZafWindowObject *tReference)
{
	reference = tReference;
	refNumberID = reference ? reference->NumberID() : (ZafNumberID)-1;
	return (ZAF_ERROR_NONE);
}

ZafAttachmentType ZafAttachment::SetType(ZafAttachmentType tType)
{
	type = tType;
	return (type);
}

int ZafAttachment::SetOffset(int tOffset)
{
	offset = tOffset;
	return (offset);
}

bool ZafAttachment::SetOppositeSide(bool tOppositeSide)
{
	oppositeSide = tOppositeSide;
	return (oppositeSide);
}

bool ZafAttachment::SetStretch(bool tStretch)
{
	stretch = tStretch;
	return (stretch);
}
	
// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
ZafAttachment::ZafAttachment(const ZafIChar *name, ZafObjectPersistence &persist) :
	ZafConstraint(name, persist.PushLevel(className, classID, ZAF_PERSIST_FILE)),
	reference(0)
{
	// Read the data.
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafAttachment::ReadData(persist);
	persist.PopLevel();
}

ZafElement *ZafAttachment::Read(const ZafIChar *name, ZafObjectPersistence &persist)
{
	return (new ZafAttachment(name, persist));
}

void ZafAttachment::ReadData(ZafObjectPersistence &persist)
{
	ZafFile *file = persist.CurrentFile();

	// Read the data.
	ZafUInt16 flag1;
	*file >> refNumberID >> offset >> flag1;
	type = (ZafAttachmentType)(((int)flag1 & 0xF000) >> 12);
	stretch = (flag1 & 0x0001) ? true : false;
	oppositeSide = (flag1 & 0x0002) ? true : false;
}

void ZafAttachment::Write(ZafObjectPersistence &persist)
{
	// Write the constraint.
	ZafConstraint::Write(persist.PushLevel(className, classID, ZAF_PERSIST_FILE));
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafAttachment::WriteData(persist);
	persist.PopLevel();
}

void ZafAttachment::WriteData(ZafObjectPersistence &persist)
{
	ZafFile *file = persist.CurrentFile();

	// Write the data.

	// Initialize refNumberID, since reference object may not have had its 
	// numberID assigned before.
	if (reference)
		refNumberID = reference->NumberID();
	ZafUInt16 flag1 = 0;
	flag1 |= (ZafUInt16)((type & 0x000F) << 12);
	flag1 |= (ZafUInt16)(stretch ? 0x0001 : 0);
	flag1 |= (ZafUInt16)(oppositeSide ? 0x0002 : 0);
	*file << refNumberID << offset << flag1;
}
#endif
