//-----------------------------------------------------------------------------
// AScript xml module
//-----------------------------------------------------------------------------
#include <ascript.h>
#include <expat.h>
#include <Conv_Japanese.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);

//-----------------------------------------------------------------------------
// Parser
//-----------------------------------------------------------------------------
class Parser {
private:
	XML_Parser _parser;
public:
	Parser();
	virtual ~Parser();
	void Parse(Signal sig, Stream &stream);
	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 *args, 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);
	static int Convert_shift_jis(void *data, const char *s);
	static int Convert_euc_jp(void *data, const char *s);
	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 *args, 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;
};

//-----------------------------------------------------------------------------
// Object_Element
//-----------------------------------------------------------------------------
AScript_DeclarePrivClass(Element);

class Object_Element : public Object_Dict {
private:
	ValueList *_pValList;
public:
	AScript_DeclareObjectAccessor(Element)
public:
	Object_Element(Environment &env, const char *name, const char **atts);
	void AddChild(const Value &value);
	String Format(Signal sig, int indentLevel) const;
	String GetText(Signal sig) const;
	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 *args, 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:
	AScript_DeclareObjectAccessor(Parser)
public:
	Object_Parser(Environment &env);
	virtual ~Object_Parser();
	void Parse(Environment &env, Signal &sig, const Value &valueObj, Stream &stream);
	const Value &GetValueObj() { return _valueObj; }
	Environment &GetEnv() { return *_pEnv; }
	void CallHandler(const Symbol *pSymbol, const ValueList argList);
};

//-----------------------------------------------------------------------------
// Reader
//-----------------------------------------------------------------------------
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, Stream &stream);
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 *args, 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, Stream &stream)
{
	const size_t bytesToRead = 1024 * 8;
	for (;;) {
		char *buff = reinterpret_cast<char *>(::XML_GetBuffer(_parser, bytesToRead));
		int bytes = static_cast<int>(stream.Read(sig, buff, bytesToRead));
		if (sig.IsSignalled()) break;
		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, "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 *args, const XML_Char *base,
							const XML_Char *systemId, const XML_Char *publicId)
{
	//Parser *pParser = reinterpret_cast<Parser *>(userData);
	//pParser->OnExternalEntityRef(args, 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)
{
	for (int i = 0; i < NUMBEROF(info->map); i++) info->map[i] = -1;
	if (::strcasecmp(name, "shift_jis") == 0) {
		for (int i = 0; i <= 0x7f; i++) info->map[i] = i;
		for (int i = 0x81; i <= 0x9f; i++) info->map[i] = -2;
		for (int i = 0xe0; i <= 0xee; i++) info->map[i] = -2;
		for (int i = 0xfa; i <= 0xfc; i++) info->map[i] = -2;
		info->data = NULL;
		info->convert = Convert_shift_jis;
		info->release = NULL;
		return XML_STATUS_OK;
	} else if (::strcasecmp(name, "euc-jp") == 0) {
		for (int i = 0; i <= 0x7f; i++) info->map[i] = i;
		for (int i = 0x81; i <= 0xff; i++) info->map[i] = -2;
		info->data = NULL;
		info->convert = Convert_euc_jp;
		info->release = NULL;
		return XML_STATUS_OK;
	}
	return XML_STATUS_ERROR;
}

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;
}

int Parser::Convert_shift_jis(void *data, const char *s)
{
	unsigned short codeCP932 =
		(static_cast<unsigned short>(static_cast<unsigned char>(s[0])) << 8) +
		static_cast<unsigned char>(s[1]);
	unsigned short codeUTF16 = CP932ToUTF16(codeCP932);
	return (codeUTF16 == 0)? -1 : codeUTF16;
}

int Parser::Convert_euc_jp(void *data, const char *s)
{
	unsigned short codeEUCJP =
		(static_cast<unsigned short>(static_cast<unsigned char>(s[0])) << 8) +
		static_cast<unsigned char>(s[1]);
	unsigned short codeCP932 = EUCJPToCP932(codeEUCJP);
	unsigned short codeUTF16 = CP932ToUTF16(codeCP932);
	return (codeUTF16 == 0)? -1 : codeUTF16;
}

//-----------------------------------------------------------------------------
// Object_Parser
//-----------------------------------------------------------------------------
AScript_DeclarePrivClass(Parser);

Object_Parser::Object_Parser(Environment &env) :
		Object(AScript_PrivClass(Parser)), _parser(this), _pEnv(NULL), _pSig(NULL)
{
}

Object_Parser::~Object_Parser()
{
}

void Object_Parser::Parse(Environment &env, Signal &sig,
											const Value &valueObj, Stream &stream)
{
	_pEnv = &env, _pSig = &sig, _valueObj = valueObj;
	_parser.Parse(sig, stream);
	_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;
		Args args(argList);
		pFunc->Eval(env, sig, args);
		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));
		valListArg.push_back(valueOfDict);
	} while (0);
	_pObj->CallHandler(AScript_PrivSymbol(StartElement), valListArg);
}

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

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

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

