//==================================================================================================
// P r o g r a m                                                                          Interface
// A n a l y z e _ r e s u l t
// C o n s o l e
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library 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 Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides facilities to execute the program in console mode. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "program/analyze_result/console.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guProgramAnalyzeResultConsole
#define guProgramAnalyzeResultConsole

// Headers //---------------------------------------------------------------------------------------
#include <bpp/calendar.hpp> /*INCLUDE*/
#include <bpp/statistics.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef PROGRAM_ANALYZE_RESULT_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  programAnalyzeResultConsole
#define private_area programAnalyzeResultConsole_private

namespace public_area  { /*NAMESPACE*/ using namespace standard; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniProgramAnalyzeResultConsole
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  { function tyReturn run(tyCardinal,tcString []); }
namespace private_area {}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erMissingMeasure; /* At least one measure is missing. */
 /*ERROR*/ extern_error erSyntax; /* Syntax error in the command line. */
 /*ERROR*/ extern_error erUnequalMeasure; /* Measures are not equal. */
}

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// R e s u l t I n f o r m a t i o n  Interface //--------------------------------------------------
namespace private_area {
 class clResultInformation {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef std_vector(clString)                          clStringS;
  public_property typedef std_vector(clStringS)                         clStringX;
  public_property typedef std_vector(tyReal)                            clRealS;
  public_property typedef std_vector(statistics::clStatisticsCollector) clCollectorS;
  public_property typedef std_vector(clCollectorS)                      clCollectorX;
  public_property typedef std_vector(clCollectorX)                      clCollectorD;
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clResultInformation(const clResultInformation &);
  private_property clResultInformation & operator = (const clResultInformation &);

  private_property clString     atTitle;
  private_property tyCardinal   atNbReplication;
  private_property tyCharacter  atCommaSymbol;
  private_property clStringS    atTestNameS;
  private_property clStringS    atTestSuffixS;
  private_property clStringS    atParameterNameS;
  private_property clStringS    atDisplayedMeasureNameS;
  private_property clStringS    atDisplayedMeasureLastWordS;
  private_property clStringS    atControlledMeasureNameS;
  private_property clStringS    atControlledMeasureLastWordS;
  private_property clRealS      atMeasureCoefficientS;
  private_property clStringS    atMeasureFormatS;
  private_property clStringX    atSerieX;
  private_property clCollectorD atCollectorD;
  private_property clStringS    atFileFormat;
  //------------------------------------------------------------------------------------------Public
  public_property constructor clResultInformation(void) {}
  public_property destructor clResultInformation(void) {}

  public_property void getParameters(tcString,tyBoolean=true);
  public_property void getResults(tyBoolean=true);
  public_property void generateAscii(tcString);
  public_property void generateHtml(tcString);
  public_property void generateLatex(tcString);

  private_property static void getFileFormat(clInFile &,std_vector(clString) &);
  private_property static clString getString(clInFile &,clString &);

