// $Id: CXUpdate.cc,v 1.12 2003/05/10 06:46:52 ta_muto Exp $

#include <xupdate/CXUpdate.h>
#include <xupdate/IAction.h>
#include <xupdate/CXmlSession.h>
#include <xupdate/CXUInsertBefore.h>
#include <xupdate/CXUInsertAfter.h>
#include <xupdate/CXUAppend.h>
#include <xupdate/CXUUpdate.h>
#include <xupdate/CXURemove.h>
#include <xupdate/CXURename.h>

#include <CWaxLibs.h>

wax::CXUpdate::CXUpdate(xmlChar* initVer)
{
	version = initVer;
}

wax::CXUpdate::~CXUpdate()
{
	if(version != NULL)	xmlFree(version);
}

bool wax::CXUpdate::parse(CEnvironment* runenv, xmlNodePtr cur)
{
	xmlNsPtr ns = xmlSearchNsByHref(runenv->getDocPtr(), cur, CEnvironment::XUPDATE);
	xmlNsPtr nsWax = xmlSearchNsByHref(runenv->getDocPtr(), cur, CEnvironment::WAX);
	CXmlStr connect(NULL);
	cur = cur->children;
	while(cur != NULL) {
		if(cur->ns == ns) {
			IAction* action = NULL;
			if(!xmlStrcmp(cur->name, (const xmlChar*) "insert-before")) {
				action = new CXUInsertBefore(connect.value());
			} else if(!xmlStrcmp(cur->name, (const xmlChar*) "insert-after")) {
				action = new CXUInsertAfter(connect.value());
			} else if(!xmlStrcmp(cur->name, (const xmlChar*) "append")) {
				action = new CXUAppend(connect.value());
			} else if(!xmlStrcmp(cur->name, (const xmlChar*) "update")) {
				action = new CXUUpdate(connect.value());
			} else if(!xmlStrcmp(cur->name, (const xmlChar*) "remove")) {
				action = new CXURemove(connect.value());
			} else if(!xmlStrcmp(cur->name, (const xmlChar*) "rename")) {
				action = new CXURename(connect.value());
			} else if(!xmlStrcmp(cur->name, (const xmlChar*) "variable")) {
				CXmlStr name(xmlGetProp(cur, (const xmlChar*) "name"));
				if(name.value() == NULL) {
					IError::message(ERR_ATTRIBUTE, "variable::name");
					return false;
				}
				CXmlStr select(xmlGetProp(cur, (const xmlChar*) "select"));
				if(select.value() == NULL) {
					xmlChar* value = NULL;
					if(CWaxLibs::parseAsContent(runenv, cur->children, nsWax, value) == false) {
						return false;
					}
					if(value != NULL) {
						CParameterItem* item = new CParameterItem(name.value(), value, false);
						vars.addItem(item);
						xmlFree(value);
					}
				} else {
					CXmlStr value(CWaxLibs::evaluateXPath(connect.value(), vars, select.value()));
					if(value.value() == NULL) {
						return false;
					}
					CParameterItem* item = new CParameterItem(name.value(), value.value(), false);
					vars.addItem(item);
				}
				goto NEXTSTEP;
			} else if(!xmlStrcmp(cur->name, (const xmlChar*) "if")) {
				// sorry, this element is not supported.
				goto NEXTSTEP;
			} else {
				goto NEXTSTEP;
			}
			if(action == NULL) {
				IError::message(ERR_OUTOFMEMORY, LOCATION);
				return false;
			}
			action->setVariables(vars);
			if(action->parse(runenv, cur) == false) {
				delete action;
				return false;
			}
			actList.addItem(action);
		} else {
			if(nsWax != NULL) {
				if(!xmlStrcmp(cur->name, (const xmlChar*) "connect")) {
					CXmlStr href(xmlGetProp(cur, (const xmlChar*) "href"));
					if(href.value() == NULL) {
						IError::message(ERR_ATTRIBUTE, "connect::href");
						return false;
					}
					connect.replace(runenv->makePath(href.value()));
				}
			}
		}
		NEXTSTEP:
		cur = cur->next;
	}
	return true;
}

bool wax::CXUpdate::execute()
{
	CXmlSession* session = CXmlSession::getSession();
	session->setVariables(vars);

	IAction* action = (IAction*)actList.getHead();
	while(action != NULL) {
		if(action->execute(session) == false) {
			session->rollback();
			delete session;
			return false;
		}
		action = (IAction*)action->getNext();
	}
	session->commit();
	delete session;
	return true;
}

void wax::CXUpdate::output(IWriter* writer)
{
	// NO OUTPUTS.
}

wax::CXUpdate* wax::CXUpdate::getInstance(CEnvironment* runenv, xmlNodePtr cur)
{
	if(!xmlStrcmp(cur->name, (const xmlChar*) "modifications")) {
		xmlChar* ver = xmlGetProp(cur, (const xmlChar*) "version");
		if(ver == NULL) {
			IError::message(ERR_ATTRIBUTE, "modifications::version");
			return NULL;
		}
		CXUpdate *xup = new CXUpdate(ver);
		if(xup->parse(runenv, cur) == true)	return xup;
		IError::message(ERR_PARSE, "modifications");
	}
	return NULL;
}
