/*
  File: include/ioutils/Interface_XML.h
  Description: XMLParse definition header
  Part of the Mantis project
  (c) 2002 Lycos Inc.
  Author(s): Nicholas Vinen
  Editor(s): Andrew McCann 

  This file is distributed for the sole purpose of allowing you to write
  software to interface with Sonique 2 and other Mantis programs. It is
  not to be modified or used for any other purpose without written
  authorization.

  If you redistribute this file, it must be in the original package
  complete with all other files provided, including the usage agreement.

  Do not remove this notice.
*/

#ifndef _INTERFACE_XML_H_
#define _INTERFACE_XML_H_

#ifdef DEBUG_INCLUDE_ORDER
#pragma message("Including " __FILE__ "\n" )
#endif


#if _MSC_VER > 1000
#pragma once
#endif


#include "mgeneric.h"
#include "charstring.h"
#include "filesys.h"
#include "Interface_ErrorSys.h"


#ifndef COMPILE_WITHOUT_MIA
// {A111ECF7-22DE-4109-A0B0-F1C12F6B97B4}
DEFINE_MID( MID_XML_PARSER,0xa111ecf7, 0x22de, 0x4109, 0xa0, 0xb0, 0xf1, 0xc1, 0x2f, 0x6b, 0x97, 0xb4);

#endif


template <class CHARTYPE, class NAMETYPE>
class TMXMLAttribute
{
public:
	TString<NAMETYPE> Name;
	TString<CHARTYPE> Value;
	int32 Line;
};
typedef TMXMLAttribute<wchar_t,char> MXMLAttribute;

typedef enum {
	XMLStyle_Compact			= 1,
	XMLStyle_UltraCompact		= 2,
	XMLStyle_Long				= 3,
	XMLStyle_Mask				= 3,
	XMLStyle_ReconstituteFormat	= 4,
	XMLStyle_StripWhiteSpace	= 16,
	XMLStyle_MinimiseWhiteSpace	= 32,
	XMLStyle_UseEntities		= 64,
} XMLStyle;

class XMLIncludeHelper
{
public:
    virtual MRESULT __stdcall GetInclude(const wchar_t* wcName, void** ppToHere, uint32* LenToHere) = 0;
    virtual void    __stdcall FreeInclude(const wchar_t* wcName, void* pData, uint32 Len)           = 0;
};

typedef enum { Line_Begin, Line_End, Line_Contents } LineSpec;
typedef enum { TagType_DocRoot = 1, TagType_Normal = 2, TagType_Closing = 3, TagType_ProcessingInstruction = 4, TagType_All = 5 } TagType;
template <class CHARTYPE, class NAMETYPE>
class TMXMLItem : public MGeneric
{
public:
	virtual													__stdcall operator const CHARTYPE* () const																							= 0;
	virtual		TString<NAMETYPE>							__stdcall GetName() const																											= 0;
	virtual		TString<NAMETYPE>							__stdcall SetName(const TString<NAMETYPE>& Name)																					= 0;
	virtual		TString<CHARTYPE>							__stdcall GetContents() const																										= 0;
	virtual		TString<CHARTYPE>							__stdcall SetContents(const TString<CHARTYPE>& Contents)																			= 0;
	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall GetParent() const																											= 0;
	virtual		int32										__stdcall GetCount(TagType type = TagType_Normal) const																											= 0;
	virtual		int32										__stdcall GetCount(const NAMETYPE* TagName, TagType type = TagType_Normal ) const													= 0;
	virtual		int32										__stdcall GetCount(const NAMETYPE* TagName, const NAMETYPE* AttributeName, const CHARTYPE* AttributeValue, TagType type = TagType_Normal) const					= 0;
	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall GetItem(int32 Index, TagType type = TagType_Normal) const																								= 0;
	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall GetItem(const NAMETYPE* TagName, int32 Index = 0, TagType type = TagType_Normal) const																= 0;
	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall GetItem(const NAMETYPE* TagName, const NAMETYPE* AttributeName, const CHARTYPE* AttributeValue, int32 Index = 0,  TagType type = TagType_Normal) const	= 0;
	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall GetNextItem(const TMXMLItem<CHARTYPE,NAMETYPE>* Item) const																= 0;
	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall InsertItem(const NAMETYPE* Name, TagType Type = TagType_Normal, int32 Index = -1)											= 0;
	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall InsertItem(const NAMETYPE* Name, const CHARTYPE* Contents, TagType Type = TagType_Normal, int32 Index = -1)				= 0;
	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall InsertItem(const TMXMLItem<CHARTYPE,NAMETYPE>* Item, int32 Index = -1)													= 0;
	virtual		int32										__stdcall RemoveItem(int32 Index = 0, TagType type = TagType_Normal)																								= 0;
	virtual		int32										__stdcall RemoveItem(const CHARTYPE* Name, int32 Index = 0, TagType type = TagType_Normal)																			= 0;
	virtual		int32										__stdcall RemoveItem(const TMXMLItem<CHARTYPE,NAMETYPE>* Item)																		= 0;
	virtual		int32										__stdcall RemoveItem(const NAMETYPE* Name, const NAMETYPE* AttributeName, const CHARTYPE* AttributeValue, int32 Index = 0, TagType type = TagType_Normal)			= 0;
	virtual		int32										__stdcall GetAttributeCount() const																									= 0;
	virtual		TMXMLAttribute<CHARTYPE,NAMETYPE>*			__stdcall GetAttribute(int32 Index) const																							= 0;
	virtual		TMXMLAttribute<CHARTYPE,NAMETYPE>*			__stdcall GetAttribute(const NAMETYPE* AttributeName) const																			= 0;
	virtual		TMXMLAttribute<CHARTYPE,NAMETYPE>*			__stdcall GetNextAttribute(const TMXMLAttribute<CHARTYPE,NAMETYPE>* Attr) const														= 0;
	virtual		TMXMLAttribute<CHARTYPE,NAMETYPE>*			__stdcall InsertAttribute(int32 Index = -1)																							= 0;
	virtual		TMXMLAttribute<CHARTYPE,NAMETYPE>*			__stdcall InsertAttribute(const NAMETYPE* Name, const CHARTYPE* Value, int32 Index = -1)											= 0;
	virtual		int32										__stdcall RemoveAttribute(int32 Index = 0)																							= 0;
	virtual		int32										__stdcall RemoveAttribute(const NAMETYPE* Name)																						= 0;
	virtual		int32										__stdcall PrintToASCII(AString& Dest, XMLStyle Style = XMLStyle_Long) const															= 0;
	virtual		int32										__stdcall PrintToUnicode(WString& Dest, XMLStyle Style = XMLStyle_Long) const														= 0;
	//returns the line on which the '<' character at the start of the tag which begins/ends this tag exists
	virtual		int32										__stdcall GetLine(LineSpec Which) const																								= 0;
	virtual		TagType										__stdcall GetType() const																											= 0;
	virtual		int32										__stdcall GetOriginalInsertionPoint() const																							= 0;

