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

#include <z_str1.hpp>
#include <z_string.hpp>
#include <z_error.hpp>
#define ZAF_STRING_INFO
#include "gbl_def.cpp"

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

// ----- ZafString ----------------------------------------------------------

ZafString::ZafString(int left, int top, int width, const ZafIChar *text,
	int maxLength) :
	ZafWindowObject(left, top, width, 1),
	allowInvalid(false), autoClear(true), invalid(false), unanswered(false),
	lowerCase(false), password(false), reportInvalid(true), upperCase(false),
	variableName(false), viewOnly(false), hzJustify(ZAF_HZ_LEFT),
	inputFormatData(ZAF_NULLP(ZafStringData)),
	outputFormatData(ZAF_NULLP(ZafStringData)),
	rangeData(ZAF_NULLP(ZafStringData)), newData(false), 
	stringData(ZAF_NULLP(ZafStringData))
{
#if defined(ZAF_INDEPENDENT) || defined(ZAF_CURSES)
	cursor = firstDisplayedChar = 0;
	beginMark = endMark = -1;
#endif
	// Initialize the string information.
	SetBordered(true);
	memberUserFunction = (MemberUserFunction)&ZafString::DefaultValidateFunction;

	// Initialize the string data.
	SetStringData(new ZafStringData(text, maxLength));
}

ZafString::ZafString(int left, int top, int width, ZafStringData *zStringData) :
	ZafWindowObject(left, top, width, 1),
	allowInvalid(false), autoClear(true), invalid(false), unanswered(false),
	lowerCase(false), password(false), reportInvalid(true), upperCase(false),
	variableName(false), viewOnly(false), hzJustify(ZAF_HZ_LEFT),
	inputFormatData(ZAF_NULLP(ZafStringData)),
	outputFormatData(ZAF_NULLP(ZafStringData)),
	rangeData(ZAF_NULLP(ZafStringData)), newData(false), 
	stringData(ZAF_NULLP(ZafStringData))
{
#if defined(ZAF_INDEPENDENT) || defined(ZAF_CURSES)
	cursor = firstDisplayedChar = 0;
	beginMark = endMark = -1;
#endif
	// Initialize the string information.
	SetBordered(true);
	memberUserFunction = (MemberUserFunction)&ZafString::DefaultValidateFunction;

	// Initialize the string data.
	if (zStringData)
		SetStringData(zStringData);
	else
		SetStringData(new ZafStringData);
}

ZafString::ZafString(const ZafString &copy) :
	ZafWindowObject(copy),
	allowInvalid(copy.allowInvalid), autoClear(copy.autoClear), invalid(copy.invalid),
	unanswered(copy.unanswered), lowerCase(copy.lowerCase),
	password(copy.password), reportInvalid(copy.reportInvalid),
	upperCase(copy.upperCase),	variableName(copy.variableName),
	viewOnly(copy.viewOnly), hzJustify(copy.hzJustify),
	inputFormatData(ZAF_NULLP(ZafStringData)),
	outputFormatData(ZAF_NULLP(ZafStringData)),
	rangeData(ZAF_NULLP(ZafStringData)), newData(false),
	stringData(ZAF_NULLP(ZafStringData))
{
#if defined(ZAF_INDEPENDENT) || defined(ZAF_CURSES)
	cursor = firstDisplayedChar = 0;
	beginMark = endMark = -1;
#endif
	// Initialize the string information.
	if (copy.stringData->Destroyable())
		SetStringData(new ZafStringData(*copy.stringData));
	else
		SetStringData(copy.stringData);

	if (copy.inputFormatData)
	{
		if (copy.inputFormatData->Destroyable())
			SetInputFormatData(new ZafStringData(*copy.inputFormatData));
		else
			SetInputFormatData(copy.inputFormatData);
	}

	if (copy.outputFormatData)
	{
		if (copy.outputFormatData->Destroyable())
			SetOutputFormatData(new ZafStringData(*copy.outputFormatData));
		else
			SetOutputFormatData(copy.outputFormatData);
	}

	if (copy.rangeData)
	{
		if (copy.rangeData->Destroyable())
			SetRangeData(new ZafStringData(*copy.rangeData));
		else
			SetRangeData(copy.rangeData);
	}
}

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

	// Restore the string information.
	if (stringData && stringData->Destroyable() && stringData->NotifyCount() == 0)
		delete stringData;
	if (inputFormatData && inputFormatData->Destroyable() && inputFormatData->NotifyCount() == 0)
		delete inputFormatData;
	if (outputFormatData && outputFormatData->Destroyable() && outputFormatData->NotifyCount() == 0)
		delete outputFormatData;
	if (rangeData && rangeData->Destroyable() && rangeData->NotifyCount() == 0)
		delete rangeData;
}

