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

  PMsrHandler.cpp

  Author: Andreas Suter
  e-mail: andreas.suter@psi.ch

  $Id$

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

/***************************************************************************
 *   Copyright (C) 2007 by Andreas Suter                                   *
 *   andreas.suter@psi.c                                                   *
 *                                                                         *
 *   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.             *
 ***************************************************************************/

#include <math.h>

#include <string>
#include <iostream>
#include <fstream>
using namespace std;

#include <TString.h>
#include <TObjArray.h>
#include <TObjString.h>
#include <TDatime.h>

#include "PMusr.h"
#include "PMsrHandler.h"

//--------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param fileName
 */
PMsrHandler::PMsrHandler(const char *fileName) : fFileName(fileName)
{
  // init variables
  fMsrBlockCounter = 0;

  fTitle = "";

  fCopyStatisticsBlock = false;
  fStatistic.fValid = false;
  fStatistic.fChisq = true;
  fStatistic.fMin   = -1.0;
  fStatistic.fNdf   = 0;

  fFuncHandler = 0;

  if (fFileName.Contains("/")) {
    Int_t idx = -1;
    while (fFileName.Index("/", idx+1) != -1) {
      idx = fFileName.Index("/", idx+1);
    }
    fMsrFileDirectoryPath = fFileName;
    fMsrFileDirectoryPath.Remove(idx+1);
  } else {
    fMsrFileDirectoryPath = "./";
  }
}

//--------------------------------------------------------------------------
// Destructor
//--------------------------------------------------------------------------
/**
 * <p>
 */
PMsrHandler::~PMsrHandler()
{
  fParam.clear();
  fTheory.clear();
  fFunctions.clear();
  for (unsigned int i=0; i<fRuns.size(); i++) {
    fRuns[i].fRunName.clear();
    fRuns[i].fBeamline.clear();
    fRuns[i].fInstitute.clear();
    fRuns[i].fFileFormat.clear();
    fRuns[i].fMap.clear();
    fRuns[i].fBkgFix.clear();
    fRuns[i].fBkgRange.clear();
    fRuns[i].fDataRange.clear();
    fRuns[i].fT0.clear();
  }
  fRuns.clear();
  fCommands.clear();
  fPlots.clear();
  fStatistic.fStatLines.clear();
  fParamInUse.clear();

  if (fFuncHandler) {
    delete fFuncHandler;
    fFuncHandler = 0;
  }
}

//--------------------------------------------------------------------------
// ReadMsrFile (public)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * <p><b>return:</b>
 * - PMUSR_SUCCESS if everything is OK
 * - line number if an error in the MSR file was encountered which cannot be handled.
 *
 */
int PMsrHandler::ReadMsrFile()
{
  ifstream f;
  string str;
  TString line;
  int line_no = 0;
  int result = PMUSR_SUCCESS;

  PMsrLineStructure current;

  PMsrLines fit_parameter;
  PMsrLines theory;
  PMsrLines functions;
  PMsrLines run;
  PMsrLines commands;
  PMsrLines fourier;
  PMsrLines plot;
  PMsrLines statistic;

  // init stuff
  InitFourierParameterStructure(fFourier);

  // open msr-file
  f.open(fFileName.Data(), iostream::in);
  if (!f.is_open()) {
    return PMUSR_MSR_FILE_NOT_FOUND;
  }

  fMsrBlockCounter = -1; // no msr block

  // read msr-file
  while (!f.eof()) {

    // read a line
    getline(f, str);
    line = str.c_str();
    line_no++;

    current.fLineNo = line_no;
    current.fLine   = line;

    if (line.BeginsWith("#") || line.IsWhitespace()) { // if the line is a comment/empty go to the next one
      continue;
    }

    if (!line.IsWhitespace()) { // if not an empty line, handle it
      // check for a msr block
      if (line_no == 1) { // title
        fTitle = line;
      } else if (line.BeginsWith("FITPARAMETER")) { // FITPARAMETER block tag
        fMsrBlockCounter = MSR_TAG_FITPARAMETER;
      } else if (line.BeginsWith("THEORY")) {       // THEORY block tag
        fMsrBlockCounter = MSR_TAG_THEORY;
        theory.push_back(current);
      } else if (line.BeginsWith("FUNCTIONS")) {    // FUNCTIONS block tag
        fMsrBlockCounter = MSR_TAG_FUNCTIONS;
        functions.push_back(current);
      } else if (line.BeginsWith("RUN")) {          // RUN block tag
        fMsrBlockCounter = MSR_TAG_RUN;
        run.push_back(current);
      } else if (line.BeginsWith("COMMANDS")) {     // COMMANDS block tag
        fMsrBlockCounter = MSR_TAG_COMMANDS;
        commands.push_back(current);
      } else if (line.BeginsWith("FOURIER")) {      // FOURIER block tag
        fMsrBlockCounter = MSR_TAG_FOURIER;
        fourier.push_back(current);
      } else if (line.BeginsWith("PLOT")) {         // PLOT block tag
        fMsrBlockCounter = MSR_TAG_PLOT;
        plot.push_back(current);
      } else if (line.BeginsWith("STATISTIC")) {    // STATISTIC block tag
        fMsrBlockCounter = MSR_TAG_STATISTIC;
        statistic.push_back(current);
      } else { // the read line is some real stuff

        switch (fMsrBlockCounter) {
          case MSR_TAG_FITPARAMETER: // FITPARAMETER block
            fit_parameter.push_back(current);
            break;
          case MSR_TAG_THEORY:       // THEORY block
            theory.push_back(current);
            break;
          case MSR_TAG_FUNCTIONS:    // FUNCTIONS block
            functions.push_back(current);
            break;
          case MSR_TAG_RUN:          // RUN block
            run.push_back(current);
            break;
          case MSR_TAG_COMMANDS:     // COMMANDS block
            commands.push_back(current);
            break;
          case MSR_TAG_FOURIER:      // FOURIER block
            fourier.push_back(current);
            break;
          case MSR_TAG_PLOT:         // PLOT block
            plot.push_back(current);
            break;
          case MSR_TAG_STATISTIC:    // STATISTIC block
            statistic.push_back(current);
            break;
          default:
            break;
        }
      }
    }
  }

  // close msr-file
  f.close();

  // execute handler of the various blocks
  if (!HandleFitParameterEntry(fit_parameter))
    result = PMUSR_MSR_SYNTAX_ERROR;
  if (result == PMUSR_SUCCESS)
    if (!HandleTheoryEntry(theory))
      result = PMUSR_MSR_SYNTAX_ERROR;
  if (result == PMUSR_SUCCESS)
    if (!HandleFunctionsEntry(functions))
      result = PMUSR_MSR_SYNTAX_ERROR;
  if (result == PMUSR_SUCCESS)
    if (!HandleRunEntry(run))
      result = PMUSR_MSR_SYNTAX_ERROR;
  if (result == PMUSR_SUCCESS)
    if (!HandleCommandsEntry(commands))
      result = PMUSR_MSR_SYNTAX_ERROR;
  if (result == PMUSR_SUCCESS)
    if (!HandleFourierEntry(fourier))
      result = PMUSR_MSR_SYNTAX_ERROR;
  if (result == PMUSR_SUCCESS)
    if (!HandlePlotEntry(plot))
      result = PMUSR_MSR_SYNTAX_ERROR;
  if (result == PMUSR_SUCCESS)
    if (!HandleStatisticEntry(statistic))
      result = PMUSR_MSR_SYNTAX_ERROR;

  // fill parameter-in-use vector
  if (result == PMUSR_SUCCESS)
    FillParameterInUse(theory, functions, run);

  // check that parameter names are unique
  if (result == PMUSR_SUCCESS) {
    unsigned int parX, parY;
    if (!CheckUniquenessOfParamNames(parX, parY)) {
      cout << endl << ">> PMsrHandler::ReadMsrFile: **SEVERE ERROR** parameter name " << fParam[parX].fName.Data() << " is identical for parameter no " << fParam[parX].fNo << " and " << fParam[parY].fNo << "!";
      cout << endl << "Needs to be fixed first!";
      result = PMUSR_MSR_SYNTAX_ERROR;
    }
  }

  // check that if maps are present in the theory- and/or function-block,
  // that there are really present in the run block
  if (result == PMUSR_SUCCESS)
    if (!CheckMaps())
      result = PMUSR_MSR_SYNTAX_ERROR;


  // check that if functions are present in the theory- and/or run-block, that they
  // are really present in the function block
  if (result == PMUSR_SUCCESS)
    if (!CheckFuncs())
      result = PMUSR_MSR_SYNTAX_ERROR;

  // clean up
  fit_parameter.clear();
  theory.clear();
  functions.clear();
  run.clear();
  commands.clear();
  fourier.clear();
  plot.clear();
  statistic.clear();

/*
cout << endl << ">> FOURIER Block:";
cout << endl << ">>   Fourier Block Present       : " << fFourier.fFourierBlockPresent;
cout << endl << ">>   Fourier Units               : " << fFourier.fUnits;
cout << endl << ">>   Fourier Power               : " << fFourier.fFourierPower;
cout << endl << ">>   Apodization                 : " << fFourier.fApodization;
cout << endl << ">>   Plot Tag                    : " << fFourier.fPlotTag;
cout << endl << ">>   Phase                       : " << fFourier.fPhase;
cout << endl << ">>   Range for Freq. Corrections : " << fFourier.fRangeForPhaseCorrection[0] << ", " << fFourier.fRangeForPhaseCorrection[1];
cout << endl << ">>   Plot Range                  : " << fFourier.fPlotRange[0] << ", " << fFourier.fPlotRange[1];
cout << endl;
*/

  return result;
}

//--------------------------------------------------------------------------
// WriteMsrLogFile (public)
//--------------------------------------------------------------------------
/**
 * <p>
 */