	virtual		TString<CHARTYPE>							__stdcall Escape(const TString<CHARTYPE>& String, bool UseEntities = false, bool UseCData = false) const							= 0;
	virtual		TString<CHARTYPE>							__stdcall Unescape(const TString<CHARTYPE>& String) const																			= 0;

//	virtual		TMXMLItem<CHARTYPE,NAMETYPE>*				__stdcall NewItem(const NAMETYPE* Name, const CHARTYPE* Contents, TagType Type = TagType_Normal) const								= 0;


	// attribute value with default
	virtual  WString         __stdcall GetAttributeValue(const NAMETYPE* Name, const CHARTYPE* sDefault = NULL, bool bUnescape = true ) const = 0;
	virtual		int32		 __stdcall GetAttributeValueAs_int32(const NAMETYPE* Name, int32 nDefault = 0 ) const = 0;
	virtual		double		 __stdcall GetAttributeValueAs_double(const NAMETYPE* Name, double rDefault = 0.0 ) const = 0;
	virtual		uint32		 __stdcall GetAttributeValueAs_uint32(const NAMETYPE* Name, uint32 nDefault = 0 ) const = 0;
	virtual		bool		 __stdcall GetAttributeValueAsBool(const NAMETYPE* Name, bool bDefault = false ) const = 0;
	// contents with default
	// default is used when contents are NULL or only whitespace (space/tab/newline)
	virtual		const CHARTYPE*		__stdcall GetContents( const CHARTYPE* sDefault ) const = 0;
	virtual		int32	            __stdcall GetContentsInt( int32 iDefault = 0) const = 0;

};
typedef TMXMLItem<wchar_t,char> MXMLItem;


template <class CHARTYPE>
class MXMLEntity
{
public:
	TString<CHARTYPE> Name;		//the name assigned to this entity
	TString<CHARTYPE> Value;	//the XML expression it represents
	TString<CHARTYPE> String;	//that expression decoded into a string
};

template <class CHARTYPE, class NAMETYPE>
class TMXMLParser : public MGeneric
{
public:
	virtual TMXMLParser<CHARTYPE,NAMETYPE>&	__stdcall operator =(const TMXMLParser<CHARTYPE,NAMETYPE>& Other)					= 0;
	virtual int32							__stdcall Load(IOObject* pIO, int32* ErrorLine = (int32*)NULL, XMLIncludeHelper* pHelper = NULL)	= 0;
	virtual int32							__stdcall Save(IOObject* pIO, bool Unicode = false, XMLStyle Style = (XMLStyle)(XMLStyle_Long|XMLStyle_ReconstituteFormat))	= 0;