ZafError ZafString::Decrement(ZafData *delta, bool wrapData)
/* START BLOCK COMMENT
**	ZafError ZafString::Decrement(ZafData *, bool)
END BLOCK COMMENT */
{
/* START BLOCK COMMENT
**		// This class has no decrement capabilities.
**		return (ZAF_ERROR_INVALID_CLASS);
END BLOCK COMMENT */

	if (!ValidDelta(delta))
		return (ZAF_ERROR_INVALID_CLASS);

	ZafData *myData = DataPtr();
	ZafData *oldData = DynamicDataPtr();

	DecrementData(myData, delta);

	if (Validate(false) != ZAF_ERROR_NONE)
	{
		const ZafIChar *rangeText = RangeText();
		ZafIChar minNumber[ZAF_STRING_DATA_LENGTH];
		ZafIChar maxNumber[ZAF_STRING_DATA_LENGTH];
		if (wrapData && rangeText)
		{
			bool done = false;
			rangeText = ParseRange(rangeText, minNumber, maxNumber);

			ZafData *minVal = DynamicDataPtr();
			ZafData *maxVal = DynamicDataPtr();

			SetValue(minVal, minNumber, OutputFormatText());

			if (Compare(myData, minVal) < 0) // Less than lowest min. Wrap
			{
				while (rangeText)
					rangeText = ParseRange(rangeText, minNumber, maxNumber);
				if (*maxNumber)
					SetValue(myData, maxNumber, OutputFormatText()); // update is automatic.
				else
					SetValue(myData, oldData);
				done = true;
			}
			
			while (!done)
			{
				SetValue(minVal, minNumber, OutputFormatText());
				if ((!*minNumber || Compare(myData, minVal) > 0) && *maxNumber)
					SetValue(maxVal, maxNumber, OutputFormatText());
				else if (*minNumber && Compare(myData, minVal) < 0)
				{
					SetValue(myData, maxVal); // update is automatic.
					done = true;
				}
				else
				{
					SetValue(myData, oldData); // update is automatic.
					done = true;
				}

				if (rangeText)
					rangeText = ParseRange(rangeText, minNumber, maxNumber);
				else if (!done)
				{
					SetValue(myData, oldData); // update is automatic.
					done = true;
				}
			}

			delete minVal;
			delete maxVal;
		}
		else
			SetValue(myData, oldData); // update is automatic.
		SetError(ZAF_ERROR_NONE);
	}
	delete oldData;

	// Return success.
	return (ZAF_ERROR_NONE);
}

ZafEventType ZafString::DefaultValidateFunction(const ZafEventStruct &event, ZafEventType ccode)
{
	// Start with the number validation.
	if (newData && (ccode == L_SELECT || ccode == N_NON_CURRENT))
	{
		bool leaveWindow = (ccode == N_NON_CURRENT && (!event.windowObject ||
			event.windowObject->RootObject() != RootObject())) ? true : false;
		error = Validate(ReportInvalid() && !leaveWindow);
		if (error && leaveWindow)
			error = ZAF_ERROR_LEAVE_INVALID;
	}
//	else
//		error = ZAF_ERROR_NONE;

	// Call the base user function.
	return (error ? error : DefaultUserFunction(event, ccode));
}

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

