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

#include <z_time1.hpp>
#include <z_error.hpp>
#include <z_string.hpp>
#include <z_app.hpp>
#define ZAF_TIME_INFO
#include "lang_def.cpp"
#include "gbl_def.cpp"

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

// ----- ZafTime -----------------------------------------------------------

ZafTime::ZafTime(int left, int top, int width, ZafTimeData *zTimeData) :
	ZafString(left, top, width, new ZafStringData),
	timeData(ZAF_NULLP(ZafTimeData))
{
	// Get the messages.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the time data.
	SetTimeData(zTimeData ? zTimeData : new ZafTimeData);
}

ZafTime::ZafTime(int left, int top, int width, int hour, int minute,
	int second, int milliSecond) :
	ZafString(left, top, width, new ZafStringData),
	timeData(ZAF_NULLP(ZafTimeData))
{
	// Get the messages.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the time data.
	SetTimeData(new ZafTimeData(hour, minute, second, milliSecond));
}

ZafTime::ZafTime(const ZafTime &copy) :
	ZafString(copy), timeData(ZAF_NULLP(ZafTimeData))
{
	// Get the messages.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Copy the time data.
	if (copy.TimeData()->Destroyable())
		SetTimeData(new ZafTimeData(*copy.TimeData()));
	else
		SetTimeData(copy.TimeData());
}

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

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

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

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

ZafEventType ZafTime::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:
		OSSetTime();
		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;

			if (Unanswered() && strlen(Text()) <1)
				return (ZAF_ERROR_NONE);

			// Keep a temporary time in case of error.
			ZafTimeData oldValue(*timeData);
			ZafError preValidateError = OSGetTime();

			// 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 = (*timeData != 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)
					timeData->SetTime(oldValue);
				else if (leavingWindow)
				{
					timeData->SubtractNotification(this, (ZafUpdateFunction)Update);
					timeData->SetTime(oldValue);
					timeData->AddNotification(this, (ZafUpdateFunction)Update);
				}
			}
			else if (!unanswered)
				OSSetTime();

			// 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;
		ZafTime *time = DynamicPtrCast(object, ZafTime);
		if (time)
			timeData->SetTime(*time->TimeData());
		}
		break;

	case S_SET_DATA:
		if (event.windowObject)
		{
			ZafWindowObject *object = event.windowObject;
			ZafTime *time = DynamicPtrCast(object, ZafTime);
			if (time)
				SetTimeData(time->TimeData());
		}
		else
			SetTimeData(new ZafTimeData(*timeData));
		break;

	case N_RESET_I18N:
		OSSetTime();
		break;

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

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

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

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

ZafError ZafTime::SetText(const ZafIChar *text) 
{ 
	return (timeData->SetTime(text, 
	 inputFormatData ? inputFormatData->Text() : ZAF_NULLP(ZafIChar))); 
}

ZafError ZafTime::SetTimeData(ZafTimeData *tTimeData)
{
	// Remove the data notification.
	if (timeData)
		timeData->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Reset the time data.
	if (timeData && timeData != tTimeData &&
		timeData->Destroyable() && timeData->NotifyCount() == 0)
		delete timeData;
	timeData = tTimeData ? tTimeData : new ZafTimeData;

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

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

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

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

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

bool ZafTime::SetVariableName(bool )
{
	// variableName is set to false by this class.
	variableName = false;
	return (variableName);
}

ZafError ZafTime::OSGetTime(void)
{
	// Disable notification.
	ZafUpdateType update = timeData->Update(this);
	timeData->SetUpdate(this, ZAF_UPDATE_NONE);

	// Set the time based on the string data.
	OSGetText();
	error = timeData->SetTime(StringData()->Text(), OutputFormatText() ? 
		OutputFormatText() : zafLocale->timeStringOutputFormat);
	if (error)
		error = timeData->SetTime(StringData()->Text(), InputFormatText());

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

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

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

ZafError ZafTime::Update(ZafTime *time, ZafUpdateType type)
{
	ZafError retVal = ZAF_ERROR_INVALID;
	if (type & ZAF_UPDATE_OBJECT)
		retVal = time->OSSetTime();
	if (type & ZAF_UPDATE_DATA)
		retVal = time->OSGetTime();
	return (retVal);
}

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

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

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

void ZafTime::ReadData(ZafObjectPersistence &persist)
{
	// Read the data.
	ZafIChar timeName[ZAF_MAXNAMELEN];
	ZafFile *file = persist.CurrentFile();
	*file >> timeName;
	SetTimeData(timeName[0] ? new ZafTimeData(timeName, persist) : new ZafTimeData);
}

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

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

// -1, 0, 1
int ZafTime::Compare(ZafData *value1, ZafData *value2)
{
	ZafTimeData *timeVal1 = DynamicPtrCast(value1, ZafTimeData);
	ZafTimeData *timeVal2 = DynamicPtrCast(value2, ZafTimeData);
	int retVal;
	if (*timeVal1 < *timeVal2)
		retVal = -1;
	else if (*timeVal1 == *timeVal2)
		retVal = 0;
	else
		retVal = 1;

	return (retVal);
}

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

ZafData *ZafTime::DynamicDataPtr(void)
{
	return (new ZafTimeData(*timeData));
}

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

int ZafTime::GetValue(ZafData *data, ZafIChar *text, int maxLength,
	const ZafIChar *format)
{
	ZafTimeData *timeVal = DynamicPtrCast(data, ZafTimeData);

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

	return (maxLength);
}

const ZafIChar *ZafTime::RangeErrorSeparator(void)
{
	return (timeSeparator);
}

ZafError ZafTime::RestoreText(void)
{
	OSSetTime();
	return (ZAF_ERROR_NONE);
}

ZafError ZafTime::SetValue(ZafData *data, ZafIChar *text, const ZafIChar *format)
{
	ZafTimeData *timeVal = DynamicPtrCast(data, ZafTimeData);

	return (timeVal->SetTime(text, format));
}

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

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

	dest->Decrement(value);

	return (ZAF_ERROR_NONE);
}

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

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

	dest->Increment(value);

	return (ZAF_ERROR_NONE);
}

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

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

	*dest = *source;

	return (ZAF_ERROR_NONE);
}

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

ZafData *ZafTime::DataPtr(void)
{
	return (timeData);
}