  private_property void buildResultFileName(clString &,tyCardinal,const std_vector(clString) &,
                                            tyCardinal);
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// X X X  Inline //---------------------------------------------------------------------------------
namespace {}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// P r o g r a m                                                                     Implementation
// A n a l y z e _ r e s u l t
// C o n s o l e
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library 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 Library General Public License for more details (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "program/analyze_result/console.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define PROGRAM_ANALYZE_RESULT_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/program/analyze_result/console.hpp> /*INTERFACE*/
#include <bpp/text_format.hpp> /*NEED*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  programAnalyzeResultConsole
#define private_area programAnalyzeResultConsole_private
#define dll_export   DLL_EXPORT

namespace public_area  { using namespace textFormatHtml; }
namespace private_area {}

static_module_name("Program/Analyze_result/Console");

// Initialization //--------------------------------------------------------------------------------
#undef iniProgramAnalyzeResultConsole
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erMissingMeasure;
 static_error erSyntax;
 static_error erUnequalMeasure;
}

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*FUNCTION*/
 /* Start function of the program. It deals with the commands the user gives through a command
    line and executes the appropriate functions. */
 function tyReturn run(tyCardinal agCounter,tcString agParameterS[]) {
  method_name("run");

  clString  lcCommand;
  tyBoolean lcError;

  tyCardinal lcCounter   = 1;
  tyBoolean  lcDisplayed = true;

  environment_private::goProgramName = "A n a l y z e   R e s u l t";

  try {
   if (agCounter==1) send_error(erSyntax);

   while (lcCounter<agCounter) {
    lcCommand=agParameterS[lcCounter];
    lcError=true;

    //---------------------------------------------------------------------------------------Context
    if (lcCommand=="+context") {
     lcError=false;
     environment::nextLine();
     environment::outContext();
    }

    //------------------------------------------------------------------------------------------Help
    else if (lcCommand=="+help") {
     lcError=false;
     environment::nextLine();
     environment::inform("-=-=- H E L P -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
     environment::out(" This program analyzes the results of series of tests.",true,true);
     environment::nextLine();
     environment::out(" * Syntax: [options] [commands] [input file] [output file]",true,true);
     environment::nextLine();
     environment::out(" * Options:",true,true);
     environment::out("   -hide = deactivates the display of information.",true,true);
     environment::nextLine();
     environment::out(" * Commands:",true,true);
     environment::out("   +context = shows the context of the program's running.",true,true);
     environment::out("   +help    = shows this help.",true,true);
     environment::out("   +info    = shows information about the program.",true,true);
     environment::out("   +license = shows the license of the program.",true,true);
     environment::out("   +ascii   = generates an ASCII file from the results.",true,true);
     environment::out("   +html    = generates a HTML file from the results.",true,true);
     environment::out("   +latex   = generates a Latex file from the results.",true,true);
     environment::out("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-",true,true);
    }

    //------------------------------------------------------------------------------------------Info
    else if (lcCommand=="+info") {
     lcError=false;
     environment::nextLine();
     environment::outInformation();
    }

    //---------------------------------------------------------------------------------------License
    else if (lcCommand=="+license") {
     lcError=false;
     environment::nextLine();
     environment::outLicense();
    }

    //------------------------------------------------------------------------------------------Hide
    else if (lcCommand=="-hide") {
     lcDisplayed=false;
     lcError=false;
    }

    //-----------------------------------------------------------------------------------------Ascii
    else if (lcCommand=="+ascii") {
     if (agCounter-lcCounter>2) {
      private_area::clResultInformation lcInformation;

      environment::nextLine();
      environment::inform("Reading Parameters...");
      lcInformation.getParameters(agParameterS[lcCounter+1],lcDisplayed);

      environment::nextLine();
      environment::inform("Reading Results...");
      lcInformation.getResults(lcDisplayed);

      environment::nextLine();
      environment::inform("Writing Output File (ASCII Format)...");
      lcInformation.generateAscii(agParameterS[lcCounter+2]);

      lcCounter+=2;
      lcError=false;
     }
    }

    //------------------------------------------------------------------------------------------Html
    else if (lcCommand=="+html") {
     if (agCounter-lcCounter>2) {
      private_area::clResultInformation lcInformation;

      environment::nextLine();
      environment::inform("Reading Parameters...");
      lcInformation.getParameters(agParameterS[lcCounter+1],lcDisplayed);

      environment::nextLine();
      environment::inform("Reading Results...");
      lcInformation.getResults(lcDisplayed);

      environment::nextLine();
      environment::inform("Writing Output File (HTML Format)...");
      lcInformation.generateHtml(agParameterS[lcCounter+2]);

      lcCounter+=2;
      lcError=false;
     }
    }

    //-----------------------------------------------------------------------------------------Latex
    else if (lcCommand=="+latex") {
     if (agCounter-lcCounter>2) {
      private_area::clResultInformation lcInformation;

      environment::nextLine();
      environment::inform("Reading Parameters...");
      lcInformation.getParameters(agParameterS[lcCounter+1],lcDisplayed);

      environment::nextLine();
      environment::inform("Reading Results...");
      lcInformation.getResults(lcDisplayed);

      environment::nextLine();
      environment::inform("Writing Output File (Latex Format)...");
      lcInformation.generateLatex(agParameterS[lcCounter+2]);

      lcCounter+=2;
      lcError=false;
     }
    }

    if (lcError) send_error(erSyntax);
    lcCounter++;
   }
  }

  program_catch;
 }
}

namespace private_area {}

// R e s u l t I n f o r m a t i o n  Implementation //---------------------------------------------
namespace private_area {
 //------------------------------------------------------------------------------------GetFileFormat
 property void clResultInformation::getFileFormat(clInFile & agFile,
                                                  std_vector(clString) & agFileFormat) {
  clString lcString;

  agFile >> lcString;

  while (lcString!=";" and not agFile.fail()) {
   agFileFormat.push_back(lcString);
   agFile >> lcString;
  }
 }
 //----------------------------------------------------------------------------------------GetString
 property clString clResultInformation::getString(clInFile & agFile,clString & agString) {
  clString lcLast("");

  clString lcString;

  agString="";
  agFile >> lcString;

  while (lcString!=";" and not agFile.fail()) {
   if (agString!="") agString+=" "+lcString;
   else agString+=lcString;

   lcLast=lcString;
   agFile >> lcString;
  }

  return (lcLast);
 }
 //------------------------------------------------------------------------------BuildResultFileName
 property void clResultInformation::buildResultFileName(clString & agString,tyCardinal agTest,
                                                        const std_vector(clString) & agSerie,
                                                        tyCardinal agReplication) {
  typedef clStringS::const_iterator clIterator;

  clIterator lcCurrentString = atFileFormat.begin();
  clIterator lcLastString    = atFileFormat.end();

  tyCardinal lcNumber;
  clString   lcPartString;
  clString   lcString;

  agString="";

  while (lcCurrentString!=lcLastString) {
   lcString=*lcCurrentString;

   if (lcString[0]=='$') {
    if (lcString[1]=='t') agString+=atTestSuffixS[agTest-1];
    else if (lcString[1]=='r') {
     if (agReplication<10) agString+="0";
     agString+=standard::string(agReplication);
    }
    else {
     lcPartString=lcString.part(1,lcString.size()-1);
     lcNumber=cardinal(lcPartString.data());

     if (lcNumber>=1 and lcNumber<=agSerie.size()) agString+=agSerie[lcNumber-1];
     else agString+="?";
    }
   }
   else agString+=lcString;

   lcCurrentString++;
  }
 }
 //------------------------------------------------------------------------------------GetParameters
 property void clResultInformation::getParameters(tcString agFileName,tyBoolean agDisplayed) {
  method_name("resultInformation::getParameters");

  tyReal     lcCoefficient;
  tyCardinal lcCounter;
  clInFile   lcFile;
  clString   lcString;

  open(lcFile,agFileName,ios::in);
  lcFile >> lcString;
  atCommaSymbol='.';
  atNbReplication=10;

  if (lcString!="<result_parameters_start>") send_error(erFileReading);

  do {
   lcFile >> lcString;

   // Title //
   if (lcString=="title") {
    lcFile >> lcString;
    getString(lcFile,atTitle);

    if (agDisplayed) {
     environment::nextLine();
     environment::out("Title = ",false,true);
     environment::out(atTitle.data(),true);
    }
   }

   // Number of Replications //
   else if (lcString=="nb_replication") {
    lcFile >> lcString >> atNbReplication;

    if (agDisplayed) {
     environment::nextLine();
     environment::out("Replications = ",false,true);
     environment::out(atNbReplication,true);
    }
   }

   // Comma Symbol //
   else if (lcString=="comma_symbol") {
    lcFile >> lcString >> lcString;
    atCommaSymbol=lcString[0];
   }

   // Tests //
   else if (lcString=="<tests_start>") {
    if (agDisplayed) environment::nextLine();
    lcFile >> lcString;

    while (lcString!="<tests_end>") {
     if (lcString=="name") {
      lcFile >> lcString;
      getString(lcFile,lcString);
      atTestNameS.push_back(lcString);
      lcFile >> lcString;
      atTestSuffixS.push_back(lcString);

      if (agDisplayed) {
       environment::out("Test = ",false,true);
       environment::out(atTestNameS.back().data());
       environment::out(" (");
       environment::out(atTestSuffixS.back().data());
       environment::out(")",true);
      }
     }
     else send_error(erFileReading);

     lcFile >> lcString;
    }
   }

   // Parameters //
   else if (lcString=="<parameters_start>") {
    if (agDisplayed) environment::nextLine();
    lcFile >> lcString;

    while (lcString!="<parameters_end>") {
     if (lcString=="name") {
      lcFile >> lcString;
      getString(lcFile,lcString);
      atParameterNameS.push_back(lcString);

      if (agDisplayed) {
       environment::out("Parameter = ",false,true);
       environment::out(atParameterNameS.back().data(),true);
      }
     }
     else send_error(erFileReading);

     lcFile >> lcString;
    }
   }

   // Measures //
   else if (lcString=="<measures_start>") {
    if (agDisplayed) environment::nextLine();

    lcFile >> lcString;

    while (lcString!="<measures_end>") {
     if (lcString=="displayed") {
      lcFile >> lcString;
      atDisplayedMeasureLastWordS.push_back(getString(lcFile,lcString));
      atDisplayedMeasureNameS.push_back(lcString);
      lcFile >> lcCoefficient;
      atMeasureCoefficientS.push_back(lcCoefficient);
      lcFile >> lcString;
      lcFile >> lcString;
      atMeasureFormatS.push_back(lcString);

      if (agDisplayed) {
       environment::out("Displayed Measure = ",false,true);
       environment::out(atDisplayedMeasureNameS.back().data());
       environment::out(" (x");
       environment::out(atMeasureCoefficientS.back());
       lcString=atMeasureFormatS.back();
       lcCounter=0;

       while (lcCounter<lcString.size()) {
        switch (lcString[lcCounter]) {
         case 'e': environment::out(", extrema"); break;
         case 'm': environment::out(", mean"); break;
         case 'M': environment::out(", median"); break;
         case 'v': environment::out(", variance");
        }

        ++lcCounter;
       }

       environment::out(")",true);
      }
     }
     else if (lcString=="controlled") {
      lcFile >> lcString;
      atControlledMeasureLastWordS.push_back(getString(lcFile,lcString));
      atControlledMeasureNameS.push_back(lcString);

      if (agDisplayed) {
       environment::out("Controlled Measure = ",false,true);
       environment::out(atControlledMeasureNameS.back().data(),true);
      }
     }
     else send_error(erFileReading);

     lcFile >> lcString;
    }
   }

   // Series //
   else if (lcString=="<series_start>") {
    if (agDisplayed) environment::nextLine();
    lcFile >> lcString;

    while (lcString!="<series_end>") {
     if (lcString=="serie") {
      if (agDisplayed) environment::out("Serie =",false,true);
      atSerieX.push_back(clStringS());
      lcFile >> lcString >> lcString;

      while (lcString!=";" and not lcFile.fail()) {
       atSerieX.back().push_back(lcString);

       if (agDisplayed) {
        environment::out(" ");
        environment::out(atSerieX.back().back().data());
       }

       lcFile >> lcString;
      }

      if (agDisplayed) environment::nextLine();
     }
     else send_error(erFileReading);

     lcFile >> lcString;
    }
   }

   else if (lcString=="file_format") {
    lcFile >> lcString;
    getFileFormat(lcFile,atFileFormat);
   }
  }
  while (lcString!="<result_parameters_end>" and not lcFile.fail());

  close(lcFile);
  if (lcFile.fail()) send_error(erFileReading);
 }
 //---------------------------------------------------------------------------------------GetResults
 property void clResultInformation::getResults(tyBoolean agDisplayed) {
  method_name("resultInformation::getResults");

  typedef clStringX::const_iterator clSerieIterator;
  typedef clStringS::const_iterator clWordIterator;

  clSerieIterator lcCurrentSerie = atSerieX.begin();
  clSerieIterator lcLastSerie    = atSerieX.end();

  tyCardinal lcCounter;
  tyBoolean  lcFound;
  clString   lcName;
  tyCardinal lcNbFound;
  tyReal     lcNumber;
  clString   lcPreviousString;
  tyCardinal lcReplication;
  clString   lcString;
  tyCardinal lcTest;

  clWordIterator lcCurrentWord;
  clRealS        lcControlS;
  clWordIterator lcLastWord;
  clRealS        lcValueS;

  lcControlS.reserve(atControlledMeasureNameS.size());
  lcValueS.reserve(atDisplayedMeasureNameS.size());

  while (lcCurrentSerie!=lcLastSerie) {
   atCollectorD.push_back(clCollectorX());

   // Control //
   lcReplication=1;

   while (lcReplication<=atNbReplication) {
    lcTest=1;

    while (lcTest<=atTestNameS.size()) {
     clInFile lcFile;

     buildResultFileName(lcName,lcTest,*lcCurrentSerie,lcReplication);

     if (agDisplayed) {
      environment::nextLine();
      environment::out("Checking '",false,true);
      environment::out(lcName.data());
      environment::out("'...",true);
     }

     open(lcFile,lcName.data(),ios::in);
     lcPreviousString="";
     lcFile >> lcString;
     lcNbFound=0;

     while (lcString!="") {
      if (lcString=="=") {
       lcCurrentWord=atControlledMeasureLastWordS.begin();
       lcLastWord=atControlledMeasureLastWordS.end();
       lcCounter=0;
       lcFound=false;

       while (not lcFound and lcCurrentWord!=lcLastWord) {
        if (lcPreviousString==*lcCurrentWord) {
         lcFile >> lcNumber;

         if (agDisplayed) {
          environment::out(atControlledMeasureNameS[lcCounter].data(),false,true);
          environment::out(" = ");
          environment::out(lcNumber,true);
         }

         if (lcTest==1) lcControlS[lcCounter]=lcNumber;
         else if (lcNumber!=lcControlS[lcCounter]) send_error(erUnequalMeasure);

         lcFound=true;
         lcNbFound++;
        }

        lcCurrentWord++;
        lcCounter++;
       }
      }

      lcPreviousString=lcString;
      lcFile >> lcString;
     }

     close(lcFile);
     if (lcNbFound<atControlledMeasureNameS.size()) send_error(erMissingMeasure);
     lcTest++;
    }

    lcReplication++;
   }

   // Extraction //
   lcTest=1;

   while (lcTest<=atTestNameS.size()) {
    lcReplication=1;
    atCollectorD.back().push_back(clCollectorS());
    lcCounter=atDisplayedMeasureNameS.size();

    while (lcCounter>0) {
     lcCounter--;
     atCollectorD.back().back().push_back(statistics::clStatisticsCollector());
    }

    while (lcReplication<=atNbReplication) {
     clInFile lcFile;

     buildResultFileName(lcName,lcTest,*lcCurrentSerie,lcReplication);

     if (agDisplayed) {
      environment::nextLine();
      environment::out("Extracting '",false,true);
      environment::out(lcName.data());
      environment::out("'...",true);
     }

     lcCounter=atDisplayedMeasureNameS.size();

     while (lcCounter>0) {
      lcCounter--;
      lcValueS[lcCounter]=0.0;
     }

     open(lcFile,lcName.data(),ios::in);
     lcPreviousString="";
     lcFile >> lcString;
     lcNbFound=0;

     while (lcString!="") {
      if (lcString=="=") {
       lcCurrentWord=atDisplayedMeasureLastWordS.begin();
       lcLastWord=atDisplayedMeasureLastWordS.end();
       lcCounter=0;
       lcFound=false;

       while (not lcFound and lcCurrentWord!=lcLastWord) {
        if (lcPreviousString==*lcCurrentWord) {
         lcFile >> lcNumber;

         if (agDisplayed) {
          environment::out(atDisplayedMeasureNameS[lcCounter].data(),false,true);
          environment::out(" = ");
          environment::out(lcNumber,true);
         }

         lcValueS[lcCounter]=lcNumber*atMeasureCoefficientS[lcCounter];
         lcFound=true;
         lcNbFound++;
        }

        lcCurrentWord++;
        lcCounter++;
       }
      }

      lcPreviousString=lcString;
      lcFile >> lcString;
     }

     close(lcFile);
     lcCounter=atDisplayedMeasureNameS.size();

     while (lcCounter>0) {
      lcCounter--;
      atCollectorD.back().back()[lcCounter].add(lcValueS[lcCounter]);
     }

     if (lcNbFound<atDisplayedMeasureNameS.size()) send_error(erMissingMeasure);
     lcReplication++;
    }

    lcTest++;
   }

   lcCurrentSerie++;
  }
 }
 //------------------------------------------------------------------------------------GenerateAscii
 property void clResultInformation::generateAscii(tcString agFileName) {
  method_name("resultInformation::generateAscii");

  typedef std_vector(clString)::const_iterator clIterator;

  tyCardinal lcCounter;
  clIterator lcCurrentString;
  clIterator lcLastString;
  tyCardinal lcMeasure;
  tyCardinal lcPosition;
  tyCardinal lcSerie;
  clString   lcString;
  tyCardinal lcTest;
  clOutFile  lcFile;

  open(lcFile,agFileName,ios::out|ios::trunc);

  // Parameters Title //
  lcCurrentString=atParameterNameS.begin();
  lcLastString=atParameterNameS.end();

  while (lcCurrentString!=lcLastString) {
   lcFile << *lcCurrentString << " ; ";
   lcCurrentString++;
  }

  // Tests + Measures Title //
  lcTest=0;

  while (lcTest<atTestNameS.size()) {
   lcMeasure=0;

   while (lcMeasure<atDisplayedMeasureNameS.size()) {
    lcFile << atTestNameS[lcTest] << " / " << atDisplayedMeasureNameS[lcMeasure];
    lcMeasure++;

    if (lcMeasure==atDisplayedMeasureNameS.size() and lcTest+1==atTestNameS.size())
     lcFile << end_line;
    else lcFile << " ; ";
   }

   lcTest++;
  }

  // Results //
  lcSerie=0;

  while (lcSerie<atSerieX.size()) {
   // Serie Values //
   lcCurrentString=atSerieX[lcSerie].begin();
   lcLastString=atSerieX[lcSerie].end();

   while (lcCurrentString!=lcLastString) {
    lcFile << *lcCurrentString << " ; ";
    lcCurrentString++;
   }

   // Measures //
   lcTest=0;

   while (lcTest<atTestNameS.size()) {
    lcMeasure=0;

    while (lcMeasure<atDisplayedMeasureNameS.size()) {
     lcCounter=0;
     lcString="";

     while (lcCounter<atMeasureFormatS[lcMeasure].size()) {
      switch (atMeasureFormatS[lcMeasure][lcCounter]) {
       case 'e':
        if (lcString.size()>0) lcString+=" ";
        lcString+="[";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].minimum());
        lcString+=";";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].maximum());
        lcString+="]";
        break;

       case 'm':
        if (lcString.size()>0) lcString+=" ";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].mean());
        break;

