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

#include <z_tree.hpp>
#include <z_string.hpp>
#include <z_app.hpp>
#define ZAF_TREE_INFO
#include "img_def.cpp"

// ----- ZafTreeItem --------------------------------------------------------

ZafTreeItem::ZafTreeItem(ZafBitmapData *zNormalBitmap,
	ZafBitmapData *zSelectedBitmap, ZafStringData *zStringData) :
	ZafWindow(0, 0, 0, 1),
	stringData(ZAF_NULLP(ZafStringData)),
	normalBitmap(ZAF_NULLP(ZafBitmapData)),
	selectedBitmap(ZAF_NULLP(ZafBitmapData)),
	autoSortData(false), expandable(false), expanded(false)
{
	// Check the image information.
	SetDestroyable(false);
	SetMoveable(false);
	SetSizeable(false);
	SetSystemObject(false);
	ImageAllocate();

	// Set the item information.
	if (zNormalBitmap)
		SetNormalBitmap(zNormalBitmap);
	if (zSelectedBitmap)
		SetSelectedBitmap(zSelectedBitmap);
	if (zStringData)
		SetStringData(zStringData);
	expandRegion = bitmapRegion = textRegion = zafRegion;
}

ZafTreeItem::ZafTreeItem(ZafBitmapData *zNormalBitmap,
	ZafBitmapData *zSelectedBitmap, const ZafIChar *zText) :
	ZafWindow(0, 0, 0, 1),
	stringData(ZAF_NULLP(ZafStringData)),
	normalBitmap(ZAF_NULLP(ZafBitmapData)),
	selectedBitmap(ZAF_NULLP(ZafBitmapData)),
	autoSortData(false), expandable(false), expanded(false)
{
	// Check the image information.
	SetDestroyable(false);
	SetMoveable(false);
	SetSizeable(false);
	SetSystemObject(false);
	ImageAllocate();

	// Set the item information.
	if (zNormalBitmap)
		SetNormalBitmap(zNormalBitmap);
	if (zSelectedBitmap)
		SetSelectedBitmap(zSelectedBitmap);
//	if (zText)
		SetStringData(new ZafStringData(zText));
	expandRegion = bitmapRegion = textRegion = zafRegion;
}

ZafTreeItem::ZafTreeItem(const ZafTreeItem &copy) :
	ZafWindow(copy),
	stringData(ZAF_NULLP(ZafStringData)),
	normalBitmap(ZAF_NULLP(ZafBitmapData)),
	selectedBitmap(ZAF_NULLP(ZafBitmapData)),
	autoSortData(copy.autoSortData), expandable(copy.expandable),
	expanded(copy.expanded)
{
	// Check the image information.
	ImageAllocate();

	// Initialize the tree information.
	if (copy.normalBitmap)
	{
		if (copy.normalBitmap->Destroyable())
			SetNormalBitmap(new ZafBitmapData(*copy.normalBitmap));
		else
			SetNormalBitmap(copy.normalBitmap);
	}

	if (copy.selectedBitmap)
	{	
		if (copy.selectedBitmap->Destroyable())
			SetSelectedBitmap(new ZafBitmapData(*copy.selectedBitmap));
		else
			SetSelectedBitmap(copy.selectedBitmap);
	}

	if (copy.stringData)
	{
		if (copy.stringData->Destroyable())
			SetStringData(new ZafStringData(*copy.stringData));
		else
			SetStringData(copy.stringData);
	}

	expandRegion = copy.expandRegion;
	bitmapRegion = copy.bitmapRegion;
	textRegion = copy.textRegion;
}

ZafTreeItem::~ZafTreeItem(void)
{
	// Remove the data notification.
	if (normalBitmap)
		normalBitmap->SubtractNotification(this, (ZafUpdateFunction)Update);
	if (selectedBitmap)
		selectedBitmap->SubtractNotification(this, (ZafUpdateFunction)Update);
	if (stringData)
		stringData->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Check the image information.
	ImageFree();

	if (normalBitmap && normalBitmap->Destroyable() && normalBitmap->NotifyCount() == 0)
		delete normalBitmap;
	if (selectedBitmap && selectedBitmap->Destroyable() && selectedBitmap->NotifyCount() == 0)
		delete selectedBitmap;
	if (stringData && stringData->Destroyable() && stringData->NotifyCount() == 0)
		delete stringData;
}

bool ZafTreeItem::CopyDraggable(void) const 
{ 
	return (TreeList()->CopyDraggable()); 
}

