/*
 * COPYRIGHT (c) 1993-1995 FRAME TECHNOLOGY CORPORATION
 *
 * This source code contained herein is proprietary and
 * confidential information of Frame Technology Corporation,
 * San Jose, CA and is covered by the U.S. and other copyright
 * and trade secret protection.  Unauthorized adaptation,
 * distribution, use or display is prohibited and may be
 * subject to civil and criminal penalties.  Disclosure to
 * others is prohibited.  For the terms and conditions of
 * source code use refer to your Frame Technology source code
 * license agreement.
 */


#include "fm_sgml.h"
#include "fstrings.h"
#include "fstrlist.h"
#include "fmemory.h"
#include "futils.h"
#include "fcharmap.h"

/*
 * application specific data
 */
typedef struct
{
	BoolT removeLeadingSpaces;
	IntT  inScreen;
	IntT  inLiteralLayout;
} SrAppDataT;


static VoidT validateListType FARGS((SrEventT *eventp, SrConvObjT srObj, StringT attrName));
static BoolT stripLeadingSpaces FARGS((SrConvObjT srObj));
static VoidT compressWhiteSpaces FARGS((SrConvObjT srObj, SrAppDataT *datap));
static VoidT createULinkTextInset FARGS((SrEventT *eventp, SrConvObjT srObj));
static BoolT isSpaceChar FARGS((UIntT c));


/*
 * SGML Reader Event Handler for DOCBOOK
 */
SrwErrorT Sr_EventHandler(eventp, srObj)
SrEventT *eventp;
SrConvObjT srObj;
{
	static SrAppDataT srdata;
	BoolT removeLeadingSpaces;

	removeLeadingSpaces = srdata.removeLeadingSpaces;
	srdata.removeLeadingSpaces = False;

	switch (eventp->evtype)
	{
	case SR_EVT_BEGIN_READER:
	case SR_EVT_BEGIN_BOOK:
	case SR_EVT_BEGIN_BOOK_COMP:
	case SR_EVT_BEGIN_DOC:
		/*
		 * re-initialize data at the beginning of a
		 * session/book/document/book-component.
		 */
		F_ClearPtr(&srdata, sizeof(srdata));
		break;
	case SR_EVT_BEGIN_ELEM:
		/*
		 * "ItemizedList" and "ListItem" attributes need special
		 * validation for the "Mark" and "Override" attributes
		 * respectively.
		 */
		if (F_StrIEqual(eventp->u.tag.gi, "ItemizedList"))
			validateListType(eventp, srObj, (StringT)"Mark");
		else if (F_StrIEqual(eventp->u.tag.gi, "ListItem"))
			validateListType(eventp, srObj, (StringT)"Override");
		/*
		 * Leading spaces in "Para" element should be removed.
		 */
		else if (F_StrIEqual(eventp->u.tag.gi, (StringT)"Para"))
			srdata.removeLeadingSpaces = True;
		/*
		 * Spaces within "Screen" and "LiteralLayout" elements
		 * should be preserved as is.
		 */
		else if (F_StrIEqual(eventp->u.tag.gi, (StringT)"Screen"))
			srdata.inScreen++;
		else if (F_StrIEqual(eventp->u.tag.gi, (StringT)"LiteralLayout"))
			srdata.inLiteralLayout++;
		/*
		 * A "ULink" element should be mapped to a a text inset.
		 */
		else if (F_StrIEqual(eventp->u.tag.gi, (StringT)"ULink"))
		{
			createULinkTextInset(eventp, srObj);
			return(SRW_E_SUCCESS);
		}
		break;
	case SR_EVT_END_ELEM:
		/*
		 * Spaces immediately after a "Screen" or a "LiteralLayout"
		 * element should be removed.
		 */
		if (F_StrIEqual(eventp->u.tag.gi, (StringT)"Screen"))
		{
			srdata.inScreen--;
			srdata.removeLeadingSpaces = True;
		}
		else if (F_StrIEqual(eventp->u.tag.gi, (StringT)"LiteralLayout"))
		{
			srdata.inLiteralLayout--;
			srdata.removeLeadingSpaces = True;
		}
		break;
	case SR_EVT_CDATA:
	case SR_EVT_RE:
		/*
		 * Remove or compress white spaces in text as needed.
		 */
		if (srObj && Sr_GetObjType(srObj) == SR_OBJ_TEXT)
		{
			if (removeLeadingSpaces)
				srdata.removeLeadingSpaces = stripLeadingSpaces(srObj);
			compressWhiteSpaces(srObj, &srdata);
		}
		break;
	default:
		break;
	}

	return Sr_Convert(eventp, srObj);
}