ZafError ZafString::Increment(ZafData *delta, bool wrapData)
/* START BLOCK COMMENT
**	ZafError ZafString::Increment(ZafData *, bool)
END BLOCK COMMENT */
{
/* START BLOCK COMMENT
**		// This class has no increment capabilities.
**		return (ZAF_ERROR_INVALID_CLASS);
END BLOCK COMMENT */

	if (!ValidDelta(delta))
		return (ZAF_ERROR_INVALID_CLASS);

	ZafData *myData = DataPtr();
	ZafData *oldData = DynamicDataPtr();

	IncrementData(myData, delta);

	if (Validate(false) != ZAF_ERROR_NONE)
	{
		const ZafIChar *rangeText = RangeText();
		ZafIChar minNumber[ZAF_STRING_DATA_LENGTH];
		ZafIChar maxNumber[ZAF_STRING_DATA_LENGTH];
		bool done = false;

		if (wrapData && rangeText)
		{
			ZafData *minVal = DynamicDataPtr();
			ZafData *maxVal = DynamicDataPtr();

			while (!done)
			{
				rangeText = ParseRange(rangeText, minNumber, maxNumber);
				SetValue(minVal, minNumber, OutputFormatText());
				SetValue(maxVal, maxNumber, OutputFormatText());
				if (*maxNumber && Compare(myData, maxVal) > 0 && rangeText)
					continue;
				else if (*minNumber && Compare(myData, minVal) < 0)
				{
					SetValue(myData, minVal);
					done = true;
				}
				else if (!rangeText)
				{
					ParseRange(RangeText(), minNumber, maxNumber);
					if (*minNumber)
						SetValue(myData, minNumber, OutputFormatText()); // update is automatic.
					else
						SetValue(myData, oldData); // update is automatic.
					done = true;
				}

			}
			delete maxVal;
			delete minVal;
		}
		else
			SetValue(myData, oldData); // update is automatic.
		SetError(ZAF_ERROR_NONE);
	}
	delete oldData;

	// Return success.
	return (ZAF_ERROR_NONE);
}

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

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

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

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

const ZafIChar *ZafString::ParseRange(const ZafIChar *buffer, ZafIChar *minValue, ZafIChar *maxValue)
{
	// Parse the minimum value.
	int position = 0, offset = 0;
	while (buffer[offset] != '\0' && buffer[offset] != '\n' &&
		(buffer[offset] != '.' || buffer[offset+1] != '.'))
		minValue[position++] = buffer[offset++];
	minValue[position] = '\0';

	// See if it is a standalone value.
	if (buffer[offset] == '\0' || buffer[offset] == '\n')
	{
		strcpy(maxValue, minValue);
		return (buffer[offset] ? &buffer[++offset] : ZAF_NULLP(ZafIChar));
	}

	// Increment the offset.
	while (buffer[offset] == '.')
		offset++;

	// Parse the maximum value.
	position = 0;
	while (buffer[offset] != '\0' && buffer[offset] != '\n')
		maxValue[position++] = buffer[offset++];
	maxValue[position] = '\0';

	// Return the offset position.
	return (buffer[offset] ? &buffer[++offset] : ZAF_NULLP(ZafIChar));
}

const ZafIChar *ZafString::Text(void)
{
	// Get the os text.
	OSGetText();
	return (stringData->Text());
}