int PMsrHandler::WriteMsrLogFile(const bool messages)
{
  const unsigned int prec = 6; // output precision for float/doubles

  int tag, lineNo = 0, number;
  int runNo = -1, addRunNo = 0;
  int plotNo = -1;
  string line;
  TString str, sstr;
  TObjArray *tokens;
  TObjString *ostr;
  bool found = false;
  bool statisticBlockFound = false;
  bool partialStatisticBlockFound = true;

  // construct log file name
  // first find the last '.' in the filename
  Int_t idx = -1;
  while (fFileName.Index(".", idx+1) != -1) {
    idx = fFileName.Index(".", idx+1);
  }
  if (idx == -1)
    return PMUSR_MSR_SYNTAX_ERROR;

  // remove extension
  str = fFileName;
  str.Remove(idx+1);
  str += "mlog";

  ifstream fin;
  ofstream fout;

  // open msr-file for reading
  fin.open(fFileName.Data(), iostream::in);
  if (!fin.is_open()) {
    return PMUSR_MSR_LOG_FILE_WRITE_ERROR;
  }

  // open mlog-file for writing
  fout.open(str.Data(), iostream::out);
  if (!fout.is_open()) {
    return PMUSR_MSR_LOG_FILE_WRITE_ERROR;
  }

  tag = MSR_TAG_TITLE;
  // read msr-file
  while (!fin.eof()) {

    // read a line
    getline(fin, line);
    str = line.c_str();
    lineNo++;

    // check for tag
    if (str.BeginsWith("FITPARAMETER")) { // FITPARAMETER block tag
      tag = MSR_TAG_FITPARAMETER;
    } else if (str.BeginsWith("THEORY")) {       // THEORY block tag
      tag = MSR_TAG_THEORY;
      fout << str.Data() << endl;
      continue;
    } else if (str.BeginsWith("FUNCTIONS")) {    // FUNCTIONS block tag
      tag = MSR_TAG_FUNCTIONS;
      fout << str.Data() << endl;
      continue;
    } else if (str.BeginsWith("RUN")) {          // RUN block tag
      tag = MSR_TAG_RUN;
      runNo++;
    } else if (str.BeginsWith("COMMANDS")) {     // COMMANDS block tag
      tag = MSR_TAG_COMMANDS;
      fout << str.Data() << endl;
      continue;
    } else if (str.BeginsWith("FOURIER")) {      // FOURIER block tag
      tag = MSR_TAG_FOURIER;
      fout << str.Data() << endl;
      continue;
    } else if (str.BeginsWith("PLOT")) {         // PLOT block tag
      tag = MSR_TAG_PLOT;
      plotNo++;
    } else if (str.BeginsWith("STATISTIC")) {    // STATISTIC block tag
      tag = MSR_TAG_STATISTIC;
    }

    // handle blocks
    switch (tag) {
      case MSR_TAG_TITLE:
        if (lineNo == 1)
          fout << fTitle.Data() << endl;
        else
          fout << str.Data() << endl;
        break;
      case MSR_TAG_FITPARAMETER:
        tokens = str.Tokenize(" \t");
        if (tokens->GetEntries() == 0) { // not a parameter line
          fout << str.Data() << endl;
        } else {
          ostr = dynamic_cast<TObjString*>(tokens->At(0));
          sstr = ostr->GetString();
          if (sstr.IsDigit()) { // parameter
            number = sstr.Atoi();
            number--;
            // make sure number makes sense
            assert ((number >= 0) && (number < (int)fParam.size()));
            // parameter no
            fout.width(9);
            fout << right << fParam[number].fNo;
            fout << " ";
            // parameter name
            fout.width(11);
            fout << left << fParam[number].fName.Data();
            fout << " ";
            // value of the parameter
            fout.width(9);
            fout.precision(prec);
            fout << left << fParam[number].fValue;
            fout << " ";
            // value of step/error/neg.error
            fout.width(11);
            fout.precision(prec);
            fout << left << fParam[number].fStep;
            fout << " ";
            fout.width(11);
            fout.precision(prec);
            if ((fParam[number].fNoOfParams == 5) || (fParam[number].fNoOfParams == 7)) // pos. error given
              if (fParam[number].fPosErrorPresent && (fParam[number].fStep != 0)) // pos error is a number
                fout << left << fParam[number].fPosError;
            else // pos error is a none
              fout << left << "none";
            else // no pos. error
              fout << left << "none";
            fout << " ";
            // boundaries
            if (fParam[number].fNoOfParams > 5) {
              fout.width(7);
              fout.precision(prec);
              if (fParam[number].fLowerBoundaryPresent)
                fout << left << fParam[number].fLowerBoundary;
              else
                fout << left << "none";
              fout << " ";
              fout.width(7);
              fout.precision(prec);
              if (fParam[number].fUpperBoundaryPresent)
                fout << left << fParam[number].fUpperBoundary;
              else
                fout << left << "none";
              fout << " ";
            }
            fout << endl;
          } else { // not a parameter, hence just copy it
            fout << str.Data() << endl;
          }
        }
        break;
      case MSR_TAG_THEORY:
        found = false;
        for (unsigned int i=0; i<fTheory.size(); i++) {
          if (fTheory[i].fLineNo == lineNo) {
            fout << fTheory[i].fLine.Data() << endl;
            found = true;
          }
        }
        if (!found) {
          fout << str.Data() << endl;
        }
        break;
      case MSR_TAG_FUNCTIONS:
        sstr = str;
        sstr.Remove(TString::kLeading, ' ');
        if (str.BeginsWith("fun")) {
          if (FilterNumber(sstr, "fun", 0, number)) {
            sstr = *fFuncHandler->GetFuncString(number-1);
            sstr.ToLower();
            fout << sstr.Data() << endl;
          }
        } else {
          fout << str.Data() << endl;
        }
        break;
      case MSR_TAG_RUN:
        sstr = str;
        sstr.Remove(TString::kLeading, ' ');
        if (sstr.BeginsWith("RUN")) {
          fout << "RUN " << fRuns[runNo].fRunName[0].Data() << " ";
          str = fRuns[runNo].fBeamline[0];
          str.ToUpper();
          fout << str.Data() << " ";
          str = fRuns[runNo].fInstitute[0];
          str.ToUpper();
          fout << str.Data() << " ";
          str = fRuns[runNo].fFileFormat[0];
          str.ToUpper();
          fout << str.Data() << "   (name beamline institute data-file-format)" << endl;
        } else if (sstr.BeginsWith("ADDRUN")) {
          addRunNo++;
          fout << "ADDRUN " << fRuns[runNo].fRunName[addRunNo].Data() << " ";
          str = fRuns[runNo].fBeamline[addRunNo];
          str.ToUpper();
          fout << str.Data() << " ";
          str = fRuns[runNo].fInstitute[addRunNo];
          str.ToUpper();
          fout << str.Data() << " ";
          str = fRuns[runNo].fFileFormat[addRunNo];
          str.ToUpper();
          fout << str.Data() << "   (name beamline institute data-file-format)" << endl;
        } else if (sstr.BeginsWith("fittype")) {
          addRunNo = 0;
          fout.width(16);
          switch (fRuns[runNo].fFitType) {
          case MSR_FITTYPE_SINGLE_HISTO:
            fout << left << "fittype" << MSR_FITTYPE_SINGLE_HISTO << "         (single histogram fit)" << endl;
            break;
          case MSR_FITTYPE_ASYM:
            fout << left << "fittype" << MSR_FITTYPE_ASYM << "         (asymmetry fit)" << endl ;
            break;
          case MSR_FITTYPE_ASYM_RRF:
            fout << left << "fittype" << MSR_FITTYPE_ASYM_RRF << "         (RRF asymmetry fit)" << endl ;
            break;
          case MSR_FITTYPE_NON_MUSR:
            fout << left << "fittype" << MSR_FITTYPE_NON_MUSR << "         (non muSR fit)" << endl ;
            break;
          default:
            break;
          }
        } else if (sstr.BeginsWith("rrffrequency")) {
          fout.width(16);
          fout << left << "rrffrequency";
          fout.precision(prec);
          fout << fRuns[runNo].fRRFFreq << endl;
        } else if (sstr.BeginsWith("rrfpacking")) {
          fout.width(16);
          fout << left << "rrfpacking";
          fout.precision(prec);
          fout << fRuns[runNo].fRRFPacking << endl;
        } else if (sstr.BeginsWith("alpha ")) {
          fout.width(16);
          fout << left << "alpha";
          fout << fRuns[runNo].fAlphaParamNo << endl;
        } else if (sstr.BeginsWith("beta ")) {
          fout.width(16);
          fout << left << "beta";
          fout << fRuns[runNo].fBetaParamNo  << endl;
        } else if (sstr.BeginsWith("alpha2")) {
          fout.width(16);
          fout << left << "alpha2";
          fout << fRuns[runNo].fAlphaParamNo << endl;
        } else if (sstr.BeginsWith("beta2")) {
          fout.width(16);
          fout << left << "beta2";
          fout << fRuns[runNo].fBetaParamNo  << endl;
        } else if (sstr.BeginsWith("norm")) {
          fout.width(16);
          fout << left << "norm";
          // check if norm is give as a function
          if (fRuns[runNo].fNormParamNo >= MSR_PARAM_FUN_OFFSET)
            fout << "fun" << fRuns[runNo].fNormParamNo-MSR_PARAM_FUN_OFFSET;
          else
            fout << fRuns[runNo].fNormParamNo;
          fout << endl;
        } else if (sstr.BeginsWith("backgr.fit")) {
          fout.width(16);
          fout << left << "backgr.fit";
          fout << fRuns[runNo].fBkgFitParamNo << endl;
        } else if (sstr.BeginsWith("rphase")) {
          fout.width(16);
          fout << left << "rphase";
          fout << fRuns[runNo].fPhaseParamNo << endl;
        } else if (sstr.BeginsWith("lifetime ")) {
          fout.width(16);
          fout << left << "lifetime";
          fout << fRuns[runNo].fLifetimeParamNo << endl;
        } else if (sstr.BeginsWith("lifetimecorrection")) {
          if ((fRuns[runNo].fLifetimeCorrection) && (fRuns[runNo].fFitType == MSR_FITTYPE_SINGLE_HISTO)) {
            fout << "lifetimecorrection" << endl;
          }
        } else if (sstr.BeginsWith("map")) {
          fout << "map         ";
          for (unsigned int j=0; j<fRuns[runNo].fMap.size(); j++) {
            fout.width(5);
            fout << right << fRuns[runNo].fMap[j];
          }
          // if there are less maps then 10 fill with zeros
          if (fRuns[runNo].fMap.size() < 10) {
            for (unsigned int j=fRuns[runNo].fMap.size(); j<10; j++)
              fout << "    0";
          }
          fout << endl;
        } else if (sstr.BeginsWith("forward")) {
          fout.width(16);
          fout << left << "forward";
          fout << fRuns[runNo].fForwardHistoNo << endl;
        } else if (sstr.BeginsWith("backward")) {
          fout.width(16);
          fout << left << "backward";
          fout << fRuns[runNo].fBackwardHistoNo << endl;
        } else if (sstr.BeginsWith("right")) {
          fout.width(16);
          fout << left << "right";
          fout << fRuns[runNo].fRightHistoNo << endl;
        } else if (sstr.BeginsWith("left")) {
          fout.width(16);
          fout << left << "left";
          fout << fRuns[runNo].fLeftHistoNo << endl;
        } else if (sstr.BeginsWith("backgr.fix")) {
          fout.width(15);
          fout << left << "backgr.fix";
          for (unsigned int j=0; j<fRuns[runNo].fBkgFix.size(); j++) {
            fout.precision(prec);
            fout.width(12);
            fout << left << fRuns[runNo].fBkgFix[j];
          }
          fout << endl;
        } else if (sstr.BeginsWith("background")) {
          fout.width(16);
          fout << left << "background";
          for (unsigned int j=0; j<fRuns[runNo].fBkgRange.size(); j++) {
            fout.width(8);
            fout << left << fRuns[runNo].fBkgRange[j];
          }
          fout << endl;
        } else if (sstr.BeginsWith("data")) {
          fout.width(16);
          fout << left << "data";
          for (unsigned int j=0; j<fRuns[runNo].fDataRange.size(); j++) {
            fout.width(8);
            fout << left << fRuns[runNo].fDataRange[j];
          }
          fout << endl;
        } else if (sstr.BeginsWith("t0")) {
          fout.width(16);
          fout << left << "t0";
          for (unsigned int j=0; j<fRuns[runNo].fT0.size(); j++) {
            fout.width(8);
            fout << left << fRuns[runNo].fT0[j];
          }
          fout << endl;
        } else if (sstr.BeginsWith("xy-data")) {
          if (fRuns[runNo].fXYDataIndex[0] != -1) { // indices
            fout.width(16);
            fout << left << "xy-data";
            for (unsigned int j=0; j<2; j++) {
              if (fRuns[runNo].fXYDataIndex[j] == -1)
                break;
              fout.width(8);
              fout.precision(2);
              fout << left << fixed << fRuns[runNo].fXYDataIndex[j];
            }
            fout << endl;
          } else if (!fRuns[runNo].fXYDataLabel[0].IsWhitespace()) { // labels
            fout.width(16);
            fout << endl << left << "xy-data";
            for (unsigned int j=0; j<2; j++) {
              if (fRuns[runNo].fXYDataLabel[j].IsWhitespace())
                break;
              fout.width(8);
              fout << left << fixed << fRuns[runNo].fXYDataLabel[j].Data();
              if (j == 0)
                fout << " ";
            }
            fout << endl;
          }
        } else if (sstr.BeginsWith("fit")) {
          fout.width(16);
          fout << left << "fit";
          for (unsigned int j=0; j<2; j++) {
            if (fRuns[runNo].fFitRange[j] == -1)
              break;
            fout.width(8);
            fout.precision(2);
            fout << left << fixed << fRuns[runNo].fFitRange[j];
          }
          fout << endl;
        } else if (sstr.BeginsWith("packing")) {
          fout.width(16);
          fout << left << "packing";
          fout << fRuns[runNo].fPacking << endl;
        } else {
          fout << str.Data() << endl;
        }
        break;
      case MSR_TAG_COMMANDS:
        fout << str.Data() << endl;
        break;
      case MSR_TAG_FOURIER:
        sstr = str;
        sstr.Remove(TString::kLeading, ' ');
        if (sstr.BeginsWith("units")) {
          fout << "units            ";
          if (fFourier.fUnits == FOURIER_UNIT_FIELD) {
            fout << "Gauss";
          } else if (fFourier.fUnits == FOURIER_UNIT_FREQ) {
            fout << "MHz ";
          } else if (fFourier.fUnits == FOURIER_UNIT_CYCLES) {
            fout << "Mc/s";
          }
          fout << "   # units either 'Gauss', 'MHz', or 'Mc/s'";
          fout << endl;
        } else if (sstr.BeginsWith("fourier_power")) {
          fout << "fourier_power    " << fFourier.fFourierPower << endl;
        } else if (sstr.BeginsWith("apodization")) {
          fout << "apodization      ";
          if (fFourier.fApodization == FOURIER_APOD_NONE) {
            fout << "NONE  ";
          } else if (fFourier.fApodization == FOURIER_APOD_WEAK) {
            fout << "WEAK  ";
          } else if (fFourier.fApodization == FOURIER_APOD_MEDIUM) {
            fout << "MEDIUM";
          } else if (fFourier.fApodization == FOURIER_APOD_STRONG) {
            fout << "STRONG";
          }
          fout << "  # NONE, WEAK, MEDIUM, STRONG";
          fout << endl;
        } else if (sstr.BeginsWith("plot")) {
          fout << "plot             ";
          if (fFourier.fPlotTag == FOURIER_PLOT_REAL) {
            fout << "REAL ";
          } else if (fFourier.fPlotTag == FOURIER_PLOT_IMAG) {
            fout << "IMAG ";
          } else if (fFourier.fPlotTag == FOURIER_PLOT_REAL_AND_IMAG) {
            fout << "REAL_AND_IMAG";
          } else if (fFourier.fPlotTag == FOURIER_PLOT_POWER) {
            fout << "POWER";
          } else if (fFourier.fPlotTag == FOURIER_PLOT_PHASE) {
            fout << "PHASE";
          }
          fout << "   # REAL, IMAG, REAL_AND_IMAG, POWER, PHASE";
          fout << endl;
        } else if (sstr.BeginsWith("phase")) {
          if (fFourier.fPhaseParamNo > 0) {
            fout << "phase            par" << fFourier.fPhaseParamNo << endl;
          } else {
            if (fFourier.fPhase != -999.0) {
              fout << "phase            " << fFourier.fPhase << endl;
            }
          }
        } else if (sstr.BeginsWith("range_for_phase_correction")) {
          fout << "range_for_phase_correction  " << fFourier.fRangeForPhaseCorrection[0] << "    " << fFourier.fRangeForPhaseCorrection[1] << endl;
        } else if (sstr.BeginsWith("range ")) {
          fout << "range            " << fFourier.fPlotRange[0] << "    " << fFourier.fPlotRange[1] << endl;
        } else {
          fout << str.Data() << endl;
        }
        break;
      case MSR_TAG_PLOT:
        sstr = str;
        sstr.Remove(TString::kLeading, ' ');
        if (sstr.BeginsWith("PLOT")) {
          switch (fPlots[plotNo].fPlotType) {
          case MSR_PLOT_SINGLE_HISTO:
            fout << "PLOT " << fPlots[plotNo].fPlotType << "   (single histo plot)" << endl;
            break;
          case MSR_PLOT_ASYM:
            fout << "PLOT " << fPlots[plotNo].fPlotType << "   (asymmetry plot)" << endl;
            break;
          case MSR_PLOT_ASYM_RRF:
            fout << "PLOT " << fPlots[plotNo].fPlotType << "   (rotating reference frame plot)" << endl;
            break;
          case MSR_PLOT_NON_MUSR:
            fout << "PLOT " << fPlots[plotNo].fPlotType << "   (non muSR plot)" << endl;
            break;
          default:
            break;
          }
        } else if (sstr.BeginsWith("runs")) {
          fout << "runs     ";
          fout.precision(0);
          for (unsigned int j=0; j<fPlots[plotNo].fRuns.size(); j++) {
            if (fPlots[plotNo].fPlotType != MSR_PLOT_ASYM_RRF) { // all but MSR_PLOT_ASYM_RRF
              fout.width(4);
              fout << fPlots[plotNo].fRuns[j].Re();
            } else { // MSR_PLOT_ASYM_RRF
              fout << fPlots[plotNo].fRuns[j].Re() << "," << fPlots[plotNo].fRuns[j].Im() << "    ";
            }
          }
          fout << endl;
        } else if (sstr.BeginsWith("range")) {
          fout << "range    ";
          fout.precision(2);
          fout << fPlots[plotNo].fTmin[0] << "   " << fPlots[plotNo].fTmax[0];
          if (fPlots[plotNo].fYmin.size() > 0) {
            fout << "   " << fPlots[plotNo].fYmin[0] << "   " << fPlots[plotNo].fYmax[0];
          }
          fout << endl;
        } else {
          fout << str.Data() << endl;
        }
        break;
      case MSR_TAG_STATISTIC:
        statisticBlockFound = true;
        sstr = str;
        sstr.Remove(TString::kLeading, ' ');
        if (sstr.BeginsWith("STATISTIC")) {
          TDatime dt;
          fout << "STATISTIC --- " << dt.AsSQLString() << endl;
        } else if (sstr.BeginsWith("chisq")) {
          partialStatisticBlockFound = false;
          if (fStatistic.fValid) { // valid fit result
            str  = "  chisq = ";
            str += fStatistic.fMin;
            str += ", NDF = ";
            str += fStatistic.fNdf;
            str += ", chisq/NDF = ";
            str += fStatistic.fMin / fStatistic.fNdf;
            fout << str.Data() << endl;
            if (messages)
              cout << endl << str.Data() << endl;
          } else {
           fout << "*** FIT DID NOT CONVERGE ***" << endl;
           if (messages)
             cout << endl << "*** FIT DID NOT CONVERGE ***" << endl;
          }
        } else if (sstr.BeginsWith("maxLH")) {
          partialStatisticBlockFound = false;
          if (fStatistic.fValid) { // valid fit result
            str  = "  maxLH = ";
            str += fStatistic.fMin;
            str += ", NDF = ";
            str += fStatistic.fNdf;
            str += ", maxLH/NDF = ";
            str += fStatistic.fMin / fStatistic.fNdf;
            fout << str.Data() << endl;
            if (messages)
              cout << endl << str.Data() << endl;
          } else {
           fout << "*** FIT DID NOT CONVERGE ***" << endl;
           if (messages)
             cout << endl << "*** FIT DID NOT CONVERGE ***" << endl;
          }
        } else if (sstr.BeginsWith("*** FIT DID NOT CONVERGE ***")) {
          partialStatisticBlockFound = false;
          if (fStatistic.fValid) { // valid fit result
            if (fStatistic.fChisq) { // chisq
              str  = "  chisq = ";
              str += fStatistic.fMin;
              str += ", NDF = ";
              str += fStatistic.fNdf;
              str += ", chisq/NDF = ";
              str += fStatistic.fMin / fStatistic.fNdf;
              fout << str.Data() << endl;
              if (messages)
                cout << endl << str.Data() << endl;
            } else { // max. log. liklihood
              str  = "  maxLH = ";
              str += fStatistic.fMin;
              str += ", NDF = ";
              str += fStatistic.fNdf;
              str += ", maxLH/NDF = ";
              str += fStatistic.fMin / fStatistic.fNdf;
              fout << str.Data() << endl;
              if (messages)
                cout << endl << str.Data() << endl;
            }
          } else {
           fout << "*** FIT DID NOT CONVERGE ***" << endl;
           if (messages)
             cout << endl << "*** FIT DID NOT CONVERGE ***" << endl;
          }
        } else {
          fout << str.Data() << endl;
        }
        break;
      default:
        break;
    }
  }

  // there was no statistic block present in the msr-input-file
  if (!statisticBlockFound) {
    partialStatisticBlockFound = false;
    cout << endl << "PMsrHandler::WriteMsrLogFile: **WARNING** no STATISTIC block present, will write a default one" << endl;
    fout << "###############################################################" << endl;
    TDatime dt;
    fout << "STATISTIC --- " << dt.AsSQLString() << endl;
    if (fStatistic.fValid) { // valid fit result
      if (fStatistic.fChisq) { // chisq
        str  = "  chisq = ";
        str += fStatistic.fMin;
        str += ", NDF = ";
        str += fStatistic.fNdf;
        str += ", chisq/NDF = ";
        str += fStatistic.fMin / fStatistic.fNdf;
        fout << str.Data() << endl;
        if (messages)
          cout << endl << str.Data() << endl;
      } else { // max. log. liklihood
        str  = "  maxLH = ";
        str += fStatistic.fMin;
        str += ", NDF = ";
        str += fStatistic.fNdf;
        str += ", maxLH/NDF = ";
        str += fStatistic.fMin / fStatistic.fNdf;
        fout << str.Data() << endl;
        if (messages)
          cout << endl << str.Data() << endl;
      }
    } else {
      fout << "*** FIT DID NOT CONVERGE ***" << endl;
      if (messages)
        cout << endl << "*** FIT DID NOT CONVERGE ***" << endl;
    }
  }

  // there was only a partial statistic block present in the msr-input-file
  if (partialStatisticBlockFound) {
    cout << endl << "PMsrHandler::WriteMsrLogFile: **WARNING** garbage STATISTIC block present in the msr-input file.";
    cout << endl << "** WILL ADD SOME SENSIBLE STUFF, BUT YOU HAVE TO CHECK IT SINCE I AM **NOT** REMOVING THE GARBAGE! **" << endl;
    TDatime dt;
    fout << "STATISTIC --- " << dt.AsSQLString() << endl;
    if (fStatistic.fValid) { // valid fit result
      if (fStatistic.fChisq) { // chisq
        str  = "  chisq = ";
        str += fStatistic.fMin;
        str += ", NDF = ";
        str += fStatistic.fNdf;
        str += ", chisq/NDF = ";
        str += fStatistic.fMin / fStatistic.fNdf;
        fout << str.Data() << endl;
        if (messages)
          cout << endl << str.Data() << endl;
      } else { // max. log. liklihood
        str  = "  maxLH = ";
        str += fStatistic.fMin;
        str += ", NDF = ";
        str += fStatistic.fNdf;
        str += ", maxLH/NDF = ";
        str += fStatistic.fMin / fStatistic.fNdf;
        fout << str.Data() << endl;
        if (messages)
          cout << endl << str.Data() << endl;
      }
    } else {
      fout << "*** FIT DID NOT CONVERGE ***" << endl;
      if (messages)
        cout << endl << "*** FIT DID NOT CONVERGE ***" << endl;
    }
  }

  // close files
  fout.close();
  fin.close();

  return PMUSR_SUCCESS;
}

