#define ASCRIPT_DLL_MODULE
//-----------------------------------------------------------------------------
// AScript xml module
//-----------------------------------------------------------------------------
#include "AScript.h"
#include "Expr.h"
#include "expat.h"

AScript_BeginModule(xml)

AScript_DeclarePrivSymbol(StartElement);
AScript_DeclarePrivSymbol(EndElement);
AScript_DeclarePrivSymbol(CharacterData);
AScript_DeclarePrivSymbol(ProcessingInstruction);
AScript_DeclarePrivSymbol(Comment);
AScript_DeclarePrivSymbol(StartCdataSection);
AScript_DeclarePrivSymbol(EndCdataSection);
AScript_DeclarePrivSymbol(Default);
AScript_DeclarePrivSymbol(DefaultExpand);
AScript_DeclarePrivSymbol(ExternalEntityRef);
AScript_DeclarePrivSymbol(SkippedEntity);
AScript_DeclarePrivSymbol(StartNamespaceDecl);
AScript_DeclarePrivSymbol(EndNamespaceDecl);
AScript_DeclarePrivSymbol(XmlDecl);
AScript_DeclarePrivSymbol(StartDoctypeDecl);
AScript_DeclarePrivSymbol(EndDoctypeDecl);
AScript_DeclarePrivSymbol(ElementDecl);
AScript_DeclarePrivSymbol(AttlistDecl);
AScript_DeclarePrivSymbol(EntityDecl);
AScript_DeclarePrivSymbol(NotationDecl);
AScript_DeclarePrivSymbol(NotStandalone);

AScript_DeclareClass(Parser);

class Parser {
private:
	XML_Parser _parser;
public:
	Parser();
	virtual ~Parser();
	void Parse(Signal sig, File &file);
	inline void StopParser() { ::XML_StopParser(_parser, XML_FALSE); }
private:
	static void XMLCALL StartElementHandler(void *userData, const XML_Char *name, const XML_Char **atts);
	static void XMLCALL EndElementHandler(void *userData, const XML_Char *name);
	static void XMLCALL CharacterDataHandler(void *userData, const XML_Char *s, int len);
	static void XMLCALL ProcessingInstructionHandler(void *userData, const XML_Char *target, const XML_Char *data);
	static void XMLCALL CommentHandler(void *userData, const XML_Char *data);
	static void XMLCALL StartCdataSectionHandler(void *userData);
	static void XMLCALL EndCdataSectionHandler(void *userData);
	static void XMLCALL DefaultHandler(void *userData, const XML_Char *s, int len);
	static void XMLCALL DefaultHandlerExpand(void *userData, const XML_Char *s, int len);
	static int  XMLCALL ExternalEntityRefHandler(XML_Parser p, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId);
	static void XMLCALL SkippedEntityHandler(void *userData, const XML_Char *entityName, int isParameterEntity);
	static int  XMLCALL UnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name, XML_Encoding *info);
	static void XMLCALL StartNamespaceDeclHandler(void *userData, const XML_Char *prefix, const XML_Char *uri);
	static void XMLCALL EndNamespaceDeclHandler(void *userData, const XML_Char *prefix);
	static void XMLCALL XmlDeclHandler(void *userData, const XML_Char *version, const XML_Char *encoding, int standalone);
	static void XMLCALL StartDoctypeDeclHandler(void *userData, const XML_Char *doctypeName, const XML_Char *systemId, const XML_Char *publicId, int hasInternalSubset);
	static void XMLCALL EndDoctypeDeclHandler(void *userData);
	static void XMLCALL ElementDeclHandler(void *userData, const XML_Char *name, XML_Content *model);
	static void XMLCALL AttlistDeclHandler(void *userData, const XML_Char *elname, const XML_Char *attname, const XML_Char *attType, const XML_Char *dflt, int isRequired);
	static void XMLCALL EntityDeclHandler(void *userData, const XML_Char *entityName, int isParameterEntity, const XML_Char *value, int valueLength, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName);
	static void XMLCALL NotationDeclHandler(void *userData, const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId);
	static int  XMLCALL NotStandaloneHandler(void *userData);
	virtual void OnStartElement(const XML_Char *name, const XML_Char **atts) = 0;
	virtual void OnEndElement(const XML_Char *name) = 0;
	virtual void OnCharacterData(const XML_Char *s, int len) = 0;
	virtual void OnProcessingInstruction(const XML_Char *target, const XML_Char *data) = 0;
	virtual void OnComment(const XML_Char *data) = 0;
	virtual void OnStartCdataSection() = 0;
	virtual void OnEndCdataSection() = 0;
	virtual void OnDefault(const XML_Char *s, int len) = 0;
	virtual void OnDefaultExpand(const XML_Char *s, int len) = 0;
	virtual int  OnExternalEntityRef(XML_Parser p, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) = 0;
	virtual void OnSkippedEntity(const XML_Char *entityName, int isParameterEntity) = 0;
	virtual void OnStartNamespaceDecl(const XML_Char *prefix, const XML_Char *uri) = 0;
	virtual void OnEndNamespaceDecl(const XML_Char *prefix) = 0;
	virtual void OnXmlDecl(const XML_Char *version, const XML_Char *encoding, int standalone) = 0;
	virtual void OnStartDoctypeDecl(const XML_Char *doctypeName, const XML_Char *systemId, const XML_Char *publicId, int hasInternalSubset) = 0;
	virtual void OnEndDoctypeDecl() = 0;
	virtual void OnElementDecl(const XML_Char *name, XML_Content *model) = 0;
	virtual void OnAttlistDecl(const XML_Char *elname, const XML_Char *attname, const XML_Char *attType, const XML_Char *dflt, int isRequired) = 0;
	virtual void OnEntityDecl(const XML_Char *entityName, int isParameterEntity, const XML_Char *value, int valueLength, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) = 0;
	virtual void OnNotationDecl(const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) = 0;
	virtual int  OnNotStandalone() = 0;
};