ZafError ZafString::Validate(bool processError)
{
	// Check for an absolute number error. Don't set the error member to ZAF_ERROR_NONE.
	ZafIChar *stringValue = DynamicText();
	ZafData *currentValue = DynamicDataPtr();
	error = SetValue(currentValue, stringValue, InputFormatText());

	// Check for a range error.
	if (RangeText() && error == ZAF_ERROR_NONE)
		error = ZAF_ERROR_OUT_OF_RANGE;
	int numRanges = 0;
	ZafData *low = DynamicDataPtr();
	ZafData *high = DynamicDataPtr();
	ZafIChar minValue[ZAF_STRING_DATA_LENGTH];
	ZafIChar maxValue[ZAF_STRING_DATA_LENGTH];
//	ZafIChar newValue[ZAF_STRING_DATA_LENGTH];
	ZafIChar rBuffer[1024]; // Localized range string for error messages.
	rBuffer[0] = '\0';
	for (const ZafIChar *tRange = RangeText(); tRange && error == ZAF_ERROR_OUT_OF_RANGE; numRanges++)
	{
		tRange = ParseRange(tRange, minValue, maxValue);
		SetValue(low, minValue, OutputFormatText());
		SetValue(high, maxValue, OutputFormatText());
		if ((!minValue[0] || Compare(currentValue, low) >= 0) &&
			(!maxValue[0] || Compare(currentValue, high) <= 0))
			error = ZAF_ERROR_NONE;
		else if (processError)
		{
			if (rBuffer[0])
				strcat(rBuffer, rangeSeparator);
			if (minValue[0])
				GetValue(low, &rBuffer[strlen(rBuffer)], ZAF_STRING_DATA_LENGTH, OutputFormatText());
			if (RangeErrorSeparator())
				strcat(rBuffer, RangeErrorSeparator());
			if (maxValue[0])
				GetValue(high, &rBuffer[strlen(rBuffer)], ZAF_STRING_DATA_LENGTH, OutputFormatText());
		}
	}

	// Process the error code.
	if (error == ZAF_ERROR_NONE)
	{
		delete currentValue;
		delete low;
		delete high;
		delete []stringValue;
		return (error);
	}
	else
	{
		// Keep the error code.
		if (!processError || !zafErrorSystem || !numRanges)
		{
			// Restore the original number.
			RestoreText();
			//integerData->FormattedText(newValue, ZAF_STRING_DATA_LENGTH, OutputFormatText());
			//stringData->SetText(newValue);
			delete currentValue;
			delete low;
			delete high;
			delete []stringValue;
			return (error);
		}
		else if (error == ZAF_ERROR_OUT_OF_RANGE && numRanges == 1)
		{
			// Check for open-ended range errors.
			if (minValue[0] && !maxValue[0])
			{
				error = ZAF_ERROR_LESS_THAN_RANGE;
				GetValue(low, rBuffer, ZAF_STRING_DATA_LENGTH, OutputFormatText());
			}
			else if (!minValue[0] && maxValue[0])
			{
				error = ZAF_ERROR_GREATER_THAN_RANGE;
				GetValue(high, rBuffer, ZAF_STRING_DATA_LENGTH, OutputFormatText());
			}
		}
	}

	// Generate the error message and wait for a response.
	ZafIChar *title = ZafLanguageManager::blankString;
	ZafIChar *errorString = ErrorString((ZafNumberID)error, true);
	if (strlen(errorString) + strlen(stringValue) > 1000)
		stringValue[1000 - strlen(errorString)] = '\0';
	if (errorString &&
		zafErrorSystem->ReportError(this, title, (ZafDialogFlags)(allowInvalid ?
		ZAF_DIALOG_OK | ZAF_DIALOG_CANCEL : ZAF_DIALOG_CANCEL), errorString,
		stringValue, rBuffer) == S_DLG_OK)
		error = ZAF_ERROR_LEAVE_INVALID; // Keep the new value.
	delete currentValue;
	delete low;
	delete high;
	delete []stringValue;
	return (error);
}

// ----- Attributes ---------------------------------------------------------

bool ZafString::SetAllowInvalid(bool tAllowInvalid)
{
	allowInvalid = tAllowInvalid;

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

bool ZafString::SetAutoClear(bool tAutoClear)
{
	// Make sure the attribute has changed.
	if (autoClear != tAutoClear)
		autoClear = tAutoClear;

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

ZafCoordinateType ZafString::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);
}