ZafTreeItem *ZafTreeItem::DepthCurrent(void)
{
	// Push the view-current down.
	ZafTreeItem *object = DynamicPtrCast(current, ZafTreeItem);
	return ((object && object != this) ? object->DepthCurrent() : this);
}

ZafTreeItem *ZafTreeItem::DepthFirst(void)
{
	return (this);
}

ZafTreeItem *ZafTreeItem::DepthLast(void)
{
	ZafTreeItem *item = DynamicPtrCast(last, ZafTreeItem);
	return (item ? item->DepthLast() : this);
}

ZafTreeItem *ZafTreeItem::DepthNext(ZafTreeItem *start)
{
	// Find the next tree item.
	ZafTreeItem *item = ZAF_NULLP(ZafTreeItem);
	if (first)
		item = DynamicPtrCast(first, ZafTreeItem);
	else if (next)
		item = DynamicPtrCast(next, ZafTreeItem);
	else
	{
		for (ZafWindowObject *root = parent; root && root != start && !item;
			root = root->parent)
		{
			if (root->IsA(ID_ZAF_TREE_ITEM))
			{
				item = DynamicPtrCast(root, ZafTreeItem);
				item = DynamicPtrCast(item->Next(), ZafTreeItem);
			}
			else
				break;
		}
	}
	return (item);
}

ZafTreeItem *ZafTreeItem::DepthPrevious(void)
{
	// Find the previous visible tree item.
	ZafTreeItem *item = ZAF_NULLP(ZafTreeItem);
	if (previous)
	{
		item = DynamicPtrCast(previous, ZafTreeItem);
		item = item->DepthLast();
	}
	else if (parent->IsA(ID_ZAF_TREE_ITEM))
		item = DynamicPtrCast(parent, ZafTreeItem);
	return (item);
}

bool ZafTreeItem::Draggable(void) const 
{ 
	return (TreeList()->Draggable()); 
}

ZafWindowObject *ZafTreeItem::Duplicate(void)
{
	return (new ZafTreeItem(*this));
}

ZafWindowObject *ZafTreeItem::FocusObject(void) const
{
#if defined(ZAF_MSWINDOWS)
	return ((ZafWindowObject *)this);
#else
	// Return a pointer to self.
	if (current && Current()->Focus() && Expanded())
		return (Current()->FocusObject());
	else if (focus)
		return ((ZafWindowObject *)this);
	return (ZAF_NULLP(ZafWindowObject));
#endif
}

#if defined(ZAF_TEXT_MODE)
void ZafTreeItem::ImageAllocate(void) {}
void ZafTreeItem::ImageFree(bool) {}
#else
void ZafTreeItem::ImageAllocate(void)
{
	// Initialize the images.
	if (!expandBitmap)
	{
		ZafI18nData::AddStaticModule(ImageFree);
		expandBitmap = new ZafBitmapData(_expand_ZafBitmap);
		expandBitmap->SetDestroyable(false);
		compressBitmap = new ZafBitmapData(_compress_ZafBitmap);
		compressBitmap->SetDestroyable(false);
	}
}

void ZafTreeItem::ImageFree(bool globalRequest)
{
	// Destroy the static images.
	if (globalRequest && expandBitmap)
	{
		expandBitmap->staticHandle = false;
		delete expandBitmap;
		expandBitmap = ZAF_NULLP(ZafBitmapData);
		compressBitmap->staticHandle = false;
		delete compressBitmap;
		compressBitmap = ZAF_NULLP(ZafBitmapData);
	}
}
#endif

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

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

bool ZafTreeItem::LinkDraggable(void) const 
{ 
	return (TreeList()->LinkDraggable()); 
}


const ZafPaletteStruct *ZafTreeItem::MapClassPalette(ZafPaletteType type, ZafPaletteState state)
{
	const ZafPaletteStruct *palette = MapPalette(defaultPaletteMap, type, state);
	return (palette ? palette : ZafWindowObject::MapClassPalette(type, state));
}

bool ZafTreeItem::MoveDraggable(void) const 
{ 
	return (TreeList()->MoveDraggable()); 
}

bool ZafTreeItem::SetAcceptDrop(bool )
{
	// acceptDrop is false for this class.
	acceptDrop = false;
	return (acceptDrop);
}

