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

#include <z_stdio.hpp>
#include <z_bnum1.hpp>
#include <z_string.hpp>
#include <z_error.hpp>
#include <z_app.hpp>
#define ZAF_BIGNUM_INFO
#include "lang_def.cpp"
#include "gbl_def.cpp"

static ZafIChar numSeparator[3] = { '.','.',0 };

// ----- ZafBignum ----------------------------------------------------------

ZafBignum::ZafBignum(int left, int top, int width, ZafBignumData *zBignumData) :
	ZafString(left, top, width, new ZafStringData),
	bignumData(ZAF_NULLP(ZafBignumData))
{
	// Get the error stings.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the bignum data.
	SetBignumData(zBignumData ? zBignumData : new ZafBignumData);
}

ZafBignum::ZafBignum(int left, int top, int width, long value) :
	ZafString(left, top, width, new ZafStringData),
	bignumData(ZAF_NULLP(ZafBignumData))
{
	// Get the error stings.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the bignum data.
	SetBignumData(new ZafBignumData(value));
}

ZafBignum::ZafBignum(int left, int top, int width, double value) :
	ZafString(left, top, width, new ZafStringData),
	bignumData(ZAF_NULLP(ZafBignumData))
{
	// Get the error stings.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the bignum data.
	SetBignumData(new ZafBignumData(value));
}

ZafBignum::ZafBignum(const ZafBignum &copy) :
	ZafString(copy), bignumData(ZAF_NULLP(ZafBignumData))
{
	// Get the error stings.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Copy the bignum data.
	if (copy.BignumData()->Destroyable())
		SetBignumData(new ZafBignumData(*copy.BignumData()));
	else
		SetBignumData(copy.BignumData());
}

