// $Id: CTemplate.cc,v 1.11 2003/05/10 06:46:49 ta_muto Exp $

#include <templates/CTemplate.h>
#include <views/CViewer.h>
#include <views/CIncludeTask.h>
#include <xupdate/CXUpdate.h>

namespace wax {
	class CDummyTask : public ITask {
	public:
		CDummyTask();
		
		bool parse(CEnvironment* runenv, xmlNodePtr cur);
		bool execute();
		void output(IWriter* writer);
	} ;

	CDummyTask::CDummyTask() { }
	bool CDummyTask::parse(CEnvironment* runenv, xmlNodePtr cur)
	{
		return true;
	}
	
	bool CDummyTask::execute()
	{
		return true;
	}
	void CDummyTask::output(IWriter* writer)
	{
	}
}

wax::CTemplate::CTemplate()
{
	startNode = NULL;
}

wax::CTemplate::~CTemplate()
{
}

bool wax::CTemplate::parse(CEnvironment* runenv, xmlNodePtr cur)
{
	xmlNsPtr ns = xmlSearchNsByHref(runenv->getDocPtr(), cur, CEnvironment::WAX);
	startNode = cur->children;
	return parseInternal(runenv, startNode, ns);
}

bool wax::CTemplate::parseInternal(CEnvironment* runenv, xmlNodePtr cur, xmlNsPtr ns)
{
	while(cur != NULL) {
		if(cur->ns == ns) {
			ITask* task;
			bool bodyPart = true;
			
			task = CViewer::findTask(cur, bodyPart);
			if(task != NULL) {
				if(task->parse(runenv, cur) == false) {
					delete task;
					return false;
				}
				if(bodyPart == true) {
					taskList.addItem(task);
					cur->_private = task;
				} else {
					headList.addItem(task);
					CDummyTask* dmy = new CDummyTask();
					taskList.addItem(dmy);
					cur->_private = dmy;
				}
			}
			cur = cur->next;
			continue;
		} else {
			xmlNsPtr nsXUpdate = xmlSearchNsByHref(runenv->getDocPtr(), cur, CEnvironment::XUPDATE);
			if(nsXUpdate != NULL)  {
				CXUpdate* task = CXUpdate::getInstance(runenv, cur);
				if(task == NULL)	return false;
				taskList.addItem(task);
				cur->_private = task;

				cur = cur->next;
				continue;
			}
		}
		if(cur->children != NULL) {
			if(parseInternal(runenv, cur->children, ns) == false)	return false;
		}
		cur = cur->next;
	}
	return true;
}

bool wax::CTemplate::execute()
{
	ITask* task = (ITask*)headList.getHead();
	while(task != NULL) {
		if(task->execute() == false)	return false;
		task = (ITask*)task->getNext();
	}
	task = (ITask*)taskList.getHead();
	while(task != NULL) {
		if(task->execute() == false)	return false;
		task = (ITask*)task->getNext();
	}
	return true;
}

void wax::CTemplate::output(IWriter* writer)
{
	ITask* task;
	task = (ITask*)headList.getHead();
	while(task != NULL) {
		task->output(writer);
		task = (ITask*)task->getNext();
	}
	writer->writeStr("\n");
	outputInternal(writer, startNode);
}

void wax::CTemplate::outputInternal(IWriter* writer, xmlNodePtr cur)
{
	ITask* task;
	while(cur != NULL) {
		if(cur->_private != NULL) {
			ITask* task = (ITask*)cur->_private;
			
			task->output(writer);
		} else {
			switch(cur->type) {
			case XML_ELEMENT_NODE:
				outputTag(writer, cur);
				break;
			default:
				{
					xmlChar* buffer = xmlEncodeEntitiesReentrant(cur->doc, cur->content);
					writer->writeStr(buffer);
					xmlFree(buffer);
				}
				break;
			}
		}
		cur = cur->next;
	}
}

void wax::CTemplate::outputTag(IWriter* writer, xmlNodePtr cur)
{
	writer->writeStr("<");
	if((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
		writer->writeStr(cur->ns->prefix);
		writer->writeStr(":");
	}
	writer->writeStr(cur->name);
	if(cur->nsDef != NULL) {
		outputNsList(writer, cur->nsDef);
	}
	if(cur->properties != NULL) {
		outputAttrList(writer, cur->properties);
	}
	
	if(((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) && (cur->children == NULL)) {
		writer->writeStr(" />");
		return;
	}
	writer->writeStr(">");
	
	if((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
		xmlChar* buffer = xmlEncodeEntitiesReentrant(cur->doc, cur->content);
		writer->writeStr(buffer);
		xmlFree(buffer);
	}
	if(cur->children != NULL) {
		outputInternal(writer, cur->children);
	}
	writer->writeStr("</");
	if((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
		writer->writeStr(cur->ns->prefix);
		writer->writeStr(":");
	}
	writer->writeStr(cur->name);
	writer->writeStr(">");
}

void wax::CTemplate::outputNsList(IWriter* writer, xmlNsPtr nsDef)
{
	while(nsDef != NULL) {
		if((nsDef->type == XML_LOCAL_NAMESPACE) && (nsDef->href != NULL)) {
			if(xmlStrEqual(nsDef->prefix, (const xmlChar*) "xml"))	return;
			if(nsDef->prefix != NULL) {
				writer->writeStr(" xmlns:");
				writer->writeStr(nsDef->prefix);
			} else {
				writer->writeStr(" xmlns");
			}
			writer->writeStr("=");
			writer->writeQuote(nsDef->href);
		}
		nsDef = nsDef->next;
	}
}

void wax::CTemplate::outputAttrList(IWriter* writer, xmlAttrPtr attr)
{
	while(attr != NULL) {
		writer->writeStr(" ");
		if((attr->ns != NULL) && (attr->ns->prefix != NULL)) {
			writer->writeStr(attr->ns->prefix);
			writer->writeStr(":");
		}
		writer->writeStr(attr->name);
		writer->writeStr("=");
		writer->writeQuote(attr->children->content);// ???
		
		attr = attr->next;
	}
}