bool ZafTreeItem::SetAutoSortData(bool tAutoSortData)
{
	// Make sure the attribute has changed.
	if (autoSortData != tAutoSortData)
	{
		autoSortData = tAutoSortData;

		// Reset the sort function.
		if (autoSortData)
		{
			if (!compareFunction)
				SetCompareFunction((ZafCompareFunction)CompareAscending);
			Sort();
		}
		else if (compareFunction == (ZafCompareFunction)CompareAscending)
			compareFunction = ZAF_NULLF(ZafCompareFunction);
	}

	// Return the current attribute.
	return autoSortData;
}

bool ZafTreeItem::SetBordered(bool )
{
	// border is false for this class.
	bordered = false;
	return (bordered);
}

ZafCompareFunction ZafTreeItem::SetCompareFunction(ZafCompareFunction tCompareFunction)
{
	for (ZafTreeItem *item = (ZafTreeItem *)first; item; item = (ZafTreeItem *)item->Next())
		item->SetCompareFunction(tCompareFunction);
	return (ZafList::SetCompareFunction(tCompareFunction));
}

bool ZafTreeItem::SetDestroyable(bool )
{
	// destroyable is false for this class.
	destroyable = false;
	return (destroyable);
}

bool ZafTreeItem::SetExpandable(bool setExpandable)
{
	// Make sure the attribute has changed.
	if (expandable != setExpandable && !screenID)
		expandable = setExpandable;

	// Return the current attribute.
	return (expandable);
}

bool ZafTreeItem::SetFocus(bool setFocus)
{
	// Check for valid focus.
	if (Disabled() || Noncurrent())
		setFocus = false;

	if (setFocus != focus)
	{
		ZafTreeList *treeList = TreeList();
		// If the ZafTreeItem is not added to a ZafTreeList, treeList is null and 
		// nothing can be done.
		if (!treeList)
			return (focus);
		if (setFocus)
		{
			if (!treeList->Focus())
				treeList->SetFocus(true);

			// Update the view-current pointer.
			if (treeList->current != this)
			{
				if (screenID)
				{
					// Turn off the old item focus.
					if (treeList->current && treeList->Current()->Focus())
					{
						treeList->Current()->Event(ZafEventStruct(N_NON_CURRENT));
						treeList->Current()->Event(ZafEventStruct(S_NON_CURRENT));
					}

					treeList->current = this;

					if (treeList->Focus())
					{
						// Turn on the new item focus.
						Event(ZafEventStruct(S_CURRENT));
						Event(ZafEventStruct(N_CURRENT));
					}
				}
				else
					treeList->current = this;
			}
		}
		else
			treeList->SetFocus(false);
	}

	// Return the current attribute.
	return (focus);
}

bool ZafTreeItem::SetLocked(bool )
{
	// locked is false for this class.
	locked = false;
	return (locked);
}

bool ZafTreeItem::SetMaximized(bool )
{
	// maximized is false for this class.
	maximized = false;
	return (maximized);
}

bool ZafTreeItem::SetMinimized(bool )
{
	// minimized is false for this class.
	minimized = false;
	return (minimized);
}

bool ZafTreeItem::SetModal(bool )
{
	// modal is false for this class.
	modal = false;
	return (modal);
}

bool ZafTreeItem::SetMoveable(bool )
{
	// moveable is false for this class.
	moveable = false;
	return (moveable);
}

ZafError ZafTreeItem::SetNormalBitmap(ZafBitmapData *tNormalBitmap)
{
	// Remove the data notification.
	if (normalBitmap)
		normalBitmap->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Reset the bitmap data.
	if (normalBitmap && normalBitmap != tNormalBitmap &&
		normalBitmap->Destroyable() && normalBitmap->NotifyCount() == 0)
		delete normalBitmap;
	normalBitmap = tNormalBitmap;

	// Add the data notification.
	if (normalBitmap)
		normalBitmap->AddNotification(this, (ZafUpdateFunction)Update);

	return (ZAF_ERROR_NONE);
}

bool ZafTreeItem::SetNormalHotKeys(bool )
{
	// normalHotKeys is false for this class.
	normalHotKeys = false;
	return (normalHotKeys);
}

ZafWindow *ZafTreeItem::SetOwner(ZafWindow *)
{
	// owner is null for this class.
	owner = ZAF_NULLP(ZafWindow);
	return (owner);
}

bool ZafTreeItem::SetParentDrawBorder(bool setParentDrawBorder)
{
	// Defer to the root class.
	return (ZafWindowObject::SetParentDrawBorder(setParentDrawBorder));
}

