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

#include <z_date1.hpp>
#include <z_error.hpp>
#include <z_string.hpp>
#include <z_app.hpp>
#define ZAF_DATE_INFO
#include "lang_def.cpp"
#include "gbl_def.cpp"

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

// ----- ZafDate ------------------------------------------------------------

ZafDate::ZafDate(int left, int top, int width, ZafDateData *zDateData) :
	ZafString(left, top, width, new ZafStringData),
	dateData(ZAF_NULLP(ZafDateData))
{
	// Get the error stings.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the date data.
	SetDateData(zDateData ? zDateData : new ZafDateData);
}

ZafDate::ZafDate(int left, int top, int width, int year, int month, int day) :
	ZafString(left, top, width, new ZafStringData),
	dateData(ZAF_NULLP(ZafDateData))
{
	// Get the error stings.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Initialize the date data.
	SetDateData(new ZafDateData(year, month, day));
}

ZafDate::ZafDate(const ZafDate &copy) :
	ZafString(copy), dateData(ZAF_NULLP(ZafDateData))
{
	// Get the error stings.
	messages = ZafLanguageManager::Allocate(className, defaultMessages);

	// Copy the date data.
	if (copy.DateData()->Destroyable())
		SetDateData(new ZafDateData(*copy.DateData()));
	else
		SetDateData(copy.DateData());
}

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

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

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

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

ZafEventType ZafDate::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:
		OSSetDate();
		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 date in case of error.
			ZafDateData oldValue(*dateData);
			ZafError preValidateError = OSGetDate();

			// 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(windowManager, title, ZAF_DIALOG_OK, errorString, stringData->Text());
			}

			// See if the data has changed.
			newData = (*dateData != 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)
					dateData->SetDate(oldValue);
				else if (leavingWindow)
				{
					dateData->SubtractNotification(this, (ZafUpdateFunction)Update);
					dateData->SetDate(oldValue);
					dateData->AddNotification(this, (ZafUpdateFunction)Update);
				}
			}
			else if (!unanswered)
				OSSetDate();

			// 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;
		ZafDate *date = DynamicPtrCast(object, ZafDate);
		if (date)
			dateData->SetDate(*date->DateData());
		}
		break;

	case S_SET_DATA:
		if (event.windowObject)
		{
			ZafWindowObject *object = event.windowObject;
			ZafDate *date = DynamicPtrCast(object, ZafDate);
			if (date)
				SetDateData(date->DateData());
		}
		else
			SetDateData(new ZafDateData(*dateData));
		break;

	case S_UPDATE_OBJECT:
		OSSetDate();
		break;

	case S_UPDATE_DATA:
		OSGetDate();
		break;

	case N_RESET_I18N:
		OSSetDate();
		break;

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

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

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

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

ZafError ZafDate::SetDateData(ZafDateData *tDateData)
{
	// Remove the data notification.
	if (dateData)
		dateData->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Reset the date data.
	if (dateData && dateData != tDateData &&
		dateData->Destroyable() && dateData->NotifyCount() == 0)
		delete dateData;
	dateData = tDateData ? tDateData : new ZafDateData;

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

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

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

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

ZafError ZafDate::SetText(const ZafIChar *text)
{ 
	return (dateData->SetDate(text,
		inputFormatData ? inputFormatData->Text() : ZAF_NULLP(ZafIChar)));
}

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

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

ZafError ZafDate::OSGetDate(void)
{
	// Disable notification.
	ZafUpdateType update = dateData->Update(this);
	dateData->SetUpdate(this, ZAF_UPDATE_NONE);

	// Get the string data from the OS.
	OSGetText();

	// Set the date based on the string data.
	error = dateData->SetDate(stringData->Text(), OutputFormatText() ? 
		OutputFormatText() : zafLocale->dateStringOutputFormat);
	if (error)
		error = dateData->SetDate(stringData->Text(), InputFormatText());

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

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

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

ZafError ZafDate::Update(ZafDate *date, ZafUpdateType type)
{
	ZafError retVal = ZAF_ERROR_INVALID;
	if (type & ZAF_UPDATE_OBJECT)
		retVal = date->OSSetDate();
	if (type & ZAF_UPDATE_DATA)
		retVal = date->OSGetDate();
	return (retVal);
}

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

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

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

void ZafDate::ReadData(ZafObjectPersistence &persist)
{
	// Read the data.
	ZafIChar dateName[ZAF_MAXNAMELEN];
	ZafFile *file = persist.CurrentFile();
	*file >> dateName;
	SetDateData(dateName[0] ? new ZafDateData(dateName, persist) : new ZafDateData);
}

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

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

// -1, 0, 1
int ZafDate::Compare(ZafData *value1, ZafData *value2)
{
	ZafDateData *dateVal1 = DynamicPtrCast(value1, ZafDateData);
	ZafDateData *dateVal2 = DynamicPtrCast(value2, ZafDateData);
	int retVal;
	if (*dateVal1 < *dateVal2)
		retVal = -1;
	else if (*dateVal1 == *dateVal2)
		retVal = 0;
	else
		retVal = 1;

	return (retVal);
}

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

ZafData *ZafDate::DynamicDataPtr(void)
{
	return (new ZafDateData(*dateData));
}

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

int ZafDate::GetValue(ZafData *data, ZafIChar *text, int maxLength,
	const ZafIChar *format)
{
	ZafDateData *dateVal = DynamicPtrCast(data, ZafDateData);

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

	return (maxLength);
}

const ZafIChar *ZafDate::RangeErrorSeparator(void)
{
	return (dateSeparator);
}

ZafError ZafDate::RestoreText(void)
{
	OSSetDate();
	return (ZAF_ERROR_NONE);
}

ZafError ZafDate::SetValue(ZafData *data, ZafIChar *text, const ZafIChar *format)
{
	ZafDateData *dateVal = DynamicPtrCast(data, ZafDateData);

	return (dateVal->SetDate(text, format));
}

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

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

	dest->Decrement(value);

	return (ZAF_ERROR_NONE);
}

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

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

	dest->Increment(value);

	return (ZAF_ERROR_NONE);
}

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

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

	*dest = *source;

	return (ZAF_ERROR_NONE);
}

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

ZafData *ZafDate::DataPtr(void)
{
	return (dateData);
}