class Object_Element : public Object_Dict {
private:
	ValueList *_pValList;
public:
	Object_Element(Environment &env, const TCHAR *name, const TCHAR **atts);
	void AddChild(Object_Element *pObjElem);
	virtual String ToString(Signal sig, bool exprFlag);
};

class Object_Parser : public Object {
public:
	class ParserEx : public Parser {
	private:
		Object_Parser *_pObj;
	public:
		inline ParserEx(Object_Parser *pObj) : _pObj(pObj) {}
	private:
		virtual void OnStartElement(const XML_Char *name, const XML_Char **atts);
		virtual void OnEndElement(const XML_Char *name);
		virtual void OnCharacterData(const XML_Char *s, int len);
		virtual void OnProcessingInstruction(const XML_Char *target, const XML_Char *data);
		virtual void OnComment(const XML_Char *data);
		virtual void OnStartCdataSection();
		virtual void OnEndCdataSection();
		virtual void OnDefault(const XML_Char *s, int len);
		virtual void OnDefaultExpand(const XML_Char *s, int len);
		virtual int  OnExternalEntityRef(XML_Parser p, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId);
		virtual void OnSkippedEntity(const XML_Char *entityName, int isParameterEntity);
		virtual void OnStartNamespaceDecl(const XML_Char *prefix, const XML_Char *uri);
		virtual void OnEndNamespaceDecl(const XML_Char *prefix);
		virtual void OnXmlDecl(const XML_Char *version, const XML_Char *encoding, int standalone);
		virtual void OnStartDoctypeDecl(const XML_Char *doctypeName, const XML_Char *systemId, const XML_Char *publicId, int hasInternalSubset);
		virtual void OnEndDoctypeDecl();
		virtual void OnElementDecl(const XML_Char *name, XML_Content *model);
		virtual void OnAttlistDecl(const XML_Char *elname, const XML_Char *attname, const XML_Char *attType, const XML_Char *dflt, int isRequired);
		virtual void OnEntityDecl(const XML_Char *entityName, int isParameterEntity, const XML_Char *value, int valueLength, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName);
		virtual void OnNotationDecl(const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId);
		virtual int  OnNotStandalone();
	};
private:
	ParserEx _parser;
	Environment *_pEnv;
	Signal *_pSig;
	Value _valueObj;
public:
	inline static Object_Parser *GetSelfObj(Context &context) {
		return dynamic_cast<Object_Parser *>(context.GetSelfObj());
	}
public:
	Object_Parser(Class *pClass);
	virtual ~Object_Parser();
	void Parse(Environment &env, Signal &sig, const Value &valueObj, File &file);
	const Value &GetValueObj() { return _valueObj; }
	Environment &GetEnv() { return *_pEnv; }
	void CallHandler(const Symbol *pSymbol, const ValueList argList);
};