/*
 * "ItemizedList" and "ListItem" attributes need special
 * validation for the "Mark" and "Override" attributes
 * respectively. This implementation of DOCBOOK handles
 * the following values for these attributes:
 *		- Bullet
 *		- Dash
 *		- Box
 *		- Check
 * All other values result in an error message.
 */
static VoidT validateListType(eventp, srObj, attrName)
SrEventT *eventp;
SrConvObjT srObj;
StringT attrName;
{
	F_AttributeT attVal;
	StringT val = NULL;
	IntT i;

	for (i=0; i<eventp->u.tag.sgmlAttrVals.len; i++)
	{
		SgmlAttrValT *sgmlAttrValp = &(eventp->u.tag.sgmlAttrVals.val[i]);
		if (F_StrIEqual(sgmlAttrValp->sgmlAttrName, attrName))
		{
			val = F_StrCopyString(F_StrListGet(sgmlAttrValp->sgmlAttrVal, 0));
			break;
		}
	}

	if (!val)
		return;

	F_StrStripLeadingSpaces(val);
	F_StrStripTrailingSpaces(val);

	if (F_StrIsEmpty(val))
	{
		F_StrFree(val);
		return;
	}

	attVal.name = attrName;
	attVal.values.len = 1;
	attVal.values.val = &val;

	if (F_StrIEqual(val, (StringT)"Bullet"))
		F_StrCpy(val, (StringT)"Bullet");
	else if (F_StrIEqual(val, (StringT)"Dash"))
		F_StrCpy(val, (StringT)"Dash");
	else if (F_StrIEqual(val, (StringT)"Box"))
		F_StrCpy(val, (StringT)"Box");
	else if (F_StrIEqual(val, (StringT)"Check"))
		F_StrCpy(val, (StringT)"Check");
	else
	{
		/*
		 * TODO: log an error message
		 */
	}

	Sr_SetAttrVal(srObj, &attVal);
	F_StrFree(val);
}


/*
 * Strips leading spaces. Returns "True" if the text string is empty or
 * if it contains spaces only. Returns "False" otherwise.
 */
static BoolT stripLeadingSpaces(srObj)
SrConvObjT srObj;
{
	StringT s, t;
	BoolT rc;

	s = Sr_GetFmText(srObj);
	if (F_StrIsEmpty(s))
		rc = True;
	else
	{
		t = s;
		while (*t && isSpaceChar(*t))
			t++;
		Sr_SetFmText(srObj, t);
		rc = F_StrIsEmpty(t);
	}

	F_StrFree(s);
	return(rc);
}


/*
 * Compress white spaces based on current context.
 */