	virtual int32							__stdcall GetEntityCount() const													= 0;
	virtual MXMLEntity<CHARTYPE>*			__stdcall GetEntity(int32 Index) const												= 0;
	virtual MXMLEntity<CHARTYPE>*			__stdcall GetEntity(const wchar_t* Name) const										= 0;
	virtual MXMLEntity<CHARTYPE>*			__stdcall GetNextEntity(const MXMLEntity<CHARTYPE>* Entity) const					= 0;
	virtual MXMLEntity<CHARTYPE>*			__stdcall AddEntity(WString Name, WString Value)									= 0;
	virtual int32							__stdcall RemoveEntity(int32 Index = 0)												= 0;
	virtual int32							__stdcall RemoveEntity(const CHARTYPE* Name)										= 0;

	virtual	TMXMLItem<CHARTYPE,NAMETYPE>*	__stdcall GetBaseItem() const														= 0;
};
typedef TMXMLParser<wchar_t,char> MXMLParser;





enum {
	ERR_XML_NONSYMMETRICALTAGS,
	ERR_XML_FILEENDSINTAG,
	ERR_XML_ENDTAGHASPARAMETERS,
	ERR_XML_ENDTAGDOESNTMATCHSTARTTAG,
	ERR_XML_MISSINGATTRIBUTENAME,
	ERR_XML_MALFORMEDTAG,
	ERR_XML_MALFORMEDENTITYTAG,
	ERR_XML_UNKNOWNTAGTYPE,
	ERR_XML_MISMATCHEDENDINGTAG,
	ERR_XML_CONTENTCONTAINSINVALIDCHAR,
	ERR_XML_MALFORMEDMACRODEFINITION,
	ERR_XML_MALFORMEDMACROINSERTION,
	ERR_XML_MALFORMEDMACROPARAMETER,
	ERR_XML_MISSINGMACROPARAMETER,
	ERR_XML_MACRONOTDEFINED,
    ERR_XML_INCLUDENOTSUPPORTED,
	ERR_XML__NUM
};

#define ERR_XML__MODULE "XML Parser"


inline MError* GetXMLErrors(MError* Errors)
{
	Errors[ERR_XML_NONSYMMETRICALTAGS].Name = 			"open/close tags do not have equal count, tag on line %d of file %s still open";
	Errors[ERR_XML_FILEENDSINTAG].Name = 				"XML code ends with an open tag, tag started on line %d of file %s";
	Errors[ERR_XML_ENDTAGHASPARAMETERS].Name = 			"close tags can't have parameters, tag closed on line %d of file %s";
	Errors[ERR_XML_ENDTAGDOESNTMATCHSTARTTAG].Name =	"close tag has different name to open tag, tag opened on line %d of file %s";
	Errors[ERR_XML_MISSINGATTRIBUTENAME].Name = 		"Entity in tag has no name on line %d of file %s";
	Errors[ERR_XML_MALFORMEDTAG].Name = 				"tag does not have valid syntax on line %d of file %s";
	Errors[ERR_XML_MALFORMEDENTITYTAG].Name = 			"entity tag does not have valid syntax on line %d of file %s";
	Errors[ERR_XML_UNKNOWNTAGTYPE].Name = 				"special tag is unrecognised on line %d of file %s";
	Errors[ERR_XML_MISMATCHEDENDINGTAG].Name = 			"close tag type doesn't match open tag type on line %d of file %s";
	Errors[ERR_XML_CONTENTCONTAINSINVALIDCHAR].Name = 	"XML content contains an invalid character ('<') - you must escape all such characters";
	Errors[ERR_XML_MALFORMEDMACRODEFINITION].Name =		"macro definition doesn't have valid syntax";
	Errors[ERR_XML_MALFORMEDMACROINSERTION].Name =		"macro insertion doesn't have valid syntax";
	Errors[ERR_XML_MALFORMEDMACROPARAMETER].Name =		"macro parameter name not properly terminated with close parenthesis (')')";
	Errors[ERR_XML_MISSINGMACROPARAMETER].Name =		"macro parameter not defined during macro insertion";
	Errors[ERR_XML_MACRONOTDEFINED].Name =				"macro insertion requested of macro not yet defined";
	Errors[ERR_XML_INCLUDENOTSUPPORTED].Name =			"this XML parser instance does not have include tag support enabled";

	return Errors;
}




#ifdef DEBUG_INCLUDE_ORDER
#pragma message("Done including " __FILE__ "\n" )
#endif

#endif//_INTERFACE_XML_H_