class Reader : public Parser {
private:
	typedef std::vector<Object_Element *> Stack;
private:
	Stack _stack;
	Object_Element *_pObjElemRoot;
	Environment *_pEnv;
	Signal *_pSig;
public:
	inline Reader() : _pEnv(NULL), _pSig(NULL), _pObjElemRoot(NULL) {}
	Object_Element *Parse(Environment &env, Signal &sig, File &file);
private:
	virtual void OnStartElement(const XML_Char *name, const XML_Char **atts);
	virtual void OnEndElement(const XML_Char *name);
	virtual void OnCharacterData(const XML_Char *s, int len);
	virtual void OnProcessingInstruction(const XML_Char *target, const XML_Char *data);
	virtual void OnComment(const XML_Char *data);
	virtual void OnStartCdataSection();
	virtual void OnEndCdataSection();
	virtual void OnDefault(const XML_Char *s, int len);
	virtual void OnDefaultExpand(const XML_Char *s, int len);
	virtual int  OnExternalEntityRef(XML_Parser p, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId);
	virtual void OnSkippedEntity(const XML_Char *entityName, int isParameterEntity);
	virtual void OnStartNamespaceDecl(const XML_Char *prefix, const XML_Char *uri);
	virtual void OnEndNamespaceDecl(const XML_Char *prefix);
	virtual void OnXmlDecl(const XML_Char *version, const XML_Char *encoding, int standalone);
	virtual void OnStartDoctypeDecl(const XML_Char *doctypeName, const XML_Char *systemId, const XML_Char *publicId, int hasInternalSubset);
	virtual void OnEndDoctypeDecl();
	virtual void OnElementDecl(const XML_Char *name, XML_Content *model);
	virtual void OnAttlistDecl(const XML_Char *elname, const XML_Char *attname, const XML_Char *attType, const XML_Char *dflt, int isRequired);
	virtual void OnEntityDecl(const XML_Char *entityName, int isParameterEntity, const XML_Char *value, int valueLength, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName);
	virtual void OnNotationDecl(const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId);
	virtual int  OnNotStandalone();
};

//-----------------------------------------------------------------------------
// Parser
//-----------------------------------------------------------------------------
Parser::Parser()
{
	_parser = ::XML_ParserCreate(NULL);
	::XML_SetUserData(_parser, this);
	::XML_SetStartElementHandler(_parser,			StartElementHandler);
	::XML_SetEndElementHandler(_parser,				EndElementHandler);
	::XML_SetCharacterDataHandler(_parser,			CharacterDataHandler);
	::XML_SetProcessingInstructionHandler(_parser,	ProcessingInstructionHandler);
	::XML_SetCommentHandler(_parser,				CommentHandler);
	::XML_SetStartCdataSectionHandler(_parser,		StartCdataSectionHandler);
	::XML_SetEndCdataSectionHandler(_parser,		EndCdataSectionHandler);
	::XML_SetDefaultHandler(_parser,				DefaultHandler);
	::XML_SetDefaultHandlerExpand(_parser,			DefaultHandlerExpand);
	::XML_SetExternalEntityRefHandler(_parser,		ExternalEntityRefHandler);
	::XML_SetSkippedEntityHandler(_parser,			SkippedEntityHandler);
	::XML_SetUnknownEncodingHandler(_parser,		UnknownEncodingHandler, this);
	::XML_SetStartNamespaceDeclHandler(_parser,		StartNamespaceDeclHandler);
	::XML_SetEndNamespaceDeclHandler(_parser,		EndNamespaceDeclHandler);
	::XML_SetXmlDeclHandler(_parser,				XmlDeclHandler);
	::XML_SetStartDoctypeDeclHandler(_parser,		StartDoctypeDeclHandler);
	::XML_SetEndDoctypeDeclHandler(_parser,			EndDoctypeDeclHandler);
	::XML_SetElementDeclHandler(_parser,			ElementDeclHandler);
	::XML_SetAttlistDeclHandler(_parser,			AttlistDeclHandler);
	::XML_SetEntityDeclHandler(_parser,				EntityDeclHandler);
	::XML_SetNotationDeclHandler(_parser,			NotationDeclHandler);
	::XML_SetNotStandaloneHandler(_parser,			NotStandaloneHandler);
}

Parser::~Parser()
{
	::XML_ParserFree(_parser);
}