//--------------------------------------------------------------------------
// SetMsrParamValue (public)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param i
 * \param value
 */
bool PMsrHandler::SetMsrParamValue(unsigned int i, double value)
{
  if (i > fParam.size()) {
    cout << endl << "PMsrHandler::SetMsrParamValue(): i = " << i << " is larger than the number of parameters " << fParam.size();
    cout << endl;
    return false;
  }

  fParam[i].fValue = value;

  return true;
}

//--------------------------------------------------------------------------
// SetMsrParamStep (public)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param i
 * \param value
 */
bool PMsrHandler::SetMsrParamStep(unsigned int i, double value)
{
  if (i > fParam.size()) {
    cout << endl << "PMsrHandler::SetMsrParamValue(): i = " << i << " is larger than the number of parameters " << fParam.size();
    cout << endl;
    return false;
  }

  fParam[i].fStep = value;

  return true;
}

//--------------------------------------------------------------------------
// SetMsrParamPosErrorPresent (public)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param i
 * \param value
 */
bool PMsrHandler::SetMsrParamPosErrorPresent(unsigned int i, bool value)
{
  if (i > fParam.size()) {
    cout << endl << "PMsrHandler::SetMsrParamPosErrorPresent(): i = " << i << " is larger than the number of parameters " << fParam.size();
    cout << endl;
    return false;
  }

  fParam[i].fPosErrorPresent = value;

  return true;
}

//--------------------------------------------------------------------------
// SetMsrParamPosError (public)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param i
 * \param value
 */
bool PMsrHandler::SetMsrParamPosError(unsigned int i, double value)
{
  if (i > fParam.size()) {
    cout << endl << "PMsrHandler::SetMsrParamPosError(): i = " << i << " is larger than the number of parameters " << fParam.size();
    cout << endl;
    return false;
  }

  fParam[i].fPosErrorPresent = true;
  fParam[i].fPosError = value;

  return true;
}

//--------------------------------------------------------------------------
// SetMsrT0Entry (public)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param runNo
 * \param idx
 * \param bin
 */
void PMsrHandler::SetMsrT0Entry(unsigned int runNo, unsigned int idx, int bin)
{
  if ((runNo < 0) || (runNo > fRuns.size())) { // error
    cout << endl << "**ERROR** in PMsrHandler::SetMsrT0Entry: runNo = " << runNo << ", is out of valid range 0.." << fRuns.size();
    cout << endl;
    return;
  }

  if ((idx < 0) || (idx > fRuns[runNo].fT0.size())) { // error
    cout << endl << "**ERROR** in PMsrHandler::SetMsrT0Entry: idx = " << idx << ", is out of valid range 0.." << fRuns[runNo].fT0.size();
    cout << endl;
    return;
  }

  fRuns[runNo].fT0[idx] = bin;
}

//--------------------------------------------------------------------------
// SetMsrDataRangeEntry (public)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param runNo
 * \param idx
 * \param bin
 */
void PMsrHandler::SetMsrDataRangeEntry(unsigned int runNo, unsigned int idx, int bin)
{
  if ((runNo < 0) || (runNo > fRuns.size())) { // error
    cout << endl << "**ERROR** in PMsrHandler::SetMsrDataRangeEntry: runNo = " << runNo << ", is out of valid range 0.." << fRuns.size();
    cout << endl;
    return;
  }

  if ((idx < 0) || (idx > fRuns[runNo].fDataRange.size())) { // error
    cout << endl << "**ERROR** in PMsrHandler::SetMsrDataRangeEntry: idx = " << idx << ", is out of valid range 0.." << fRuns[runNo].fDataRange.size();
    cout << endl;
    return;
  }

  fRuns[runNo].fDataRange[idx] = bin;
}

//--------------------------------------------------------------------------
// SetMsrBkgRangeEntry (public)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param runNo
 * \param idx
 * \param bin
 */
void PMsrHandler::SetMsrBkgRangeEntry(unsigned int runNo, unsigned int idx, int bin)
{
  if ((runNo < 0) || (runNo > fRuns.size())) { // error
    cout << endl << "**ERROR** in PMsrHandler::SetMsrBkgRangeEntry: runNo = " << runNo << ", is out of valid range 0.." << fRuns.size();
    cout << endl;
    return;
  }

  if ((idx < 0) || (idx > fRuns[runNo].fBkgRange.size())) { // error
    cout << endl << "**ERROR** in PMsrHandler::SetMsrBkgRangeEntry: idx = " << idx << ", is out of valid range 0.." << fRuns[runNo].fBkgRange.size();
    cout << endl;
    return;
  }

  fRuns[runNo].fBkgRange[idx] = bin;
}

//--------------------------------------------------------------------------
// ParameterInUse (public)
//--------------------------------------------------------------------------
/**
 * <p>Needed for the following purpose: if minuit is minimizing, it varies
 * all the parameters of the parameter list (if not fixed), even if a particular
 * parameter is <b>NOT</b> used at all. This is stupid! Hence one has to check
 * if the parameter is used at all and if not, it has to be fixed.
 *
 * \param paramNo
 */
int PMsrHandler::ParameterInUse(unsigned int paramNo)
{
  // check that paramNo is within acceptable range
  if ((paramNo < 0) || (paramNo > fParam.size()))
    return -1;

  return fParamInUse[paramNo];
}

