/*
 Copyright (C) 2000-2004

 Code contributed by Greg Collecutt, Joseph Hope and Paul Cochrane

 This file is part of xmds.
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

/*
  $Id: xmdsoutput.cc,v 1.26 2004/10/21 09:49:27 paultcochrane Exp $
*/

/*! @file xmdsoutput.cc
  @brief Output element parsing classes and methods

  More detailed explanation...
*/

#include<xmlbasics.h>
#include<dom3.h>
#include<xmdsutils.h>
#include<xmdsclasses.h>
#include<vector>

// ******************************************************************************
// ******************************************************************************
//                              xmdsOutput public
// ******************************************************************************
// ******************************************************************************

extern bool debugFlag;
extern vector<string> simHeaderText, simBodyText, simFooterText;

long nxmdsOutputs=0;  //!< Number of xmds output objects

// ******************************************************************************
xmdsOutput::xmdsOutput(
		       const xmdsSimulation *const yourSimulation,
		       const bool& yourVerboseMode) :
  xmdsElement(yourSimulation,yourVerboseMode) {
  if(debugFlag) {
    nxmdsOutputs++;
    printf("xmdsOutput::xmdsOutput\n");
    printf("nxmdsOutputs=%li\n",nxmdsOutputs);
  }
  myInFileSplitPoint = 0;
};

// ******************************************************************************
xmdsOutput::~xmdsOutput() {
  if(debugFlag) {
    nxmdsOutputs--;
    printf("xmdsOutput::~xmdsOutput\n");
    printf("nxmdsOutputs=%li\n",nxmdsOutputs);
  }
};

// ******************************************************************************
void xmdsOutput::processElement(
				const Element *const yourElement) {
  if(debugFlag) {
    printf("xmdsOutput::processElement\n");
  }

  if(verbose()) {
    printf("Processing output element ...\n");
  }

  list<XMLString> myXMLStringList;
  list<bool> myBoolList;

  // ************************************
  // find output file name

  getAssignmentStrings(yourElement,"filename",0,1,myXMLStringList);

  if(myXMLStringList.size()==1) {
    myOutputFileName=*myXMLStringList.begin();
    if(verbose()) {
      printf("Output file is '%s'\n",myOutputFileName.c_str());
    }
  }
  else {
    // Create default output file name
    myOutputFileName = simulation()->parameters()->simulationName;
    myOutputFileName += ".xsil";

    printf("Output file name defaulting to '%s'\n",myOutputFileName.c_str());
  }

  // ************************************
  // find and process moment groups
  // ************************************

  const NodeList* candidateElements;

  // find constants element and process if present

  candidateElements = yourElement->getElementsByTagName("group",NOT_DEEP);

  if(candidateElements->length()==0) {
    throw xmdsException(yourElement,"No moment <group>s defined!");
  }

  for(unsigned long i=0; i<candidateElements->length(); i++) {
    xmdsMomentGroup* newxmdsMomentGroup = createxmdsMomentGroup();
    const Element* yourElement = dynamic_cast<const Element*> (candidateElements->item(i));
    newxmdsMomentGroup->processElement(yourElement);
  }

  // ************************************
  // find and process breakpoint
  // ************************************

  // find breakpoint element and process if present

  candidateElements = yourElement->getElementsByTagName("breakpoint",NOT_DEEP);

  if(candidateElements->length()>1) {
    throw xmdsException(yourElement,"More than one <breakpoint> defined!");
  }
  
  if(candidateElements->length()==1) {
    if (debugFlag) {
      printf("xmdsOutput::processElement; found <breakpoint> tag\n");
    }

    bpEnabledFlag = true;  // by default, if the <breakpoint> tag is given, then breakpoints are enabled
    getAttributeBools(yourElement, "breakpoint", "enabled", NOT_REQD, bpEnabledFlag);
    if (debugFlag) {
      printf("xmdsOutput::processElement : bpEnabledFlag = %d\n", bpEnabledFlag);
    }

    xmdsBreakPoint* newxmdsBreakPoint = createxmdsBreakPoint();
    const Element* yourElement = dynamic_cast<const Element*> (candidateElements->item(0));
    newxmdsBreakPoint->processElement(yourElement);
  }

};

// ******************************************************************************
void xmdsOutput::setInFileSplitPoint(
				     const unsigned long& inFileSplitPoint) {
  if(debugFlag) {
    printf("xmdsOutput::setInFileSplitPoint\n");
  }

  myInFileSplitPoint = inFileSplitPoint;
};