void Parser::Parse(Signal sig, File &file)
{
	const size_t bytesToRead = 1024 * 8;
	for (;;) {
		char *buff = reinterpret_cast<char *>(::XML_GetBuffer(_parser, bytesToRead));
		size_t bytes = file.Read(buff, bytesToRead);
		int doneFlag = (bytes < bytesToRead);
		XML_Status status = ::XML_Parse(_parser, buff, bytes, doneFlag);
		if (sig.IsSignalled()) {
			break;
		} else if (status == XML_STATUS_ERROR) {
			sig.SetError(ERR_IOError, _T("expat: %s at line %lu\n"),
					::XML_ErrorString(XML_GetErrorCode(_parser)),
					::XML_GetCurrentLineNumber(_parser));
			break;
		} else if (status != XML_STATUS_OK) {
			break;
		}
		if (doneFlag) break;
	}
}

void Parser::StartElementHandler(void *userData,
								const XML_Char *name, const XML_Char **atts)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnStartElement(name, atts);
}

void Parser::EndElementHandler(void *userData, const XML_Char *name)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnEndElement(name);
}

void XMLCALL Parser::CharacterDataHandler(void *userData,
												const XML_Char *text, int len)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnCharacterData(text, len);
}

void XMLCALL Parser::ProcessingInstructionHandler(void *userData,
									const XML_Char *target, const XML_Char *data)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnProcessingInstruction(target, data);
}

void XMLCALL Parser::CommentHandler(void *userData, const XML_Char *data)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnComment(data);
}

void XMLCALL Parser::StartCdataSectionHandler(void *userData)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnStartCdataSection();
}

void XMLCALL Parser::EndCdataSectionHandler(void *userData)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnEndCdataSection();
}

void XMLCALL Parser::DefaultHandler(void *userData,
											const XML_Char *text, int len)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnDefault(text, len);
}

void XMLCALL Parser::DefaultHandlerExpand(void *userData,
											const XML_Char *text, int len)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnDefaultExpand(text, len);
}

int XMLCALL Parser::ExternalEntityRefHandler(XML_Parser parser,
							const XML_Char *context, const XML_Char *base,
							const XML_Char *systemId, const XML_Char *publicId)
{
	//Parser *pParser = reinterpret_cast<Parser *>(userData);
	//pParser->OnExternalEntityRef(context, base, systemId, publicId);
	return 0;
}

void XMLCALL Parser::SkippedEntityHandler(void *userData,
							const XML_Char *entityName, int isParameterEntity)
{
}

int XMLCALL Parser::UnknownEncodingHandler(void *encodingHandlerData,
							const XML_Char *name, XML_Encoding *info)
{
	
	
	return 0;
}

void XMLCALL Parser::StartNamespaceDeclHandler(void *userData,
							const XML_Char *prefix, const XML_Char *uri)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnStartNamespaceDecl(prefix, uri);
}

void XMLCALL Parser::EndNamespaceDeclHandler(void *userData,
													const XML_Char *prefix)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnEndNamespaceDecl(prefix);
}

void XMLCALL Parser::XmlDeclHandler(void *userData,
				const XML_Char *version, const XML_Char *encoding, int standalone)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnXmlDecl(version, encoding, standalone);
}

void XMLCALL Parser::StartDoctypeDeclHandler(void *userData,
				const XML_Char *doctypeName, const XML_Char *systemId,
				const XML_Char *publicId, int hasInternalSubset)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnStartDoctypeDecl(doctypeName, systemId, publicId, hasInternalSubset);
}

void XMLCALL Parser::EndDoctypeDeclHandler(void *userData)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnEndDoctypeDecl();
}

void XMLCALL Parser::ElementDeclHandler(void *userData,
									const XML_Char *name, XML_Content *model)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnElementDecl(name, model);
}

void XMLCALL Parser::AttlistDeclHandler(void *userData,
			const XML_Char *elemName, const XML_Char *attName,
			const XML_Char *attType, const XML_Char *defaultValue, int isRequired)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnAttlistDecl(elemName, attName, attType, defaultValue, isRequired);
}

void XMLCALL Parser::EntityDeclHandler(void *userData,
			const XML_Char *entityName, int isParameterEntity,
			const XML_Char *value, int valueLength, const XML_Char *base,
			const XML_Char *systemId, const XML_Char *publicId,
			const XML_Char *notationName)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnEntityDecl(entityName, isParameterEntity, value, valueLength, base,
										systemId, publicId, notationName);
}

void XMLCALL Parser::NotationDeclHandler(void *userData,
			const XML_Char *notationName, const XML_Char *base,
			const XML_Char *systemId, const XML_Char *publicId)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnNotationDecl(notationName, base, systemId, publicId);
}

