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

#include <z_utime1.hpp>
#include <z_string.hpp>
#include <z_error.hpp>
#include <z_app.hpp>
#define ZAF_UTIME_INFO
#include "lang_def.cpp"
#include "gbl_def.cpp"

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

// ----- ZafUTime -----------------------------------------------------------

ZafUTime::ZafUTime(int left, int top, int width, ZafUTimeData *zUTimeData) :
	ZafString(left, top, width, new ZafStringData),
	utimeData(ZAF_NULLP(ZafUTimeData))
{
	// Get the messages.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the utime data.
	SetUTimeData(zUTimeData ? zUTimeData : new ZafUTimeData);
}

ZafUTime::ZafUTime(int left, int top, int width, int year, int month,
	int day, int hour, int minute, int second, int milliSecond) :
	ZafString(left, top, width, new ZafStringData),
	utimeData(ZAF_NULLP(ZafUTimeData))
{
	// Get the messages.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the utime data.
	SetUTimeData(new ZafUTimeData(year, month, day, hour, minute, second, milliSecond));
}

ZafUTime::ZafUTime(const ZafUTime &copy) :
	ZafString(copy), utimeData(ZAF_NULLP(ZafUTimeData))
{
	// Get the messages.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Copy the time data.
	if (copy.UTimeData()->Destroyable())
		SetUTimeData(new ZafUTimeData(*copy.UTimeData()));
	else
		SetUTimeData(copy.UTimeData());
}

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

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

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

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

ZafEventType ZafUTime::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:
		OSSetUTime();
		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 time in case of error.
			ZafUTimeData oldValue(*utimeData);
			ZafError preValidateError = OSGetUTime();


			// Report the error if not leaving the window.
			if (preValidateError != ZAF_ERROR_NONE && !leavingWindow &&
				error != ZAF_ERROR_NONE && 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 = (*utimeData != 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)
					utimeData->SetUTime(oldValue);
				else if (leavingWindow)
				{
					utimeData->SubtractNotification(this, (ZafUpdateFunction)Update);
					utimeData->SetUTime(oldValue);
					utimeData->AddNotification(this, (ZafUpdateFunction)Update);
				}
			}
			else if (!unanswered)
				OSSetUTime();

			// 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;
		ZafUTime *utime = DynamicPtrCast(object, ZafUTime);
		if (utime)
			utimeData->SetUTime(*utime->UTimeData());
		}
		break;

	case S_SET_DATA:
		if (event.windowObject)
		{
			ZafWindowObject *object = event.windowObject;
			ZafUTime *utime = DynamicPtrCast(object, ZafUTime);
			if (utime)
				SetUTimeData(utime->UTimeData());
		}
		else
			SetUTimeData(new ZafUTimeData(*utimeData));
		break;

	case S_UPDATE_OBJECT:
		OSSetUTime();
		break;

	case S_UPDATE_DATA:
		OSGetUTime();
		break;

	case N_RESET_I18N:
		OSSetUTime();
		break;

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

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

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

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

ZafError ZafUTime::SetText(const ZafIChar *text) 
{ 
	return (utimeData->SetUTime(text, 
	 inputFormatData ? inputFormatData->Text() : ZAF_NULLP(ZafIChar))); 
}

ZafError ZafUTime::SetUTimeData(ZafUTimeData *tUTimeData)
{
	// Remove the data notification.
	if (utimeData)
		utimeData->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Reset the utime data.
	if (utimeData && utimeData != tUTimeData &&
		utimeData->Destroyable() && utimeData->NotifyCount() == 0)
		delete utimeData;
	utimeData = tUTimeData ? tUTimeData : new ZafUTimeData;

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

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

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

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

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

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

ZafError ZafUTime::OSGetUTime(void)
{
	// Disable notification.
	ZafUpdateType update = utimeData->Update(this);
	utimeData->SetUpdate(this, ZAF_UPDATE_NONE);

	// Set the utime based on the string data.
	OSGetText();
	error = utimeData->SetUTime(stringData->Text(), OutputFormatText() ?
		OutputFormatText() : zafLocale->dateTimeStringOutputFormat);
	if (error)
		error = utimeData->SetUTime(stringData->Text(), InputFormatText());

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

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

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

ZafError ZafUTime::Update(ZafUTime *utime, ZafUpdateType type)
{
	ZafError retVal = ZAF_ERROR_INVALID;
	if (type & ZAF_UPDATE_OBJECT)
		retVal = utime->OSSetUTime();
	if (type & ZAF_UPDATE_DATA)
		retVal = utime->OSGetUTime();
	return (retVal);
}

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

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

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

void ZafUTime::ReadData(ZafObjectPersistence &persist)
{
	// Read the data.
	ZafIChar utimeName[ZAF_MAXNAMELEN];
	ZafFile *file = persist.CurrentFile();
	*file >> utimeName;
	SetUTimeData(utimeName[0] ? new ZafUTimeData(utimeName, persist) : new ZafUTimeData);
}

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

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

// -1, 0, 1
int ZafUTime::Compare(ZafData *value1, ZafData *value2)
{
	ZafUTimeData *utimeVal1 = DynamicPtrCast(value1, ZafUTimeData);
	ZafUTimeData *utimeVal2 = DynamicPtrCast(value2, ZafUTimeData);
	int retVal;
	if (*utimeVal1 < *utimeVal2)
		retVal = -1;
	else if (*utimeVal1 == *utimeVal2)
		retVal = 0;
	else
		retVal = 1;

	return (retVal);
}

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

ZafData *ZafUTime::DynamicDataPtr(void)
{
	return (new ZafUTimeData(*utimeData));
}

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

int ZafUTime::GetValue(ZafData *data, ZafIChar *text, int maxLength,
	const ZafIChar *format)
{
	ZafUTimeData *utimeVal = DynamicPtrCast(data, ZafUTimeData);

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

	return (maxLength);
}

const ZafIChar *ZafUTime::RangeErrorSeparator(void)
{
	return (utimeSeparator);
}

ZafError ZafUTime::RestoreText(void)
{
	OSSetUTime();
	return (ZAF_ERROR_NONE);
}

ZafError ZafUTime::SetValue(ZafData *data, ZafIChar *text, const ZafIChar *format)
{
	ZafUTimeData *utimeVal = DynamicPtrCast(data, ZafUTimeData);

	return (utimeVal->SetUTime(text, format));
}

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

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

	dest->Decrement(value);

	return (ZAF_ERROR_NONE);
}

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

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

	dest->Increment(value);

	return (ZAF_ERROR_NONE);
}

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

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

	*dest = *source;

	return (ZAF_ERROR_NONE);
}

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

ZafData *ZafUTime::DataPtr(void)
{
	return (utimeData);
}