static VoidT compressWhiteSpaces(srObj, datap)
SrConvObjT srObj;
SrAppDataT *datap;
{
	StringT s;
	IntT i, j;

	if (datap->inScreen || datap->inLiteralLayout)
		return;

	/*
	 * get text string from the object.
	 */
	s = Sr_GetFmText(srObj);
	if (F_StrIsEmpty(s))
	{
		F_StrFree(s);
		return;
	}

	/*
	 * compress multiple spaces
	 */
	for (i=j=0; s[i];)
	{
		s[j] = s[i];
		if (!s[i])
			break;

		if (isSpaceChar(s[i]))
		{
			while (s[i] && isSpaceChar(s[i]))
				i++;
		}
		else
			i++;
		j++;
	}
	s[j] = s[i];

	/*
	 * if last character in the string is a space
	 * character, we need to strip any leading space
	 * characters in any immediately following string.
	 */
	if (!F_StrIsEmpty(s) && isSpaceChar(s[F_StrLen(s) - 1]))
		datap->removeLeadingSpaces = True;

	/*
	 * post back the altered string to the text object.
	 */
	Sr_SetFmText(srObj, s);
	F_StrFree(s);
}


/*
 * create a text inset to the file referenced by the URL attribute.
 */
static VoidT createULinkTextInset(eventp, srObj)
SrEventT *eventp;
SrConvObjT srObj;
{
	F_PropValsT props, *retprops = NULL;
	FilePathT *fpSgml, *fp, *srcDirPath;
	StringT filename = NULL;
	F_ElementLocT eloc;
	F_TextLocT tloc;
	SrConvObjT parentObj, docObj;
	F_ObjHandleT docId;
	IntT i, err;
	BoolT smartQuotes;

	for (i=0; i<eventp->u.tag.sgmlAttrVals.len; i++)
	{
		if (F_StrIEqual(eventp->u.tag.sgmlAttrVals.val[i].sgmlAttrName,
						(StringT)"URL"))
		{
			filename = F_StrCopyString(F_StrListGet(
					eventp->u.tag.sgmlAttrVals.val[i].sgmlAttrVal, 0));
			break;
		}
	}

	if (!filename)
		return;

	docObj = Sr_GetCurConvObjOfType(SR_OBJ_DOC);
	if (!docObj)
	{
		docObj = Sr_GetCurConvObjOfType(SR_OBJ_BOOK_COMP);
		if (!docObj)
			goto done;
	}
	docId = Sr_GetDocId(docObj);

	parentObj = Sr_GetParentConvObj(srObj);
	while (parentObj && !(eloc.parentId = Sr_GetFmElemId(parentObj)))
		parentObj = Sr_GetParentConvObj(parentObj);
	if (!docId || !eloc.parentId)
		goto done;

	eloc.childId = 0;
	eloc.offset = 0;
	tloc = F_ApiElementLocToTextLoc(docId, &eloc);
	if (!tloc.objId)
		goto done;

	/*
	 * If filepath is relative, it is assumed to be present in the
	 * same directory as the SGML source document.
	 */
	fpSgml = Srw_GetSgmlDocFilePath();
	if (!fpSgml)
		goto done;
	srcDirPath = F_FilePathParent(fpSgml, &err);
	F_FilePathFree(fpSgml);
	if (!srcDirPath)
		goto done;

	fp = F_PathNameToFilePath(filename, srcDirPath, FDefaultPath);
	F_FilePathFree(srcDirPath);
	if (fp)
	{
		F_StrFree(filename);
		filename = F_FilePathToPathName(fp, FDefaultPath);
		F_FilePathFree(fp);
	}

	props = F_ApiGetImportDefaultParams();
	i = F_ApiGetPropIndex(&props, FS_ForceImportAsText);
	props.val[i].propVal.u.ival = True;
	smartQuotes = F_ApiGetInt(FV_SessionId, docId, FP_SmartQuotes);
	F_ApiSetInt(FV_SessionId, docId, FP_SmartQuotes, False);
	F_ApiImport(docId, &tloc, filename, &props, &retprops);
	F_ApiSetInt(FV_SessionId, docId, FP_SmartQuotes, smartQuotes);
	F_ApiDeallocatePropVals(&props);
	F_ApiDeallocatePropVals(retprops);

  done:
	F_StrFree(filename);
}

static BoolT isSpaceChar(c)
UIntT c;
{
	return(c == FC_SPACE || c == FC_TAB);
}