int XMLCALL Parser::NotStandaloneHandler(void *userData)
{
	Parser *pParser = reinterpret_cast<Parser *>(userData);
	pParser->OnNotStandalone();
	return 0;
}

//-----------------------------------------------------------------------------
// Object_Parser
//-----------------------------------------------------------------------------
Object_Parser::Object_Parser(Class *pClass) :
					Object(pClass), _parser(this), _pEnv(NULL), _pSig(NULL)
{
}

Object_Parser::~Object_Parser()
{
}

void Object_Parser::Parse(Environment &env, Signal &sig,
											const Value &valueObj, File &file)
{
	_pEnv = &env, _pSig = &sig, _valueObj = valueObj;
	_parser.Parse(sig, file);
	_pEnv = NULL, _pSig = NULL;
}

void Object_Parser::CallHandler(const Symbol *pSymbol, const ValueList argList)
{
	const Function *pFunc = LookupFunction(pSymbol, false);
	if (pFunc != NULL) {
		Environment &env = *_pEnv;
		Signal &sig = *_pSig;
		pFunc->Eval(env, sig, Context(argList));
		if (sig.IsSignalled()) {
			_parser.StopParser();
		}
	}
}

void Object_Parser::ParserEx::OnStartElement(const XML_Char *name, const XML_Char **atts)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	do {
		Value valueOfDict(new Object_Element(env, name, atts), VTYPE_Dict);
		valListArg.push_back(valueOfDict);
	} while (0);
	_pObj->CallHandler(AScript_PrivSymbol(StartElement), valListArg);
}

void Object_Parser::ParserEx::OnEndElement(const XML_Char *name)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, name));
	_pObj->CallHandler(AScript_PrivSymbol(EndElement), valListArg);
}

void Object_Parser::ParserEx::OnCharacterData(const XML_Char *text, int len)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, text, len));
	_pObj->CallHandler(AScript_PrivSymbol(CharacterData), valListArg);
}

void Object_Parser::ParserEx::OnProcessingInstruction(const XML_Char *target, const XML_Char *data)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, target));
	valListArg.push_back(Value(*_pObj, data));
	_pObj->CallHandler(AScript_PrivSymbol(ProcessingInstruction), valListArg);
}

void Object_Parser::ParserEx::OnComment(const XML_Char *data)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, data));
	_pObj->CallHandler(AScript_PrivSymbol(Comment), valListArg);
}

void Object_Parser::ParserEx::OnStartCdataSection()
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	_pObj->CallHandler(AScript_PrivSymbol(StartCdataSection), valListArg);
}

void Object_Parser::ParserEx::OnEndCdataSection()
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	_pObj->CallHandler(AScript_PrivSymbol(EndCdataSection), valListArg);
}

void Object_Parser::ParserEx::OnDefault(const XML_Char *text, int len)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, text, len));
	_pObj->CallHandler(AScript_PrivSymbol(Default), valListArg);
}

void Object_Parser::ParserEx::OnDefaultExpand(const XML_Char *text, int len)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, text, len));
	_pObj->CallHandler(AScript_PrivSymbol(DefaultExpand), valListArg);
}

int Object_Parser::ParserEx::OnExternalEntityRef(XML_Parser parser,
							const XML_Char *context, const XML_Char *base,
							const XML_Char *systemId, const XML_Char *publicId)
{
	//ValueList valListArg;
	//_pObj->CallHandler(AScript_PrivSymbol(ExternalEntityRef), valListArg);
	return 0;
}

void Object_Parser::ParserEx::OnSkippedEntity(const XML_Char *entityName, int isParameterEntity)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, entityName));
	valListArg.push_back(Value(isParameterEntity != 0));
	_pObj->CallHandler(AScript_PrivSymbol(SkippedEntity), valListArg);
}

void Object_Parser::ParserEx::OnStartNamespaceDecl(const XML_Char *prefix, const XML_Char *uri)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, prefix));
	valListArg.push_back(Value(*_pObj, uri));
	_pObj->CallHandler(AScript_PrivSymbol(StartNamespaceDecl), valListArg);
}

void Object_Parser::ParserEx::OnEndNamespaceDecl(const XML_Char *prefix)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, prefix));
	_pObj->CallHandler(AScript_PrivSymbol(EndNamespaceDecl), valListArg);
}