void Object_Parser::ParserEx::OnComment(const XML_Char *data)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, 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)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, text, len));
	_pObj->CallHandler(AScript_PrivSymbol(Default), valListArg);
}

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

int Object_Parser::ParserEx::OnExternalEntityRef(XML_Parser parser,
							const XML_Char *args, 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)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, 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)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, prefix));
	valListArg.push_back(Value(env, uri));
	_pObj->CallHandler(AScript_PrivSymbol(StartNamespaceDecl), valListArg);
}

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

void Object_Parser::ParserEx::OnXmlDecl(const XML_Char *version, const XML_Char *encoding, int standalone)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, version));
	valListArg.push_back(Value(env, 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)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, doctypeName));
	valListArg.push_back(Value(env, systemId));
	valListArg.push_back(Value(env, 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)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, 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)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, elemName));
	valListArg.push_back(Value(env, attName));
	valListArg.push_back(Value(env, attType));
	valListArg.push_back(Value(env, 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)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, entityName));
	valListArg.push_back(Value(isParameterEntity != 0));
	valListArg.push_back(Value(env, value, valueLength));
	valListArg.push_back(Value(env, base));
	valListArg.push_back(Value(env, systemId));
	valListArg.push_back(Value(env, publicId));
	valListArg.push_back(Value(env, 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)
{
	Environment &env = _pObj->GetEnv();
	ValueList valListArg;
	valListArg.push_back(_pObj->GetValueObj());
	valListArg.push_back(Value(env, notationName));
	valListArg.push_back(Value(env, base));
	valListArg.push_back(Value(env, systemId));
	valListArg.push_back(Value(env, 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;
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Parser
//-----------------------------------------------------------------------------
// str = xml.parser#parse(stream:stream)
AScript_DeclareMethod(Parser, parse)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "obj", VTYPE_Any);
	DeclareArg(env, "stream", VTYPE_Stream);
}

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

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

//-----------------------------------------------------------------------------
// Object_Element
//-----------------------------------------------------------------------------
Object_Element::Object_Element(Environment &env, const char *name, const char **atts) :
						Object_Dict(env.LookupClass(AScript_PrivVTYPE(Element)))
{
	AssignValue(AScript_Symbol(name), Value(env, name), false);
	if (atts != NULL) {
		ValueDict &valDict = GetDict();
		for (const char **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(const Value &value)
{
	_pValList->push_back(value);
}

String Object_Element::Format(Signal sig, int indentLevel) const
{
	const char *indentUnit = "  ";
	String str;
	String name = "";
	String indent;
	for (int i = 0; i < indentLevel; i++) indent += indentUnit;
	do {
		const Value *pValue = LookupValue(AScript_Symbol(name), false);
		if (pValue != NULL) name = pValue->ToString(sig, false);
	} while (0);
	str += indent;
	str += "<";
	str += name;
	foreach_const (ValueDict, iter, GetDict()) {
		str += " ";
		str += iter->first.ToString(sig, false);
		str += "=\"";
		str += iter->second.ToString(sig, false);
		str += "\"";
	}
	const Value *pValChildren = LookupValue(AScript_Symbol(children), false);
	if (pValChildren == NULL || !pValChildren->IsList() ||
									pValChildren->GetList().empty()) {
		str += " />";
	} else {
		str += ">\n";
		foreach_const (ValueList, pValue, pValChildren->GetList()) {
			if (pValue->IsString()) {
				str += indent;
				str += indentUnit;
				str += pValue->GetString();
				str += "\n";
			} else if (pValue->IsType(AScript_PrivVTYPE(Element))) {
				const Object *pObj = pValue->GetObject();
				str += dynamic_cast<const Object_Element *>(pObj)->
													Format(sig, indentLevel + 1);
				str += "\n";
			}
		}
		str += indent;
		str += "</";
		str += name;
		str += ">";
	}
	return str;
}

String Object_Element::GetText(Signal sig) const
{
	String str;
	const Value *pValChildren = LookupValue(AScript_Symbol(children), false);
	if (pValChildren != NULL && pValChildren->IsList() &&
									!pValChildren->GetList().empty()) {
		foreach_const (ValueList, pValue, pValChildren->GetList()) {
			if (pValue->IsString()) {
				str += pValue->GetString();
			} else if (pValue->IsType(AScript_PrivVTYPE(Element))) {
				const Object *pObj = pValue->GetObject();
				str += dynamic_cast<const Object_Element *>(pObj)->GetText(sig);
			}
		}
	}
	return str;
}

String Object_Element::ToString(Signal sig, bool exprFlag)
{
	String str;
	const Value *pValue = LookupValue(AScript_Symbol(name), false);
	if (pValue == NULL) {
		str = "<element>";
	} else {
		str = "<element:";
		str += pValue->ToString(sig, false);
		str += ">";
	}
	return str;
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Element
//-----------------------------------------------------------------------------
// xml.element#format()
AScript_DeclareMethod(Element, format)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Element, format)
{
	Object_Element *pObj = Object_Element::GetSelfObj(args);
	String str = pObj->Format(sig, 0);
	if (sig.IsSignalled()) return Value::Null;
	return Value(env, str.c_str());
}

// xml.element#text()
AScript_DeclareMethod(Element, text)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Element, text)
{
	Object_Element *pObj = Object_Element::GetSelfObj(args);
	String str = pObj->GetText(sig);
	if (sig.IsSignalled()) return Value::Null;
	return Value(env, str.c_str());
}

// implementation of class Element
AScript_ImplementPrivClass(Element)
{
	AScript_AssignMethod(Element, format);
	AScript_AssignMethod(Element, text);
}

//-----------------------------------------------------------------------------
// Reader
//-----------------------------------------------------------------------------
Object_Element *Reader::Parse(Environment &env, Signal &sig, Stream &stream)
{
	_pObjElemRoot = NULL, _pEnv = &env, _pSig = &sig;
	Parser::Parse(sig, stream);
	_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(Value(pObjElem));
	}
	_stack.push_back(pObjElem);
}

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

void Reader::OnCharacterData(const XML_Char *text, int len)
{
	if (!_stack.empty()) {
		_stack.back()->AddChild(Value(*_pEnv,
							reinterpret_cast<const char *>(text), 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 *args, 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;
}

//-----------------------------------------------------------------------------
// AScript module functions: xml
//-----------------------------------------------------------------------------
// p = xml.parser() {block}
AScript_DeclareFunctionBegin(parser)
	SymbolSet _symbolsAcceptable;
AScript_DeclareFunctionEnd(parser)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	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)
{
	const Expr_Block *pExprBlock = args.GetBlock(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	Object_Parser *pObj = new Object_Parser(env);
	Value valueSelf(pObj, false);
	if (!pObj->BuildContent(env, sig, valueSelf, pExprBlock, &_symbolsAcceptable)) {
		Object::Delete(pObj);
		return Value::Null;
	}
	return Value(pObj);
}

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

AScript_ImplementFunction(element)
{
	Object_Element *pObjElem = new Object_Element(env, args.GetString(0), NULL);
	foreach_const (ValueDict, iter, args.GetDictArg()) {
		pObjElem->GetDict()[iter->first] = iter->second;
	}
	const Expr_Block *pExprBlock = args.GetBlock(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	if (pExprBlock != NULL) {
		Environment envLister(&env, ENVTYPE_Lister);
		Value valueRaw =
			pExprBlock->GetExprList().ExecForList(envLister, sig, false, 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);
}

// obj = xml.read(stream:stream)
AScript_DeclareFunction(read)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "stream", VTYPE_Stream);
}

AScript_ImplementFunction(read)
{
	Value result;
	Object_Element *pObjElem = Reader().Parse(env, sig, args.GetStream(0));
	if (sig.IsError()) return Value::Null;
	return Value(pObjElem);
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Stream
//-----------------------------------------------------------------------------
// stream#xmlread()
AScript_DeclareMethod(Stream, xmlread)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Stream, xmlread)
{
	Object_Stream *pSelf = Object_Stream::GetSelfObj(args);
	Value result;
	Object_Element *pObjElem = Reader().Parse(env, sig, pSelf->GetStream());
	if (sig.IsError()) return Value::Null;
	return Value(pObjElem);
}

// Module entry
AScript_ModuleEntry()
{
	// symbol realization
	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);
	// class realization
	AScript_RealizePrivClass(Element, "element", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Parser, "parser", env.LookupClass(VTYPE_Object));
	// function assignment
	AScript_AssignFunction(parser);
	AScript_AssignFunction(element);
	AScript_AssignFunction(read);
	// method assignment to stream type
	AScript_AssignMethodTo(VTYPE_Stream, Stream, xmlread);
}

AScript_ModuleTerminate()
{
}

AScript_EndModule(xml, xml)

AScript_RegisterModule(xml)