//--------------------------------------------------------------------------
// HandleFitParameterEntry (private)
//--------------------------------------------------------------------------
/**
 * <p>The routine analyze a parameter line and, if the possible parameter list
 * is OK (what this means see below), it adds the parameter to the parameter list.
 *
 * <p>Possible cases:
 * \code
 * No Name Value Step/Neg_Error Pos_Error Boundary_Low Boundary_High
 * x  x    x     x              x         x            x              -> 7 Parameters, e.g. after a MINOS fit
 * x  x    x     x              x                                     -> 5 Parameters, e.g. after a MINOS fit
 *                                                                                     without boundaries
 * x  x    x     x                                                    -> 4 Parameters, e.g. after MIGRAD fit
 *                                                                                     without boundaries, or
 *                                                                                     when starting
 * \endcode
 *
 * \param lines is a list of lines containing the fitparameter block
 */
bool PMsrHandler::HandleFitParameterEntry(PMsrLines &lines)
{
  PMsrParamStructure param;
  bool    error = false;

  PMsrLines::iterator iter;

  TObjArray *tokens;
  TObjString *ostr;
  TString str;

  // fill param structure
  iter = lines.begin();
  while ((iter != lines.end()) && !error) {

    // init param structure
    param.fNoOfParams           = -1;
    param.fNo                   = -1;
    param.fName                 = TString("");
    param.fValue                = 0.0;
    param.fStep                 = 0.0;
    param.fPosErrorPresent      = false;
    param.fPosError             = 0.0;
    param.fLowerBoundaryPresent = false;
    param.fLowerBoundary        = 0.0;
    param.fUpperBoundaryPresent = false;
    param.fUpperBoundary        = 0.0;

    tokens = iter->fLine.Tokenize(" \t");
    if (!tokens) {
      cout << endl << ">> PMsrHandler::HandleFitParameterEntry: **SEVERE ERROR** Couldn't tokenize Parameters in line " << iter->fLineNo;
      cout << endl << endl;
      return false;
    }

    // handle various input possiblities
    if ((tokens->GetEntries() < 4) || (tokens->GetEntries() > 7) || (tokens->GetEntries() == 6)) {
      error = true;
    } else { // handle the first 4 parameter since they are always the same
      // parameter number
      ostr = dynamic_cast<TObjString*>(tokens->At(0));
      str = ostr->GetString();
      if (str.IsDigit())
        param.fNo = str.Atoi();
      else
        error = true;

      // parameter name
      ostr = dynamic_cast<TObjString*>(tokens->At(1));
      str = ostr->GetString();
      param.fName = str;

      // parameter value
      ostr = dynamic_cast<TObjString*>(tokens->At(2));
      str = ostr->GetString();
      if (str.IsFloat())
        param.fValue = (double)str.Atof();
      else
        error = true;

      // parameter value
      ostr = dynamic_cast<TObjString*>(tokens->At(3));
      str = ostr->GetString();
      if (str.IsFloat())
        param.fStep = (double)str.Atof();
      else
        error = true;

      // 4 values, i.e. No Name Value Step
      if (tokens->GetEntries() == 4) {
        param.fNoOfParams = 4;
      }

      // 5 values, i.e. No Name Value Neg_Error Pos_Error
      if (tokens->GetEntries() == 5) {
        param.fNoOfParams = 5;

        // positive error
        ostr = dynamic_cast<TObjString*>(tokens->At(4));
        str = ostr->GetString();
        if (str.IsFloat()) {
          param.fPosErrorPresent = true;
          param.fPosError = (double)str.Atof();
        } else {
          str.ToLower();
          if (!str.CompareTo("none", TString::kIgnoreCase))
            param.fPosErrorPresent = false;
          else
            error = true;
        }
      }

      // 7 values, i.e. No Name Value Neg_Error Pos_Error Lower_Boundary Upper_Boundary
      if (tokens->GetEntries() == 7) {
        param.fNoOfParams = 7;

        // positive error
        ostr = dynamic_cast<TObjString*>(tokens->At(4));
        str = ostr->GetString();
        if (str.IsFloat()) {
          param.fPosErrorPresent = true;
          param.fPosError = (double)str.Atof();
        } else {
          str.ToLower();
          if (!str.CompareTo("none", TString::kIgnoreCase))
            param.fPosErrorPresent = false;
          else
            error = true;
        }

        // lower boundary
        ostr = dynamic_cast<TObjString*>(tokens->At(5));
        str = ostr->GetString();
        // check if lower boundary is "none", i.e. upper boundary limited only
        if (!str.CompareTo("none", TString::kIgnoreCase)) { // none
          param.fLowerBoundaryPresent = false;
        } else { // assuming that the lower boundary is a number
          if (str.IsFloat()) {
            param.fLowerBoundary = (double)str.Atof();
            param.fLowerBoundaryPresent = true;
          } else {
            error = true;
          }
        }

        // upper boundary
        ostr = dynamic_cast<TObjString*>(tokens->At(6));
        str = ostr->GetString();
        // check if upper boundary is "none", i.e. lower boundary limited only
        if (!str.CompareTo("none", TString::kIgnoreCase)) { // none
          param.fUpperBoundaryPresent = false;
        } else { // assuming a number
          if (str.IsFloat()) {
            param.fUpperBoundary = (double)str.Atof();
            param.fUpperBoundaryPresent = true;
          } else {
            error = true;
          }
        }
      }
    }

    // check if enough elements found
    if (error) {
      cout << endl;
      cout << endl << ">> PMsrHandler::HandleFitParameterEntry: **ERROR** in line " << iter->fLineNo << ":";
      cout << endl << iter->fLine.Data();
      cout << endl << "A Fit Parameter line needs to have the following form: ";
      cout << endl;
      cout << endl << "No Name Value Step/Error [Lower_Boundary Upper_Boundary]";
      cout << endl;
      cout << endl << "or";
      cout << endl;
      cout << endl << "No Name Value Step/Neg_Error Pos_Error [Lower_Boundary Upper_Boundary]";
      cout << endl;
      cout << endl << "No:             the parameter number (an int)";
      cout << endl << "Name:           the name of the parameter (less than 256 character)";
      cout << endl << "Value:          the starting value of the parameter (a double)";
      cout << endl << "Step/Error,";
      cout << endl << "Step/Neg_Error: the starting step value in a fit  (a double), or";
      cout << endl << "                the symmetric error (MIGRAD, SIMPLEX), or";
      cout << endl << "                the negative error (MINOS)";
      cout << endl << "Pos_Error:      the positive error (MINOS),  (a double or \"none\")";
      cout << endl << "Lower_Boundary: the lower boundary allowed for the fit parameter  (a double or \"none\")";
      cout << endl << "Upper_Boundary: the upper boundary allowed for the fit parameter  (a double or \"none\")";
      cout << endl;
    } else { // everything is OK, therefore add the parameter to the parameter list
      fParam.push_back(param);
    }

    // clean up
    if (tokens) {
      delete tokens;
      tokens = 0;
    }

    iter++;
  }

  return !error;
}

//--------------------------------------------------------------------------
// HandleTheoryEntry (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param lines is a list of lines containing the fitparameter block
 */
bool PMsrHandler::HandleTheoryEntry(PMsrLines &lines)
{
  // store the theory lines
  fTheory = lines;

  return true;
}

//--------------------------------------------------------------------------
// HandleFunctionsEntry (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param lines is a list of lines containing the fitparameter block
 */
bool PMsrHandler::HandleFunctionsEntry(PMsrLines &lines)
{
  // store the functions lines
  fFunctions = lines;

  // create function handler
  fFuncHandler = new PFunctionHandler(fFunctions);
  if (fFuncHandler == 0) {
    cout << endl << ">> PMsrHandler::HandleFunctionsEntry: **ERROR** Couldn't invoke PFunctionHandler." << endl;
    return false;
  }

  // do the parsing
  if (!fFuncHandler->DoParse()) {
    return false;
  }

  // check if an empty FUNCTIONS block is present
  if ((fFuncHandler->GetNoOfFuncs() == 0) && !lines.empty()) {
    cout << endl << ">> PMsrHandler::HandleFunctionsEntry: **ERROR** empty FUNCTIONS block are not supported!";
    cout << endl << ">> If you want to keep it, just comment the whole block ;-)";
    cout << endl;
    return false;
  }

  return true;
}

//--------------------------------------------------------------------------
// HandleRunEntry (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param lines is a list of lines containing the fitparameter block
 */