void Object_Parser::ParserEx::OnXmlDecl(const XML_Char *version, const XML_Char *encoding, int standalone)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, version));
	valListArg.push_back(Value(*_pObj, encoding));
	if (standalone >= 0) {
		valListArg.push_back(Value(standalone != 0));
	}
	_pObj->CallHandler(AScript_PrivSymbol(XmlDecl), valListArg);
}

void Object_Parser::ParserEx::OnStartDoctypeDecl(
				const XML_Char *doctypeName, const XML_Char *systemId,
				const XML_Char *publicId, int hasInternalSubset)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, doctypeName));
	valListArg.push_back(Value(*_pObj, systemId));
	valListArg.push_back(Value(*_pObj, publicId));
	valListArg.push_back(Value(hasInternalSubset != 0));
	_pObj->CallHandler(AScript_PrivSymbol(StartDoctypeDecl), valListArg);
}

void Object_Parser::ParserEx::OnEndDoctypeDecl()
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	_pObj->CallHandler(AScript_PrivSymbol(EndDoctypeDecl), valListArg);
}

void Object_Parser::ParserEx::OnElementDecl(const XML_Char *name, XML_Content *model)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, name));
	//**************************
	// todo
	//**************************
	_pObj->CallHandler(AScript_PrivSymbol(ElementDecl), valListArg);
}

void Object_Parser::ParserEx::OnAttlistDecl(
			const XML_Char *elemName, const XML_Char *attName,
			const XML_Char *attType, const XML_Char *defaultValue, int isRequired)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, elemName));
	valListArg.push_back(Value(*_pObj, attName));
	valListArg.push_back(Value(*_pObj, attType));
	valListArg.push_back(Value(*_pObj, defaultValue));
	valListArg.push_back(Value(isRequired != 0)); // #IMPLIED / #REQUIRED
	_pObj->CallHandler(AScript_PrivSymbol(AttlistDecl), valListArg);
}

void Object_Parser::ParserEx::OnEntityDecl(
			const XML_Char *entityName, int isParameterEntity,
			const XML_Char *value, int valueLength, const XML_Char *base,
			const XML_Char *systemId, const XML_Char *publicId,
			const XML_Char *notationName)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, entityName));
	valListArg.push_back(Value(isParameterEntity != 0));
	valListArg.push_back(Value(*_pObj, value, valueLength));
	valListArg.push_back(Value(*_pObj, base));
	valListArg.push_back(Value(*_pObj, systemId));
	valListArg.push_back(Value(*_pObj, publicId));
	valListArg.push_back(Value(*_pObj, notationName));
	_pObj->CallHandler(AScript_PrivSymbol(EntityDecl), valListArg);
}

void Object_Parser::ParserEx::OnNotationDecl(
			const XML_Char *notationName, const XML_Char *base,
			const XML_Char *systemId, const XML_Char *publicId)
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(*_pObj, notationName));
	valListArg.push_back(Value(*_pObj, base));
	valListArg.push_back(Value(*_pObj, systemId));
	valListArg.push_back(Value(*_pObj, publicId));
	_pObj->CallHandler(AScript_PrivSymbol(NotationDecl), valListArg);
}

int Object_Parser::ParserEx::OnNotStandalone()
{
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	_pObj->CallHandler(AScript_PrivSymbol(NotStandalone), valListArg);
	return 0;
}

//-----------------------------------------------------------------------------
// Object_Element
//-----------------------------------------------------------------------------
Object_Element::Object_Element(Environment &env, const TCHAR *name, const TCHAR **atts) :
												Object_Dict(env.GetClass_Dict())
{
	AssignValue(AScript_Symbol(name), Value(env, name), false);
	if (atts != NULL) {
		ValueDict &valDict = GetDict();
		for (const TCHAR **p = atts; *p != NULL && *(p + 1) != NULL; p += 2) {
			valDict[Value(env, *p)] = Value(env, *(p + 1));
		}
	}
	Value valueOfList;
	_pValList = &valueOfList.InitAsList(env);
	AssignValue(AScript_Symbol(children), valueOfList, false);
}

void Object_Element::AddChild(Object_Element *pObjElem)
{
	_pValList->push_back(Value(pObjElem, VTYPE_Object));
}

