/* **************************************************************************

 Author: Achim Gaedke
 Created: June 2004

****************************************************************************/
#include "job_receiver.h"
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMException.hpp>

job_receiver::job_receiver(std::string the_jobfilenamepattern) {
  try {
    xercesc::XMLPlatformUtils::Initialize();
  }
  catch (const xercesc::XMLException& toCatch) {
    char* ini_error=xercesc::XMLString::transcode(toCatch.getMessage());
    job_exception new_exception(std::string("xerces initialisation error: ")+ini_error);
    xercesc::XMLString::release(&ini_error);
    throw new_exception;
  }

  jobfilename=NULL;
  setFilenamePattern(the_jobfilenamepattern);
  parser=new xercesc::XercesDOMParser();
  if (parser==NULL) {
    delete jobfilename;
    throw job_exception("could not allocate parser");
  }
  parser->setValidationScheme(xercesc::XercesDOMParser::Val_Always);
  parser->setDoNamespaces(true);
  errHandler = (xercesc::ErrorHandler*) new xercesc::HandlerBase();
  parser->setErrorHandler(errHandler);
}

void job_receiver::setFilenamePattern(const std::string& filenamepattern) {
  if (jobfilename!=NULL) delete jobfilename;
  jobfilenamepattern=filenamepattern;
  jobfilenamesize=filenamepattern.size()+20;
  jobfilename=new char[jobfilenamesize];
  if (jobfilename==NULL) throw job_exception("could not allocate memory for filename");
}

job* job_receiver::receive(size_t no) {
  snprintf(jobfilename,jobfilenamesize+20,jobfilenamepattern.c_str(),no);
  job* new_job=receive(std::string(jobfilename));
  if (new_job->no()!=no) fprintf(stderr, "expected job number %" SIZETPRINTFLETTER " and specified number %" SIZETPRINTFLETTER " are different\n", no, new_job->no() );
  new_job->job_no=no;
  return new_job;
}

job* job_receiver::receive(const std::string& filename) {

  try {
    parser->parse(filename.c_str());
  }
  catch(const xercesc::XMLException& toCatch) {
    char* message = xercesc::XMLString::transcode(toCatch.getMessage());
    job_exception je(std::string("XML error: ")+message);
    xercesc::XMLString::release(&message);
    throw je;
  }
  catch(const xercesc::DOMException& toCatch) {
    char* message = xercesc::XMLString::transcode(toCatch.msg);
    job_exception je(std::string("XML DOM error: ")+message); 
    xercesc::XMLString::release(&message);
    throw je;
  }
  catch(const xercesc::SAXParseException& toCatch) {
    // more verbose for parser errors
    char* message = xercesc::XMLString::transcode(toCatch.getMessage());
    job_exception je(std::string("XML SAX Parser error: ")+message);
    char location[100];
    snprintf(location,sizeof(location),", line %ld column %ld",(long int) toCatch.getLineNumber(),(long int)toCatch.getColumnNumber());
    je.append(location);
    xercesc::XMLString::release(&message);
    throw je;
  }
  catch(const xercesc::SAXException& toCatch) {
    char* message = xercesc::XMLString::transcode(toCatch.getMessage());
    job_exception je(std::string("XML SAX error: ")+message); 
    xercesc::XMLString::release(&message);
    throw je;
  }

  // extract root element, root attributes and root name
  xercesc::DOMDocument* doc=parser->getDocument();
  if (doc==NULL) throw job_exception("xml job document not found");
  xercesc::DOMElement* rootelement=doc->getDocumentElement();
  if (rootelement==NULL) throw job_exception("xml job root document not found");
  char* docname=xercesc::XMLString::transcode(rootelement->getNodeName());
  xercesc::DOMNamedNodeMap* rootattrs=rootelement->getAttributes();

  // check the job number
  XMLCh* docnoname=xercesc::XMLString::transcode("no");
  xercesc::DOMNode* jobno_attr=rootattrs->getNamedItem(docnoname);
  xercesc::XMLString::release(&docnoname);
  if (jobno_attr==NULL) {
    docnoname=xercesc::XMLString::transcode("no");
    jobno_attr=rootattrs->getNamedItem(docnoname);
    xercesc::XMLString::release(&docnoname);
  }
  size_t no=0;
  if (jobno_attr==NULL) fprintf(stderr,"Warning: job %" SIZETPRINTFLETTER ": root element has no job number\n",no);
  else {
    char* docno=xercesc::XMLString::transcode(jobno_attr->getNodeValue());
    no=strtoul(docno,NULL,0);
    xercesc::XMLString::release(&docno);
  }

  job* this_job=NULL;
  // determine the job type by name
  if (strcasecmp(docname,"quit")==0) {
    this_job=new quit_job(no);
  }
  else if (strcasecmp(docname,"nop")==0) {
    this_job=new do_nothing_job(no);
  }
  else if (strcasecmp(docname,"pause")==0) {
    this_job=new pause_job(no);
  } /* pause */
  else if (strcasecmp(docname,"restart")==0) {
    this_job=new restart_job(no);
  } /* restart */
  else if (strcasecmp(docname,"wait")==0) {
    this_job=new wait_job(no,rootattrs);
  } /* wait */
  else if (strcasecmp(docname,"experiment")==0) {
    try {
      this_job=new experiment(no, rootelement);
    }
    catch (const xercesc::DOMException& de) {
      char* domerrmsg=xercesc::XMLString::transcode(de.msg);
      char domerrno[5];
      snprintf(domerrno,5,"%d",de.code);
      job_exception je("sorry, something happend while parsing experiment job: ");
      je.append(domerrmsg);
      je.append(", code ");
      je.append(domerrno);
      xercesc::XMLString::release(&domerrmsg);
      // cleanup missing
      throw je;
    }
  }
  else if (strcasecmp(docname,"configuration")==0) {
    try {
      this_job=new configuration(no, rootelement);
    }
    catch (const xercesc::DOMException& de) {
      char* domerrmsg=xercesc::XMLString::transcode(de.msg);
      char domerrno[5];
      snprintf(domerrno,5,"%d",de.code);
      job_exception je("sorry, something happend while parsing configuration job: ");
      je.append(domerrmsg);
      je.append(", code ");
      je.append(domerrno);
      xercesc::XMLString::release(&domerrmsg);
      // cleanup missing
      throw je;
    }
  }

  xercesc::XMLString::release(&docname);
  parser->reset();
  parser->resetDocument();
  parser->resetDocumentPool();

  return this_job;
}


job_receiver::~job_receiver() {
  delete jobfilename;
  delete errHandler;
  delete parser;
  xercesc::XMLPlatformUtils::Terminate();
}