bool PMsrHandler::HandleRunEntry(PMsrLines &lines)
{
  PMsrLines::iterator iter;
  PMsrRunStructure param;
  bool first = true; // first run line tag
  bool error = false;

  TString str;
  TObjString *ostr;
  TObjArray *tokens;

  // init some stuff
  param.fXYDataIndex[0]  = -1;
  param.fXYDataIndex[1]  = -1;
  param.fXYDataLabel[0]  = TString("");
  param.fXYDataLabel[1]  = TString("");

  iter = lines.begin();
  while ((iter != lines.end()) && !error) {
    // tokenize line
    tokens = iter->fLine.Tokenize(" \t");
    if (!tokens) {
      cout << endl << ">> PMsrHandler::HandleRunEntry: **SEVERE ERROR** Couldn't tokenize Parameters in line " << iter->fLineNo;
      cout << endl << endl;
      return false;
    }

    // RUN line ----------------------------------------------
    if (iter->fLine.BeginsWith("run", TString::kIgnoreCase)) {

      if (!first) { // not the first run in the list
        fRuns.push_back(param);
      } else {
        first = false;
      }

      InitRunParameterStructure(param);

      // get run name, beamline, institute, and file-format
      if (tokens->GetEntries() < 5) {
        error = true;
      } else {
        // run name
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        param.fRunName.push_back(ostr->GetString());
        // beamline
        ostr = dynamic_cast<TObjString*>(tokens->At(2));
        param.fBeamline.push_back(ostr->GetString());
        // institute
        ostr = dynamic_cast<TObjString*>(tokens->At(3));
        param.fInstitute.push_back(ostr->GetString());
        // data file format
        ostr = dynamic_cast<TObjString*>(tokens->At(4));
        param.fFileFormat.push_back(ostr->GetString());
      }
    }

    // ADDRUN line ---------------------------------------------
    if (iter->fLine.BeginsWith("addrun", TString::kIgnoreCase)) {
      // get run name, beamline, institute, and file-format
      if (tokens->GetEntries() < 5) {
        error = true;
      } else {
        // run name
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        param.fRunName.push_back(ostr->GetString());
        // beamline
        ostr = dynamic_cast<TObjString*>(tokens->At(2));
        param.fBeamline.push_back(ostr->GetString());
        // institute
        ostr = dynamic_cast<TObjString*>(tokens->At(3));
        param.fInstitute.push_back(ostr->GetString());
        // data file format
        ostr = dynamic_cast<TObjString*>(tokens->At(4));
        param.fFileFormat.push_back(ostr->GetString());
      }
    }

    // fittype -------------------------------------------------
    if (iter->fLine.BeginsWith("fittype", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit()) {
          int fittype = str.Atoi();
          if ((fittype == MSR_FITTYPE_SINGLE_HISTO) ||
              (fittype == MSR_FITTYPE_ASYM) ||
              (fittype == MSR_FITTYPE_ASYM_RRF) ||
              (fittype == MSR_FITTYPE_NON_MUSR)) {
            param.fFitType = fittype;
          } else {
            error = true;
          }
        } else {
          error = true;
        }
      }
    }

    // alpha -------------------------------------------------
    if (iter->fLine.BeginsWith("alpha", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fAlphaParamNo = str.Atoi();
        else
          error = true;
      }
    }

    // beta -------------------------------------------------
    if (iter->fLine.BeginsWith("beta", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fBetaParamNo = str.Atoi();
        else
          error = true;
      }
    }

    // norm -------------------------------------------------
    if (iter->fLine.BeginsWith("norm", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit()) {
          param.fNormParamNo = str.Atoi();
        } else if (str.Contains("fun")) {
          int no;
          if (FilterNumber(str, "fun", MSR_PARAM_FUN_OFFSET, no))
            param.fNormParamNo = no;
          else
            error = true;
        } else {
          error = true;
        }
      }
    }

    // backgr.fit --------------------------------------------
    if (iter->fLine.BeginsWith("backgr.fit", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fBkgFitParamNo = str.Atoi();
        else
          error = true;
      }
    }

    // rphase ------------------------------------------------
    if (iter->fLine.BeginsWith("rphase", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fPhaseParamNo = str.Atoi();
        else
          error = true;
      }
    }

    // lifetime ------------------------------------------------
    if (iter->fLine.BeginsWith("lifetime ", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fLifetimeParamNo = str.Atoi();
        else
          error = true;
      }
    }

    // lifetimecorrection ---------------------------------------
    if (iter->fLine.BeginsWith("lifetimecorrection", TString::kIgnoreCase)) {
      param.fLifetimeCorrection = true;
    }

    // map ------------------------------------------------------
    if (iter->fLine.BeginsWith("map", TString::kIgnoreCase)) {
      for (int i=1; i<tokens->GetEntries(); i++) {
        ostr = dynamic_cast<TObjString*>(tokens->At(i));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fMap.push_back(str.Atoi());
        else
          error = true;
      }
      // check map entries, i.e. if the map values are within parameter bounds
      for (unsigned int i=0; i<param.fMap.size(); i++) {
        if ((param.fMap[i] < 0) || (param.fMap[i] > (int) fParam.size())) {
          cout << endl << ">> PMsrHandler::HandleRunEntry: **SEVERE ERROR** map value " << param.fMap[i] << " in line " << iter->fLineNo << " is out of range!";
          error = true;
          break;
        }
      }
    }

    // forward ------------------------------------------------
    if (iter->fLine.BeginsWith("forward", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fForwardHistoNo = str.Atoi();
        else
          error = true;
      }
    }

    // backward -----------------------------------------------
    if (iter->fLine.BeginsWith("backward", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fBackwardHistoNo = str.Atoi();
        else
          error = true;
      }
    }

    // backgr.fix ----------------------------------------------
    if (iter->fLine.BeginsWith("backgr.fix", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        for (int i=1; i<tokens->GetEntries(); i++) {
          ostr = dynamic_cast<TObjString*>(tokens->At(i));
          str = ostr->GetString();
          if (str.IsFloat())
            param.fBkgFix.push_back(str.Atof());
          else
            error = true;
        }
      }
    }

    // background ---------------------------------------------
    if (iter->fLine.BeginsWith("background", TString::kIgnoreCase)) {
      if ((tokens->GetEntries() < 3) || (tokens->GetEntries() % 2 != 1)) { // odd number (>=3) of entries needed
        error = true;
      } else {
        for (int i=1; i<tokens->GetEntries(); i++) {
          ostr = dynamic_cast<TObjString*>(tokens->At(i));
          str = ostr->GetString();
          if (str.IsDigit())
            param.fBkgRange.push_back(str.Atoi());
          else
            error = true;
        }
      }
    }

    // data --------------------------------------------------
    if (iter->fLine.BeginsWith("data", TString::kIgnoreCase)) {
      if ((tokens->GetEntries() < 3) || (tokens->GetEntries() % 2 != 1)) { // odd number (>=3) of entries needed
        error = true;
      } else {
        for (int i=1; i<tokens->GetEntries(); i++) {
          ostr = dynamic_cast<TObjString*>(tokens->At(i));
          str = ostr->GetString();
          if (str.IsDigit())
            param.fDataRange.push_back(str.Atoi());
          else
            error = true;
        }
      }
    }

    // t0 -----------------------------------------------------
    if (iter->fLine.BeginsWith("t0", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) {
        error = true;
      } else {
        for (int i=1; i<tokens->GetEntries(); i++) {
          ostr = dynamic_cast<TObjString*>(tokens->At(i));
          str = ostr->GetString();
          if (str.IsDigit())
            param.fT0.push_back(str.Atoi());
          else
            error = true;
        }
      }
    }

    // fit -----------------------------------------------------
    if (iter->fLine.BeginsWith("fit ", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 3) {
        error = true;
      } else {
        for (int i=1; i<3; i++) {
          ostr = dynamic_cast<TObjString*>(tokens->At(i));
          str = ostr->GetString();
          if (str.IsFloat())
            param.fFitRange[i-1] = str.Atof();
          else
            error = true;
        }
      }
    }

    // packing --------------------------------------------------
    if (iter->fLine.BeginsWith("packing", TString::kIgnoreCase)) {
      if (tokens->GetEntries() != 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fPacking = str.Atoi();
        else
          error = true;
      }
    }

    // rrffrequency --------------------------------------------------
    if (iter->fLine.BeginsWith("rrffrequency", TString::kIgnoreCase)) {
      if (tokens->GetEntries() != 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsFloat())
          param.fRRFFreq = str.Atof();
        else
          error = true;
      }
    }

    // rrfpacking --------------------------------------------------
    if (iter->fLine.BeginsWith("rrfpacking", TString::kIgnoreCase)) {
      if (tokens->GetEntries() != 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fRRFPacking = str.Atoi();
        else
          error = true;
      }
    }

    // alpha2 --------------------------------------------------
    if (iter->fLine.BeginsWith("alpha2", TString::kIgnoreCase)) {
      if (tokens->GetEntries() != 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fAlpha2ParamNo = str.Atoi();
        else
          error = true;
      }
    }

    // beta2 --------------------------------------------------
    if (iter->fLine.BeginsWith("beta2", TString::kIgnoreCase)) {
      if (tokens->GetEntries() != 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fBeta2ParamNo = str.Atoi();
        else
          error = true;
      }
    }

    // right --------------------------------------------------
    if (iter->fLine.BeginsWith("right", TString::kIgnoreCase)) {
      if (tokens->GetEntries() != 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fRightHistoNo = str.Atoi();
        else
          error = true;
      }
    }

    // left --------------------------------------------------
    if (iter->fLine.BeginsWith("left", TString::kIgnoreCase)) {
      if (tokens->GetEntries() != 2) {
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit())
          param.fLeftHistoNo = str.Atoi();
        else
          error = true;
      }
    }

    // xy-data -----------------------------------------------
    if (iter->fLine.BeginsWith("xy-data", TString::kIgnoreCase)) {
      if (tokens->GetEntries() != 3) { // xy-data x-label y-label
        error = true;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit()) { // xy-data indices given
          param.fXYDataIndex[0] = str.Atoi(); // x-index
          ostr = dynamic_cast<TObjString*>(tokens->At(2));
          str = ostr->GetString();
          if (str.IsDigit())
            param.fXYDataIndex[1] = str.Atoi(); // y-index
          else
            error = true;
        } else { // xy-data labels given
          param.fXYDataLabel[0] = str; // x-label
          ostr = dynamic_cast<TObjString*>(tokens->At(2));
          str = ostr->GetString();
          param.fXYDataLabel[1] = str; // y-label
        }
      }
    }

    // clean up
    if (tokens) {
      delete tokens;
      tokens = 0;
    }

    ++iter;
  }

  if (error) {
    --iter;
    cout << endl << ">> PMsrHandler::HandleRunEntry: **ERROR** in line " << iter->fLineNo << ":";
    cout << endl << iter->fLine.Data();
    cout << endl << "RUN block syntax is too complex to print it here. Please check the manual.";
  } else { // save last run found
    fRuns.push_back(param);
  }

  // check if for fittypes: single histo, asymmetry, RRF any background info is given
  for (unsigned int i=0; i<fRuns.size(); i++) {
    if ((fRuns[i].fFitType == MSR_FITTYPE_SINGLE_HISTO) ||
        (fRuns[i].fFitType == MSR_FITTYPE_ASYM) ||
        (fRuns[i].fFitType == MSR_FITTYPE_ASYM_RRF)) {
      bool found;
      if (fRuns[i].fBkgFitParamNo >= 0) { // check if backgr.fit is given
        found = true;
      } else if (fRuns[i].fBkgFix.size() > 0) { // check if backgr.fix is given
        found = true;
      } else if (fRuns[i].fBkgRange.size() > 0) { // check if background window is given
        found = true;
      } else {
        found = false;
      }
      if (!found) {
        cout << endl << ">> PMsrHandler::HandleRunEntry: **ERROR** for run " << fRuns[i].fRunName[0].Data() << ",  forward " << fRuns[i].fForwardHistoNo;
        cout << endl << "   no background information found!";
        cout << endl << "   Either of the tags 'backgr.fit', 'backgr.fix', 'background'";
        cout << endl << "   with data is needed.";
        cout << endl;
        return false;
      }
    }
  }

  return !error;
}

//--------------------------------------------------------------------------
// InitRunParameterStructure (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param param
 */
void PMsrHandler::InitRunParameterStructure(PMsrRunStructure &param)
{
  param.fRunName.clear();
  param.fBeamline.clear();
  param.fInstitute.clear();
  param.fFileFormat.clear();
  param.fFitType         = -1;
  param.fAlphaParamNo    = -1;
  param.fBetaParamNo     = -1;
  param.fNormParamNo     = -1;
  param.fBkgFitParamNo   = -1;
  param.fPhaseParamNo    = -1;
  param.fLifetimeParamNo = -1;
  param.fLifetimeCorrection = false;
  param.fMap.clear(); // empty list
  param.fForwardHistoNo  = -1;
  param.fBackwardHistoNo = -1;
  param.fBkgFix.clear();
  param.fBkgRange.clear();
  param.fDataRange.clear();
  param.fT0.clear();
  for (int i=0; i<4; i++)
    param.fFitRange[i] = -1;
  param.fPacking = 1;
  param.fRRFFreq       = -1.0;
  param.fRRFPacking    = -1;
  param.fAlpha2ParamNo = -1;
  param.fBeta2ParamNo  = -1;
  param.fRightHistoNo  = -1;
  param.fLeftHistoNo   = -1;
  for (int i=0; i<2; i++)
    param.fXYDataIndex[i] = -1;
  for (int i=0; i<2; i++)
    param.fXYDataLabel[i] = "";
}

//--------------------------------------------------------------------------
// FilterNumber (private)
//--------------------------------------------------------------------------
/**
 * <p>Used to filter numbers from a string of the structure strX, where
 * X is a number. The filter string is used to define the offset to X.
 * It is used to filter strings like: map1 or fun4. At the moment only
 * the filter strings 'map', 'fun', and 'par' are supported.
 *
 * \param str  input string
 * \param filter filter string
 * \param offset it is used to offset to found number, e.g. strX -> no = X+offset
 * \param no filtered number
 */
bool PMsrHandler::FilterNumber(TString str, const char *filter, int offset, int &no)
{
  int  found, no_found=-1;

  // copy str to an ordinary c-like string
  char *cstr, filterStr[32];
  cstr = new char[str.Sizeof()];
  strncpy(cstr, str.Data(), str.Sizeof());
  sprintf(filterStr, "%s%%d", filter);

  // get number if present
  found = sscanf(cstr, filterStr, &no_found);
  if (found == 1)
    if (no_found < 1000)
      no = no_found + offset;

  // clean up
  if (cstr) {
    delete [] cstr;
    cstr = 0;
  }

  if ((no_found < 0) || (no_found > 1000))
    return false;
  else
    return true;
}

//--------------------------------------------------------------------------
// HandleCommandsEntry (private)
//--------------------------------------------------------------------------
/**
 * <p> In the command block there shall be a new command which can be used
 * to switch between chi2 and maximum_likelihood!!
 *
 * \param lines is a list of lines containing the fitparameter block
 */
bool PMsrHandler::HandleCommandsEntry(PMsrLines &lines)
{
  PMsrLines::iterator iter;

  if (lines.empty()) {
    cout << endl << "**WARNING**: There is no COMMANDS block! Do you really want this?";
    cout << endl;
  }

  for (iter = lines.begin(); iter != lines.end(); ++iter) {
    if (!iter->fLine.BeginsWith("COMMANDS"))
      fCommands.push_back(*iter);
  }

  return true;
}

//--------------------------------------------------------------------------
// InitFourierParameterStructure (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param fourier fourier parameters
 */
void PMsrHandler::InitFourierParameterStructure(PMsrFourierStructure &fourier)
{
  fourier.fFourierBlockPresent = false;           // fourier block present
  fourier.fUnits = FOURIER_UNIT_NOT_GIVEN;        // fourier untis, default: NOT GIVEN
  fourier.fFourierPower = -1;                     // zero padding, default: -1 = NOT GIVEN
  fourier.fApodization = FOURIER_APOD_NOT_GIVEN;  // apodization, default: NOT GIVEN
  fourier.fPlotTag = FOURIER_PLOT_NOT_GIVEN;      // initial plot tag, default: NOT GIVEN
  fourier.fPhaseParamNo = 0;                      // initial parameter no = 0 means not a parameter
  fourier.fPhase = -999.0;                        // fourier phase: -999 = NOT GIVEN
  for (unsigned int i=0; i<2; i++) {
    fourier.fRangeForPhaseCorrection[i] = -1.0;  // frequency range for phase correction, default: {-1, -1} = NOT GIVEN
    fourier.fPlotRange[i] = -1.0;                // fourier plot range, default: {-1, -1} = NOT GIVEN
  }
}

//--------------------------------------------------------------------------
// HandleFourierEntry (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param lines is a list of lines containing the fourier parameter block
 */