bool ZafTreeItem::SetParentDrawFocus(bool setParentDrawFocus)
{
	// Defer to the root class.
	return (ZafWindowObject::SetParentDrawBorder(setParentDrawFocus));
}

ZafRegionType ZafTreeItem::SetRegionType(ZafRegionType )
{
	// regionType is ZAF_INSIDE_REGION for this class.
	regionType = ZAF_INSIDE_REGION;
	return (regionType);
}

ZafSelectionType ZafTreeItem::SetSelectionType(ZafSelectionType setSelectionType)
{
	// Set the object and update all the children.
	ZafWindow::SetSelectionType(setSelectionType);
	for (ZafTreeItem *item = First(); item; item = item->Next())
		item->SetSelectionType(selectionType);

	// Return the current attribute.
	return (selectionType);
}

ZafError ZafTreeItem::SetSelectedBitmap(ZafBitmapData *tSelectedBitmap)
{
	// Remove the data notification.
	if (selectedBitmap)
		selectedBitmap->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Reset the bitmap data.
	if (selectedBitmap && selectedBitmap != tSelectedBitmap &&
		selectedBitmap->Destroyable() && selectedBitmap->NotifyCount() == 0)
		delete selectedBitmap;
	selectedBitmap = tSelectedBitmap;

	// Add the data notification.
	if (selectedBitmap)
		selectedBitmap->AddNotification(this, (ZafUpdateFunction)Update);

	return (ZAF_ERROR_NONE);
}

bool ZafTreeItem::SetSizeable(bool )
{
	// sizeable is false for this class.
	sizeable = false;
	return (sizeable);
}

ZafError ZafTreeItem::SetStringData(ZafStringData *tStringData)
{
	// Remove the data notification.
	if (stringData)
		stringData->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Reset the string data.
	if (stringData && stringData != tStringData &&
		stringData->Destroyable() && stringData->NotifyCount() == 0)
		delete stringData;
	stringData = tStringData;

	// Add the data notification.
	if (stringData)
		stringData->AddNotification(this, (ZafUpdateFunction)Update);
	return (ZAF_ERROR_NONE);
}

bool ZafTreeItem::SetTemporary(bool )
{
	// temporary is false for this class.
	temporary = false;
	return (temporary);
}

ZafError ZafTreeItem::SetText(const ZafIChar *text)
{
	// Reset the tree item's text.
	if (stringData)
		stringData->SetText(text);
	else
		SetStringData(new ZafStringData(text));

	return (ZAF_ERROR_NONE);
}

ZafStringData *ZafTreeItem::StringData(void) const
{
	return (stringData);
}

const ZafIChar *ZafTreeItem::Text(void)
{
	return (stringData ? stringData->Text() : ZAF_NULLP(ZafIChar));
}

ZafTreeList *ZafTreeItem::TreeList(void) const
{
	// Find the tree list.
	for (ZafWindowObject *rootObject = parent; rootObject; rootObject = rootObject->parent)
		if (rootObject->IsA(ID_ZAF_TREE_LIST))
			return (DynamicPtrCast(rootObject, ZafTreeList));
	return (ZAF_NULLP(ZafTreeList));
}

ZafTreeItem *ZafTreeItem::ViewCurrent(void)
{
	// Make sure the item is expanded.
	if (!Expanded())
		return (this);

	// Push the view-current down.
	ZafTreeItem *object = DynamicPtrCast(current, ZafTreeItem);
	return (object ? object->ViewCurrent() : this);
}

ZafTreeItem *ZafTreeItem::ViewFirst(void)
{
	return (this);
}

ZafTreeItem *ZafTreeItem::ViewLast(void)
{
	ZafTreeItem *item = DynamicPtrCast(last, ZafTreeItem);
	return ((Expanded() && item) ? item->ViewLast() : this);
}

int ZafTreeItem::ViewLevel(void)
{
	// Count the tree item levels.
	int level = 0;
	for (ZafWindowObject *rootObject = parent; rootObject && rootObject->IsA(ID_ZAF_TREE_ITEM); rootObject = rootObject->parent)
		level++;
	return (level);
}

ZafTreeItem *ZafTreeItem::ViewNext(ZafTreeItem *start)
{
	// Find the next visible tree item.
	ZafTreeItem *item = ZAF_NULLP(ZafTreeItem);
	if (first && Expanded())
		item = DynamicPtrCast(first, ZafTreeItem);
	else if (next)
		item = DynamicPtrCast(next, ZafTreeItem);
	else
	{
		for (ZafWindowObject *root = parent; root && root != start && !item;
			root = root->parent)
		{
			if (root->IsA(ID_ZAF_TREE_ITEM))
			{
				item = DynamicPtrCast(root, ZafTreeItem);
				item = DynamicPtrCast(item->Next(), ZafTreeItem);
			}
			else
				break;
		}
	}
	return (item);
}