       case 'M':
        if (lcString.size()>0) lcString+=" ";
        lcString+="<";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].median());
        lcString+=">";
        break;

       case 'v':
        if (lcString.size()>0) lcString+=" ";
        lcString+="(+/-";
        lcString+=standard::string(std::sqrt(atCollectorD[lcSerie][lcTest][lcMeasure].variance()));
        lcString+=")";
        break;
      }

      ++lcCounter;
     }

     if (lcString.find('.',lcPosition)) {
      lcString[lcPosition]=atCommaSymbol;
      while (lcString[lcString.size()-1]=='0') lcString.resize(lcString.size()-1);
      if (lcString[lcString.size()-1]==atCommaSymbol) lcString.resize(lcString.size()-1);
     }

     lcFile << lcString;
     lcMeasure++;

     if (lcMeasure==atDisplayedMeasureNameS.size() and lcTest+1==atTestNameS.size())
      lcFile << end_line;
     else lcFile << " ; ";
    }

    lcTest++;
   }

   lcSerie++;
  }

  if (lcFile.fail()) send_error(erFileWriting);
  close(lcFile);
 }
 //-------------------------------------------------------------------------------------GenerateHtml
 property void clResultInformation::generateHtml(tcString agFileName) {
  typedef std_vector(clString)::const_iterator clIterator;

  tyCardinal lcCounter;
  clIterator lcCurrentString;
  clIterator lcLastString;
  tyCardinal lcMeasure;
  tyCardinal lcPosition;
  tyCardinal lcSerie;
  clString   lcString;
  tyCardinal lcTest;

  clHtmlFile lcFile(defaultHtmlTemplate(),agFileName);

  lcFile.normalPage(atTitle.data()).table("","1","2");

  // Parameters Title //
  lcCurrentString=atParameterNameS.begin();
  lcLastString=atParameterNameS.end();
  lcFile.row();

  while (lcCurrentString!=lcLastString) {
   lcFile.cell().center().little().bold() << *lcCurrentString << 4;
   lcCurrentString++;
  }

  // Tests + Measures Title //
  lcTest=0;

  while (lcTest<atTestNameS.size()) {
   lcMeasure=0;

   while (lcMeasure<atDisplayedMeasureNameS.size()) {
    lcFile.cell().center().little().bold();
    lcFile << atTestNameS[lcTest] << " / " << atDisplayedMeasureNameS[lcMeasure] << 4;
    lcMeasure++;
   }

   lcTest++;
  }

  lcFile << 1;

  // Results //
  lcSerie=0;

  while (lcSerie<atSerieX.size()) {
   // Serie Values //
   lcCurrentString=atSerieX[lcSerie].begin();
   lcLastString=atSerieX[lcSerie].end();
   lcFile.row();

   while (lcCurrentString!=lcLastString) {
    lcFile.cell().center().little() << *lcCurrentString << 3;
    lcCurrentString++;
   }

   // Measures //
   lcTest=0;

   while (lcTest<atTestNameS.size()) {
    lcMeasure=0;

    while (lcMeasure<atDisplayedMeasureNameS.size()) {
     lcFile.cell().center().little();
     lcCounter=0;
     lcString="";

     while (lcCounter<atMeasureFormatS[lcMeasure].size()) {
      switch (atMeasureFormatS[lcMeasure][lcCounter]) {
       case 'e':
        if (lcString.size()>0) lcString+=" ";
        lcString+="[";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].minimum());
        lcString+=";";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].maximum());
        lcString+="]";
        break;

       case 'm':
        if (lcString.size()>0) lcString+=" ";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].mean());
        break;

       case 'M':
        if (lcString.size()>0) lcString+=" ";
        lcString+="<";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].median());
        lcString+=">";
        break;

       case 'v':
        if (lcString.size()>0) lcString+=" ";
        lcString+="(+/-";
        lcString+=standard::string(std::sqrt(atCollectorD[lcSerie][lcTest][lcMeasure].variance()));
        lcString+=")";
        break;
      }

      ++lcCounter;
     }

     if (lcString.find('.',lcPosition)) {
      lcString[lcPosition]=atCommaSymbol;
      while (lcString[lcString.size()-1]=='0') lcString.resize(lcString.size()-1);
      if (lcString[lcString.size()-1]==atCommaSymbol) lcString.resize(lcString.size()-1);
     }

     lcFile << lcString << 3;
     lcMeasure++;
    }

    lcTest++;
   }

   lcFile << 1;
   lcSerie++;
  }

  lcFile.terminate();
 }
 //------------------------------------------------------------------------------------GenerateLatex
 property void clResultInformation::generateLatex(tcString agFileName) {
  method_name("resultInformation::generateLatex");

  typedef std_vector(clString)::const_iterator clIterator;

  tyCardinal lcCounter;
  clIterator lcCurrentString;
  clIterator lcLastString;
  tyCardinal lcMeasure;
  tyCardinal lcPosition;
  tyCardinal lcSerie;
  clString   lcString;
  tyCardinal lcTest;
  clOutFile  lcFile;

  open(lcFile,agFileName,ios::out|ios::trunc);

  // Parameters Title //
  lcCurrentString=atParameterNameS.begin();
  lcLastString=atParameterNameS.end();

  while (lcCurrentString!=lcLastString) {
   lcFile << *lcCurrentString << " & ";
   lcCurrentString++;
  }

  // Tests + Measures Title //
  lcTest=0;

  while (lcTest<atTestNameS.size()) {
   lcMeasure=0;

   while (lcMeasure<atDisplayedMeasureNameS.size()) {
    lcFile << atTestNameS[lcTest] << " / " << atDisplayedMeasureNameS[lcMeasure];
    lcMeasure++;

    if (lcMeasure==atDisplayedMeasureNameS.size() and lcTest+1==atTestNameS.size())
     lcFile << "\\\\" << end_line;
    else lcFile << " & ";
   }

   lcTest++;
  }

  // Results //
  lcSerie=0;

  while (lcSerie<atSerieX.size()) {
   // Serie Values //
   lcCurrentString=atSerieX[lcSerie].begin();
   lcLastString=atSerieX[lcSerie].end();

   while (lcCurrentString!=lcLastString) {
    lcFile << *lcCurrentString << " & ";
    lcCurrentString++;
   }

   // Measures //
   lcTest=0;

   while (lcTest<atTestNameS.size()) {
    lcMeasure=0;

    while (lcMeasure<atDisplayedMeasureNameS.size()) {
     lcCounter=0;
     lcString="";

     while (lcCounter<atMeasureFormatS[lcMeasure].size()) {
      switch (atMeasureFormatS[lcMeasure][lcCounter]) {
       case 'e':
        if (lcString.size()>0) lcString+=" ";
        lcString+="[";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].minimum());
        lcString+=";";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].maximum());
        lcString+="]";
        break;

       case 'm':
        if (lcString.size()>0) lcString+=" ";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].mean());
        break;

       case 'M':
        if (lcString.size()>0) lcString+=" ";
        lcString+="<";
        lcString+=standard::string(atCollectorD[lcSerie][lcTest][lcMeasure].median());
        lcString+=">";
        break;

       case 'v':
        if (lcString.size()>0) lcString+=" ";
        lcString+="(+/-";
        lcString+=standard::string(std::sqrt(atCollectorD[lcSerie][lcTest][lcMeasure].variance()));
        lcString+=")";
        break;
      }

      ++lcCounter;
     }

     if (lcString.find('.',lcPosition)) {
      lcString[lcPosition]=atCommaSymbol;
      while (lcString[lcString.size()-1]=='0') lcString.resize(lcString.size()-1);
      if (lcString[lcString.size()-1]==atCommaSymbol) lcString.resize(lcString.size()-1);
     }

     lcFile << lcString;
     lcMeasure++;

     if (lcMeasure==atDisplayedMeasureNameS.size() and lcTest+1==atTestNameS.size())
      lcFile << "\\\\" << end_line;
     else lcFile << " & ";
    }

    lcTest++;
   }

   lcSerie++;
  }

  if (lcFile.fail()) send_error(erFileWriting);
  close(lcFile);
 }
}

// I n i t i a l i z e r  Implementation //---------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Start
 property void clInitializer::start(void) {
  if (atCounter++ == 0) {
   try {
    #include <bpp/modules.hpp> /*NEED*/
    registerStop(this);
    environment::informInitialization(goModuleName);

    erMissingMeasure.create("Analyze Result - At least one measure is missing.");
    erSyntax.create("Analyze Result - Use the '+help' parameter to get some help.");
    erUnequalMeasure.create("Analyze Result - Measures are not equal.");
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) { environment::informTermination(goModuleName); }
}

// End //-------------------------------------------------------------------------------------------
}