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

#include <z_spin.hpp>
#include <z_str1.hpp>
#if defined(ZAF_INDEPENDENT)
#	include "i_spin.hpp"
#endif
#define ZAF_SPIN_CONTROL_INFO
#include "gbl_def.cpp"

// ----- ZafSpinControl -----------------------------------------------------

ZafSpinControl::ZafSpinControl(int left, int top, int width,
	ZafData *zDelta) :
	ZafWindow(left, top, width, 1),
	viewOnly(false), wrappedData(true), delta(ZAF_NULLP(ZafData))
{
	if (zDelta)
		SetDelta(zDelta);

	SetDestroyable(false);
	SetMoveable(false);
	SetSizeable(false);

#	if defined(ZAF_INDEPENDENT) || defined(ZAF_CURSES)
	ZafWindow::Add(new ZafSpinButton);
	mouseObject = ZAF_NULLP(ZafWindowObject);
#	endif
}

ZafSpinControl::ZafSpinControl(const ZafSpinControl &copy) :
	ZafWindow(copy),
	viewOnly(copy.viewOnly), wrappedData(copy.wrappedData),
	delta(ZAF_NULLP(ZafData))
{
	SetDelta(copy.delta->Duplicate());
#if defined(ZAF_INDEPENDENT) || defined(ZAF_CURSES)
	mouseObject = ZAF_NULLP(ZafWindowObject);
#endif
}

ZafSpinControl::~ZafSpinControl(void)
{
	if (delta)
	{
		// Remove the data notification.
		delta->SubtractNotification(this);

		// Restore the integer information.
		if (delta->Destroyable() && delta->NotifyCount() == 0)
			delete delta;
	}
}

ZafWindowObject *ZafSpinControl::Add(ZafWindowObject *object, ZafWindowObject *position)
{
	// If the spin control is already on the screen, don't change the 
	// field object.
	if (screenID)
		return (First());

	// Check for other entries.
	if (first)
	{
		ZafWindowObject *oldObject = First();
		Subtract(oldObject);
		delete oldObject;
	}

	// Reset the child callback, so the spin-control is notified on L_SELECT
	// messages.  Also, default the child to take the spin-control palette.
	if (!object->userFunction)
		object->SetUserFunction(ChildCallback);
	object->SetParentPalette(true);

	// Match the "bordered" attributes.
#if !defined(ZAF_TEXT_MODE)
	bordered = object->Bordered();
#endif

	// Defer actual addition to the base class.
	return (ZafWindow::Add(object, position));
}

bool ZafSpinControl::Changed(void) const 
{ 
	return (First() ? First()->Changed() : changed); 
}

ZafEventType ZafSpinControl::ChildCallback(ZafWindowObject *object, ZafEventStruct &event, ZafEventType ccode)
{
	// This function simply chains the L_SELECT callback to the parent's 
	// callback function.  When the user hits <enter> the message originates 
	// with the sub-object within the spin control, not with the spin 
	// control.  N_CURRENT and N_NON_CURRENT will be handled correctly since
	// focus moves off the entire spin-control, not just the sub-object.
	if (ccode == L_SELECT)
	{
		object = object->parent;
		(object->*(object->memberUserFunction))(event, ccode);
	}

	// Return the results.
	return (0);
}

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

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

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

ZafLogicalEvent ZafSpinControl::LogicalEvent(const ZafEventStruct &event)
{
	ZafLogicalEvent ccode = MapEvent(defaultEventMap, event);
	return ((ccode == L_NONE) ? ZafWindowObject::LogicalEvent(event) : ccode);
}

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