String Object_Element::ToString(Signal sig, bool exprFlag)
{
	String str;
	String name = _T("");
	do {
		const Value *pValue = LookupValue(AScript_Symbol(name), false);
		if (pValue != NULL) name = pValue->ToString(sig, false);
	} while (0);
	str += _T("<");
	str += name;
	foreach_const (ValueDict, iter, GetDict()) {
		str += _T(" ");
		str += iter->first.ToString(sig, false);
		str += _T("=\"");
		str += iter->second.ToString(sig, false);
		str += _T("\"");
	}
	do {
		const Value *pValChildren = LookupValue(AScript_Symbol(children), false);
		if (pValChildren == NULL || !pValChildren->IsList() ||
										pValChildren->GetList().empty()) {
			str += _T(" />");
		} else {
			str += _T(">\n");
			foreach_const (ValueList, pValue, pValChildren->GetList()) {
				str += pValue->ToString(sig, false);
				str += _T("\n");
			}
			str += _T("</");
			str += name;
			str += _T(">");
		}
	} while (0);
	return str;
}

//-----------------------------------------------------------------------------
// Reader
//-----------------------------------------------------------------------------
Object_Element *Reader::Parse(Environment &env, Signal &sig, File &file)
{
	_pObjElemRoot = NULL, _pEnv = &env, _pSig = &sig;
	Parser::Parse(sig, file);
	_pEnv = NULL, _pSig = NULL;
	return _pObjElemRoot;
}

void Reader::OnStartElement(const XML_Char *name, const XML_Char **atts)
{
	Object_Element *pObjElem = new Object_Element(*_pEnv, name, atts);
	if (_stack.empty()) {
		_pObjElemRoot = pObjElem;
	} else {
		_stack.back()->AddChild(pObjElem);
	}
	_stack.push_back(pObjElem);
}

void Reader::OnEndElement(const XML_Char *name)
{
	_stack.pop_back();
}

void Reader::OnCharacterData(const XML_Char *text, int len)
{
}

void Reader::OnProcessingInstruction(const XML_Char *target, const XML_Char *data)
{
}

void Reader::OnComment(const XML_Char *data)
{
}

void Reader::OnStartCdataSection()
{
}

void Reader::OnEndCdataSection()
{
}

void Reader::OnDefault(const XML_Char *text, int len)
{
}

void Reader::OnDefaultExpand(const XML_Char *text, int len)
{
}

int Reader::OnExternalEntityRef(XML_Parser parser,
							const XML_Char *context, const XML_Char *base,
							const XML_Char *systemId, const XML_Char *publicId)
{
	return 0;
}

void Reader::OnSkippedEntity(const XML_Char *entityName, int isParameterEntity)
{
}

void Reader::OnStartNamespaceDecl(const XML_Char *prefix, const XML_Char *uri)
{
}

void Reader::OnEndNamespaceDecl(const XML_Char *prefix)
{
}

void Reader::OnXmlDecl(const XML_Char *version, const XML_Char *encoding, int standalone)
{
}

void Reader::OnStartDoctypeDecl(
				const XML_Char *doctypeName, const XML_Char *systemId,
				const XML_Char *publicId, int hasInternalSubset)
{
}

void Reader::OnEndDoctypeDecl()
{
}

void Reader::OnElementDecl(const XML_Char *name, XML_Content *model)
{
}

void Reader::OnAttlistDecl(
			const XML_Char *elemName, const XML_Char *attName,
			const XML_Char *attType, const XML_Char *defaultValue, int isRequired)
{
}

void Reader::OnEntityDecl(
			const XML_Char *entityName, int isParameterEntity,
			const XML_Char *value, int valueLength, const XML_Char *base,
			const XML_Char *systemId, const XML_Char *publicId,
			const XML_Char *notationName)
{
}

void Reader::OnNotationDecl(
			const XML_Char *notationName, const XML_Char *base,
			const XML_Char *systemId, const XML_Char *publicId)
{
}

int Reader::OnNotStandalone()
{
	return 0;
}

// p = xml.parser() {block}
AScript_DeclareFunctionBegin(parser)
	SymbolSet _symbolsAcceptable;