// ******************************************************************************
unsigned long xmdsOutput::nMomentGroups() const {
  if(debugFlag) {
    printf("xmdsOutput::nMomentGroups\n");
  }

  return myMomentGroupsList.size();
};

// ******************************************************************************
XMLString xmdsOutput::getOutputFileName() const {
  if (debugFlag) {
    printf("xmdsOutput::getOutputFileName\n");
  }

  return myOutputFileName;
};

// ******************************************************************************
const xmdsMomentGroup* xmdsOutput::momentGroup(
					       const unsigned long& index) const {
  if(debugFlag) {
    printf("xmdsOutput::momentGroup\n");
  }

  if(index>=myMomentGroupsList.size()) {
    throw xmdsException("Internal range error in xmdsOutput::momentGroup");
  }

  list<xmdsMomentGroup*>::const_iterator ppxmdsMomentGroup = myMomentGroupsList.begin();

  for(unsigned long i=0; i<index; i++) {
    ppxmdsMomentGroup++;
  }

  return *ppxmdsMomentGroup;
};

// ******************************************************************************
void xmdsOutput::addSamples(
			    const list<unsigned long>& samplesList) const {
  if(debugFlag) {
    printf("xmdsOutput::addSamples\n");
  }

  if(samplesList.size() != myMomentGroupsList.size()) {
    throw xmdsException("Internal error in xmdsOutput::addSamples: wrong number of samples.");
  }

  list<unsigned long>::const_iterator pLong = samplesList.begin();
  for(list<xmdsMomentGroup*>::const_iterator pxmdsMomentGroup = myMomentGroupsList.begin(); pxmdsMomentGroup != myMomentGroupsList.end(); pxmdsMomentGroup++) {
    (*pxmdsMomentGroup)->addSamples(*pLong);
    pLong++;
  }
};

// ******************************************************************************
void xmdsOutput::finaliseGeometry() {
  if(debugFlag) {
    printf("xmdsOutput::finaliseGeometry\n");
  }

  for(list<xmdsMomentGroup*>::const_iterator pxmdsMomentGroup = myMomentGroupsList.begin(); pxmdsMomentGroup != myMomentGroupsList.end(); pxmdsMomentGroup++) {
    (*pxmdsMomentGroup)->finaliseGeometry();
  }
};

// ******************************************************************************
void xmdsOutput::assignActiveVectorPointers(
					    FILE *const outfile,
					    const char *const tempVectorName) const {
  if(debugFlag) {
    printf("xmdsOutput::assignActiveVectorPointers\n");
  }

  for(list<xmdsMomentGroup*>::const_iterator pxmdsMomentGroup = myMomentGroupsList.begin(); pxmdsMomentGroup != myMomentGroupsList.end(); pxmdsMomentGroup++) {
    (*pxmdsMomentGroup)->assignActiveVectorPointers(outfile,tempVectorName);
  }
};


// ******************************************************************************
void xmdsOutput::writePlanCreationCalls(
					FILE *const outfile,
					const bool& useFFTWMeasure,
					const bool& useWisdom) const {
  if(debugFlag) {
    printf("xmdsOutput::writePlanCreationCalls\n");
  }

  for(list<xmdsMomentGroup*>::const_iterator pxmdsMomentGroup = myMomentGroupsList.begin(); pxmdsMomentGroup != myMomentGroupsList.end(); pxmdsMomentGroup++) {
    (*pxmdsMomentGroup)->writePlanCreationCalls(outfile,useFFTWMeasure,useWisdom);
  }
};

// ******************************************************************************
void xmdsOutput::writePlanDeletionCalls(
					FILE *const outfile) const {
  if(debugFlag) {
    printf("xmdsOutput::writePlanDeletionCalls\n");
  }

  for(list<xmdsMomentGroup*>::const_iterator pxmdsMomentGroup = myMomentGroupsList.begin(); pxmdsMomentGroup != myMomentGroupsList.end(); pxmdsMomentGroup++) {
    (*pxmdsMomentGroup)->writePlanDeletionCalls(outfile);
  }
};

// ******************************************************************************
// ******************************************************************************
//                              xmdsOutput private
// ******************************************************************************
// ******************************************************************************

// ******************************************************************************
void xmdsOutput::writePrototypes(
				 FILE *const outfile) const {
  if(debugFlag) {
    printf("xmdsOutput::writePrototypes\n");
  }

  if(verbose()) {
    printf("Writing output prototypes ...\n");
  }

  fprintf(outfile,
	  "// ********************************************************\n"
	  "// output prototypes\n"
	  "\n"
	  "void _write_output();\n"
	  "\n");

  xmdsElement::writePrototypes(outfile);
  fprintf(outfile,"\n");
};