ZafTreeItem *ZafTreeItem::ViewPrevious(void)
{
	// Find the previous visible tree item.
	ZafTreeItem *item = ZAF_NULLP(ZafTreeItem);
	if (previous)
	{
		item = DynamicPtrCast(previous, ZafTreeItem);
		item = item->ViewLast();
	}
	else if (parent->IsA(ID_ZAF_TREE_ITEM))
		item = DynamicPtrCast(parent, ZafTreeItem);
	return (item);
}

ZafError ZafTreeItem::Update(ZafTreeItem *item, ZafUpdateType type)
{
	ZafError retVal = ZAF_ERROR_INVALID;
	if (type & ZAF_UPDATE_OBJECT)
		{
			item->Event(S_REDISPLAY_DATA);
			retVal = ZAF_ERROR_NONE;
		}
	if (type & ZAF_UPDATE_DATA)
		retVal = ZAF_ERROR_NONE;
	return (retVal);
}

// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
ZafTreeItem::ZafTreeItem(const ZafIChar *name, ZafObjectPersistence &persist) :
	ZafWindow(name, persist.PushLevel(className, classID, ZAF_PERSIST_DIRECTORY)),
	stringData(ZAF_NULLP(ZafStringData)),
	normalBitmap(ZAF_NULLP(ZafBitmapData)),
	selectedBitmap(ZAF_NULLP(ZafBitmapData))
{
	// Check the image information.
	ImageAllocate();

	// Set all children as non-system objects.  ZafWindow persistent
	// constructor will not call ZafVtList::Add() since it is in the base
	// class phase of construction when the children are added.
	for (ZafWindowObject *object = First(); object; object = object->Next())
	{
		object->SetSystemObject(false);
		object->SetParentPalette(true);
	}

	// Read the data.
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafTreeItem::ReadData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());

	expandRegion = bitmapRegion = textRegion = zafRegion;
}

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

void ZafTreeItem::ReadData(ZafObjectPersistence &persist)
{
	// Read the data.
	ZafUInt16 flag1 = 0;
	ZafIChar stringName[ZAF_MAXNAMELEN], normalName[32], selectedName[32];
	ZafFile *file = persist.CurrentFile();
	*file >> flag1 >> stringName >> normalName >> selectedName;
	expandable = (flag1 & 0x0001) ? true : false;
	expanded = (flag1 & 0x0002) ? true : false;
	autoSortData = (flag1 & 0x0004) ? true : false;

	// Read the string data.
	if (*stringName)
		stringData = new ZafStringData(stringName, persist);

	// Read the bitmap data.
	if (*normalName)
		normalBitmap = new ZafBitmapData(normalName, persist);
	if (*selectedName)
		selectedBitmap = new ZafBitmapData(selectedName, persist);
}

void ZafTreeItem::Write(ZafObjectPersistence &persist)
{
	// Write the object.
	ZafWindow::Write(persist.PushLevel(className, classID, ZAF_PERSIST_DIRECTORY));
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafTreeItem::WriteData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
}

void ZafTreeItem::WriteData(ZafObjectPersistence &persist)
{
	// Write the data.
	ZafUInt16 flag1 = 0;
	flag1 |= (ZafUInt16)(expandable  ? 0x0001 : 0);
	flag1 |= (ZafUInt16)(expanded ? 0x0002 : 0);
	flag1 |= (ZafUInt16)(autoSortData ? 0x0004 : 0);
	const ZafIChar *stringName = stringData ? stringData->StringID() : ZAF_NULLP(ZafIChar);
	const ZafIChar *normalName = normalBitmap ? normalBitmap->StringID() : ZAF_NULLP(ZafIChar);
	const ZafIChar *selectedName = selectedBitmap ? selectedBitmap->StringID() : ZAF_NULLP(ZafIChar);
	ZafFile *file = persist.CurrentFile();
	*file << flag1 << stringName << normalName << selectedName;

	// Write the string data.
	if (stringData)
		stringData->Write(persist);

	// Write the bitmap data.
	if (normalBitmap)
		normalBitmap->Write(persist);
	if (selectedBitmap)
		selectedBitmap->Write(persist);
}
#endif