bool ZafSpinControl::SetBordered(bool setBordered)
{
#if defined(ZAF_TEXT_MODE)
	bordered = setBordered = false;
	ZafWindowObject::SetBordered(setBordered);
#else
	// Defer the first part to the base class.
	if (First())
		bordered = First()->SetBordered(setBordered);
	else
		ZafWindowObject::SetBordered(setBordered);
#endif	

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

bool ZafSpinControl::SetChanged(bool setChanged)
{
	// Defer the first part to the base class.
	if (First())
		changed = First()->SetChanged(setChanged);
	else
		ZafWindowObject::SetChanged(setChanged);

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

ZafCoordinateType ZafSpinControl::SetCoordinateType(ZafCoordinateType newCoordinateType)
{
	// Make sure the attribute has changed.
	if (coordinateType != newCoordinateType && !screenID)
	{
		if (coordinateType == ZAF_CELL && zafRegion.Height() == 1)
		{
			ZafRegionStruct convertRegion = zafRegion;
			ConvertRegion(convertRegion, newCoordinateType);
			zafRegion.bottom = zafRegion.top + convertRegion.Height() - 1;
		}
		coordinateType = zafRegion.coordinateType = newCoordinateType;
	}

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

bool ZafSpinControl::SetCopyDraggable(bool setCopyDraggable)
{
	// Defer the first part to the base class.
	if (First())
		copyDraggable = First()->SetCopyDraggable(setCopyDraggable);
	else
		ZafWindowObject::SetCopyDraggable(setCopyDraggable);

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

ZafError ZafSpinControl::SetDelta(ZafData *newDelta)
{
	// Reset the delta data.
	if (delta && delta != newDelta &&
		delta->Destroyable() && delta->NotifyCount() == 0)
		delete delta;
	delta = newDelta ? newDelta : ZAF_NULLP(ZafData);
	return (ZAF_ERROR_NONE);
}

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

const ZafIChar *ZafSpinControl::SetHelpObjectTip(const ZafIChar *newHelpObjectTip)
{
	// Defer the first part to the base class.
	ZafWindowObject::SetHelpObjectTip(newHelpObjectTip);

	// Now mirror the spin object.
	if (First())
		First()->SetHelpObjectTip(helpObjectTip);

	// Return the current help object tip.
	return (helpObjectTip);
}

const ZafIChar *ZafSpinControl::SetHelpContext(const ZafIChar *newHelpContext)
{
	// Defer the first part to the base class.
	ZafWindowObject::SetHelpContext(newHelpContext);

	// Now mirror the spin object.
	if (First())
		First()->SetHelpContext(helpContext);

	// Return the current help object tip.
	return (helpContext);
}

bool ZafSpinControl::SetLinkDraggable(bool setLinkDraggable)
{
	// Defer the first part to the base class.
	if (First())
		linkDraggable = First()->SetLinkDraggable(setLinkDraggable);
	else
		ZafWindowObject::SetLinkDraggable(setLinkDraggable);

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

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

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

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

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

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

bool ZafSpinControl::SetMoveDraggable(bool setMoveDraggable)
{
	// Defer the first part to the base class.
	if (First())
		moveDraggable = First()->SetMoveDraggable(setMoveDraggable);
	else
		ZafWindowObject::SetMoveDraggable(setMoveDraggable);

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

bool ZafSpinControl::SetNoncurrent(bool setNoncurrent)
{
	// Defer the first part to the base class.
	ZafWindowObject::SetNoncurrent(setNoncurrent);

	// Now mirror the spin object.
	if (First())
		First()->SetNoncurrent(noncurrent);

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

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

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

const ZafIChar *ZafSpinControl::SetQuickTip(const ZafIChar *newQuickTip)
{
	// Defer the first part to the base class.
	ZafWindowObject::SetQuickTip(newQuickTip);

	// Now mirror the spin object.
	if (First())
		First()->SetQuickTip(quickTip);

	// Return the current help object tip.
	return (quickTip);
}

ZafSelectionType ZafSpinControl::SetSelectionType(ZafSelectionType )
{
	// selectionType is ZAF_SINGLE_SELECTION for this class.
	selectionType = ZAF_SINGLE_SELECTION;
	return (selectionType);
}

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

bool ZafSpinControl::SetSystemObject(bool setSystemObject)
{
	// Set the system object.
	ZafWindowObject::SetSystemObject(setSystemObject);
	if (First())
		First()->SetSystemObject(systemObject);

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

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

ZafError ZafSpinControl::SetText(const ZafIChar *text)
{
	// Pass the value to the editable field.
	if (First())
		First()->SetText(text);
	return (ZAF_ERROR_NONE);
}

bool ZafSpinControl::SetViewOnly(bool setViewOnly)
{
	// Check for equivalent flag.
	if (viewOnly != setViewOnly && !screenID)
	{
		viewOnly = setViewOnly;

		// Now mirror the spin object.
		ZafString *string = DynamicPtrCast(First(), ZafString);
		if (string)
			string->SetViewOnly(viewOnly);
	}

	// Return the current status.
	return (viewOnly);
}

ZafWindowObject *ZafSpinControl::Subtract(ZafWindowObject *object)
{
	// If the spin control is already on the screen, don't change the 
	// field object.
	if (screenID)
		return (First());

	// Check for other entries.
	return (ZafWindow::Subtract(object));
}

const ZafIChar *ZafSpinControl::Text(void)
{
	// Get the value from the editable field.
	if (First())
		return (First()->Text());
	return (ZAF_NULLP(ZafIChar));
}

bool ZafSpinControl::SetWrappedData(bool setWrappedData)
{
	// Make sure the attribute has changed.
	if (wrappedData != setWrappedData)
		wrappedData = setWrappedData;

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

// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
ZafSpinControl::ZafSpinControl(const ZafIChar *name, ZafObjectPersistence &persist) :
	ZafWindow(name, persist.PushLevel(className, classID, ZAF_PERSIST_DIRECTORY)),
	delta(ZAF_NULLP(ZafData))
{
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafSpinControl::ReadData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());

#	if defined(ZAF_INDEPENDENT) || defined(ZAF_CURSES)
	ZafWindow::Add(new ZafSpinButton);
	mouseObject = ZAF_NULLP(ZafWindowObject);
#	endif
}

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

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

	ZafUInt16 flag1;
	ZafClassID deltaID;
	ZafIChar deltaName[ZAF_MAXNAMELEN];
	*file >> flag1 >> deltaID >> deltaName;
	viewOnly = (flag1 & 0x0001) ? true : false;
	wrappedData = (flag1 & 0x0002) ? true : false;

	// Load the delta object.  Don't use classID to get the constructor
	// (supposed to use className).

	// First, find the delta object using deltaName.
	ZafFileInfoStruct fileInfo;
	ZafFileSystem *storage = persist.CurrentFileSystem();
	int unfound = true;
	if (storage)
		unfound = storage->FindFirst(fileInfo, deltaName);
	ZafDataConstructor constructor = ZAF_NULLF(ZafDataConstructor);

	// Get the constructor using the className obtained in fileInfo.
	if (!unfound)
		constructor = persist.GetDataConstructor(0, (ZafClassName)fileInfo.stringID);

	// Actually load the delta object.
	if (constructor)
		delta = (ZafData *)(constructor)(deltaName, persist);
}

void ZafSpinControl::Write(ZafObjectPersistence &persist)
{
	// Write the object.
	ZafWindowObject::Write(persist.PushLevel(className, classID, ZAF_PERSIST_DIRECTORY));
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafWindow::WriteData(persist);
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafWindow::WriteChildren(persist);
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafSpinControl::WriteData(persist);

	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
}

void ZafSpinControl::WriteData(ZafObjectPersistence &persist)
{
	// Write the data.
	ZafUInt16 flag1 = 0;
	flag1 |= (ZafUInt16)(viewOnly ? 0x0001 : 0);
	flag1 |= (ZafUInt16)(wrappedData ? 0x0002 : 0);
	ZafFile *file = persist.CurrentFile();
	ZafClassID deltaID = delta ? delta->ClassID() : (ZafClassID)0;
	const ZafIChar *deltaName = delta ? delta->StringID() : ZAF_NULLP(ZafIChar);

	*file << flag1 << deltaID << deltaName;
	if (delta)
		delta->Write(persist);
}
#endif