bool PMsrHandler::HandleFourierEntry(PMsrLines &lines)
{
//cout << endl << ">> in PMsrHandler::HandleFourierEntry ...";

  bool error = false;

  if (lines.empty()) // no fourier block present
    return true;

//cout << endl << ">> in PMsrHandler::HandleFourierEntry, Fourier block present ...";

  PMsrFourierStructure fourier;

  InitFourierParameterStructure(fourier);

  fourier.fFourierBlockPresent = true;

  PMsrLines::iterator iter;

  TObjArray *tokens;
  TObjString *ostr;
  TString str;

  int ival;

  iter = lines.begin();
  while ((iter != lines.end()) && !error) {
    // tokenize line
    tokens = iter->fLine.Tokenize(" \t");
    if (!tokens) {
      cout << endl << ">> PMsrHandler::HandleRunEntry: **SEVERE ERROR** Couldn't tokenize Parameters in line " << iter->fLineNo;
      cout << endl << endl;
      return false;
    }

    // units -----------------------------------------------
    if (iter->fLine.BeginsWith("units", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) { // units are missing
        error = true;
        continue;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (!str.CompareTo("gauss", TString::kIgnoreCase)) {
          fourier.fUnits = FOURIER_UNIT_FIELD;
        } else if (!str.CompareTo("mhz", TString::kIgnoreCase)) {
          fourier.fUnits = FOURIER_UNIT_FREQ;
        } else if (!str.CompareTo("mc/s", TString::kIgnoreCase)) {
          fourier.fUnits = FOURIER_UNIT_CYCLES;
        } else {
          error = true;
          continue;
        }
      }
    }

    // fourier power (zero padding) ------------------------
    if (iter->fLine.BeginsWith("fourier_power", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) { // fourier power exponent is missing
        error = true;
        continue;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.IsDigit()) {
          ival = str.Atoi();
          if ((ival >= 0) && (ival <= 20)) {
            fourier.fFourierPower = ival;
          } else { // fourier power out of range
            error = true;
            continue;
          }
        } else { // fourier power not a number
          error = true;
          continue;
        }
      }
    }

    // apodization -----------------------------------------
    if (iter->fLine.BeginsWith("apodization", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) { // apodization tag is missing
        error = true;
        continue;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (!str.CompareTo("none", TString::kIgnoreCase)) {
          fourier.fApodization = FOURIER_APOD_NONE;
        } else if (!str.CompareTo("weak", TString::kIgnoreCase)) {
          fourier.fApodization = FOURIER_APOD_WEAK;
        } else if (!str.CompareTo("medium", TString::kIgnoreCase)) {
          fourier.fApodization = FOURIER_APOD_MEDIUM;
        } else if (!str.CompareTo("strong", TString::kIgnoreCase)) {
          fourier.fApodization = FOURIER_APOD_STRONG;
        } else { // unrecognized apodization tag
          error = true;
          continue;
        }
      }
    }

    // plot tag --------------------------------------------
    if (iter->fLine.BeginsWith("plot", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) { // plot tag is missing
        error = true;
        continue;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (!str.CompareTo("real", TString::kIgnoreCase)) {
          fourier.fPlotTag = FOURIER_PLOT_REAL;
        } else if (!str.CompareTo("imag", TString::kIgnoreCase)) {
          fourier.fPlotTag = FOURIER_PLOT_IMAG;
        } else if (!str.CompareTo("real_and_imag", TString::kIgnoreCase)) {
          fourier.fPlotTag = FOURIER_PLOT_REAL_AND_IMAG;
        } else if (!str.CompareTo("power", TString::kIgnoreCase)) {
          fourier.fPlotTag = FOURIER_PLOT_POWER;
        } else if (!str.CompareTo("phase", TString::kIgnoreCase)) {
          fourier.fPlotTag = FOURIER_PLOT_PHASE;
        } else { // unrecognized plot tag
          error = true;
          continue;
        }
      }
    }

    // phase -----------------------------------------------
    if (iter->fLine.BeginsWith("phase", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 2) { // phase value is missing
        error = true;
        continue;
      } else {
        ostr = dynamic_cast<TObjString*>(tokens->At(1));
        str = ostr->GetString();
        if (str.BeginsWith("par", TString::kIgnoreCase)) { // parameter value
          int no = 0;
          if (FilterNumber(str, "par", 0, no)) {
            // check that the parameter is in range
            if ((int)fParam.size() < no) {
              error = true;
              continue;
            }
            // keep the parameter number
            fourier.fPhaseParamNo = no;
            // get parameter value
            fourier.fPhase = fParam[no-1].fValue;
          } else {
            error = true;
            continue;
          }
        } else if (str.IsFloat()) { // phase value
          fourier.fPhase = str.Atof();
        } else {
          error = true;
          continue;
        }
      }
    }

    // range for automatic phase correction ----------------
    if (iter->fLine.BeginsWith("range_for_phase_correction", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 3) { // range values are missing
        error = true;
        continue;
      } else {
        for (unsigned int i=0; i<2; i++) {
          ostr = dynamic_cast<TObjString*>(tokens->At(i+1));
          str = ostr->GetString();
          if (str.IsFloat()) {
            fourier.fRangeForPhaseCorrection[i] = str.Atof();
          } else {
            error = true;
            continue;
          }
        }
      }
    }

    // fourier plot range ----------------------------------
    if (iter->fLine.BeginsWith("range", TString::kIgnoreCase)) {
      if (tokens->GetEntries() < 3) { // plot range values are missing
        error = true;
        continue;
      } else {
        for (unsigned int i=0; i<2; i++) {
          ostr = dynamic_cast<TObjString*>(tokens->At(i+1));
          str = ostr->GetString();
          if (str.IsFloat()) {
            fourier.fPlotRange[i] = str.Atof();
          } else {
            error = true;
            continue;
          }
        }
      }
    }

    ++iter;
  }

  if (error) {
    cout << endl << ">> PMsrHandler::HandleFourierEntry: **ERROR** in line " << iter->fLineNo << ":";
    cout << endl;
    cout << endl << iter->fLine.Data();
    cout << endl;
    cout << endl << "FOURIER block syntax, parameters in [] are optinal:";
    cout << endl;
    cout << endl << "FOURIER";
    cout << endl << "[units Gauss | MHz | Mc/s]";
    cout << endl << "[fourier_power n # n is a number such that zero padding up to 2^n will be used]";
    cout << endl << "   n=0 means no zero padding";
    cout << endl << "   0 <= n <= 20 are allowed values";
    cout << endl << "[apodization none | weak | medium | strong]";
    cout << endl << "[plot real | imag | real_and_imag | power | phase]";
    cout << endl << "[phase value]";
    cout << endl << "[range_for_phase_correction min max]";
    cout << endl << "[range min max]";
    cout << endl;
  } else { // save last run found
    fFourier = fourier;
  }

  return !error;
}

//--------------------------------------------------------------------------
// HandlePlotEntry (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param lines is a list of lines containing the fitparameter block
 */
bool PMsrHandler::HandlePlotEntry(PMsrLines &lines)
{
  bool error = false;

  PMsrPlotStructure param;

  PMsrLines::iterator iter1;
  PMsrLines::iterator iter2;
  TObjArray *tokens;
  TObjArray *tokens2;
  TObjString *ostr;
  TString str;
  TString str2;

  if (lines.empty()) {
    cout << endl << "**WARNING**: There is no PLOT block! Do you really want this?";
    cout << endl;
  }

  iter1 = lines.begin();
  while ((iter1 != lines.end()) && !error) {

    // initialize param structure
    param.fPlotType = -1;
    param.fUseFitRanges = false; // i.e. if not overwritten use the range info of the plot block
    param.fLogX = false; // i.e. if not overwritten use linear x-axis
    param.fLogY = false; // i.e. if not overwritten use linear y-axis
    param.fViewPacking = -1; // i.e. if not overwritten use the packing of the run blocks

    // find next plot if any is present
    iter2 = iter1;
    ++iter2;
    for ( ; iter2 != lines.end(); ++iter2) {
      if (iter2->fLine.Contains("PLOT"))
        break;
    }

    // handle a single PLOT block
    while ((iter1 != iter2) && !error) {

      if (iter1->fLine.Contains("PLOT")) { // handle plot header
        tokens = iter1->fLine.Tokenize(" \t");
        if (!tokens) {
          cout << endl << ">> PMsrHandler::HandlePlotEntry: **SEVERE ERROR** Couldn't tokenize PLOT in line " << iter1->fLineNo;
          cout << endl << endl;
          return false;
        }
        if (tokens->GetEntries() < 2) { // plot type missing
          error = true;
        } else {
          ostr = dynamic_cast<TObjString*>(tokens->At(1));
          str = ostr->GetString();
          if (str.IsDigit())
            param.fPlotType = str.Atoi();
          else
            error = true;
        }
        // clean up
        if (tokens) {
          delete tokens;
          tokens = 0;
        }
      } else if (iter1->fLine.Contains("runs", TString::kIgnoreCase)) { // handle plot runs
        TComplex run;
        switch (param.fPlotType) {
          case -1:
            error = true;
            break;
          case MSR_PLOT_SINGLE_HISTO: // like: runs 1 5 13
          case MSR_PLOT_ASYM:
          case MSR_PLOT_NON_MUSR:
            tokens = iter1->fLine.Tokenize(" \t");
            if (!tokens) {
              cout << endl << ">> PMsrHandler::HandlePlotEntry: **SEVERE ERROR** Couldn't tokenize PLOT in line " << iter1->fLineNo;
              cout << endl << endl;
              return false;
            }
            if (tokens->GetEntries() < 2) { // runs missing
              error = true;
            } else {
              for (int i=1; i<tokens->GetEntries(); i++) {
                ostr = dynamic_cast<TObjString*>(tokens->At(i));
                str = ostr->GetString();
                if (str.IsDigit()) {
                  run = TComplex(str.Atoi(),-1.0);
                  param.fRuns.push_back(run);
                } else {
                  error = true;
                }
              }
            }
            // clean up
            if (tokens) {
              delete tokens;
              tokens = 0;
            }
            break;
          case MSR_PLOT_ASYM_RRF: // like: runs 1,1 1,2
            tokens = iter1->fLine.Tokenize(" \t");
            if (!tokens) {
              cout << endl << ">> PMsrHandler::HandlePlotEntry: **SEVERE ERROR** Couldn't tokenize PLOT in line " << iter1->fLineNo;
              cout << endl << endl;
              return false;
            }
            if (tokens->GetEntries() < 2) { // runs missing
              error = true;
            } else {
              for (int i=1; i<tokens->GetEntries(); i++) {
                ostr = dynamic_cast<TObjString*>(tokens->At(i)); // something like 1,2
                str = ostr->GetString();
                tokens2 = str.Tokenize(",");
                if (!tokens2) {
                  error = true;
                } else {
                  ostr = dynamic_cast<TObjString*>(tokens2->At(0)); // real part
                  str = ostr->GetString();
                  ostr = dynamic_cast<TObjString*>(tokens2->At(1)); // imag part
                  str2 = ostr->GetString();
                  if (str.IsDigit() && str2.IsDigit()) {
                    run = TComplex(str.Atoi(),str2.Atoi());
                    param.fRuns.push_back(run);
                  } else {
                    error = true;
                  }
                }
                if (tokens2) {
                  delete tokens2;
                  tokens2 = 0;
                }
              }
            }
            // clean up
            if (tokens) {
              delete tokens;
              tokens = 0;
            }
            break;
          default:
            error = true;
            break;
        }
      } else if (iter1->fLine.Contains("range ", TString::kIgnoreCase)) { // handle plot range
        // remove previous entries
        param.fTmin.clear();
        param.fTmax.clear();
        param.fYmin.clear();
        param.fYmax.clear();

        tokens = iter1->fLine.Tokenize(" \t");
        if (!tokens) {
          cout << endl << ">> PMsrHandler::HandlePlotEntry: **SEVERE ERROR** Couldn't tokenize PLOT in line " << iter1->fLineNo;
          cout << endl << endl;
          return false;
        }
        if ((tokens->GetEntries() != 3) && (tokens->GetEntries() != 5)) {
          error = true;
        } else {

          // handle t_min
          ostr = dynamic_cast<TObjString*>(tokens->At(1));
          str = ostr->GetString();
          if (str.IsFloat())
            param.fTmin.push_back((double)str.Atof());
          else
            error = true;

          // handle t_max
          ostr = dynamic_cast<TObjString*>(tokens->At(2));
          str = ostr->GetString();
          if (str.IsFloat())
            param.fTmax.push_back((double)str.Atof());
          else
            error = true;

          if (tokens->GetEntries() == 5) { // y-axis interval given as well

            // handle y_min
            ostr = dynamic_cast<TObjString*>(tokens->At(3));
            str = ostr->GetString();
            if (str.IsFloat())
              param.fYmin.push_back((double)str.Atof());
            else
              error = true;

            // handle y_max
            ostr = dynamic_cast<TObjString*>(tokens->At(4));
            str = ostr->GetString();
            if (str.IsFloat())
              param.fYmax.push_back((double)str.Atof());
            else
              error = true;
          }
        }
        // clean up
        if (tokens) {
          delete tokens;
          tokens = 0;
        }
      } else if (iter1->fLine.Contains("sub_ranges", TString::kIgnoreCase)) {
        // remove previous entries
        param.fTmin.clear();
        param.fTmax.clear();
        param.fYmin.clear();
        param.fYmax.clear();

        tokens = iter1->fLine.Tokenize(" \t");
        if (!tokens) {
          cout << endl << ">> PMsrHandler::HandlePlotEntry: **SEVERE ERROR** Couldn't tokenize PLOT in line " << iter1->fLineNo;
          cout << endl << endl;
          return false;
        }
        if ((tokens->GetEntries() != (int)(2*param.fRuns.size() + 1)) && (tokens->GetEntries() != (int)(2*param.fRuns.size() + 3))) {
          error = true;
        } else {
          // get all the times
          for (unsigned int i=0; i<param.fRuns.size(); i++) {

            // handle t_min
            ostr = dynamic_cast<TObjString*>(tokens->At(2*i+1));
            str = ostr->GetString();
            if (str.IsFloat())
              param.fTmin.push_back((double)str.Atof());
            else
              error = true;

            // handle t_max
            ostr = dynamic_cast<TObjString*>(tokens->At(2*i+2));
            str = ostr->GetString();
            if (str.IsFloat())
              param.fTmax.push_back((double)str.Atof());
            else
              error = true;
          }

          // get y-range if present
          if (tokens->GetEntries() == (int)(2*param.fRuns.size() + 3)) {

            // handle y_min
            ostr = dynamic_cast<TObjString*>(tokens->At(2*param.fRuns.size()+1));
            str = ostr->GetString();
            if (str.IsFloat())
              param.fYmin.push_back((double)str.Atof());
            else
              error = true;

            // handle y_max
            ostr = dynamic_cast<TObjString*>(tokens->At(2*param.fRuns.size()+2));
            str = ostr->GetString();
            if (str.IsFloat())
              param.fYmax.push_back((double)str.Atof());
            else
              error = true;
          }
        }

        // clean up
        if (tokens) {
          delete tokens;
          tokens = 0;
        }
      } else if (iter1->fLine.Contains("use_fit_ranges", TString::kIgnoreCase)) {
        param.fUseFitRanges = true;
      } else if (iter1->fLine.Contains("logx", TString::kIgnoreCase)) {
        param.fLogX = true;
      } else if (iter1->fLine.Contains("logy", TString::kIgnoreCase)) {
        param.fLogY = true;
      } else if (iter1->fLine.Contains("view_packing", TString::kIgnoreCase)) {
        tokens = iter1->fLine.Tokenize(" \t");
        if (!tokens) {
          cout << endl << ">> PMsrHandler::HandlePlotEntry: **SEVERE ERROR** Couldn't tokenize PLOT in line " << iter1->fLineNo;
          cout << endl << endl;
          return false;
        }
        if (tokens->GetEntries() != 2) {
          error = true;
        } else {
          ostr = dynamic_cast<TObjString*>(tokens->At(1));
          str = ostr->GetString();
          if (str.IsDigit()) {
            int val = str.Atoi();
            if (val > 0)
              param.fViewPacking = val;
            else
              error = true;
          } else {
            error = true;
          }
        }

        // clean up
        if (tokens) {
          delete tokens;
          tokens = 0;
        }
      } else {
        error = true;
      }

      ++iter1;

    }

    // analyze if the plot block is valid
    double keep;
    if (!error) {
      if (param.fRuns.empty()) { // there was no run tag
        error = true;
      } else { // everything ok
        if ((param.fTmin.size() > 0) || (param.fTmax.size() > 0)) { // if range is given, check that it is ordered properly
          for (unsigned int i=0; i<param.fTmin.size(); i++) {
            if (param.fTmin[i] > param.fTmax[i]) {
              keep = param.fTmin[i];
              param.fTmin[i] = param.fTmax[i];
              param.fTmax[i] = keep;
            }
          }
        }

        if ((param.fYmin.size() > 0) || (param.fYmax.size() > 0)) { // if range is given, check that it is ordered properly
          for (unsigned int i=0; i<param.fYmin.size(); i++) {
            if (param.fYmin[i] > param.fYmax[i]) {
              keep = param.fYmin[i];
              param.fYmin[i] = param.fYmax[i];
              param.fYmax[i] = keep;
            }
          }
        }
        fPlots.push_back(param);
      }
    }

    if (error) { // print error message
      --iter1;
      cout << endl << ">> PMsrHandler::HandlePlotEntry: **ERROR** in line " << iter1->fLineNo << ": " << iter1->fLine.Data();
      cout << endl << "A PLOT block needs to have the following structure:";
      cout << endl;
      cout << endl << "PLOT <plot_type>";
      cout << endl << "runs <run_list>";
      cout << endl << "[range tmin tmax [ymin ymax]]";
      cout << endl << "[sub_ranges tmin1 tmax1 tmin2 tmax2 ... tminN tmaxN [ymin ymax]";
      cout << endl << "[logx | logy]";
      cout << endl << "[use_fit_ranges]";
      cout << endl << "[view_packing n]";
      cout << endl;
      cout << endl << "where <plot_type> is: 0=single histo asym,";
      cout << endl << "                      2=forward-backward asym,"; 
      cout << endl << "                      4=RRF asym (not implemented yet),";
      cout << endl << "                      8=non muSR.";
      cout << endl << "<run_list> is the list of runs";
      cout << endl << "   for <plot_type> 0,2,8 it is a list of run numbers, e.g. runs 1 3";
      cout << endl << "   for <plot_type> 4     it is a list of 'complex' numbers, where";
      cout << endl << "                         the real part is the run number, and the";
      cout << endl << "                         imaginary one is 1=real part or 2=imag part, e.g.";
      cout << endl << "                         runs 1,1 1,2";
      cout << endl << "range is optional";
      cout << endl << "sub_ranges (if present) will plot the N given runs each on its own sub-range";
      cout << endl << "logx, logy (if present) will present the x-, y-axis in log-scale";
      cout << endl << "use_fit_ranges (if present) will plot each run on its fit-range";
      cout << endl << "view_packing n (if present) will bin all data by n (> 0) rather than the binning of the fit";
      cout << endl;
    }

    param.fRuns.clear();

  }

  return !error;
}