AScript_DeclareFunctionEnd(parser)
{
	SetMode(RSLTMODE_Normal, MAP_Off);
	DeclareBlock(OCCUR_Once);
	_symbolsAcceptable.Insert(AScript_PrivSymbol(StartElement));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(EndElement));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(CharacterData));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(ProcessingInstruction));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(Comment));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(StartCdataSection));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(EndCdataSection));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(Default));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(DefaultExpand));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(ExternalEntityRef));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(SkippedEntity));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(StartNamespaceDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(EndNamespaceDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(XmlDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(StartDoctypeDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(EndDoctypeDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(ElementDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(AttlistDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(EntityDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(NotationDecl));
	_symbolsAcceptable.Insert(AScript_PrivSymbol(NotStandalone));
}

AScript_ImplementFunction(parser)
{
	Object_Parser *pObj = new Object_Parser(AScript_Class(Parser, env));
	if (!pObj->BuildContent(env, sig, context.GetBlock(), &_symbolsAcceptable)) {
		Object::Delete(pObj);
		return Value::Null;
	}
	return Value(pObj, VTYPE_Object);
}

// p = xml.element(name:string, %attrs) {block?}
AScript_DeclareFunction(element)
{
	SetMode(RSLTMODE_Normal, MAP_Off);
	DeclareArg(env, _T("name"), VTYPE_String);
	DeclareDictArg(_T("attrs"));
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementFunction(element)
{
	Object_Element *pObjElem = new Object_Element(env, context.GetString(0), NULL);
	foreach_const (ValueDict, iter, context.GetDict()) {
		pObjElem->GetDict()[iter->first] = iter->second;
	}
	const Expr_Block *pExprBlock = context.GetBlock();
	if (pExprBlock != NULL) {
		Environment envLister(&env, ENVTYPE_Lister);
		Value valueRaw = pExprBlock->GetExprList().ExecForList(envLister, sig, false);
		if (sig.IsSignalled() || !valueRaw.IsList()) return Value::Null;
		Value result;
		ValueList &valList = result.InitAsList(env);
		foreach_const (ValueList, pValue, valueRaw.GetList()) {
			valList.push_back(*pValue);
		}
		pObjElem->AssignValue(AScript_Symbol(children), result, false);
	}
	return Value(pObjElem, VTYPE_Dict);
}

// obj = xml.read(input)
AScript_DeclareFunction(read)
{
	SetMode(RSLTMODE_Normal, MAP_Off);
	DeclareArg(env, _T("input"), VTYPE_AnyType);
}

AScript_ImplementFunction(read)
{
	Value result;
	if (context.IsFile(0)) {
		Object_Element *pObjElem = Reader().Parse(env, sig, context.GetFile(0));
		result.InitAsObject(pObjElem, VTYPE_Object);
	}
	return result;
}

// str = xml.Parser#parse(input)
AScript_DeclareMethod(Parser, parse)
{
	SetMode(RSLTMODE_Normal, MAP_Off);
	DeclareArg(env, _T("obj"), VTYPE_AnyType);
	DeclareArg(env, _T("input"), VTYPE_AnyType);
}

AScript_ImplementMethod(Parser, parse)
{
	Object_Parser *pObj = Object_Parser::GetSelfObj(context);
	if (context.IsFile(1)) {
		pObj->Parse(env, sig, context.GetValue(0), context.GetFile(1));
	}
	return Value::Null;
}

// implementation of class Parser
AScript_ImplementClass(Parser)
{
	AScript_AssignMethod(Parser, parse);
}

// Module entry
AScript_ModuleEntry()
{
	AScript_RealizePrivSymbol(StartElement);
	AScript_RealizePrivSymbol(EndElement);
	AScript_RealizePrivSymbol(CharacterData);
	AScript_RealizePrivSymbol(ProcessingInstruction);
	AScript_RealizePrivSymbol(Comment);
	AScript_RealizePrivSymbol(StartCdataSection);
	AScript_RealizePrivSymbol(EndCdataSection);
	AScript_RealizePrivSymbol(Default);
	AScript_RealizePrivSymbol(DefaultExpand);
	AScript_RealizePrivSymbol(ExternalEntityRef);
	AScript_RealizePrivSymbol(SkippedEntity);
	AScript_RealizePrivSymbol(StartNamespaceDecl);
	AScript_RealizePrivSymbol(EndNamespaceDecl);
	AScript_RealizePrivSymbol(XmlDecl);
	AScript_RealizePrivSymbol(StartDoctypeDecl);
	AScript_RealizePrivSymbol(EndDoctypeDecl);
	AScript_RealizePrivSymbol(ElementDecl);
	AScript_RealizePrivSymbol(AttlistDecl);
	AScript_RealizePrivSymbol(EntityDecl);
	AScript_RealizePrivSymbol(NotationDecl);
	AScript_RealizePrivSymbol(NotStandalone);
	AScript_AssignFunction(parser);
	AScript_AssignFunction(element);
	AScript_AssignFunction(read);
}

AScript_EndModule(xml)

AScript_DLLModuleEntry(xml)