ZafBignum::~ZafBignum(void)
{
	// Remove the data notification.
	bignumData->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Free the error strings.
	ZafLanguageManager::Free(messages);

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

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

ZafEventType ZafBignum::Event(const ZafEventStruct &event)
{
	// Process OS specific messages.
	ZafEventType ccode = event.type;
	if (event.InputType() == E_KEY)
		ccode = LogicalEvent(event);

	// Check for zinc events.
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		OSSetBignum();
		ccode = ZafString::Event(event);
		break;

	// ----- Action messages -----
	case L_SELECT:
	case N_NON_CURRENT:
		if (!error)
		{
			// Errors are reported only when focus changes within a window.
			bool leavingWindow = (ccode == N_NON_CURRENT && (!event.windowObject ||
				event.windowObject->RootObject() != RootObject())) ? true : false;

			// Keep a temporary number in case of error.
			ZafBignumData oldValue(*bignumData);
			ZafError preValidateError = OSGetBignum();

			// Report the error if not leaving the window.
			if (preValidateError != ZAF_ERROR_NONE && !leavingWindow &&
				zafErrorSystem && reportInvalid)
			{
				ZafIChar *title = ZafLanguageManager::blankString;
				ZafIChar *errorString = messages->GetMessage(ZAF_ERROR_INVALID, true);
				zafErrorSystem->ReportError(this, title, ZAF_DIALOG_OK, errorString, stringData->Text());
			}

			// See if the data has changed.
			newData = (*bignumData != oldValue || ((stringData->Length() == 0) != (unanswered == true))) ? true : false;
			if (newData)
				SetChanged(true);

			// Call the user/validate function.
			ccode = ZafString::Event(event);

			// Check for errors.
			if (preValidateError != ZAF_ERROR_NONE)
				ccode = leavingWindow ? ZAF_ERROR_LEAVE_INVALID : preValidateError;
			if (ccode != 0)
			{
				if (ccode != ZAF_ERROR_LEAVE_INVALID)
					bignumData->SetBignum(oldValue);
				else if (leavingWindow)
				{
					bignumData->SubtractNotification(this, (ZafUpdateFunction)Update);
					bignumData->SetBignum(oldValue);
					bignumData->AddNotification(this, (ZafUpdateFunction)Update);
				}
			}
			else if (!unanswered && newData)
				OSSetBignum();

			// Clear the error code.
			SetError(ZAF_ERROR_NONE);
		}
		else
			// Nested call.
			return (ZAF_ERROR_LEAVE_INVALID);
		break;

	case S_COPY_DATA:
		{
		ZafWindowObject *object = event.windowObject;
		ZafBignum *bignum = DynamicPtrCast(object, ZafBignum);
		if (bignum)
			bignumData->SetBignum(*bignum->BignumData());
		}
		break;

	case S_SET_DATA:
		if (event.windowObject)
		{
			ZafWindowObject *object = event.windowObject;
			ZafBignum *bignum = DynamicPtrCast(object, ZafBignum);
			if (bignum)
				SetBignumData(bignum->BignumData());
		}
		else
			SetBignumData(new ZafBignumData(*bignumData));
		break;

	case S_UPDATE_OBJECT:
		OSSetBignum();
		break;

	case S_UPDATE_DATA:
		OSGetBignum();
		break;

	case N_RESET_I18N:
		OSSetBignum();
		break;

	// ----- Default or unknown messages -----
	default:
		ccode = ZafString::Event(event);
		break;
	}

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

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

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

long ZafBignum::IValue(void)
{
	OSGetBignum();
	return (BignumData()->IValue());
}

double ZafBignum::RValue(void)
{
	OSGetBignum();
	return (BignumData()->RValue());
}

ZafError ZafBignum::SetBignum(long value)
{
	return (BignumData()->SetBignum(value));
}

ZafError ZafBignum::SetBignum(double value)
{
	return (BignumData()->SetBignum(value));
}

ZafError ZafBignum::SetBignumData(ZafBignumData *tBignumData)
{
	// Remove the data notification.
	if (bignumData)
		bignumData->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Reset the bignum data.
	if (bignumData && bignumData != tBignumData &&
		bignumData->Destroyable() && bignumData->NotifyCount() == 0)
		delete bignumData;
	bignumData = tBignumData ? tBignumData : new ZafBignumData;

	// Add the data notification.
	bignumData->AddNotification(this, (ZafUpdateFunction)Update);
	return (OSSetBignum());
}

bool ZafBignum::SetLowerCase(bool )
{
	// lowerCase is set to false by this class.
	lowerCase = false;
	return (lowerCase);
}

bool ZafBignum::SetPassword(bool )
{
	// password is set to false by this class.
	password = false;
	return (password);
}

ZafError ZafBignum::SetStringData(ZafStringData *)
{
	// String data cannot be set for this class.
	return (ZAF_ERROR_INVALID);
}

ZafError ZafBignum::SetText(const ZafIChar *text) 
{ 
	return (bignumData->SetBignum(text, 
	 inputFormatData ? inputFormatData->Text() : ZAF_NULLP(ZafIChar))); 
}

bool ZafBignum::SetUpperCase(bool )
{
	// upperCase is set to false by this class.
	upperCase = false;
	return (upperCase);
}

bool ZafBignum::SetVariableName(bool )
{
	// variableName is false for this class.
	variableName = false;
	return (variableName);
}

ZafError ZafBignum::OSGetBignum(void)
{
	// Disable notification.
	ZafUpdateType update = bignumData->Update(this);
	bignumData->SetUpdate(this, ZAF_UPDATE_NONE);

	// Set the bignum based on the string data.
	OSGetText();
	error = bignumData->SetBignum(stringData->Text(), InputFormatText());

	// Restore notification.
	bignumData->SetUpdate(this, update);
	return (error);
}

ZafError ZafBignum::OSSetBignum(void)
{
	if (unanswered)
		stringData->Clear();
	else
	{
		// Set the string based on the bignum data.
		ZafIChar text[ZAF_STRING_DATA_LENGTH];
		bignumData->FormattedText(text, ZAF_STRING_DATA_LENGTH, OutputFormatText());
		stringData->SetText(text);
	}

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

ZafError ZafBignum::Update(ZafBignum *bignum, ZafUpdateType type)
{
	ZafError retVal = ZAF_ERROR_INVALID;
	if (type & ZAF_UPDATE_OBJECT)
		retVal = bignum->OSSetBignum();
	if (type & ZAF_UPDATE_DATA)
		retVal = bignum->OSGetBignum();
	return (retVal);
}

// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
ZafBignum::ZafBignum(const ZafIChar *name, ZafObjectPersistence &persist) :
	ZafString(name, persist.PushLevel(className, classID, ZAF_PERSIST_DIRECTORY)),
	bignumData(ZAF_NULLP(ZafBignumData))
{
	// Get the error stings.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

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

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

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

	// Read the bignum data.
	ZafIChar bignumName[ZAF_MAXNAMELEN];
	*file >> bignumName;
	SetBignumData(bignumName[0] ? new ZafBignumData(bignumName, persist) : new ZafBignumData);
}

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

void ZafBignum::WriteData(ZafObjectPersistence &persist)
{
	// Write the data.
	const ZafIChar *bignumName = bignumData ? bignumData->StringID() : ZAF_NULLP(ZafIChar);
	ZafFile *file = persist.CurrentFile();
	*file << bignumName;
	if (bignumData)
		bignumData->Write(persist);
}
#endif

// -1, 0, 1
int ZafBignum::Compare(ZafData *value1, ZafData *value2)
{
	ZafBignumData *bignumVal1 = DynamicPtrCast(value1, ZafBignumData);
	ZafBignumData *bignumVal2 = DynamicPtrCast(value2, ZafBignumData);
	int retVal;
	if (*bignumVal1 < *bignumVal2)
		retVal = -1;
	else if (*bignumVal1 == *bignumVal2)
		retVal = 0;
	else
		retVal = 1;

	return (retVal);
}

/* START BLOCK COMMENT
**	ZafIChar *ZafBignum::DynamicText(void)
**	{
**		return (stringData->DynamicText());
**	}
END BLOCK COMMENT */

ZafData *ZafBignum::DynamicDataPtr(void)
{
	return (new ZafBignumData(*bignumData));
}

ZafIChar *ZafBignum::ErrorString(ZafNumberID errorID, bool useDefault)
{
	ZafIChar *errorString = messages->GetMessage((ZafNumberID)errorID, useDefault);
	return (errorString);
}

int ZafBignum::GetValue(ZafData *data, ZafIChar *text, int maxLength,
	const ZafIChar *format)
{
	ZafBignumData *bignumVal = DynamicPtrCast(data, ZafBignumData);

	bignumVal->FormattedText(text, maxLength, format);

	return (maxLength);
}

const ZafIChar *ZafBignum::RangeErrorSeparator(void)
{
	return (numSeparator);
}

ZafError ZafBignum::RestoreText(void)
{
	OSSetBignum();
	return (ZAF_ERROR_NONE);
}

ZafError ZafBignum::SetValue(ZafData *data, ZafIChar *text, const ZafIChar *format)
{
	ZafBignumData *bignumVal = DynamicPtrCast(data, ZafBignumData);

	return (bignumVal->SetBignum(text, format));
}

ZafError ZafBignum::DecrementData(ZafData *data, ZafData *delta)
{
	ZafBignumData *dest = DynamicPtrCast(data, ZafBignumData);
	ZafBignumData *value = DynamicPtrCast(delta, ZafBignumData);

	if (!dest || !value)
		return (ZAF_ERROR_INVALID);

	*dest -= *value;

	return (ZAF_ERROR_NONE);
}

ZafError ZafBignum::IncrementData(ZafData *data, ZafData *delta)
{
	ZafBignumData *dest = DynamicPtrCast(data, ZafBignumData);
	ZafBignumData *value = DynamicPtrCast(delta, ZafBignumData);

	if (!dest || !value)
		return (ZAF_ERROR_INVALID);

	*dest += *value;

	return (ZAF_ERROR_NONE);
}

ZafError ZafBignum::SetValue(ZafData *data, ZafData *newValue)
{
	ZafBignumData *dest = DynamicPtrCast(data, ZafBignumData);
	ZafBignumData *source = DynamicPtrCast(newValue, ZafBignumData);

	if (!dest || !source)
		return (ZAF_ERROR_INVALID);

	*dest = *source;

	return (ZAF_ERROR_NONE);
}

bool ZafBignum::ValidDelta(ZafData *delta)
{
	ZafBignumData *value = DynamicPtrCast(delta, ZafBignumData);
	return (value ? true : false);
}

ZafData *ZafBignum::DataPtr(void)
{
	return (bignumData);
}