//--------------------------------------------------------------------------
// HandleStatisticEntry (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param lines is a list of lines containing the fitparameter block
 */
bool PMsrHandler::HandleStatisticEntry(PMsrLines &lines)
{
  if (lines.empty()) {
    cout << endl << ">> PMsrHandler::HandleStatisticEntry: **WARNING** There is no STATISTIC block! Do you really want this?";
    cout << endl;
    fStatistic.fValid = false;
    return true;
  }

  // check if chisq or max.log likelihood
  fStatistic.fChisq = true;
  for (unsigned int i=0; i<fCommands.size(); i++) {
    if (fCommands[i].fLine.Contains("MAX_LIKELIHOOD"))
      fStatistic.fChisq = false; // max.log likelihood
  }

  char str[128];
  char date[128];
  char time[128];
  int  status;
  double dval;
  unsigned int ival;
  TString tstr;
  for (unsigned int i=0; i<lines.size(); i++) {
    // check if the statistic block line is illegal
    tstr = lines[i].fLine;
    tstr.Remove(TString::kLeading, ' ');
    if (tstr.Length() > 0) {
      if (!tstr.BeginsWith("#") && !tstr.BeginsWith("STATISTIC") && !tstr.BeginsWith("chisq") &&
          !tstr.BeginsWith("maxLH") && !tstr.BeginsWith("*** FIT DID NOT CONVERGE ***")) {
        cout << endl << ">> PMsrHandler::HandleStatisticEntry: **SYNTAX ERROR** in line " << lines[i].fLineNo;
        cout << endl << ">> '" << lines[i].fLine.Data() << "'";
        cout << endl << ">> not a valid STATISTIC block line";
        cout << endl << ">> If you do not understand this, just remove the STATISTIC block, musrfit will recreate after fitting";
        cout << endl << endl;
        return false;
      }
    }

    // filter date and chisq etc from strings
    // extract date and time
    if (lines[i].fLine.Contains("STATISTIC")) {
      status = sscanf(lines[i].fLine.Data(), "STATISTIC --- %s%s", date, time);
      if (status == 2) {
        fStatistic.fDate = TString(date)+TString(", ")+TString(time);
      } else {
        fStatistic.fDate = TString("????-??-??, ??:??:??");
      }
    }
    // extract chisq
    if (lines[i].fLine.Contains("chisq =")) {
      fStatistic.fValid = true;
      strncpy(str, lines[i].fLine.Data(), sizeof(str));
      status = sscanf(str+lines[i].fLine.Index("chisq = ")+8, "%lf", &dval);
      if (status == 1) {
        fStatistic.fMin = dval;
      } else {
        fStatistic.fMin = -1.0;
      }
    }
    // extract maxLH
    if (lines[i].fLine.Contains("maxLH =")) {
      fStatistic.fValid = true;
      strncpy(str, lines[i].fLine.Data(), sizeof(str));
      status = sscanf(str+lines[i].fLine.Index("maxLH = ")+8, "%lf", &dval);
      if (status == 1) {
        fStatistic.fMin = dval;
      } else {
        fStatistic.fMin = -1.0;
      }
    }
    // extract NDF
    if (lines[i].fLine.Contains(", NDF =")) {
      strncpy(str, lines[i].fLine.Data(), sizeof(str));
      status = sscanf(str+lines[i].fLine.Index(", NDF = ")+8, "%u", &ival);
      if (status == 1) {
        fStatistic.fNdf = ival;
      } else {
        fStatistic.fNdf = 0;
      }
    }
    // keep string
    fStatistic.fStatLines.push_back(lines[i]);
  }

// cout << endl << "Statistic:";
// cout << endl << " Date & Time: " << fStatistic.fDate.Data();
// if (fStatistic.fChisq) { // chisq
//   cout << endl << " chisq = " << fStatistic.fMin;
//   cout << endl << " NDF   = " << fStatistic.fNdf;
// } else { // maximum likelihood
//   cout << endl << " maxLH = " << fStatistic.fMin;
//   cout << endl << " NDF   = " << fStatistic.fNdf;
// }

  return true;
}

//--------------------------------------------------------------------------
// FillParameterInUse (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param theory
 * \param funcs
 * \param run
 */