// ******************************************************************************
void xmdsOutput::writeRoutines(
			       FILE *const outfile) const {
  if(debugFlag) {
    printf("xmdsOutput::writeRoutines\n");
  }

  if(verbose()) {
    printf("Writing output routines ...\n");
  }

  // write out code to handle original simulation script
  fprintf(outfile,
	  "// ********************************************************\n"
	  "//		output routines\n"
	  "// ********************************************************\n"
	  "\n"
	  "// *************************\n"
	  "void _write_output() {\n"
	  "\n"
	  "  printf(\"Generating output for %s\\n\");\n"
	  "  //system(\"rm -f %s\");\n\n"
	  "  //if(system(\"split -b %li %s\")) {\n"
	  "\n"
	  "    //printf(\"Cannot open my original simulation script '%s'\\n\");\n"
	  "    //printf(\"Writing xsil data to separate xml document\\n\");\n"
	  "\n"
	  "    //FILE* _outfile=fopen(\"%s\",\"w\");\n"
	  "\n"
	  "    //if(_outfile==0) {\n"
	  "      //printf(\"Unable to create output file '%s'\\n\");\n"
	  "      //printf(\"Exiting.\\n\");\n"
	  "      //return;\n"
	  "    //}\n"
	  "\n"
	  "    //fprintf(_outfile,\"<?xml version=\\\"1.0\\\"?>\\n\");\n"
	  "    //fprintf(_outfile,\"\\n\");\n"
	  "\n",
	  simulation()->parameters()->simulationName.c_str(),
	  myOutputFileName.c_str(),
	  myInFileSplitPoint,simulation()->parameters()->rawFileName.c_str(),
	  simulation()->parameters()->rawFileName.c_str(),
	  myOutputFileName.c_str(),
	  myOutputFileName.c_str());

  // biff out some informative text about xmds - this is the header
  fprintf(outfile,"    //fprintf(_outfile,\"<info>\\n\");\n");
  fprintf(outfile,"    //fprintf(_outfile,\"Output generated with xmds version %s, release %s.\\n\");\n",
	  simulation()->parameters()->version.c_str(),
	  simulation()->parameters()->release.c_str());
  fprintf(outfile,"    //fprintf(_outfile,\"See http://www.xmds.org for more information.\\n\");\n");
  fprintf(outfile,"    //fprintf(_outfile,\"</info>\\n\");\n");
  // end of informative text

  // it's more logical to put the simulation tag here
  fprintf(outfile,"    //fprintf(_outfile,\"<simulation>\\n\");\n");

  // now write out all of the moment groups
  for(unsigned long i=0;i<myMomentGroupsList.size();i++) {
    fprintf(outfile,"	//_mg%li_write_out(_outfile);\n",i);
  }

  fprintf(outfile,
	  "\n"
	  "    //fprintf(_outfile,\"\\n\");\n"
	  "    //fprintf(_outfile,\"</simulation>\\n\");\n");

  // biff out some informative text about xmds - this is the footer
  fprintf(outfile,"    //fprintf(_outfile,\"<info>\\n\");\n");
  fprintf(outfile,"    //fprintf(_outfile,\"Output generated with xmds version %s, release %s.\\n\");\n",
	  simulation()->parameters()->version.c_str(),
	  simulation()->parameters()->release.c_str());
  fprintf(outfile,"    //fprintf(_outfile,\"See http://www.xmds.org for more information.\\n\");\n");
  fprintf(outfile,"    //fprintf(_outfile,\"</info>\\n\");\n");
  // end of informative text
  
  fprintf(outfile,
	  "\n"
	  "    //fclose(_outfile);\n"
	  "  //}\n"
	  "  //else {\n"
	  "\n"
	  "    //system(\"mv -f xaa %s\");\n"
	  "\n"
	  "    FILE* _outfile=fopen(\"%s\",\"w\");\n"
	  "\n"
	  "    if(_outfile==0) {\n"
	  "      printf(\"Unable to open output file %s\\n\");\n"
	  "      printf(\"Exiting.\\n\");\n"
	  "      return;\n"
	  "    }\n"
	  "\n",
	  myOutputFileName.c_str(),
	  myOutputFileName.c_str(),
	  myOutputFileName.c_str());

  // put the header text into the output from the xmds script
  fprintf(outfile,"\n");
  for (unsigned int i=0; i<simHeaderText.size(); i++) {
    fprintf(outfile,"      fprintf(_outfile,\"%s\\n\");\n",simHeaderText[i].c_str());
  }

  // put the body text into the output from the xmds script
  fprintf(outfile,"\n");
  for (unsigned int i=0; i<simBodyText.size(); i++) {
    fprintf(outfile,"      fprintf(_outfile,\"%s\\n\");\n",simBodyText[i].c_str());
  }
  
  // biff out some informative text about xmds - this is the footer
  fprintf(outfile,"    fprintf(_outfile,\"\\n<info>\\n\");\n");
  fprintf(outfile,"    fprintf(_outfile,\"Output generated with xmds version %s, release %s.\\n\");\n",
	  simulation()->parameters()->version.c_str(),
	  simulation()->parameters()->release.c_str());
  fprintf(outfile,"    fprintf(_outfile,\"See http://www.xmds.org for more information.\\n\");\n");

  if (simulation()->argStruct()->nameList.size() != 0) {
    fprintf(outfile,"    fprintf(_outfile,\"  Variables that can be specified on the command line: \\n\");\n");
    list<string>::const_iterator inameList = simulation()->argStruct()->nameList.begin();
    list<string>::const_iterator itypeList = simulation()->argStruct()->typeList.begin();
    for (long unsigned int i=0; i<simulation()->argStruct()->nameList.size(); i++) 
      {
    string theType=itypeList->c_str();
      if( theType=="double "){
          fprintf(outfile,"    fprintf(_outfile,\"    Command line argument '%s' = %%e \\n\",%s);\n",inameList->c_str(),inameList->c_str());}
      else if(theType=="long "){
          fprintf(outfile,"    fprintf(_outfile,\"    Command line argument '%s' = %%li \\n\",%s);\n",inameList->c_str(),inameList->c_str());}
      else if(theType=="float "){
          fprintf(outfile,"    fprintf(_outfile,\"    Command line argument '%s' = %%e \\n\",%s);\n",inameList->c_str(),inameList->c_str());}
      else if(theType=="int "){
          fprintf(outfile,"    fprintf(_outfile,\"    Command line argument '%s' = %%i \\n\",%s);\n",inameList->c_str(),inameList->c_str());}
      else {
          fprintf(outfile,"    fprintf(_outfile,\"    Command line argument '%s' is an unimplemented output type '%s'\\n\");\n",inameList->c_str(),itypeList->c_str());}
      itypeList++;
      inameList++;
      }
    fprintf(outfile,"\n");
  }

  fprintf(outfile,"    fprintf(_outfile,\"</info>\\n\");\n");
  // end of informative text

  // now put the data into the file
  for(unsigned long i=0;i<myMomentGroupsList.size();i++) {
    fprintf(outfile,"	_mg%li_write_out(_outfile);\n",i);
  }

  // put the footer text into the xmds simulation output
  fprintf(outfile,"\n");
  for (unsigned int i=0; i<simFooterText.size(); i++) {
    fprintf(outfile,"      fprintf(_outfile,\"%s\\n\");\n",simFooterText[i].c_str());
  }

  // close things down and tidy up a bit
  fprintf(outfile,
	  "\n"
	  "    fclose(_outfile);\n"
	  "\n"
	  "    //system(\"cat xab >> %s\");\n"
	  "\n"
	  "    //system(\"rm -f xab\");\n"
	  "  //}\n"
	  "}\n"
	  "\n",
	  myOutputFileName.c_str());

  xmdsElement::writeRoutines(outfile);
  fprintf(outfile,"\n");
};

// ******************************************************************************
xmdsMomentGroup* xmdsOutput::createxmdsMomentGroup() {
  if(debugFlag) {
    printf("xmdsOutput::createxmdsMomentGroup\n");
  }

  xmdsMomentGroup* newxmdsMomentGroup = new xmdsMomentGroup(simulation(),verbose(),myMomentGroupsList.size());
  addChild((xmdsElement*) newxmdsMomentGroup);
  myMomentGroupsList.push_back(newxmdsMomentGroup);
  return newxmdsMomentGroup;
};

// ******************************************************************************
xmdsBreakPoint* xmdsOutput::createxmdsBreakPoint() {
  if(debugFlag) {
    printf("xmdsOutput::createxmdsBreakPoint\n");
  }

  xmdsBreakPoint* newxmdsBreakPoint = new xmdsBreakPoint(simulation(),verbose());
  addChild((xmdsElement*) newxmdsBreakPoint);
  return newxmdsBreakPoint;
};



syntax highlighted by Code2HTML, v. 0.9.1