ZafHzJustify ZafString::SetHzJustify(ZafHzJustify setHzJustify)
{
	// Make sure the request is valid.
	if (!screenID && hzJustify != setHzJustify)
		hzJustify = setHzJustify;

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

ZafError ZafString::SetInputFormat(const ZafIChar *setInputFormat)
{
	// Make sure the request is valid.
	if (screenID)
		return (ZAF_ERROR_INVALID);
	
	ZafError retError;

	// Reset the format data.
	if (outputFormatData)
	{
		// The output format is always the first input format.
		ZafStringData tempString;
		ZafIChar *outFormat = outputFormatData->DynamicText();
		ZafIChar *inFormat = strdup(setInputFormat);
	 	ZafIChar *outputPos = strstr(inFormat, outFormat);
		int length = outputFormatData->Length();

		if (outputPos == inFormat && (outputPos[length] == '\n' ||
			outputPos[length] == '\0'))
		{
			if (inputFormatData)
				retError = inputFormatData->SetText(setInputFormat);
			else
				retError = SetInputFormatData(new ZafStringData(setInputFormat));
		}
		else if (!outputPos)
		{
		 	tempString += *outputFormatData;
		 	tempString += ZAF_ITEXT("\n");
			tempString += setInputFormat;
			if (inputFormatData)
				retError = inputFormatData->SetText(tempString.Text());
			else
				retError = SetInputFormatData(new ZafStringData(tempString));
		}
		else
		{
			bool found = (outputPos[-1] == '\n' && (outputPos[length] == '\n' ||
				outputPos[length] == '\0'));
			while (!found && outputPos)
			{
				outputPos += length;
				outputPos = strstr(outputPos, outFormat);
				found = (outputPos && outputPos[-1] == '\n' &&
					(outputPos[length] == '\n' ||	outputPos[length] == '\0'));
			}
			if (found)
				*outputPos = '\0';
			ZafStringData newInput(inFormat);
			if (found &&outputPos[length])
					newInput += &outputPos[length + 1];
		 	tempString += *outputFormatData;
			tempString += ZAF_ITEXT("\n");
			tempString += newInput;
			if (inputFormatData)
				retError = inputFormatData->SetText(tempString.Text());
			else
				retError = SetInputFormatData(new ZafStringData(tempString));

		}
		delete []outFormat;
		delete []inFormat;
	}
	else
	{
		if (inputFormatData)
			retError = inputFormatData->SetText(setInputFormat);
		else
			retError = SetInputFormatData(new ZafStringData(setInputFormat));
	}


	return (retError);
}

ZafError ZafString::SetInputFormatData(ZafStringData *tInputFormatData)
{
	// Make sure the request is valid.
	if (screenID)
		return (ZAF_ERROR_INVALID);

	// Reset the string data.
	if (inputFormatData && inputFormatData != tInputFormatData &&
		inputFormatData->Destroyable() && inputFormatData->NotifyCount() == 0)
		delete inputFormatData;
	inputFormatData = tInputFormatData;
	return (ZAF_ERROR_NONE);
}

bool ZafString::SetInvalid(bool setInvalid)
{
	// Make sure the request is valid.
	if (invalid != setInvalid)
		invalid = setInvalid;
	return (invalid);
}

bool ZafString::SetLowerCase(bool setLowerCase)
{
	// Make sure the request is valid.
	if (lowerCase != setLowerCase && !screenID)
	{
		lowerCase = setLowerCase;
		if (lowerCase && upperCase)
			upperCase = false;
	}

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

ZafError ZafString::SetOutputFormat(const ZafIChar *setOutputFormat)
{
	// Make sure the request is valid.
	if (screenID)
		return (ZAF_ERROR_INVALID);

	ZafError retError;

	// Reset the format data.
	if (outputFormatData)
		retError = outputFormatData->SetText(setOutputFormat);
	else
		retError = SetOutputFormatData(new ZafStringData(setOutputFormat));

	// Reset the input format with outputFormatData->Text() as the first format.
	if (inputFormatData)
		SetInputFormat(inputFormatData->Text());
	else
		SetInputFormat(outputFormatData->Text());

	return (retError);
}

ZafError ZafString::SetOutputFormatData(ZafStringData *tOutputFormatData)
{
	// Make sure the request is valid.
	if (screenID)
		return (ZAF_ERROR_INVALID);

	// Reset the string data.
	if (outputFormatData && outputFormatData != tOutputFormatData &&
		outputFormatData->Destroyable() && outputFormatData->NotifyCount() == 0)
		delete outputFormatData;
	outputFormatData = tOutputFormatData;
	return (ZAF_ERROR_NONE);
}

bool ZafString::SetPassword(bool setPassword)
{
	// Make sure the request is valid.
	if (password != setPassword && !screenID)
		password = setPassword;

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

ZafError ZafString::SetRange(const ZafIChar *setRange)
{
	// Reset the range data.
	if (rangeData)
		return (rangeData->SetText(setRange));
	return (SetRangeData(new ZafStringData(setRange)));
}

ZafError ZafString::SetRangeData(ZafStringData *tRangeData)
{
	// Reset the range data.
	if (rangeData && rangeData != tRangeData &&
		rangeData->Destroyable() && rangeData->NotifyCount() == 0)
		delete rangeData;
	rangeData = tRangeData;
	return (ZAF_ERROR_NONE);
}

bool ZafString::SetReportInvalid(bool tReportInvalid)
{
	reportInvalid = tReportInvalid;

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

ZafError ZafString::SetStringData(ZafStringData *tStringData)
{
	// Remove the data notification.
	if (stringData)
		stringData->SubtractNotification(this, (ZafUpdateFunction)Update);

	// Reset the string data.
	if (stringData && stringData != tStringData &&
		stringData->Destroyable() && stringData->NotifyCount() == 0)
		delete stringData;
	stringData = tStringData ? tStringData : new ZafStringData;

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

ZafError ZafString::SetText(const ZafIChar *text)
{
	// Set the OS text.
	stringData->SetText(text);
	unanswered = (text && *text) ? false : true;
	return (ZAF_ERROR_NONE);
}

bool ZafString::SetUnanswered(bool setUnanswered)
{
	// Make sure the request is valid.
	if (unanswered != setUnanswered)
	{
		// Re-compute the text before resetting the flag.
		if (setUnanswered)
			stringData->Clear();

		unanswered = setUnanswered;
	}

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

bool ZafString::SetUpperCase(bool setUpperCase)
{
	// Make sure the request is valid.
	if (upperCase != setUpperCase && !screenID)
	{
		upperCase = setUpperCase;
		if (upperCase && lowerCase)
			lowerCase = false;
	}

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

bool ZafString::SetVariableName(bool setVariableName)
{
	// Check for equivalent flag.
	if (variableName != setVariableName && !screenID)
		variableName = setVariableName;
	return (variableName);
}

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

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

ZafStringData *ZafString::StringData(void) const
{
	return (stringData);
}

ZafError ZafString::Update(ZafString *string, ZafUpdateType type)
{
	ZafError retVal = ZAF_ERROR_INVALID;
	if (type & ZAF_UPDATE_OBJECT)
		retVal = (string->OSSetText());
	if (type & ZAF_UPDATE_DATA)
		retVal = (string->OSGetText());
	return (retVal);
}

// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
ZafString::ZafString(const ZafIChar *name, ZafObjectPersistence &persist) :
	ZafWindowObject(name, persist.PushLevel(className, classID, ZAF_PERSIST_DIRECTORY)),
	inputFormatData(ZAF_NULLP(ZafStringData)),
	outputFormatData(ZAF_NULLP(ZafStringData)),
	rangeData(ZAF_NULLP(ZafStringData)), newData(false),
	stringData(ZAF_NULLP(ZafStringData))
{
#if defined(ZAF_INDEPENDENT) || defined(ZAF_CURSES)
	cursor = firstDisplayedChar = 0;
	beginMark = endMark = -1;
#endif
	// Initialize the string information.
	memberUserFunction = (MemberUserFunction)&ZafString::DefaultValidateFunction;

	// Read the data.
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafString::ReadData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
}

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

void ZafString::ReadData(ZafObjectPersistence &persist)
{
	// Read the data.
	ZafUInt16 flag1, flag2;
	ZafIChar stringName[ZAF_MAXNAMELEN], inputFormatName[ZAF_MAXNAMELEN];
	ZafIChar outputFormatName[ZAF_MAXNAMELEN], rangeName[ZAF_MAXNAMELEN];
	ZafFile *file = persist.CurrentFile();
	*file >> flag1 >> flag2 >> stringName >> inputFormatName >> outputFormatName >> rangeName;
	autoClear = (flag1 & 0x0001) ? true : false;
	invalid = (flag1 & 0x0002) ? true : false;
	unanswered = (flag1 & 0x0004) ? true : false;
	lowerCase = (flag1 & 0x0008) ? true : false;
	password = (flag1 & 0x0010) ? true : false;
	upperCase = (flag1 & 0x0020) ? true : false;
	variableName = (flag1 & 0x0040) ? true : false;
	viewOnly = (flag1 & 0x0080) ? true : false;
	allowInvalid = (flag1 & 0x0100) ? true : false;
	reportInvalid = (flag1 & 0x0200) ? true : false;
	hzJustify = (ZafHzJustify)((int)flag2 & 0x000F);

	ZafStringData *tempStringData;
	// Read the string data.
	if (*stringName)
		SetStringData(new ZafStringData(stringName, persist));
	if (*inputFormatName)
	{
		tempStringData = new ZafStringData(inputFormatName, persist);
		SetInputFormat(tempStringData->Text());
		delete tempStringData;
	}
	if (*outputFormatName)
	{
		tempStringData  = new ZafStringData(outputFormatName, persist);
		SetOutputFormat(tempStringData->Text());
		delete tempStringData;
	}
	if (*rangeName)
		rangeData = new ZafStringData(rangeName, persist);
}

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

void ZafString::WriteData(ZafObjectPersistence &persist)
{
	// Write the data.
	ZafUInt16 flag1 = 0, flag2 = 0;
	flag1 |= (ZafUInt16)(autoClear ? 0x0001 : 0);
	flag1 |= (ZafUInt16)(invalid ? 0x0002 : 0);
	flag1 |= (ZafUInt16)(unanswered ? 0x0004 : 0);
	flag1 |= (ZafUInt16)(lowerCase ? 0x0008 : 0);
	flag1 |= (ZafUInt16)(password ? 0x0010 : 0);
	flag1 |= (ZafUInt16)(upperCase ? 0x0020 : 0);
	flag1 |= (ZafUInt16)(variableName ? 0x0040 : 0);
	flag1 |= (ZafUInt16)(viewOnly ? 0x0080 : 0);
	flag1 |= (ZafUInt16)(allowInvalid ? 0x0100 : 0);
	flag1 |= (ZafUInt16)(reportInvalid ? 0x0200 : 0);
	flag2 |= (ZafUInt16)(hzJustify & 0x000F);
	const ZafIChar *stringName = stringData ? stringData->StringID() : ZAF_NULLP(ZafIChar);
	const ZafIChar *inputFormatName = inputFormatData ? inputFormatData->StringID() : ZAF_NULLP(ZafIChar);
	const ZafIChar *outputFormatName = outputFormatData ? outputFormatData->StringID() : ZAF_NULLP(ZafIChar);
	const ZafIChar *rangeName = rangeData ? rangeData->StringID() : ZAF_NULLP(ZafIChar);
	ZafFile *file = persist.CurrentFile();
	*file << flag1 << flag2 << stringName << inputFormatName << outputFormatName << rangeName;

	// Write the string data.
	if (stringData)
		stringData->Write(persist);
	if (inputFormatData)
		inputFormatData->Write(persist);
	if (outputFormatData)
		outputFormatData->Write(persist);
	if (rangeData)
		rangeData->Write(persist);
}
#endif

// -1, 0, 1
int ZafString::Compare(ZafData *value1, ZafData *value2)
{
	ZafStringData *str1 = DynamicPtrCast(value1, ZafStringData);
	ZafStringData *str2 = DynamicPtrCast(value2, ZafStringData);

	return (strcmp(*str1, *str2));
}

ZafIChar *ZafString::DynamicText(void)
{
	return (stringData->DynamicText());
}

ZafData *ZafString::DynamicDataPtr(void)
{
	return (new ZafStringData(*stringData));
}

ZafIChar *ZafString::ErrorString(ZafNumberID, bool)
{
	return (0);
}

int ZafString::GetValue(ZafData *data, ZafIChar *text, int maxLength,
	const ZafIChar *)
{
	ZafStringData *str = DynamicPtrCast(data, ZafStringData);

	strncpy(text, str->Text(), (size_t)maxLength);

	return (maxLength);
}

const ZafIChar *ZafString::RangeErrorSeparator(void)
{
	return (0);
}

ZafError ZafString::RestoreText(void)
{
	OSSetText();
	return (ZAF_ERROR_NONE);
}

ZafError ZafString::SetValue(ZafData *data, ZafIChar *text, const ZafIChar *)
{
	ZafStringData *str = DynamicPtrCast(data, ZafStringData);

	return (str->SetText(text));
}

ZafError ZafString::DecrementData(ZafData *, ZafData *)
{
	return (ZAF_ERROR_INVALID);
}

ZafError ZafString::IncrementData(ZafData *, ZafData *)
{
	return (ZAF_ERROR_INVALID);
}

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

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

	*dest = *source;

	return (ZAF_ERROR_NONE);
}

bool ZafString::ValidDelta(ZafData *)
{
	return (false);
}

ZafData *ZafString::DataPtr(void)
{
	return (stringData);
}