void PMsrHandler::FillParameterInUse(PMsrLines &theory, PMsrLines &funcs, PMsrLines &run)
{
  PIntVector map;
  PIntVector fun;
  PMsrLines::iterator iter;
  TObjArray  *tokens = 0;
  TObjString *ostr = 0;
  TString    str;
  int        ival, funNo;

  // create and initialize fParamInUse vector
  for (unsigned int i=0; i<fParam.size(); i++)
    fParamInUse.push_back(0);

  // go through all the theory lines ------------------------------------
//cout << endl << ">> theory block check ...";
  for (iter = theory.begin(); iter != theory.end(); ++iter) {
    // remove potential comments
    str = iter->fLine;
    if (str.First('#') != -1)
      str.Resize(str.First('#'));

    // everything to lower case
    str.ToLower();

    // tokenize string
    tokens = str.Tokenize(" \t");
    if (!tokens)
      continue;

    // filter param no, map no, and fun no
    for (int i=0; i<tokens->GetEntries(); i++) {
      ostr = dynamic_cast<TObjString*>(tokens->At(i));
      str = ostr->GetString();
      if (str.IsDigit()) { // parameter number
        ival = str.Atoi();
        if ((ival > 0) && (ival < (int)fParam.size()+1)) {
          fParamInUse[ival-1]++;
//cout << endl << ">>>> theo: param no : " << ival;
        }
      } else if (str.Contains("map")) { // map
        if (FilterNumber(str, "map", MSR_PARAM_MAP_OFFSET, ival))
          map.push_back(ival-MSR_PARAM_MAP_OFFSET);
      } else if (str.Contains("fun")) { // fun
//cout << endl << "theo:fun: " << str.Data();
        if (FilterNumber(str, "fun", MSR_PARAM_FUN_OFFSET, ival))
          fun.push_back(ival-MSR_PARAM_FUN_OFFSET);
      }
    }

    // delete tokens
    if (tokens) {
      delete tokens;
      tokens = 0;
    }
  }

  // go through all the function lines: 1st time -----------------------------
//cout << endl << ">> function block check (1st time) ...";
  for (iter = funcs.begin(); iter != funcs.end(); ++iter) {
    // remove potential comments
    str = iter->fLine;
    if (str.First('#') != -1)
      str.Resize(str.First('#'));

    // everything to lower case
    str.ToLower();

// cout << endl << "-----------------------";
// cout << endl << ">> " << str.Data();

    tokens = str.Tokenize(" /t");
    if (!tokens)
      continue;

    // filter fun number
    ostr = dynamic_cast<TObjString*>(tokens->At(0));
    str = ostr->GetString();
    if (!FilterNumber(str, "fun", MSR_PARAM_FUN_OFFSET, funNo))
      continue;
    funNo -= MSR_PARAM_FUN_OFFSET;

    // check if fun number is used, and if yes, filter parameter numbers and maps
    TString sstr;
//cout << endl << ">> fun.size() = " << fun.size();
    for (unsigned int i=0; i<fun.size(); i++) {
//cout << endl << ">> funNo: " << fun[i] << ", funNo: " << funNo;
      if (fun[i] == funNo) { // function number found
        // filter for parX
        sstr = iter->fLine;
        char sval[128];
        while (sstr.Index("par") != -1) {
          memset(sval, 0, sizeof(sval));
          sstr = &sstr[sstr.Index("par")+3]; // trunc sstr
//cout << endl << ">> par:sstr: " << sstr.Data();
          for (int j=0; j<sstr.Sizeof(); j++) {
            if (!isdigit(sstr[j]))
              break;
            sval[j] = sstr[j];
          }
          sscanf(sval, "%d", &ival);
//cout << endl << ">>>> parX from func 1st, X = " << ival;
          fParamInUse[ival-1]++;
        }

        // filter for mapX
        sstr = iter->fLine;
        while (sstr.Index("map") != -1) {
          memset(sval, 0, sizeof(sval));
          sstr = &sstr[sstr.Index("map")+3]; // trunc sstr
//cout << endl << ">> map:sstr: " << sstr.Data();
          for (int j=0; j<sstr.Sizeof(); j++) {
            if (!isdigit(sstr[j]))
              break;
            sval[j] = sstr[j];
          }
          sscanf(sval, "%d", &ival);
//cout << endl << ">>>> mapX from func 1st, X = " << ival;
          // check if map value already in map, otherwise add it
          if (ival > 0) {
            unsigned int pos;
            for (pos=0; pos<map.size(); pos++) {
              if (ival == map[pos])
                break;
            }
            if (pos == map.size()) { // new map value
              map.push_back(ival);
            }
          }
        }
        break; // since function was found, break the loop
      }
    }

    // delete tokens
    if (tokens) {
      delete tokens;
      tokens = 0;
    }
  }

  // go through all the run block lines -------------------------------------
//cout << endl << ">> run block check (1st time) ...";
  for (iter = run.begin(); iter != run.end(); ++iter) {
    // remove potential comments
    str = iter->fLine;
    if (str.First('#') != -1)
      str.Resize(str.First('#'));

    // everything to lower case
    str.ToLower();

    // handle everything but the maps
    if (str.Contains("alpha") || str.Contains("beta") ||
        str.Contains("alpha2") || str.Contains("beta2") ||
        str.Contains("norm") || str.Contains("backgr.fit") ||
        str.Contains("rphase") || str.Contains("lifetime ")) {
      // tokenize string
      tokens = str.Tokenize(" \t");
      if (!tokens)
        continue;
      if (tokens->GetEntries()<2)
        continue;

      ostr = dynamic_cast<TObjString*>(tokens->At(1)); // parameter number or function
      str = ostr->GetString();
      // check if parameter number
      if (str.IsDigit()) {
        ival = str.Atoi();
        fParamInUse[ival-1]++;
//cout << endl << ">>>> run : parameter no : " << ival;
      }
      // check if fun
      if (str.Contains("fun")) {
        if (FilterNumber(str, "fun", MSR_PARAM_FUN_OFFSET, ival)) {
          fun.push_back(ival-MSR_PARAM_FUN_OFFSET);
//cout << endl << ">>>> run : fun no : " << ival-MSR_PARAM_FUN_OFFSET;
        }
      }

      // delete tokens
      if (tokens) {
        delete tokens;
        tokens = 0;
      }
    }

    // handle the maps
    if (str.Contains("map")) {
//cout << endl << ">> " << str.Data();
      // tokenize string
      tokens = str.Tokenize(" \t");
      if (!tokens)
        continue;

      // get the parameter number via map
//cout << endl << ">> map.size() = " << map.size();
      for (unsigned int i=0; i<map.size(); i++) {
        if (map[i] == 0)
          continue;
        if (map[i] < tokens->GetEntries()) {
          ostr = dynamic_cast<TObjString*>(tokens->At(map[i]));
          str = ostr->GetString();
          if (str.IsDigit()) {
            ival = str.Atoi();
            if (ival > 0) {
              fParamInUse[ival-1]++; // this is OK since map is ranging from 1 ..
//cout << endl << ">>>> param no : " << ival << ", via map no : " << map[i];
            }
          }
        }
      }

      // delete tokens
      if (tokens) {
        delete tokens;
        tokens = 0;
      }
    }
  }

  // go through all the function lines: 2nd time -----------------------------
//cout << endl << ">> function block check (2nd time) ...";
  for (iter = funcs.begin(); iter != funcs.end(); ++iter) {
    // remove potential comments
    str = iter->fLine;
    if (str.First('#') != -1)
      str.Resize(str.First('#'));

    // everything to lower case
    str.ToLower();

// cout << endl << "===========================";
// cout << endl << ">> " << str.Data();

    tokens = str.Tokenize(" /t");
    if (!tokens)
      continue;

    // filter fun number
    ostr = dynamic_cast<TObjString*>(tokens->At(0));
    str = ostr->GetString();
    if (!FilterNumber(str, "fun", MSR_PARAM_FUN_OFFSET, funNo))
      continue;
    funNo -= MSR_PARAM_FUN_OFFSET;

    // check if fun number is used, and if yes, filter parameter numbers and maps
    TString sstr;
    for (unsigned int i=0; i<fun.size(); i++) {
//cout << endl << ">> funNo: " << fun[i] << ", funNo: " << funNo;
      if (fun[i] == funNo) { // function number found
        // filter for parX
        sstr = iter->fLine;
        char sval[128];
        while (sstr.Index("par") != -1) {
          memset(sval, 0, sizeof(sval));
          sstr = &sstr[sstr.Index("par")+3]; // trunc sstr
          for (int j=0; j<sstr.Sizeof(); j++) {
            if (!isdigit(sstr[j]))
              break;
            sval[j] = sstr[j];
          }
          sscanf(sval, "%d", &ival);
          fParamInUse[ival-1]++;
//cout << endl << ">>>> parX from func 2nd, X = " << ival;
        }

        // filter for mapX
        sstr = iter->fLine;
        while (sstr.Index("map") != -1) {
          memset(sval, 0, sizeof(sval));
          sstr = &sstr[sstr.Index("map")+3]; // trunc sstr
          for (int j=0; j<sstr.Sizeof(); j++) {
            if (!isdigit(sstr[j]))
              break;
            sval[j] = sstr[j];
          }
          sscanf(sval, "%d", &ival);
//cout << endl << ">>>> mapX from func 2nd, X = " << ival;
          // check if map value already in map, otherwise add it
          if (ival > 0) {
            unsigned int pos;
            for (pos=0; pos<map.size(); pos++) {
              if (ival == map[pos])
                break;
            }
            if ((unsigned int)pos == map.size()) { // new map value
              map.push_back(ival);
            }
          }
        }
      }
    }

    // delete tokens
    if (tokens) {
      delete tokens;
      tokens = 0;
    }
  }

  // go through all the run block lines 2nd time to filter remaining maps
//cout << endl << ">> run block check (2nd time) ...";
  for (iter = run.begin(); iter != run.end(); ++iter) {
    // remove potential comments
    str = iter->fLine;
    if (str.First('#') != -1)
      str.Resize(str.First('#'));

    // everything to lower case
    str.ToLower();

    // handle the maps
    if (str.Contains("map")) {
//cout << endl << ">> " << str.Data();
      // tokenize string
      tokens = str.Tokenize(" \t");
      if (!tokens)
        continue;

      // get the parameter number via map
//cout << endl << ">> map.size() = " << map.size();
      for (unsigned int i=0; i<map.size(); i++) {
        if (map[i] == 0)
          continue;
        if (map[i] < tokens->GetEntries()) {
          ostr = dynamic_cast<TObjString*>(tokens->At(map[i]));
          str = ostr->GetString();
          if (str.IsDigit()) {
            ival = str.Atoi();
            if (ival > 0) {
              fParamInUse[ival-1]++; // this is OK since map is ranging from 1 ..
//cout << endl << ">>>> param no : " << ival << ", via map no : " << map[i];
            }
          }
        }
      }

      // delete tokens
      if (tokens) {
        delete tokens;
        tokens = 0;
      }
    }
  }

// cout << endl << ">> fParamInUse: ";
// for (unsigned int i=0; i<fParamInUse.size(); i++)
//   cout << endl << i+1 << ", " << fParamInUse[i];
// cout << endl;

  // if unused parameters are present, set the step value to 0.0
  for (unsigned int i=0; i<fParam.size(); i++) {
    if (!ParameterInUse(i)) {
      if (fParam[i].fStep != 0.0) {
        cout << endl << "**WARNING** : Parameter No " << i+1 << " is not used at all, will fix it" << endl;
        fParam[i].fStep = 0.0;
      }
    }
  }

  // clean up
  map.clear();
  fun.clear();
}

//--------------------------------------------------------------------------
// CheckUniquenessOfParamNames (private)
//--------------------------------------------------------------------------
/**
 * <p>
 *
 * \param parX
 * \param parY
 */
bool PMsrHandler::CheckUniquenessOfParamNames(unsigned int &parX, unsigned int &parY)
{
  bool unique = true;

  for (unsigned int i=0; i<fParam.size()-1; i++) {
    for (unsigned int j=i+1; j<fParam.size(); j++) {
      if (fParam[i].fName.CompareTo(fParam[j].fName) == 0) { // equal
        unique = false;
        parX = i;
        parY = j;
        break;
      }
    }
  }

  return unique;
}

//--------------------------------------------------------------------------
// CheckMaps (private)
//--------------------------------------------------------------------------
/**
 * <p>Checks if map entries found in the theory- or function-block are also
 * present in the run-block, if yes return true otherwise return false.
 */
bool PMsrHandler::CheckMaps()
{
  bool result = true;

  PIntVector mapVec;
  PIntVector mapBlock;
  PIntVector mapLineNo;

  TObjArray  *tokens = 0;
  TObjString *ostr = 0;
  TString    str;

  int no;

  // check if map is present in the theory-block
  for (unsigned int i=0; i<fTheory.size(); i++) {
    if (fTheory[i].fLine.Contains("map", TString::kIgnoreCase)) {
      // map found hence filter out map number
      tokens = fTheory[i].fLine.Tokenize(" \t");
      for (int j=0; j<tokens->GetEntries(); j++) {
        ostr = dynamic_cast<TObjString*>(tokens->At(j));
        str = ostr->GetString();
        if (str.Contains("map", TString::kIgnoreCase)) {
          if (FilterNumber(str, "map", MSR_PARAM_MAP_OFFSET, no)) {
            mapVec.push_back(no);
            mapBlock.push_back(0); // 0 = theory-block
            mapLineNo.push_back(fTheory[i].fLineNo);
          }
        }
      }
      // clean up tokens
      if (tokens) {
        delete tokens;
        tokens = 0;
      }
    }
  }

  // check if map is present in the function-block
  for (unsigned int i=0; i<fFunctions.size(); i++) {
    if (fFunctions[i].fLine.Contains("map", TString::kIgnoreCase)) {
      // map found hence filter out map number
      tokens = fFunctions[i].fLine.Tokenize(" \t");
      for (int j=0; j<tokens->GetEntries(); j++) {
        ostr = dynamic_cast<TObjString*>(tokens->At(j));
        str = ostr->GetString();
        if (str.Contains("map", TString::kIgnoreCase)) {
          if (FilterNumber(str, "map", MSR_PARAM_MAP_OFFSET, no)) {
            mapVec.push_back(no);
            mapBlock.push_back(1); // 1 = theory-block
            mapLineNo.push_back(fTheory[i].fLineNo);
          }
        }
      }
      // clean up tokens
      if (tokens) {
        delete tokens;
        tokens = 0;
      }
    }
  }

  // check if present maps are found in the run-block
  bool found;
  for (unsigned int i=0; i<mapVec.size(); i++) { // loop over found maps in theory- and function-block
    found = false;
    for (unsigned int j=0; j<fRuns.size(); j++) { // loop over all run-blocks
      if ((mapVec[i]-MSR_PARAM_MAP_OFFSET-1 < (int)fRuns[j].fMap.size()) &&
          (mapVec[i]-MSR_PARAM_MAP_OFFSET-1 >= 0)) { // map value smaller than run-block map length
        if (fRuns[j].fMap[mapVec[i]-MSR_PARAM_MAP_OFFSET-1] != 0) { // map value in the run-block != 0
          found = true;
          break;
        }
      }
    }
    if (!found) { // map not found
      result = false;
      cout << endl << ">> PMsrHandler::CheckMaps: **ERROR** map" << mapVec[i]-MSR_PARAM_MAP_OFFSET << " found in the ";
      if (mapBlock[i] == 0)
        cout << "theory-block ";
      else
        cout << "functions-block ";
      cout << "in line " << mapLineNo[i] << " is not present in the run-block!";
      if (mapVec[i]-MSR_PARAM_MAP_OFFSET == 0) {
        cout << endl << ">> by the way: map must be > 0 ...";
      }
    }
  }

  // clean up
  mapVec.clear();
  mapBlock.clear();
  mapLineNo.clear();

  return result;
}

//--------------------------------------------------------------------------
// CheckFuncs (private)
//--------------------------------------------------------------------------
/**
 * <p>Checks if fun entries found in the theory- and run-block are also
 * present in the functions-block, if yes return true otherwise return false.
 */
bool PMsrHandler::CheckFuncs()
{
  bool result = true;

  PIntVector funVec;
  PIntVector funBlock;
  PIntVector funLineBlockNo;

  TObjArray  *tokens = 0;
  TObjString *ostr = 0;
  TString    str;

  int no;

  // check if func is present in the theory-block
  for (unsigned int i=0; i<fTheory.size(); i++) {
    if (fTheory[i].fLine.Contains("fun", TString::kIgnoreCase)) {
      // func found hence filter out func number
      tokens = fTheory[i].fLine.Tokenize(" \t");
      for (int j=0; j<tokens->GetEntries(); j++) {
        ostr = dynamic_cast<TObjString*>(tokens->At(j));
        str = ostr->GetString();
        if (str.Contains("fun", TString::kIgnoreCase)) {
          if (FilterNumber(str, "fun", MSR_PARAM_FUN_OFFSET, no)) {
            funVec.push_back(no);
            funBlock.push_back(0); // 0 = theory-block
            funLineBlockNo.push_back(fTheory[i].fLineNo);
          }
        }
      }
      // clean up tokens
      if (tokens) {
        delete tokens;
        tokens = 0;
      }
    }
  }

  // check if func is present in the run-block
  for (unsigned int i=0; i<fRuns.size(); i++) {
    if (fRuns[i].fNormParamNo >= MSR_PARAM_FUN_OFFSET) { // function found
      funVec.push_back(fRuns[i].fNormParamNo);
      funBlock.push_back(1); // 1 = run-block
      funLineBlockNo.push_back(i+1);
    }
  }

  // check if present funcs are found in the functions-block
  bool found;
  for (unsigned int i=0; i<funVec.size(); i++) { // loop over found funcs in theory- and run-block
    found = false;
    // check if function is present in the functions-block
    for (unsigned int j=0; j<fFunctions.size(); j++) {
      if (fFunctions[j].fLine.BeginsWith("#") || fFunctions[j].fLine.IsWhitespace())
        continue;
      str = TString("fun");
      str += funVec[i] - MSR_PARAM_FUN_OFFSET;
      if (fFunctions[j].fLine.Contains(str, TString::kIgnoreCase)) {
        found = true;
        break;
      }
    }
    if (!found) { // func not found
      result = false;
      cout << endl << ">> PMsrHandler::CheckFuncs: **ERROR** fun" << funVec[i]-MSR_PARAM_FUN_OFFSET << " found in the ";
      if (funBlock[i] == 0)
        cout << "theory-block in line " << funLineBlockNo[i] << " is not present in the functions-block!";
      else
        cout << "run-block No " << funLineBlockNo[i] << " (norm) is not present in the functions-block!";
    }
  }

  // clean up
  funVec.clear();
  funBlock.clear();
  funLineBlockNo.clear();

  return result;
}

// end ---------------------------------------------------------------------
