/*
  for ducumentation see basefield.h

Author:      Raimundo Sierra
             www.rsierra.com

Copyright:   Copyright (c) 2000 Raimundo Sierra. All rights reserved.
LICENSE:     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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "basefield.h"

// ---------------------------------------------------------------------------
//  Local data
// ---------------------------------------------------------------------------
static XMLCh*                   gEncodingName          = 0;
static XMLFormatter::UnRepFlags gUnRepFlags            = XMLFormatter::UnRep_CharRef;
static XMLFormatter*            gFormatter             = 0;
// ---------------------------------------------------------------------------
//  End Local data
// ---------------------------------------------------------------------------


// ---------------------------------------------------------------------------
//  Local const data
//
//  Note: This is the 'safe' way to do these strings. If you compiler supports
//        L"" style strings, and portability is not a concern, you can use
//        those types constants directly.
// ---------------------------------------------------------------------------
static const XMLCh  gEndElement[] = { chOpenAngle, chForwardSlash, chNull };
static const XMLCh  gEndPI[] = { chQuestion, chCloseAngle, chNull};
static const XMLCh  gStartPI[] = { chOpenAngle, chQuestion, chNull };
static const XMLCh  gXMLDecl1[] =
{
        chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l
    ,   chSpace, chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i
    ,   chLatin_o, chLatin_n, chEqual, chDoubleQuote, chNull
};
static const XMLCh  gXMLDecl2[] =
{
        chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c
    ,   chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual
    ,   chDoubleQuote, chNull
};
static const XMLCh  gXMLDecl3[] =
{
        chDoubleQuote, chSpace, chLatin_s, chLatin_t, chLatin_a
    ,   chLatin_n, chLatin_d, chLatin_a, chLatin_l, chLatin_o
    ,   chLatin_n, chLatin_e, chEqual, chDoubleQuote, chNull
};
static const XMLCh  gXMLDecl4[] =
{
        chDoubleQuote, chQuestion, chCloseAngle
    ,   chCR, chLF, chNull
};

static const XMLCh  gStartCDATA[] =
{ 
        chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D,
        chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull
};

static const XMLCh  gEndCDATA[] =
{
    chCloseSquare, chCloseSquare, chCloseAngle, chNull
};
static const XMLCh  gStartComment[] =
{ 
    chOpenAngle, chBang, chDash, chDash, chNull
};

static const XMLCh  gEndComment[] =
{
    chDash, chDash, chCloseAngle, chNull
};

static const XMLCh  gStartDoctype[] =
{ 
    chOpenAngle, chBang, chLatin_D, chLatin_O, chLatin_C, chLatin_T,
    chLatin_Y, chLatin_P, chLatin_E, chSpace, chNull
};
static const XMLCh  gPublic[] =
{ 
    chLatin_P, chLatin_U, chLatin_B, chLatin_L, chLatin_I,
    chLatin_C, chSpace, chDoubleQuote, chNull
};
static const XMLCh  gSystem[] =
{ 
    chLatin_S, chLatin_Y, chLatin_S, chLatin_T, chLatin_E,
    chLatin_M, chSpace, chDoubleQuote, chNull
};
static const XMLCh  gStartEntity[] =
{ 
    chOpenAngle, chBang, chLatin_E, chLatin_N, chLatin_T, chLatin_I,
    chLatin_T, chLatin_Y, chSpace, chNull
};
static const XMLCh  gNotation[] =
{ 
    chLatin_N, chLatin_D, chLatin_A, chLatin_T, chLatin_A,
    chSpace, chDoubleQuote, chNull
};

const int MAXSTRINGLENGTH = 300;
// ---------------------------------------------------------------------------
//  End local const data
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Local classes
// ---------------------------------------------------------------------------
class DOMPrintFormatTarget : public XMLFormatTarget
{
 public:
  DOMPrintFormatTarget(const char* location)  {
    out_file.open(location, ios::app);
    if(out_file.bad()){
      cerr << "ERROR: Unable to open output file in local class DOMPrintFormatTarget in basefield.cc\n"
	"Exit\n";
      exit(0);
    }
  }
  ~DOMPrintFormatTarget() {
    out_file.close();
  } 
  
  // -----------------------------------------------------------------------
  //  Implementations of the format target interface
  // -----------------------------------------------------------------------
  void writeChars(const   XMLByte* const  toWrite,
                    const   unsigned int    count = 0,
                            XMLFormatter * const formatter= NULL)
    {
      // Without the cast, it was printing the pointer value in hex.
      out_file << (char *) toWrite;
    }
  
 private:
  ofstream out_file;
  // -----------------------------------------------------------------------
  //  Unimplemented methods:
  // -----------------------------------------------------------------------
  DOMPrintFormatTarget(const DOMPrintFormatTarget& other);
  void operator=(const DOMPrintFormatTarget& rhs);
};
// ---------------------------------------------------------------------------
//  End Local classes
// ---------------------------------------------------------------------------


basefield::basefield(){
  
  try {
    XMLPlatformUtils::Initialize();
  }
  catch (const XMLException& toCatch) {
    cerr << "Error during initialization! :\n"
	 << "  Exception message:"
	 << DOMString(toCatch.getMessage()) << endl;
    exit(0);
  }

  _originalfile   = new char[MAXSTRINGLENGTH];
  _sourcefile     = new char[MAXSTRINGLENGTH]; 
  _orientation    = new char[15];
  _datafile       = new char[MAXSTRINGLENGTH];
  _date           = new char[15];  

  _gestationalAge = 0; 
  _mrNumber       = 0;
  _studyNumber    = 0;
  _seriesNumber   = 0;

  _dimx           = 0;
  _dimy           = 0;
  _dimz           = 0;
  _deltax         = 1;
  _deltay         = 1;
  _deltaz         = 1;  
}

basefield::~basefield(){
  // Call the termination method
  XMLPlatformUtils::Terminate();

  // clean up
  delete[] _date;
  delete[] _datafile;
  delete[] _orientation;
  delete[] _sourcefile;
  delete[] _originalfile;
}

short* 
basefield::read_pic(short *image, char path_file[], int offset=0)
{
  FILE *in_file;
  in_file = fopen(path_file, "r");
  if(in_file == NULL) {
    cerr << "\nERROR: Cannot open " << path_file << "\tExit\n";
    exit(0);
  } else {
    fseek(in_file, offset, 0);
    fread(image,sizeof(short),_dimx*_dimy,in_file);
  }
  fclose(in_file);
  return image;
}


unsigned short* 
basefield::read_pic(unsigned short *image, char path_file[], int offset=0)
{
  FILE *in_file;
  in_file = fopen(path_file, "r");
  if(in_file == NULL) {
    cerr << "\nERROR: Cannot open " << path_file << "\tExit\n";
    exit(0);
  } else {
    fseek(in_file, offset, 0);
    fread(image,sizeof(unsigned short),_dimx*_dimy,in_file);
  }
  fclose(in_file);
  return image;
}

void 
basefield::setNumbers(const int age, const int patient_id, const int studyNr, const int seriesNumber)
{
  _gestationalAge = age; 
  _mrNumber       = patient_id;
  _studyNumber    = studyNr;
  _seriesNumber   = seriesNumber;
}
  
void 
basefield::setDate(const char* date)
{
  strcpy(_date, date);
  //cout << "After setting date: "<< _date<<endl;
}
  
void 
basefield::setOrig(const char* orig)
{
  strcpy(_originalfile, orig);
}
  
void 
basefield::setOrientation(const char orientation)
{
  switch(orientation){
  case 's': strcpy(_orientation, "saggital");
  case 'c': strcpy(_orientation, "coronal");
  case 'a': strcpy(_orientation, "axial");
  default: strcpy(_orientation, "axial");
  }
}

void 
basefield::setDelta(const float deltax, const float deltay, const float deltaz)
{
  _deltax = deltax;
  _deltay = deltay;
  _deltaz = deltaz;
}

void 
basefield::getDelta(float& deltax, float& deltay, float& deltaz) 
{
  deltax = _deltax;
  deltay = _deltay;
  deltaz = _deltaz;
}
  
void 
basefield::getDimension(int& dimx, int& dimy, int& dimz)
{
  dimx = _dimx;
  dimy = _dimy;
  dimz = _dimz;
}

char * 
basefield::getPath(char * path)
{
  strcpy(path, _datafile);
  return path;
}

char * 
basefield::getSource(char * path)
{
  strcpy(path, _sourcefile);
  return path;
}

char * 
basefield::getOriginal(char * path)
{
  strcpy(path, _originalfile);
  return path;
}

char * 
basefield::getDate(char * date)
{
  strcpy(date, _date);
  return date;
}

char * 
basefield::getOrientation(char * orientation)
{
  strcpy(orientation, _orientation);
  return orientation;
}

void
basefield::getNumbers(int& Age, int& ID, int& Study, int& SerieNR)
{
  Age = _gestationalAge;
  ID  = _mrNumber;
  Study = _studyNumber;
  SerieNR = _seriesNumber;
}

void 
basefield::getProperties(basefield &b_field)
{
  b_field.getPath(_datafile);
  b_field.getSource(_sourcefile);
  b_field.getOriginal(_originalfile);
  b_field.getDimension(_dimx, _dimy, _dimz);
  b_field.getDelta(_deltax, _deltay, _deltaz);
  b_field.getDate(_date);
  b_field.getOrientation(_orientation);
  b_field.getNumbers(_gestationalAge, _mrNumber, _studyNumber, _seriesNumber);
}

void
basefield::check_boundaries(int offset[3], int windowsize[3], int plane[4]=NULL) const
{
#ifdef debug
  int offtmp[3];
  int wintmp[3];
  for(int i=0; i<3; i++){
    offtmp[i] = offset[i]; 
    wintmp[i] = windowsize[i];
  }
#endif
  // this is for checking offset
  if (offset[0]>_dimx || offset[0]<0){ 
    offset[0] = 0; 
  }
  if (offset[1]>_dimy || offset[1]<0){
    offset[1] = 0;
  }    
  if (offset[2]>_dimz || offset[2]<0){
    offset[2] = 0;
  } 
  // this is for checking boundaries of a 3D volume
  if (offset[0]+windowsize[0]>_dimx || windowsize[0]<0 ){ 
    windowsize[0] = _dimx-offset[0];
  }
  if (offset[1]+windowsize[1]>_dimy || windowsize[1]<0 ){
    windowsize[1] = _dimy-offset[1];
  }
  if (offset[2]+windowsize[2]>_dimz || windowsize[2]<0 ){
    windowsize[2] = _dimz-offset[2];
  } 
#ifdef debug
  if(offtmp[0] != offset[0] || wintmp[0] != windowsize[0] ||
     offtmp[1] != offset[1] || wintmp[1] != windowsize[1] ||
     offtmp[2] != offset[2] || wintmp[2] != windowsize[2]){
    cout << "Values have been modified in check_boundaries():\n";
    cout << "Windowsize is: ("<<windowsize[0]<<", "<<windowsize[1]<<", "<<windowsize[2]<<")\n";
    cout << "Offset is:     ("<<offset[0]    <<", "<<offset[1]    <<", "<<offset[2]    <<")\n";
  }
#endif
  if(plane!=NULL){
    if      ((windowsize[0] >= windowsize[1] && windowsize[1] >= windowsize[2]) ||   // 0 1 2 default
	     (windowsize[1] >= windowsize[0] && windowsize[0] >= windowsize[2])) {   // 1 0 2
      plane[0] = windowsize[0]; 
      plane[1] = windowsize[1]; 
      plane[2] = windowsize[2]; 
      plane[3] = 2;
    }   
    else if ((windowsize[0] >= windowsize[2] && windowsize[2] >= windowsize[1]) ||   // 0 2 1
             (windowsize[2] >= windowsize[0] && windowsize[0] >= windowsize[1])) {   // 2 0 1
      plane[0] = windowsize[0]; 
      plane[1] = windowsize[2]; 
      plane[2] = windowsize[1]; 
      plane[3] = 1;
    }
    else if ((windowsize[1] >= windowsize[2] && windowsize[2] >= windowsize[0]) ||   // 1 2 0
	     (windowsize[2] >= windowsize[1] && windowsize[1] >= windowsize[0])) {   // 2 1 0
      plane[0] = windowsize[1]; 
      plane[1] = windowsize[2]; 
      plane[2] = windowsize[0]; 
      plane[3] = 0;
    }
    else {
      cout << "WARNING: could not define plane in check_boundaries() in eigenfield.h\n";
      cout << "Returning plane 012\n";
      plane[0] = windowsize[0]; 
      plane[1] = windowsize[1]; 
      plane[2] = windowsize[2]; 
      plane[3] = 2;      
    }
  }
}

void 
basefield::read_XMLHeader( const char xmlFile[])
{
  //  Create our parser, then attach an error handler to the parser.
  //  The parser will call back to methods of the ErrorHandler if it
  //  discovers errors during the course of parsing the XML document.

  DOMParser *parser= new DOMParser;                        // the xml parser
  ErrorHandler *errReporter = new DOMTreeErrorReporter();  // the xml errorhandler
  DOMParser::ValSchemes ValScheme = DOMParser::Val_Auto;
  parser->setValidationScheme(ValScheme);
  parser->setDoNamespaces(false);
  parser->setErrorHandler(errReporter);
  parser->setCreateEntityReferenceNodes(false);
  parser->setToCreateXMLDeclTypeNode(true);

  //  Parse the XML file, catching any XML exceptions that might propogate
  //  out of it.

  bool errorsOccured = false;
  try
    {
      parser->parse(xmlFile);
    }
  catch (const XMLException& e)
    {
      cerr << "An error occured during parsing (1)\nMessage: \n"
	   << DOMString(e.getMessage()) << endl;
      errorsOccured = true;
    } 
  catch (const DOM_DOMException& e)
    {
      cerr << "An error occured during parsing (2)\nMessage: \n"
	   << DOMString(e.msg) << endl;
      errorsOccured = true;
    }
  catch (...)
    {
      cerr << "An error occured during parsing (3)\n " << endl;
      errorsOccured = true;
    }

  // If the parse was successful, get the document data from the DOM tree

  if (!errorsOccured) {
    DOM_Node doc = parser->getDocument();
    XMLCh* EncodingName = 0;
    DOMString encNameStr("UTF-8");    // default
    DOM_Node aNode = doc.getFirstChild();
    if (aNode.getNodeType() == DOM_Node::XML_DECL_NODE) {
      DOMString aStr = ((DOM_XMLDecl &)aNode).getEncoding();
      if (aStr != "") {
	encNameStr = aStr;
      }
    }
    unsigned int lent = encNameStr.length();
    EncodingName = new XMLCh[lent + 1];
    XMLString::copyNString(EncodingName, encNameStr.rawBuffer(), lent);
    EncodingName[lent] = 0;
    // recursively read data. calls propietary function to process content
    try 
      {
	readdata(doc);
      }
    catch (XMLException& e)
      {
	cerr << "An error occurred during creation of output transcoder. Msg is:"
	     << endl
	     << DOMString(e.getMessage()) << endl;
      }
    delete EncodingName;
  }
  else {
    cout << "Enter the required values manualy:\n";
    this->readmanualy();
  }
  //  Clean up the error handler. The parser does not adopt handlers
  //  since they could be many objects or one object installed for multiple
  //  handlers.
  delete errReporter;
  //  Delete the parser itself.  Must be done prior to calling Terminate, below.
  delete parser;
}

void 
basefield::readdata(DOM_Node& node)
{
  // Get the name and value out for convenience
  DOMString   nodeName = node.getNodeName();
  DOMString   nodeValue = node.getNodeValue();
  //unsigned long lent = nodeValue.length();

  switch (node.getNodeType()){
  case DOM_Node::DOCUMENT_NODE:                  // Document root 
    {
      DOM_Node child = node.getFirstChild();
      while( child != 0) 
	{                                        // there are children => recursion
	  readdata(child);  
	  child = child.getNextSibling();
	}
      break;
    }
  case DOM_Node::ELEMENT_NODE:                   // normal elements
    {
#ifdef debug
      cout << nodeName << "\t is a  ELEMENT_NODE with value"<< nodeValue <<endl;
#endif
      // if I know this Node => Process
      char *tmp = nodeName.transcode();
      if(!strcmp(tmp, "file")){
	int test = readstring(node, _datafile);
	if (test==-1){
	  this->readmanualy(_datafile);
	}
	strcpy(_orientation, "orientation");
	test = readattribute(node, _orientation);
	if (test==-1){
	  this->readmanualy(_orientation);
	}
	//this->readfile(node);
      }	

      // only try to read the following
      else if(!strcmp(tmp, "source")){
	readstring(node, _sourcefile);
	//int test = readstring(node, _sourcefile);
      }	
      else if(!strcmp(tmp, "original")){
	readstring(node, _originalfile);
	//int test = readstring(node, _originalfile);
      }
      else if (!strcmp(tmp, "mrNumber")){
	_mrNumber = int(readfloat(node));
      }
      else if (!strcmp(tmp, "studyNumber")){
	_studyNumber = int(readfloat(node));
      }
      else if (!strcmp(tmp, "seriesNumber")){
	_seriesNumber = int(readfloat(node));
      }
      else if (!strcmp(tmp, "age")){
	_gestationalAge = int(readfloat(node));
      }
      // end only try to read

      else if (!strcmp(tmp, "dim_x")){
	_dimx = int(readfloat(node));
	if (_dimx == -1) {
	  cout << "\nNo value for x-dimension available\n";
	  this->readmanualy(_dimx);
	}
      }	
      else if (!strcmp(tmp, "dim_y")){
	_dimy = int(readfloat(node));
	if (_dimy == -1) {
	  cout << "\nNo value for y-dimension available\n";
	  this->readmanualy(_dimy);
	}
      }	
      else if (!strcmp(tmp, "dim_z")){
	_dimz = int(readfloat(node));
	if (_dimz == -1) {
	  cout << "\nNo value for z-dimension available\n";
	  this->readmanualy(_dimz);
	}
      }	
      else if (!strcmp(tmp, "delta_x")){
	_deltax = readfloat(node);
	if (_deltax == -1) {
	  cout << "\nNo value for x-voxelsize available\n";
	  this->readmanualy(_deltax);
	}
      }	
      else if (!strcmp(tmp, "delta_y")){
	_deltay = readfloat(node);
	if (_deltay == -1) {
	  cout << "\nNo value for y-voxelsize available\n";
	  this->readmanualy(_deltay);
	}
      }	
      else if (!strcmp(tmp, "delta_z")){
	_deltaz = readfloat(node);
	if (_deltaz == -1) {
	  cout << "\nNo value for z-voxelsize available\n";
	  this->readmanualy(_deltaz);
	}
      }	
      else {  
	//  Test for the presence of children, which includes both
	//  text content and nested elements.
	DOM_Node child = node.getFirstChild();
	if (child != 0){
	  while (child!=0){ // there are children => recursion
	    this->readdata(child);  
	    child = child.getNextSibling();
	  }
	}
	else {              // do nothing, unkown name of node => ignore
	} 
      }
      delete[] tmp;
      break;
    }
  case DOM_Node::TEXT_NODE:  {                                                        break; }
  case DOM_Node::DOCUMENT_TYPE_NODE:  {                                               break; } 
  case DOM_Node::PROCESSING_INSTRUCTION_NODE:  {
      cout << nodeName << "\t is a PROCESSING_INSTRUCTION_NODE, no implementation\n"; break; }
  case DOM_Node::ENTITY_REFERENCE_NODE:  {
      cout << nodeName << "\t is a ENTITY_REFERENCE_NODE, no implementation\n";       break; }  
  case DOM_Node::CDATA_SECTION_NODE:     {
      cout << nodeName << "\t is a CDATA_SECTION_NODE, no implementation\n";          break; }
  case DOM_Node::COMMENT_NODE: {
      cout << nodeName << "\t is a COMMENT_NODE_NODE, no implementation\n";           break; }  
  case DOM_Node::ENTITY_NODE:  {
      cout << nodeName << "\t is a ENTITY_NODE, no implementation\n";                 break; }
  case DOM_Node::XML_DECL_NODE:  {                                                    break; }
  default:
    cerr << "Unrecognized node type = "
	 << (long)node.getNodeType() << endl;
  }
}


float 
basefield::readfloat(DOM_Node& node){
  float value=-1;
  char *tmp;
  DOM_Node child = node.getFirstChild();
  if (child==0) return -1;
  DOMString childvalue = child.getNodeValue();
  tmp =  childvalue.transcode();
  if(tmp==NULL) return -1;
  value = atof(tmp);
  return value;
}
 
void 
basefield::readfile(DOM_Node& node)
{      
  DOM_Node child = node.getFirstChild();
  if (child==0){
    cout << "\nNo location for data found\n";
    readmanualy(_datafile);
  }
  else {
    strcpy(_datafile, child.getNodeValue().transcode());
  }
  // Process any attributes on this element
  DOM_NamedNodeMap attributes = node.getAttributes();
  int attrCount = attributes.getLength();
  for (int i = 0; i < attrCount; i++){
    DOM_Node  attribute = attributes.item(i);
    // I'm interested in orientation
    if(!strcmp(attribute.getNodeName().transcode(), "orientation")){
      strcpy(_orientation, attribute.getNodeValue().transcode());
    }
    else if(!strcmp(attribute.getNodeName().transcode(), "byteorder")){
      //cout << "Byteorder has value       "<< attribute.getNodeValue()<<endl;
    }
  }  
}

int 
basefield::readstring(DOM_Node& node, char* mystring)
{   
  DOM_Node child = node.getFirstChild();
  if (child==0) return -1;
  else {
    strcpy(mystring, child.getNodeValue().transcode());
  }
  return 1; 
}

int
basefield::readattribute(DOM_Node& node, char* mystring)
{
  // Process any attributes on this element
  DOM_NamedNodeMap attributes = node.getAttributes();
  int attrCount = attributes.getLength();
  for (int i = 0; i < attrCount; i++){
    DOM_Node  attribute = attributes.item(i);
    // I'm interested in value of attribute passed by mystring
    if(!strcmp(attribute.getNodeName().transcode(), mystring)){
      strcpy(mystring, attribute.getNodeValue().transcode());
      return 1; // success
    }
  }    
  return -1;   // attribute not found
}

void
basefield::readmanualy()
{
  cout << "\nLocation of the data: ";
  this->readmanualy(_datafile);
  cout << "\nx-dimension:          ";
  this->readmanualy(_dimx);
  cout << "\ny-dimension:          ";
  this->readmanualy(_dimy);
  cout << "\nz-dimension:          ";
  this->readmanualy(_dimz);
  cout << "\nx-voxelsize:          ";
  this->readmanualy(_deltax);
  cout << "\ny-voxelsize:          ";
  this->readmanualy(_deltay);
  cout << "\nz-voxelsize:          ";
  this->readmanualy(_deltaz);
}

void 
basefield::readmanualy(int& value)
{
  cout << "Enter integer value (-1 to exit): \t";
  cin >> value;
  cout << "\t\t\t\t\t\t";
  if (value==-1) exit(0);
}
  
void  
basefield::readmanualy(float& value)
{
  cout << "Enter float value (-1 to exit): \t";
  cin >> value;
  cout << "\t\t\t\t\t\t";
  if (value==-1) exit(0);
}        

void  
basefield::readmanualy(char* value)
{
  cout << "Enter string ('exit' to exit): \t";
  cin >> value;
  cout << "\t\t\t\t\t\t";
  if (!strcmp(value, "exit")) exit(0);
}

void  
basefield::assert_values()
{
  char orientation;
  char* prepend = new char[MAXSTRINGLENGTH];
  char* tmp     = new char[MAXSTRINGLENGTH];
  // PRE: _dimx,y,z exists
  // if any path starts without a / (not a full path) prepend current path 
  if(!_originalfile || _originalfile[0]!='/'){
    cout << "\nProvide full path to original data (no / at the end): ";
    cin >> prepend;
    strcpy(_originalfile, prepend);
  }
  if(!_sourcefile || _sourcefile[0]!='/'){
    cout << "\nProvide current path (no / at the end): ";
    cin >> prepend;
    if(_sourcefile){
      strcpy(tmp, _sourcefile);
      strcpy(_sourcefile, prepend);
      strcat(_sourcefile, "/");
      strcat(_sourcefile, tmp);
    }
    else {
      strcpy(_sourcefile, prepend);
    }
  }
  if(!_datafile || _datafile[0]!='/'){
    cout << "\nProvide current path (no / at the end): ";
    cin >> prepend;
    if(_datafile){
      strcpy(tmp, _datafile);
      strcpy(_datafile, prepend);
      strcat(_datafile, "/");
      strcat(_datafile, tmp);
    }
    else {
      strcpy(_datafile, prepend);
    }
  }
  // if all deltas are 1 ask to modify
  if(_deltax==1 && _deltay==1 && _deltaz==1) {
    cout << "Enter deltax, deltay, deltaz (voxelsize) values: ";
    cin >> _deltax >> _deltay >> _deltaz;
  }
  // if _orientation is not set ask for it
  if(!_orientation || !(!strcmp(_orientation, "saggital") || !strcmp(_orientation, "axial") || !strcmp(_orientation, "coronal"))){
    cout << "Enter orientation (a for axial, s for saggital, c for coronal): ";
    cin >> orientation;
    switch(orientation){
    case 'a': strcpy(_orientation, "axial");    break;
    case 's': strcpy(_orientation, "saggital"); break;
    case 'c': strcpy(_orientation, "coronal");  break;
    default: cout << "Invalid orientation in asssert_values() in basefield.h, assume axial";
      strcpy(_orientation, "axial");
    }
  }
  if(_gestationalAge<=0){
    cout << "Enter gestational age: ";
    cin  >> _gestationalAge;
  }  
  if(_mrNumber<=0){
    cout << "Enter MR Number:       ";
    cin  >> _mrNumber;
  }  
  if(_studyNumber<=0){
    cout << "Enter study number:    ";
    cin  >> _studyNumber;
  }  
  if(_seriesNumber<=0){
    cout << "Enter series number:   ";
    cin  >> _seriesNumber;
  }
  if(!_date){
    cout << "Enter date (mm/dd/yyyy): ";
    cin  >> _date;
  }
  delete[] tmp;
  delete[] prepend;
}

void 
basefield::write_XMLHeader(const char xmlPath[]){
  
  int length = strlen(xmlPath);
  char *xmlFile = new char[length+5];
  strcpy(xmlFile, xmlPath);
  if(!(xmlPath[length-3] =='x' && xmlPath[length-2] =='m' && xmlPath[length-1] =='l')){
    // append .xml to file
    xmlFile[length] = '.';
    xmlFile[length+1] = 'x';
    xmlFile[length+2] = 'm';
    xmlFile[length+3] = 'l';
    xmlFile[length+4] = '\0';
  }
#ifdef debug
  cout << "XML File befor writing header: "<<xmlFile<<endl<<flush;
#endif
  FILE *test_file;
  test_file = fopen(xmlFile, "r");
  if(!test_file==0) {  // file already exists, output warning!
    char overwrite;
    cout << "\nWARNING: \nXML header:\n"<<xmlFile<<"\nalready exists!\n"
      "Overwrite the file (y=yes, any character else): ";
    cin >> overwrite;
    if(!(overwrite=='y' || overwrite=='Y')){
      cout << "Will not overwrite XMLHeader";
      fclose(test_file);
      return;
    }
    fclose(test_file);
  }

  char buffer[100];

  this->assert_values();  // make shure all the required values are present and valid

  //cout << "In write_XMLHeader after assert_values before writting header\n"<< flush;
  ofstream out_file(xmlFile);
  out_file << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n";
  out_file << "<!DOCTYPE spl_tensor SYSTEM \"/home/rsierra/c++/tensor/data/spl_tensor.dtd\">\n\n";
  out_file.close();

  DOM_DOMImplementation impl;
  
  DOM_Document doc1 = impl.createDocument(
					  0,                    // root element namespace URI.
					  "spl_tensor",         // root element name
					  DOM_DocumentType());  // document type object (DTD).
  
  DOM_Element rootElem = doc1.getDocumentElement();
  rootElem.setAttribute("version", "1.0");
  
  DOM_Element  headElem = doc1.createElement("header");
  rootElem.appendChild(headElem);

  //cout << "Before mrNumber\n" << flush;
  DOM_Element  mrElem = doc1.createElement("mrNumber");
  headElem.appendChild(mrElem);
  sprintf(buffer, "%d", _mrNumber);
  DOM_Text     mrVal  = doc1.createTextNode(buffer);
  mrElem.appendChild(mrVal);

  //cout << "Before studyNumber\n" << flush;
  DOM_Element  stElem = doc1.createElement("studyNumber");
  headElem.appendChild(stElem);
  sprintf(buffer, "%d", _studyNumber);
  DOM_Text     stVal  = doc1.createTextNode(buffer);
  stElem.appendChild(stVal);

  //cout << "Before seriesNumber\n" << flush;
  DOM_Element  serElem = doc1.createElement("seriesNumber");
  headElem.appendChild(serElem);
  sprintf(buffer, "%d", _seriesNumber);
  DOM_Text     serVal  = doc1.createTextNode(buffer);
  serElem.appendChild(serVal);

  //cout << "Before age\n" << flush;
  DOM_Element  gaElem = doc1.createElement("age");
  headElem.appendChild(gaElem);
  sprintf(buffer, "%d", _gestationalAge);
  DOM_Text     gaVal  = doc1.createTextNode(buffer);
  gaElem.appendChild(gaVal);
  gaElem.setAttribute("type",   "gestational");

  //cout << "Before original\n" << flush;
  DOM_Element  origElem = doc1.createElement("original");
  headElem.appendChild(origElem);
  origElem.setAttribute("date",       "");
  origElem.setAttribute("orientation", _orientation);
  origElem.setAttribute("byteorder",   "MSB");
  DOM_Text     origDataVal = doc1.createTextNode(_originalfile);
  origElem.appendChild(origDataVal);
  
  //cout << "Before source\n" << flush;
  DOM_Element  sourceElem = doc1.createElement("source");
  headElem.appendChild(sourceElem);
  sourceElem.setAttribute("date",        _date);
  sourceElem.setAttribute("orientation", _orientation);
  sourceElem.setAttribute("byteorder",   "MSB");
  DOM_Text     sourceDataVal = doc1.createTextNode(_sourcefile);
  sourceElem.appendChild(sourceDataVal);
  
  //cout << "Before file\n" << flush;
  DOM_Element  fileElem = doc1.createElement("file");
  headElem.appendChild(fileElem);
  //cout << ctime() << endl;
  fileElem.setAttribute("date",        _date);
  fileElem.setAttribute("orientation", _orientation);
  fileElem.setAttribute("byteorder",   "MSB");
  DOM_Text     fileDataVal = doc1.createTextNode(_datafile);
  fileElem.appendChild(fileDataVal);
  
  //cout << "Before data\n" << flush;
  DOM_Element  dataElem = doc1.createElement("data");
  rootElem.appendChild(dataElem);   
  
  DOM_Element  dimElem  = doc1.createElement("dimensions");
  dataElem.appendChild(dimElem); 
  
  DOM_Element  volElem  = doc1.createElement("volumesize");
  dimElem.appendChild(volElem); 
  DOM_Element  dimxElem  = doc1.createElement("dim_x");
  volElem.appendChild(dimxElem);
  sprintf(buffer, "%d", _dimx);
  DOM_Text     dimxDataVal = doc1.createTextNode(buffer);
  dimxElem.appendChild(dimxDataVal); 
  DOM_Element  dimyElem  = doc1.createElement("dim_y");
  volElem.appendChild(dimyElem);
  sprintf(buffer, "%d", _dimy);
  DOM_Text     dimyDataVal = doc1.createTextNode(buffer);
  dimyElem.appendChild(dimyDataVal); 
  DOM_Element  dimzElem  = doc1.createElement("dim_z");
  volElem.appendChild(dimzElem);
  sprintf(buffer, "%d", _dimz);
  DOM_Text     dimzDataVal = doc1.createTextNode(buffer);
  dimzElem.appendChild(dimzDataVal);
  
  DOM_Element  voxelElem  = doc1.createElement("voxelsize");
  dimElem.appendChild(voxelElem);  
  DOM_Element  deltaxElem  = doc1.createElement("delta_x");
  voxelElem.appendChild(deltaxElem);
  sprintf(buffer, "%f", _deltax);
  DOM_Text     deltaxDataVal = doc1.createTextNode(buffer);
  deltaxElem.appendChild(deltaxDataVal); 
  DOM_Element  deltayElem  = doc1.createElement("delta_y");
  voxelElem.appendChild(deltayElem);
  sprintf(buffer, "%f", _deltay);
  DOM_Text     deltayDataVal = doc1.createTextNode(buffer);
  deltayElem.appendChild(deltayDataVal); 
  DOM_Element  deltazElem  = doc1.createElement("delta_z");
  voxelElem.appendChild(deltazElem);
  sprintf(buffer, "%f", _deltaz);
  DOM_Text     deltazDataVal = doc1.createTextNode(buffer);
  deltazElem.appendChild(deltazDataVal);
  
  //cout << "In write_XMLHeader after assert_values before writting header after composing\n"<< flush;
  // now save to disc
  DOM_Node doc = doc1;
  DOMPrintFormatTarget* formatTarget = new DOMPrintFormatTarget(xmlFile);
  
  DOMString encNameStr("UTF-8");
  DOM_Node aNode = doc.getFirstChild();
  if (aNode.getNodeType() == DOM_Node::XML_DECL_NODE)
    {
      DOMString aStr = ((DOM_XMLDecl &)aNode).getEncoding();
      if (aStr != "")
	{
	  encNameStr = aStr;
	}
    }
  unsigned int lent = encNameStr.length();
  gEncodingName = new XMLCh[lent + 1];
  XMLString::copyNString(gEncodingName, encNameStr.rawBuffer(), lent);
  gEncodingName[lent] = 0;
  try{
    gFormatter = new XMLFormatter(gEncodingName, formatTarget,  XMLFormatter::NoEscapes, gUnRepFlags);  
    cout << doc;
  }
  catch (XMLException& e){
    cerr << "An error occurred during creation of output transcoder. Msg is:"
	 << endl
	 << DOMString(e.getMessage()) << endl;
  }
  
  // clean up
  delete formatTarget;
  delete gFormatter;
  delete gEncodingName;
}

ostream& operator<<(ostream& target, DOM_Node& toWrite)
{
    // Get the name and value out for convenience
    DOMString   nodeName = toWrite.getNodeName();
    DOMString   nodeValue = toWrite.getNodeValue();
    unsigned long lent = nodeValue.length();

    switch (toWrite.getNodeType())
    {
        case DOM_Node::TEXT_NODE:
        {
            gFormatter->formatBuf(nodeValue.rawBuffer(), 
                                  lent, XMLFormatter::CharEscapes);
            break;
        }


        case DOM_Node::PROCESSING_INSTRUCTION_NODE :
        {
            *gFormatter << XMLFormatter::NoEscapes << gStartPI  << nodeName;
            if (lent > 0)
            {
                *gFormatter << chSpace << nodeValue;
            }
            *gFormatter << XMLFormatter::NoEscapes << gEndPI;
            break;
        }


        case DOM_Node::DOCUMENT_NODE :
        {

            DOM_Node child = toWrite.getFirstChild();
            while( child != 0)
            {
	      target << child ;//<< "\n";
                child = child.getNextSibling();
            }
            break;
        }


        case DOM_Node::ELEMENT_NODE :
        {
            // The name has to be representable without any escapes
            *gFormatter  << XMLFormatter::NoEscapes
                         << chOpenAngle << nodeName;

            // Output the element start tag.

            // Output any attributes on this element
            DOM_NamedNodeMap attributes = toWrite.getAttributes();
            int attrCount = attributes.getLength();
            for (int i = 0; i < attrCount; i++)
            {
                DOM_Node  attribute = attributes.item(i);

                //
                //  Again the name has to be completely representable. But the
                //  attribute can have refs and requires the attribute style
                //  escaping.
                //
                *gFormatter  << XMLFormatter::NoEscapes
                             << chSpace << attribute.getNodeName()
                             << chEqual << chDoubleQuote
                             << XMLFormatter::AttrEscapes
                             << attribute.getNodeValue()
                             << XMLFormatter::NoEscapes
                             << chDoubleQuote;
            }

            //
            //  Test for the presence of children, which includes both
            //  text content and nested elements.
            //
            DOM_Node child = toWrite.getFirstChild();
            if (child != 0)
            {
                // There are children. Close start-tag, and output children.
                // No escapes are legal here
	        *gFormatter << XMLFormatter::NoEscapes << chCloseAngle;

		if(child.getNodeType() != DOM_Node::TEXT_NODE){
		  *gFormatter <<"\n";
		}
                while( child != 0)
                {
                    target << child;
                    child = child.getNextSibling();
                }

                //
                // Done with children.  Output the end tag.
                //
                *gFormatter << XMLFormatter::NoEscapes << gEndElement
                            << nodeName << chCloseAngle<<"\n";
            }
            else
            {
                //
                //  There were no children. Output the short form close of
                //  the element start tag, making it an empty-element tag.
                //
                *gFormatter << XMLFormatter::NoEscapes << chForwardSlash << chCloseAngle<<"\n";
            }
            break;
        }
        
        
        case DOM_Node::ENTITY_REFERENCE_NODE:
            {
                DOM_Node child;
#if 0
                for (child = toWrite.getFirstChild();
                child != 0;
                child = child.getNextSibling())
                {
                    target << child;
                }
#else
                //
                // Instead of printing the refernece tree 
                // we'd output the actual text as it appeared in the xml file.
                // This would be the case when -e option was chosen
                //
                    *gFormatter << XMLFormatter::NoEscapes << chAmpersand
                        << nodeName << chSemiColon;
#endif
                break;
            }
            
            
        case DOM_Node::CDATA_SECTION_NODE:
            {
            *gFormatter << XMLFormatter::NoEscapes << gStartCDATA
                        << nodeValue << gEndCDATA;
            break;
        }

                case DOM_Node::COMMENT_NODE:
        {
            *gFormatter << XMLFormatter::NoEscapes << gStartComment
                        << nodeValue << gEndComment;
            break;
        }

        
        case DOM_Node::DOCUMENT_TYPE_NODE:
        {
            DOM_DocumentType doctype = (DOM_DocumentType &)toWrite;;

            *gFormatter << XMLFormatter::NoEscapes  << gStartDoctype
                        << nodeName;
 
            DOMString id = doctype.getPublicId();
            if (id != 0)
            {
                *gFormatter << XMLFormatter::NoEscapes << chSpace << gPublic
                    << id << chDoubleQuote;
                id = doctype.getSystemId();
                if (id != 0)
                {
                    *gFormatter << XMLFormatter::NoEscapes << chSpace 
                       << chDoubleQuote << id << chDoubleQuote;
                }
            }
            else
            {
                id = doctype.getSystemId();
                if (id != 0)
                {
                    *gFormatter << XMLFormatter::NoEscapes << chSpace << gSystem
                        << id << chDoubleQuote;
                }
            }
            
            id = doctype.getInternalSubset(); 
            if (id !=0)
                *gFormatter << XMLFormatter::NoEscapes << chOpenSquare
                            << id << chCloseSquare;

            *gFormatter << XMLFormatter::NoEscapes << chCloseAngle;
            break;
        }
        
        
        case DOM_Node::ENTITY_NODE:
        {
            *gFormatter << XMLFormatter::NoEscapes << gStartEntity
                        << nodeName;


            DOMString id = ((DOM_Entity &)toWrite).getPublicId();
            if (id != 0)
                *gFormatter << XMLFormatter::NoEscapes << gPublic
                            << id << chDoubleQuote;

            id = ((DOM_Entity &)toWrite).getSystemId();
            if (id != 0)
                *gFormatter << XMLFormatter::NoEscapes << gSystem
                            << id << chDoubleQuote;
            
            id = ((DOM_Entity &)toWrite).getNotationName();
            if (id != 0)
                *gFormatter << XMLFormatter::NoEscapes << gNotation
                            << id << chDoubleQuote;

            *gFormatter << XMLFormatter::NoEscapes << chCloseAngle << chCR << chLF;

            break;
        }
        
        
        case DOM_Node::XML_DECL_NODE:
        {
            DOMString  str;

            *gFormatter << gXMLDecl1 << ((DOM_XMLDecl &)toWrite).getVersion();

            *gFormatter << gXMLDecl2 << gEncodingName;
            
            str = ((DOM_XMLDecl &)toWrite).getStandalone();
            if (str != 0)
                *gFormatter << gXMLDecl3 << str;
            
            *gFormatter << gXMLDecl4;

            break;
        }
        
        
        default:
            cerr << "Unrecognized node type = "
                 << (long)toWrite.getNodeType() << endl;
    }
    return target;
}

ostream& operator<< (ostream& target, const DOMString& s)
{
  char *p = s.transcode();
  target << p;
  delete [] p;
  return target;
}

XMLFormatter& operator<< (XMLFormatter& strm, const DOMString& s)
{
  unsigned int lent = s.length();
  
  if (lent <= 0)   return strm;
  
  XMLCh*  buf = new XMLCh[lent + 1];
  XMLString::copyNString(buf, s.rawBuffer(), lent);
  buf[lent] = 0;
  strm << buf;
  delete [] buf;
  return strm;
}
