Index: trunk/Mars/mfileio/FileIOLinkDef.h
===================================================================
--- trunk/Mars/mfileio/FileIOLinkDef.h	(revision 14447)
+++ trunk/Mars/mfileio/FileIOLinkDef.h	(revision 14792)
@@ -18,4 +18,5 @@
 #pragma link C++ class MWriteAsciiFile+;
 #pragma link C++ class MWriteRootFile+;
+#pragma link C++ class MWriteFitsFile+;
 
 #endif
Index: trunk/Mars/mfileio/MFitsArray.cc
===================================================================
--- trunk/Mars/mfileio/MFitsArray.cc	(revision 14792)
+++ trunk/Mars/mfileio/MFitsArray.cc	(revision 14792)
@@ -0,0 +1,195 @@
+#include "MAGIC.h"
+#include "MLogManip.h"
+
+#include "MFitsArray.h"
+
+#include <TDataMember.h>
+#include <TClonesArray.h>
+#include <TClass.h>
+#include <TList.h>
+
+using namespace std;
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// Opens the FITS table of this TClonesArray. This should be done after all    
+// columns are initialized. baseFileName is the name of the group, this        
+// children table belongs to. dataName is the name of the TClonesArray         
+// variable in the MParContainer - class.                                      
+//                                                                             
+Bool_t MArrayHelperBase::OpenFitsTable(const char * baseFileName, 
+                                         const char * dataName, 
+                                         const char * option, MLog * log )
+{
+   // get the baseFileName without extension                     
+   char fileNameNoExt[strlen(baseFileName) + 1];
+   strcpy(fileNameNoExt, baseFileName);
+   // remove the extension                                       
+   char * pos = strrchr(fileNameNoExt, '.');
+   if (pos) *pos = 0;
+
+   // add the dataName to the file name define the table name:   
+   // result will be something like:                             
+   // baseFileName_dataName.fits[dataName]                       
+   TString dol = fileNameNoExt;
+   TString fileName;
+   dol += "_";
+   dol += dataName;
+   dol += ".fits";
+   fileName = dol;
+//   dol += "[";
+//   dol += dataName;
+//   dol += "]";
+
+//   try {
+
+      if (strcmp(option, "RECREATE") == 0)
+         // remove the file
+         unlink(fileName.Data());
+
+      // create the file with the FITS table and all its columns    
+      //FIXME I must implement a constructor and set fFitsTable to NULL
+      //Otherwise I cannot safely destroy the object (in the destructor, also to be implemented)
+      fFitsTable = new ofits();
+      fFitsTable->open(dol.Data());
+
+//      }
+//   catch (exception & e)
+//      {
+//      *log << err << e.what() << endl;
+//      return kFALSE;
+ //     }
+   return kTRUE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// Determines the size of the buffer to store all data of the clonesArray -    
+// Class, which should be written to a FITS table. The buffer is allocated.    
+//                                                                             
+// status is set to kFALSE if some data cannot be stored in a FITS table,      
+// for example more than 1 dimensional arrays.                                 
+MClonesArrayHelper::MClonesArrayHelper(TClonesArray * clonesArray, MLog * log, 
+                                       Bool_t & status)
+  :  fClonesArray(clonesArray) 
+{
+   status = kTRUE;
+
+   // get size of buffer
+   fDataBufferSize = 0;
+   fStartOfData    = 0x7fffffff;
+
+   TList * dataMembers = fClonesArray->GetClass()->GetListOfDataMembers();
+   TIter next(dataMembers);
+   TDataMember * dataMember;
+
+   while ((dataMember = (TDataMember*)next()) != NULL)
+      {
+      if (!dataMember->IsPersistent())
+         continue;
+
+      if (dataMember->Property() & ( G__BIT_ISENUM | G__BIT_ISSTATIC))
+         continue;
+
+      if (strcmp(dataMember->GetTrueTypeName(), "TClass*") == 0)
+         continue;
+
+      // is it an array of more than 1 dimension?
+      if (dataMember->GetArrayDim() > 1)
+         {
+         *log << err << "Two and more dimensional arrays of member variables"
+                         " are not supported." << endl;
+         *log <<        "See variable " << dataMember->GetName() << 
+                         " in container " << fClonesArray->GetClass()->GetName() <<  endl;
+         status = kFALSE;
+         return;
+         }
+
+
+      // get the position, where the current variable ends.
+      Int_t endPos;
+      if (dataMember->GetArrayDim() == 1)
+         endPos = dataMember->GetOffset() + (dataMember->GetUnitSize() * 
+                                             dataMember->GetMaxIndex(0)  );
+      else
+         endPos = dataMember->GetOffset() + dataMember->GetUnitSize();
+
+      if (endPos > fDataBufferSize)
+         fDataBufferSize = endPos;
+
+      if (dataMember->GetOffset() < fStartOfData)
+         fStartOfData = dataMember->GetOffset();
+      }      
+
+   fDataBuffer = new Byte_t[fDataBufferSize];
+
+}
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// the fClonesArray, the size of the data buffer and the fits Table are        
+// copied. A new buffer is allocated. Note: the fArraySize is not copied.      
+// Anyhow only its pointer is needed, which will change during this copy       
+//                                                                             
+MClonesArrayHelper::MClonesArrayHelper(const MClonesArrayHelper & clHelper)
+   : fClonesArray(clHelper.fClonesArray)
+{
+   fFitsTable       = clHelper.fFitsTable;
+   fDataBufferSize  = clHelper.fDataBufferSize;
+   fStartOfData     = clHelper.fStartOfData;
+   fDataBuffer      = new Byte_t[fDataBufferSize];
+}
+
+
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// Writes all currently stored classes in the fClonesArray, i. e. writes 0 to  
+// may rows to the FITS table.                                                 
+// fArraySize is updated with the number of new row, written to the FITS       
+// table. Therefore the parent FITS table must be updated after calling this   
+// method.                                                                     
+//                                                                             
+void MClonesArrayHelper::Write()
+{
+   // get number of classes in fClonesArray.                                 
+   fArraySize = fClonesArray->GetLast() + 1;
+
+   for (int idx = 0; idx < fArraySize; idx++)
+      {
+      // copy the data of one class to fDataBuffer                           
+      memcpy(fDataBuffer, (*fClonesArray)[idx], fDataBufferSize);
+
+      // now the data can be written from the fDataBuffer to the FITS table  
+      fFitsTable->WriteRow(fDataBuffer, fDataBufferSize);
+      }
+}
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// resize the clone array (fClonesArray) and reads fArraySize data sets from   
+// the FITS file into the fClonesArray.                                        
+// The number of data sets must be determined before calling this function,    
+// i.e. the parent FITS table must be read before calling this method.         
+Int_t MClonesArrayHelper::Read()
+{
+ /*  fClonesArray->ExpandCreate(fArraySize);
+
+   for (int idx = 0; idx < fArraySize; idx++)
+      {
+      // read the data in the buffer
+      if (!fFitsTable.Read())
+         {
+         gLog << "Expecting more entries in " << fFitsTable.GetFileName() << endl;
+         return kERROR;
+         }
+      // copy the data of one class from fDataBuffer into the class
+      memcpy( (Byte_t*)((*fClonesArray)[idx]) + fStartOfData, 
+              fDataBuffer + fStartOfData, fDataBufferSize - fStartOfData);
+      }
+*/
+   return kTRUE;
+}
Index: trunk/Mars/mfileio/MFitsArray.h
===================================================================
--- trunk/Mars/mfileio/MFitsArray.h	(revision 14792)
+++ trunk/Mars/mfileio/MFitsArray.h	(revision 14792)
@@ -0,0 +1,114 @@
+#ifndef MARS_MFitsArray
+#define MARS_MFitsArray
+
+//#include "astroroot.h"
+//#include "fitsio.h"
+#include "../mcore/fits.h"
+#include "../mcore/ofits.h"
+
+class TClonesArray;
+class MLog;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// A base class for arrays, which has to be written into their own FITS table  
+class MArrayHelperBase
+{
+protected:
+
+   // the FITS table to which the data are written                      
+   std::ofits*     fFitsTable;
+   
+   // number of elements in fClonesArray / MArrayX / TArrayX  during 
+   // one write operation. This number is written into a column of   
+   // the parent FITS table.                                         
+   UInt_t           fArraySize;
+
+public:
+   std::ofits* GetFitsTable()     {return fFitsTable;}
+   UInt_t *      GetArraySizePtr()  {return &fArraySize;}
+
+   Bool_t  OpenFitsTable(const char * baseFileName, const char * dataName, 
+                         const char * option, MLog * log);
+
+   virtual void  InitCol() {}
+
+   virtual Int_t Read() = 0;
+   virtual void  Write() = 0;
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// A class to write data of one TClonesArray into one FITS table.              
+class MClonesArrayHelper : public MArrayHelperBase
+{
+   // data of this TClonesArray are written to fFitsTable               
+   TClonesArray *  fClonesArray;  
+
+
+
+   // fFitsTable writes during one fFitsTable.Write() call data which   
+   // are currently stored in this buffer. That means the data pointers 
+   // of fFitsTable for each column point to this data buffer.          
+   Byte_t *        fDataBuffer;
+
+   // the size of fDataBufferer.                                        
+   Int_t           fDataBufferSize;
+
+   // the first used byte in fDataBuffer                                
+   Int_t           fStartOfData;
+
+public:
+   MClonesArrayHelper(TClonesArray * clonesArray, MLog * log, Bool_t & status);
+   MClonesArrayHelper(const MClonesArrayHelper & clHelper);
+
+   ~MClonesArrayHelper()   {delete [] fDataBuffer;}
+
+   void  *       GetDataBuffer()    {return fDataBuffer;}
+
+   Int_t   Read();
+   void    Write();
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes to write and read data of MArray* classes                           
+template<class BaseT, class ClassT>
+   class MArrayHelper : public MArrayHelperBase
+{
+   ClassT   *  fArrayClass;
+
+   BaseT       fDataBuffer;
+   char        fDataType[10];
+
+public:
+   MArrayHelper(ClassT * arrayClass, const char * dataType)
+      {fArrayClass = arrayClass;
+       strcpy(fDataType, dataType);}
+
+   void    InitCol()
+   {
+       //FIXME ETIENNE HERE
+//       fFitsTable.InitCol("Data", fDataType, &fDataBuffer);
+//       fFitsTable->AddColumn(
+//       fFitsTables[tableName]->AddColumn(count, typeChar, truncatedName, unit, truncatedComment);
+
+   }
+
+   Int_t   Read() { return 0;}
+   void    Write()
+   {
+       fArraySize = fArrayClass->GetSize();
+       for (UInt_t idx = 0; idx < fArraySize; idx++)
+       {
+          fDataBuffer = (*fArrayClass)[idx];
+//FIXME ETIENNE HERE
+          //          fFitsTable.Write();
+       }
+   }
+
+
+};
+
+#endif
+
Index: trunk/Mars/mfileio/MTopFitsGroup.cc
===================================================================
--- trunk/Mars/mfileio/MTopFitsGroup.cc	(revision 14792)
+++ trunk/Mars/mfileio/MTopFitsGroup.cc	(revision 14792)
@@ -0,0 +1,26 @@
+
+#include "MTopFitsGroup.h"
+
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// Attaches the table to this FITS group                                       
+// Note: This FITS group as well as the table must be open, before calling     
+//       this method!                                                          
+void MTopFitsGroup::Attach(std::ofits* table)
+{
+//   fTopGroup.SetChild(table);
+//   fTopGroup.Write();
+}
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// Opens "table" with the next child in this group.                            
+// If table is an already open FITS table, then that table we be closed,       
+// before the new child is assigned to "table"                                 
+Bool_t MTopFitsGroup::GetNextChild(std::ofits* table)
+{
+//   fTopGroup.SetChild(table);
+//   return fTopGroup.Read();
+}
+
Index: trunk/Mars/mfileio/MTopFitsGroup.h
===================================================================
--- trunk/Mars/mfileio/MTopFitsGroup.h	(revision 14792)
+++ trunk/Mars/mfileio/MTopFitsGroup.h	(revision 14792)
@@ -0,0 +1,66 @@
+#ifndef MARS_MTopFitsGroup
+#define MARS_MTopFitsGroup
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "TString.h"
+
+//#include "astroroot.h"
+//#include "fitsio.h"
+#include "../mcore/fits.h"
+#include "../mcore/ofits.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// An unique id of files. It is sortable, i. e. can be uses as a key in maps   
+class MUniqueFileId
+{
+   dev_t       fst_dev;   // id of the device of this file                  
+   ino_t       fst_ino;   // inode number of the file on the device fst_dev 
+
+public:
+  MUniqueFileId(dev_t st_dev, ino_t st_ino)
+      : fst_dev(st_dev), fst_ino(st_ino) {}
+   
+   bool operator < (const MUniqueFileId & fileId) const
+      { if (fst_dev == fileId.fst_dev)
+           return fst_ino < fileId.fst_ino;
+        return fst_dev < fileId.fst_dev;   }
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// All information of one open Top Level FITS group                            
+class MTopFitsGroup
+{  
+   // filename of the group, but expanded by ROOT                         
+   // ( see gSystem->ExpandPathName() )                                   
+   TString     fFileName;  
+
+   // the top level group as AstroROOT-2 data structure                   
+   std::ofits*    fTopGroup;
+
+   // number of usage of this group by different MWriteFitsFile instances 
+   Int_t       fNumOpen;     
+
+public:
+   MTopFitsGroup(const char * fileName, std::ofits* file) : fFileName(fileName),
+                                          fTopGroup(file),
+                                          fNumOpen(1)
+   {}
+
+   void   IncreaseUsage()               {++fNumOpen;}
+   void   DecreaseUsage()               {--fNumOpen;}
+   Int_t  GetNumUsage()                 {return fNumOpen;}
+
+   void   Attach(std::ofits* table);
+   Bool_t GetNextChild(std::ofits* table);
+
+   std::ofits*  GetGroup()        {return fTopGroup;}
+   TString        &  GetFileName()     {return fFileName;}
+
+};
+
+#endif
+
Index: trunk/Mars/mfileio/MWriteFitsFile.cc
===================================================================
--- trunk/Mars/mfileio/MWriteFitsFile.cc	(revision 14792)
+++ trunk/Mars/mfileio/MWriteFitsFile.cc	(revision 14792)
@@ -0,0 +1,1137 @@
+#include <TDataMember.h>
+#include <TClonesArray.h>
+
+#include "MArrayS.h"
+#include "MArrayB.h"
+
+#include "MRead.h"
+#include "MParList.h"
+#include "MStatusDisplay.h"
+
+#include "MLog.h"
+#include "MLogManip.h"
+#include "MWriteRootFile.h"
+
+#include "MWriteFitsFile.h"
+#include "MFitsArray.h"
+
+//for find
+#include <algorithm>
+
+ClassImp(MWriteFitsFile);
+//ClassImp(MArrayHelper);
+//ClassImp(MTopFitsGroup);
+
+using namespace std;
+//ClassImp(std::ofits);
+
+
+map<MUniqueFileId, MTopFitsGroup> MWriteFitsFile::fTopFitsGroups;
+
+
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// if fileMode == kSingleFile                                                  
+//    Opens the top level group file, if it was not already opened by an other 
+//    instance of MWriteFitsFile.                                              
+// if fileMode == kMultiFiles                                                  
+//    fname defines the rules to build the output filenames from the current   
+//    input filename. The files are opened in the ReInit() method.             
+//                                                                             
+// opt = RECREATE : an existing file will be deleted                           
+//     = NEW      : an already existing file will not be deleted and the new   
+//                  file is not created. Check with IsFileOpen() if the new    
+//                  top level group could be opened.                           
+// name will be the name of the group                                          
+// title will be written as keyword TITLE into the header                      
+//                                                                             
+MWriteFitsFile::MWriteFitsFile(const char *fname,
+                               FILE_MODE fileMode,
+                               const Option_t *opt,
+                               const char *name,
+                               const char *title)
+{
+   fOpenOption = opt;
+   if (name && name[0] != 0)
+      fGroupName = name;
+   else
+      fGroupName = "MARS";
+
+   if (title)
+      fTitle = title;
+
+   iTopFitsGroup = fTopFitsGroups.end();
+
+   if (fileMode == kMultiFiles)
+      fRule = fname;
+   else
+       *fLog << err << "The new version of MWriteFitsFile does not support multiple tables in one file. Please use kMultiFiles instead" << endl;
+      //ETIENNE DEPREC
+      // iTopFitsGroup will be set by OpenTopLevelGroup, if a top level   
+      // group can be assigned to this MWriteFitsFile.                    
+      //OpenTopLevelGroup(fname);
+}
+
+MWriteFitsFile::MWriteFitsFile(const Int_t comp,
+                               const char* rule,
+                               const Option_t* option,
+                               const char* ftitle,
+                               const char* name,
+                               const char* title)
+{
+    fOpenOption = option;
+    if (name && name[0] != 0)
+        fGroupName = name;
+    else
+        fGroupName = "MARS";
+    if (title) fTitle = ftitle;
+    iTopFitsGroup = fTopFitsGroups.end();
+    //always kMultiFiles
+    fRule = rule;
+}
+// ----------------------------------------------------------------------------
+//                                                                             
+// Closes the top level group, it is is not used by an other instance of       
+// MWriteFitsFile.                                                             
+//                                                         std::map<TString, std::ofits*>
+MWriteFitsFile::~MWriteFitsFile()
+{
+    for (std::map<TString, std::ofits*>::iterator it=fFitsTables.begin(); it!= fFitsTables.end();it++)
+    {
+        if (it->second != NULL)
+        {
+            it->second->close();
+            delete it->second;
+        }
+    }
+//   CloseTopLevelGroup();
+   DeleteArrayHelper();
+}
+
+// ----------------------------------------------------------------------------
+//                                                                             
+// If the same file is already used by an other instance of MWriteFitsFile,    
+// the user counter is increasesd.                                             
+// Else: If the file exist and option is "RECREATE", the file is deleted and   
+//       recreated.                                                            
+// Finally the file with an empty group file is created.                       
+//                                                                             
+void MWriteFitsFile::OpenTopLevelGroup(const char * fname)
+{
+   // get rid of environment variables, ~, ... in filename
+   char * expandedFileName = gSystem->ExpandPathName(fname);
+
+   // get unique identifier of the new file
+   struct stat fileId;
+   if (stat(expandedFileName, &fileId) == 0)
+      {
+      // file exist already
+      iTopFitsGroup = fTopFitsGroups.find(MUniqueFileId(fileId.st_dev, fileId.st_ino));
+      if (iTopFitsGroup != fTopFitsGroups.end())
+         {
+          *fLog << err << "You are trying to use an already existing file. Please choose a different file name (" << fname << ")" << endl;
+          exit(0);
+         // this group is already open. we use it as well
+         *fLog << inf2 << "Found open file '" << GetFileName() << "'... re-using." << endl;
+         iTopFitsGroup->second.IncreaseUsage();
+         delete [] expandedFileName;
+         return;
+         } 
+
+      // file exist, but we cannot use
+      if (fOpenOption == "RECREATE") 
+         // remove the file
+         unlink(expandedFileName);
+
+      else if (fOpenOption == "NEW")
+         {
+         *fLog << err << "File '" << expandedFileName << "' exist already." << endl;
+         delete [] expandedFileName;
+         return;
+         }
+      else
+         {
+         *fLog << err << "Unsupported option (" << fOpenOption.Data() << ") to open file " <<
+                          expandedFileName << endl;
+         delete [] expandedFileName;
+         return;
+         }
+      }
+
+   // file does not yet exist or was deleted
+
+//   try {
+//      AstroRootGroup topGroup;
+//      char wrTitle[fTitle.Length() + 1];
+//      if (fTitle.Length() > 0)
+//         {
+//         strcpy(wrTitle, fTitle.Data());
+//         topGroup.InitAttr("TITLE", "A", wrTitle);
+//         }
+
+   //ETIENNE do not open top level group as using one file per table
+   //I kept this code active anyway, because it is checked elsewhere in the code that iTopFitsGroup is set.
+        ofits* topGroup = NULL;
+//      ofits* topGroup = new ofits();
+//      TString dol = expandedFileName;
+//      topGroup->open(dol.Data());
+
+
+      // store this new file in fTopFitsGroups and get the iterator to the  
+      // new group                                                          
+      stat(expandedFileName, &fileId);
+      iTopFitsGroup = fTopFitsGroups.insert(pair<MUniqueFileId, MTopFitsGroup>
+                           (MUniqueFileId(fileId.st_dev, fileId.st_ino),
+                           MTopFitsGroup(expandedFileName, topGroup)        )).first; 
+
+   delete [] expandedFileName;
+
+}
+
+// --------------------------------------------------------------------------
+//                                                                           
+// Reduces the use - counter of the top level group. Closes the group        
+// table, if the counter is 0, i.e. no other MWriteFitsFile instance uses    
+// the same top level group.                                                 
+//
+
+void MWriteFitsFile::CloseTopLevelGroup()
+{
+   if (iTopFitsGroup != fTopFitsGroups.end())
+      {
+      iTopFitsGroup->second.DecreaseUsage();
+      if (iTopFitsGroup->second.GetNumUsage() <= 0)
+         fTopFitsGroups.erase(iTopFitsGroup);
+
+      iTopFitsGroup = fTopFitsGroups.end();
+      }
+}
+
+// --------------------------------------------------------------------------
+//                                                                           
+// returns the name of the top level group file. It may be expanded if the   
+// name, given by the user, contained environment variables of the ~ sign.   
+// If no top level group is open, "no_open_file" is returned.                
+//                                                                           
+const char * MWriteFitsFile::GetFileName() const            
+{
+   if (IsFileOpen())
+      return iTopFitsGroup->second.GetFileName().Data();
+   else
+      return "no_open_file";
+}
+
+// --------------------------------------------------------------------------
+//                                                                           
+// Add a new Container to list of containers which should be written to the  
+// file. Give the name of the container which will identify the container    
+// in the parameterlist. tname is the name of the FITS table to which the    
+// container should be written (Remark: one table can hold more than one     
+// container). The default is the same name as the container name.           
+// If "mus"t is set to kTRUE (the default), then the container must exist    
+// in the parameterlist. The container will be ignored, if "must" is set to  
+// kFALSE and the container does not exist in the parameterlist.             
+//                                                                           
+void MWriteFitsFile::AddContainer(const char *cName,
+                                  const char *tName,
+                                  Bool_t must)
+{
+   if (cName == NULL || strlen(cName) == 0)
+      {
+      *fLog << warn << "Warning - container name in method MWriteFitsFile::"
+                       "AddContainer not defined... ignored" << endl;
+      return;
+      }
+
+   // if tName is not defined, we use cName as the table name  
+   TString tableName;
+   if (tName == NULL || strlen(tName) == 0)
+      tableName = cName;
+   else
+      tableName = tName;
+
+   // try to insert this container to the list of sub-tables. Write a     
+   // warning, if the same container name was already defined and ignore  
+   // this one.                                                           
+   if (fSubTables[tableName].insert( pair<TString, MFitsSubTable>
+                             (cName, MFitsSubTable(must))).second == false) 
+      {
+      *fLog << warn << "Warning - Container '"<< cName <<"' in table '" <<
+                       tableName.Data() << "' already scheduled... ignored." << endl;
+      }
+}
+
+// --------------------------------------------------------------------------
+//                                                                           
+// Add a new Container to list of containers which should be written to the  
+// file. tname is the name of the FITS table to which the                    
+// container should be written (Remark: one table can hold more than one     
+// container). The default is the same name as the container name.           
+// "must" is ignored. It is just for compatibility with MWriteRootFiles.     
+//                                                                           
+void MWriteFitsFile::AddContainer(MParContainer *cont, const char *tName, 
+                                  Bool_t must)
+{
+   if (cont == NULL)
+      {
+      *fLog << warn << "Warning - container in method MWriteFitsFile::"
+                       "AddContainer not defined... ignored" << endl;
+      return;
+      }
+
+   TString tableName;
+   if (tName == NULL || strlen(tName) == 0)
+      tableName = cont->IsA()->GetName();
+   else
+      tableName = tName;
+
+   TString cName = cont->IsA()->GetName();
+   if (fSubTables[tableName].insert( pair<TString, MFitsSubTable>
+                             (cName, MFitsSubTable(cont, must))).second == false) 
+      {
+      *fLog << warn << "Warning - Container '"<< cName.Data() <<
+                       "' in table '" << tableName.Data() << 
+                       "' already scheduled... ignored." << endl;
+      }
+}
+
+// --------------------------------------------------------------------------
+//
+// Tries to open the given output file.
+//
+Int_t MWriteFitsFile::PreProcess(MParList *pList)
+{
+   if (fRule.Length() != 0)
+      // the file is not yet open
+      return kTRUE;
+    //
+    // test whether file is now open or not
+    //
+    if (!IsFileOpen())
+    {
+        *fLog << err << dbginf << "Cannot open file '" << GetFileName() << "'" << endl;
+        return kFALSE;
+    }
+
+    *fLog << inf << "File '" << GetFileName() << "' open for writing." << endl;
+
+    //
+    // Get the containers (pointers) from the parameter list you want to write
+    //
+    if (!GetContainer(pList))
+        return kFALSE;
+
+    //
+    // write the container if it is already in changed state
+    //
+    return CheckAndWrite();
+
+}
+
+Int_t MWriteFitsFile::PostProcess()
+{
+    for (std::map<TString, std::ofits*>::iterator it=fFitsTables.begin(); it!= fFitsTables.end();it++)
+    {
+        it->second->close();
+        delete it->second;
+        it->second = NULL;
+    }
+
+    return kTRUE;
+}
+
+
+// --------------------------------------------------------------------------
+//                                                                           
+// Opens all FITS files for all container, which were registered with the    
+// AddContainer() - methods. The container is taken from the pList, if it    
+// was registered just by its name.                                          
+// Calling the AddContainer() after calling this method will not add new     
+// containers to the list.                                                   
+//                                                                           
+Bool_t  MWriteFitsFile::GetContainer(MParList *pList)
+{
+   if (iTopFitsGroup == fTopFitsGroups.end())
+      // something went wrong while the top level group was created
+      return kFALSE;
+
+
+   // remove the extension from the filename
+   char fileNameNoExt[strlen(GetFileName()) + 1];
+   strcpy(fileNameNoExt, GetFileName());
+   char * pos = strrchr(fileNameNoExt, '.');
+   if (pos) *pos = 0;
+
+   // loop over all FITS tables which have to be created.
+   map<TString, map<TString, MFitsSubTable> >::iterator i_table =
+      fSubTables.begin();
+   while (i_table != fSubTables.end())
+      {
+
+      ofits* fitsTable = new ofits();
+      TString dol = fileNameNoExt;
+      //get rid of the ".root" extension in the file name (if any)
+      if (dol(dol.Length()-5, dol.Length()) == ".root")
+      {
+          dol = dol(0, dol.Length()-5);
+//          *fLog << err << "New name: " << dol.Data() << endl;
+      }
+//      else
+//          *fLog << err << dol(dol.Length()-5, dol.Length()).Data() << endl;
+      dol += "_";
+      dol += i_table->first;
+      dol += ".fits";
+      fitsTable->open(dol.Data());
+      *fLog << inf << "Opening FITS file: " << dol.Data() << endl;
+      fFitsTables[i_table->first] = fitsTable;
+      fTableObjectCreated[i_table->first] = true;
+      fTableHeaderWritten[i_table->first] = false;
+
+      // loop over all containers, which define a sub-table of the current table
+      Int_t num = 0;
+      map<TString, MFitsSubTable>::iterator i_subTable = i_table->second.begin();
+      while (i_subTable != i_table->second.end())
+         {
+
+         MFitsSubTable & subTable = i_subTable->second;
+         if (subTable.GetContainer() == NULL)
+            {
+            // container address is not yet known
+            const char * cname = i_subTable->first.Data();
+            MParContainer *cont = (MParContainer*)pList->FindObject(cname);
+            if (!cont)
+               {
+               // no corresponding container is available in pList
+               if (subTable.MustHave())
+                  {
+                  *fLog << err << "Cannot find parameter container '" << cname << "'." << endl;
+                  return kFALSE;
+                  }
+
+               // we can ignore this container, delete it from the map
+               *fLog << inf2 << "Unnecessary parameter container '" << cname << "' not found..." << endl;
+               map<TString, MFitsSubTable>::iterator i_tmp = i_subTable;
+               i_subTable++;
+               i_table->second.erase(i_tmp);
+               continue;
+               }
+
+            // we have our container address and can use it
+            subTable.SetContainer(cont);
+            }
+
+         // initialize all columns of the sub-table, defined by the current container
+         TClass * cl = i_subTable->second.GetContainer()->IsA();
+         if (!InitColumns(i_table->first, TString(cl->GetName()) + ".",  fitsTable, 
+                          i_subTable->second.GetContainer(), cl)     ) 
+            return kFALSE;
+
+         char attrName[10];
+         sprintf(attrName, "CLNAME%d", num);
+         num++;
+
+         InitAttr(attrName,
+                  "A",
+                  (void*)i_subTable->first.Data(),
+                  NULL,
+                  "MARS container name",
+                  fitsTable);
+
+         i_subTable++;
+         }
+
+      // in case not all sub-tables were removed, we can now create the FITS table
+      if (i_table->second.size() > 0)
+         {
+         // create the DOL of the table. It will be something like:     
+         // fileNameNoExt_dataName.fits[dataName]                       
+         TString dol = fileNameNoExt;
+         dol += "_";
+         dol += i_table->first;
+         dol += ".fits";
+
+         if (fOpenOption == "RECREATE") 
+            // remove the file
+            unlink(dol.Data());
+
+         dol += "[";
+         dol += i_table->first;
+         dol += "]";
+//         *fLog << err << "Reiner would have opened fits file: " << dol.Data() << endl;
+         //exit(0);
+         //fitsTable->open(dol.Data());
+
+         // attach the new table to the top level group
+         //TODO make sure that this attach below is not needed...
+         //iTopFitsGroup->second.Attach(fitsTable);
+         }
+               
+      i_table++;
+      }
+   
+   return kTRUE;
+}
+void MWriteFitsFile::InitAttr(const char* attrName,
+                              const char* dataType,
+                              void* var,
+                              const char* unit,
+                              const char* comment,
+                              std::ofits* outFile)
+{
+    if (outFile == NULL)
+        return;
+    string dts(dataType);
+    string ans(attrName);
+    string cs;
+    if (comment != NULL)
+        cs = string(comment);
+    else
+        cs = "";
+    ostringstream val;
+    if ((dts == "bool") || (dts == "Bool_t") || (dts == "L"))
+    {
+        outFile->SetBool(ans, ((bool*)(var))[0], cs);
+        return;
+    }
+    if ((dts == "char") || (dts == "Char_t") || (dts == "S"))
+    {
+        val << ((char*)(var))[0];
+        outFile->SetStr(ans, val.str(), cs);
+        return;
+    }
+    if ((dts == "unsigned char") || (dts == "UChar_t") || (dts == "B"))
+    {
+        val << ((unsigned char*)(var))[0];
+        outFile->SetStr(ans, val.str(), cs);
+        return;
+    }
+    if ((dts == "short") || (dts == "Short_t") || (dts == "I"))
+    {
+        val << ((short*)(var))[0];
+        outFile->SetStr(ans, val.str(), cs);
+        return;
+    }
+    if ((dts == "unsigned short") || (dts == "UShort_t") || (dts == "U"))
+    {
+        val << ((unsigned short*)(var))[0];
+        outFile->SetStr(ans, val.str(), cs);
+        return;
+    }
+    if ((dts == "int") || (dts == "Int_t") || (dts == "V"))
+    {
+        outFile->SetInt(ans, ((int*)(var))[0], cs);
+        return;
+    }
+    if ((dts == "unsigned int") || (dts == "UInt_t") || (dts == "V"))
+    {
+        outFile->SetInt(ans, ((unsigned int*)(var))[0], cs);
+        return;
+    }
+    if ((dts == "long long") || (dts == "Long64_t") || (dts == "K"))
+    {
+        outFile->SetInt(ans, ((long long*)(var))[0], cs);
+        return;
+    }
+    if ((dts == "unsigned long long") || (dts == "ULong64_t") || (dts == "W"))
+    {
+        val << ((unsigned long long*)(var))[0];
+        outFile->SetStr(ans, val.str(), cs);
+        return;
+    }
+    if ((dts == "float") || (dts == "TFloat_t") || (dts == "E"))
+    {
+        outFile->SetFloat(ans, ((float*)(var))[0], cs);
+        return;
+    }
+    if ((dts == "double") || (dts == "TDouble_t") || (dts == "D"))
+    {
+        outFile->SetFloat(ans, ((double*)(var))[0], cs);
+        return;
+    }
+    if ((dts == "char*") || (dts == "A"))
+    {
+        outFile->SetStr(ans, string((char*)(var)), cs);
+        return;
+    }
+    //trigger error
+    *fLog << err << "Format string not recognized while adding header entry " << ans << " with type " << dts << endl;
+}
+// --------------------------------------------------------------------------
+//                                                                           
+// This method is called when new data should be written to the FITS table.  
+// In general only one row is written. (There are exceptions for Arrays).    
+// A new row to a FITS table is written if at least for one container        
+// (one sub-table) the ReadyToSave - flag is set.                            
+//                                                                           
+Bool_t MWriteFitsFile::CheckAndWrite()
+{
+//   try {
+
+      // loop over all tables
+      map<TString, map<TString, MFitsSubTable> >::iterator i_table =
+         fSubTables.begin();
+      while (i_table != fSubTables.end())
+         {
+         // is this table open?
+         if (fFitsTables.find(i_table->first) != fFitsTables.end())
+            {
+
+            // loop over all sub-tables
+            map<TString, MFitsSubTable>::iterator i_subTable = i_table->second.begin();
+            while (i_subTable != i_table->second.end())
+               {
+
+               if (i_subTable->second.GetContainer()->IsReadyToSave())
+                  {
+                  // first write the TClonesArray and set the size of the arrays
+                  list<MArrayHelperBase*> & clHelper = fClHelper[i_table->first];
+                  list<MArrayHelperBase*>::iterator i_clHelper = clHelper.begin();
+                  while (i_clHelper != clHelper.end())
+                     {
+                     // write all entries in the TClonesArray in its FITS table
+  //removed this write because I do it elsewhere. is that alright ?
+ //                    (*i_clHelper)->Write();
+                     i_clHelper++;
+                     }
+
+                  // write one line to this table
+                  writeOneRow(i_table->first);
+//                  fFitsTables[i_table->first].Write();
+                  break;
+                  }
+               i_subTable++;
+               }
+            }
+
+         i_table++;
+         }
+//      }
+//   catch (exception &e)
+ //     {
+ //     *fLog << err << e.what() << endl;
+ //     return kFALSE;
+ //     }
+
+   return kTRUE;
+}
+
+string MWriteFitsFile::Trim(const string &str)
+{
+    // Trim Both leading and trailing spaces
+    const size_t first = str.find_first_not_of(' '); // Find the first character position after excluding leading blank spaces
+    const size_t last  = str.find_last_not_of(' ');  // Find the first character position from reverse af
+
+    // if all spaces or empty return an empty string
+    if (string::npos==first || string::npos==last)
+        return string();
+
+    return str.substr(first, last-first+1);
+}
+
+Bool_t MWriteFitsFile::VetoColumn(const std::string& colName)
+{
+    for (std::vector<string>::iterator it=fVetoedColumns.begin(); it != fVetoedColumns.end(); it++)
+        if (*it == colName)
+        {
+            *fLog << warn << "Warning: column " << colName << " is being vetoed twice" << endl;
+            return kFALSE;
+        }
+    fVetoedColumns.push_back(colName);
+    return kTRUE;
+}
+
+Bool_t MWriteFitsFile::SetBytesPerSample(const std::string& colName, uint32_t numBytes)
+{
+    for (map<string, uint32_t>::iterator it=fBytesPerSamples.begin(); it!=fBytesPerSamples.end(); it++)
+        if (it->first == colName)
+        {
+            *fLog << warn << "Warning: column " << colName << " bytes per sample is being redefined twice" << endl;
+            return kFALSE;
+        }
+    if (numBytes != 1 && numBytes != 2 && numBytes != 4 && numBytes != 8)
+    {
+        *fLog << warn << "Only powers of two are allowed for types re-mapping." << endl;
+        return kFALSE;
+    }
+    fBytesPerSamples[colName] = numBytes;
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//                                                                           
+// Initialize all columns in "fitsTable" of the class "classDef". The data   
+// of this class are stored in a buffer, beginning at "baseAdr".             
+//                                                                           
+Bool_t MWriteFitsFile::InitColumns(const TString & tableName, 
+                                   const TString & parentVarName,
+                                   ofits* fitsTable,
+                                   void * baseAdr,
+                                   TClass * classDef)
+{
+    // get all data members of the class
+   TList * dataMembers = classDef->GetListOfDataMembers();
+   TIter next(dataMembers);
+   TDataMember * dataMember;
+
+   // loop over all data members
+   while ((dataMember = (TDataMember*)next()) != NULL)
+      {
+      if (!dataMember->IsPersistent())
+         // don't store this variable
+         continue;
+
+      if (dataMember->Property() & ( G__BIT_ISENUM | G__BIT_ISSTATIC))
+         // we cannot store this
+         continue;
+
+      if (strcmp(dataMember->GetTrueTypeName(), "TClass*") == 0)
+         // we don't want to store this. 
+         continue;
+
+      // is it an array of more than 1 dimension?
+      if (dataMember->GetArrayDim() > 1)
+         {
+         *fLog << err << "Two and more dimensional arrays of member variables"
+                         " are not supported." << endl;
+         *fLog <<        "See variable " << dataMember->GetName() << 
+                         " in container " << classDef->GetName() <<  endl;
+         return kFALSE;
+         }
+
+
+      // replace � by **2 in the comment field
+      string comment(dataMember->GetTitle());
+      string::size_type pos1, pos2;
+      if ((pos1 = comment.find(178)) != string::npos)
+         comment.replace(pos1, 1, "**2");
+
+      // get the optional mapping to the fits column names
+      string fitsOptions="";
+      string unit="unit";
+
+      pos1 = comment.find("[fits: ");
+      pos2 = comment.find(']');
+      std::map<string, string> fitsTokens;
+      if (pos1 != string::npos && pos2 != string::npos)
+      {
+          fitsOptions=comment.substr(pos1+7, (pos2-pos1)-7);
+          //do we have more than one option ?
+          string::size_type pos3= fitsOptions.find_first_of(';');
+          string::size_type pos4 = string::npos;
+          string key="";
+          string value="";
+          string keyValue="";
+          while (pos3 != string::npos)
+          {//we have at least 2 options left
+ //             *fLog << err << "fitsOptions: " << fitsOptions << endl;
+              keyValue = fitsOptions.substr(0,pos3);
+ //             *fLog << err << "keyValue: " << keyValue << endl;
+              pos4 = keyValue.find('=');
+              if (pos4 == string::npos)
+              {
+                  *fLog << err << "Error while parsing comment \"" << comment << "\" from variable " << parentVarName + dataMember->GetName() << endl;
+                  return kFALSE;
+              }
+              key = Trim(keyValue.substr(0, pos4));
+              value = Trim(keyValue.substr(pos4+1, pos3));
+              fitsTokens[key] = value;
+ //             *fLog << err << "key: " << key << " value: " << value << endl;
+              fitsOptions = fitsOptions.substr(pos3+1, fitsOptions.size());
+              pos3 = fitsOptions.find_first_of(';');
+          }
+//          *fLog << err << "fitsOptions: " << fitsOptions << endl;
+          keyValue = fitsOptions;
+          pos4 = keyValue.find('=');
+          if (pos4 == string::npos)
+          {
+              *fLog << err << "Error while parsing comment \"" << comment << "\" from variable " << parentVarName + dataMember->GetName() << endl;
+              return kFALSE;
+          }
+          key = Trim(keyValue.substr(0, pos4));
+          value = Trim(keyValue.substr(pos4+1, pos3));
+          fitsTokens[key] = value;
+//          *fLog << err << "key: " << key << " value: " << value << endl;
+      }
+
+      TString colName = parentVarName + dataMember->GetName();
+
+      if (fitsTokens.find("unit") != fitsTokens.end())
+          unit = fitsTokens["unit"];
+      if (fitsTokens.find("name") != fitsTokens.end())
+          colName = fitsTokens["name"];
+
+      //check for column veto
+      if (std::find(fVetoedColumns.begin(), fVetoedColumns.end(), colName.Data())!=fVetoedColumns.end())
+      {
+          *fLog << inf << "Vetoing column " << colName.Data() << endl;
+          continue;
+      }
+
+      // set the array size
+      TString dataType = dataMember->GetTrueTypeName();
+
+      uint32_t dataLength = 0;
+      switch (dataMember->GetArrayDim())
+      {
+          case 0:
+              dataLength = 1;
+              break;
+          case 1:
+              dataLength = dataMember->GetMaxIndex(0);
+              break;
+          default:
+              *fLog << err << "n-dimensional array should have been discarded already " << colName.Data();
+              break;
+      };
+//      if (dataLength == 0)
+//          continue;
+
+      if (dataMember->Property() & G__BIT_ISCLASS)
+         {
+         // special treatment for classes
+          uint32_t arraySize = 0;
+          TString typeName;
+
+          if (strncmp(dataMember->GetTrueTypeName(), "MArray", 6) == 0)
+          {
+//              MArrayHelperBase * clHelper;
+              if (strcmp(dataMember->GetTrueTypeName(), "MArrayS*") == 0)
+              {
+                    typeName = "UShort_t";
+                    arraySize = (*((MArrayS**)((char*)baseAdr + dataMember->GetOffset())))->GetSize();
+                    InitSingleColumn(tableName,
+                                     arraySize,
+                                     typeName.Data(),
+                                     (char*)(*((MArrayS**)((char*)baseAdr + dataMember->GetOffset())))->GetArray(),
+                                     colName.Data(),
+                                     unit,
+                                     comment);
+              }
+              else
+              {
+                  if (strcmp(dataMember->GetTrueTypeName(), "MArrayB*") == 0)
+                  {
+                      typeName = "UChar_t";
+                      arraySize = (*((MArrayB**)((char*)baseAdr + dataMember->GetOffset())))->GetSize();
+                      InitSingleColumn(tableName,
+                                       arraySize,
+                                       typeName.Data(),
+                                       (char*)(*((MArrayB**)((char*)baseAdr + dataMember->GetOffset())))->GetArray(),
+                                       colName.Data(),
+                                       unit,
+                                       comment);
+                  }
+                  else
+                  {
+                      *fLog << err << dataMember->GetTrueTypeName() << " not yet implemented." << endl;
+                      return kFALSE;
+                  }
+              }
+
+            continue;
+          }
+         else if (strcmp(dataMember->GetTrueTypeName(), "TClonesArray") == 0)
+            {
+             *fLog << warn << "I'm skipping the TClonesArray for now" << endl;
+             continue;
+            // each TClonesArray requires a FITS table by itself.
+            MClonesArrayHelper * clHelper;
+
+            TClonesArray * cloneArray = (TClonesArray*)((char*)baseAdr + dataMember->GetOffset());
+            Bool_t status;
+            clHelper = new MClonesArrayHelper(cloneArray, fLog, status);
+            if (!status)   return status;
+
+            fClHelper[tableName].push_back(clHelper);
+
+            // add one column in the parent table of the TClonesArray to store the  
+            // number of entries in the TClonesArray.
+            InitSingleColumn(tableName,
+                             1,
+                             "UInt_t",
+                             clHelper->GetArraySizePtr(),
+                             colName.Data(),
+                             unit,
+                             comment);
+
+            // initialize the columns of the new FITS table, which will store the   
+            // data entries of the TClonesArray                                     
+            if (InitColumns(TString("noName"),
+                            colName + "_",
+                            fitsTable,
+                            clHelper->GetDataBuffer(),
+                            cloneArray->GetClass())
+                    == kFALSE)
+               return kFALSE;
+
+            // the columns are initialized. We can create the FITS table
+            if (clHelper->OpenFitsTable(GetFileName(), dataMember->GetName(), 
+                                       fOpenOption, fLog)                        == kFALSE)
+               return kFALSE;
+            }
+
+         else
+            {
+            // the current container has a variable of an other class. We create 
+            // also columns of this other class in the same table                
+            TClass * newClassDef = TClass::GetClass(dataMember->GetTrueTypeName(), kFALSE, kTRUE);
+            if (newClassDef)
+               {
+               if (InitColumns(tableName, colName + ".", fitsTable, (char*)baseAdr + dataMember->GetOffset(),
+                        newClassDef) == kFALSE)
+                  return kFALSE;
+               }
+            else
+               *fLog << warn << "Cannot write data of class " << colName + "." + dataMember->GetTrueTypeName() << endl;
+            }
+         continue;
+         } 
+
+         InitSingleColumn(tableName,
+                          dataLength,
+                          dataType.Data(),
+                          (char*)baseAdr + dataMember->GetOffset(),
+                          colName.Data(),
+                          unit,
+                          comment);
+
+      }
+   return kTRUE;
+}
+void MWriteFitsFile::InitSingleColumn(const TString& tableName,
+                                      uint32_t count,
+                                      const string& typeName,
+                                      void* dataPointer,
+                                      const string& columnName,
+                                      const string& unit,
+                                      const string& comment)
+{
+    if (!fTableObjectCreated[tableName])
+    {
+        *fLog << err << "ERROR: Cannot init column " << columnName << " before assigning object: " << tableName << endl;
+        return;
+    }
+    int typeFound = 0;
+    char typeChar = '0';
+    if ((typeName == "bool") || (typeName == "Bool_t") || (typeName == "L"))
+    {
+        typeChar = 'L';
+        typeFound++;
+    }
+    if ((typeName == "char") || (typeName == "Char_t") || (typeName == "S"))
+    {
+        typeChar = 'A';
+        typeFound++;
+    }
+    if ((typeName == "unsigned char") || (typeName == "UChar_t") || (typeName == "B"))
+    {
+        typeChar = 'A';
+//        *fLog << warn << "Converting unsigned char to char in fits file" << endl;
+        typeFound++;
+    }
+    if ((typeName == "short") || (typeName == "Short_t") || (typeName == "I"))
+    {
+        typeChar = 'I';
+        typeFound++;
+    }
+    if ((typeName == "unsigned short") || (typeName == "UShort_t") || (typeName == "U"))
+    {
+        typeChar = 'I';
+//        *fLog << warn << "Converting unsigned short to short in fits file" << endl;
+        typeFound++;
+    }
+    if ((typeName == "int") || (typeName == "Int_t") || (typeName == "V"))
+    {
+        typeChar = 'J';
+        typeFound++;
+    }
+    if ((typeName == "unsigned int") || (typeName == "UInt_t") || (typeName == "V"))
+    {
+        typeChar = 'J';
+//        *fLog << warn << "Converting unsigned int to int in fits file" << endl;
+        typeFound++;
+    }
+    if ((typeName == "long long") || (typeName == "Long64_t") || (typeName == "K"))
+    {
+        typeChar = 'K';
+        typeFound++;
+    }
+    if ((typeName == "unsigned long long") || (typeName == "ULong64_t") || (typeName == "W"))
+    {
+        typeChar = 'K';
+//        *fLog << warn << "Converting unsigned long to long in fits file" << endl;
+        typeFound++;
+    }
+    if ((typeName == "float") || (typeName=="TFloat_t") || (typeName == "E"))
+    {
+        typeChar = 'E';
+        typeFound++;
+    }
+    if ((typeName == "double") || (typeName == "TDouble_t") || (typeName == "D"))
+    {
+        typeChar = 'D';
+        typeFound++;
+    }
+//    if ((typeName == "char*") || (typeName == "A"))
+//    {
+//        typeFound++;
+//    }
+    if (typeFound != 1)
+    {
+        *fLog << err << "We have a problem with the data type: " << typeName << endl;
+        return;
+    }
+    uint32_t colWidth = 0;
+    switch (typeChar)
+    {
+        case 'L':  colWidth = 1*count; break;
+        case 'A':  colWidth = 1*count; break;
+        case 'B':  colWidth = 1*count; break;
+        case 'I':  colWidth = 2*count; break;
+        case 'J':  colWidth = 4*count; break;
+        case 'K':  colWidth = 8*count; break;
+        case 'E':  colWidth = 4*count; break;
+        case 'D':  colWidth = 8*count; break;
+        default:
+            *fLog << err << "ERROR: typeChar could not be resolved to an actual type" << endl;
+    };
+    //check for type remapping here
+    if (fBytesPerSamples.find(columnName) != fBytesPerSamples.end())
+    {
+        if (typeChar != 'A')
+        {
+            *fLog << err << "Attempt to remap type " << typeChar << " to " << fBytesPerSamples[columnName] << " is only allowed on bytes (variable name: " << columnName << "). Ignoring column" << endl;
+            return;
+        }
+        uint32_t bytesPerSample = fBytesPerSamples.find(columnName)->second;
+        if (colWidth%bytesPerSample != 0)
+        {
+            *fLog << err << "Type remapping cannot be done using " << bytesPerSample << " bytes per sample on an array of char of size " << colWidth << ". Ignoring column " << columnName << endl;
+            return;
+        }
+        switch (bytesPerSample)
+        {
+            case 1: count = count/1; typeChar = 'A'; break;
+            case 2: count = count/2; typeChar = 'I'; break;
+            case 4: count = count/4; typeChar = 'J'; break;
+            case 8: count = count/8; typeChar = 'K'; break;
+            default:
+                *fLog << err << "ERROR: num bytes per sample = " << bytesPerSample << " should have been forbidden already" << endl;
+        }
+
+    }
+
+    fDataPointers[tableName].push_back(dataPointer);
+    fTypeChars[tableName].push_back(typeChar);
+    fColSizes[tableName].push_back(count);
+    fColWidth[tableName].push_back(colWidth);
+
+    //FIXME ofits does not allow for much liberty regarding the size of the column names.
+    //Truncating them badly here, will probably cause other problems -> Modify ofits.h instead
+    string truncatedName=columnName.substr((columnName.size()>40)?columnName.size()-40:0,columnName.size());
+    string truncatedComment = comment.substr((comment.size()>10)?comment.size()-10:0,comment.size());
+//    *fLog << warn << "In table " << tableName << " Adding column |" << truncatedName << "| |" << truncatedComment << "| |" << count << "| |" << typeChar;
+//    *fLog << warn << "| Real: "<< columnName << " comment: " << comment << endl;
+    fFitsTables[tableName]->AddColumn(count, typeChar, truncatedName, unit, truncatedComment);
+}
+
+void MWriteFitsFile::writeOneRow(const TString& tableName)
+{
+    if (!fTableHeaderWritten[tableName])
+    {
+        fFitsTables[tableName]->WriteTableHeader(tableName.Data());
+        fTableHeaderWritten[tableName] = true;
+    }
+    if (!fTableObjectCreated[tableName])
+    {
+        *fLog << err << "This is not good. Please initialize the fits table before writing to it: " << tableName << endl;
+        return;
+    }
+    //first calculate the size of one row
+    uint32_t rowWidth = 0;
+    for (uint32_t i=0;i<fTypeChars[tableName].size();i++)
+        rowWidth += fColWidth[tableName][i];
+    unsigned char* tempBuffer = new unsigned char[rowWidth];
+    //then copy the data to be written contiguously
+    uint32_t bytesCounter = 0;
+    for (uint32_t i=0;i<fDataPointers[tableName].size();i++)
+    {
+        memcpy(&tempBuffer[bytesCounter], fDataPointers[tableName][i], fColWidth[tableName][i]);
+        bytesCounter+=fColWidth[tableName][i];
+    }
+    if (fFitsTables[tableName]->WriteRow(tempBuffer, bytesCounter) == false)
+        *fLog << err << "Error while writing to FITS table " << tableName << endl;
+    else
+        fFitsTables[tableName]->FlushNumRows();
+
+    delete[] tempBuffer;
+}
+Bool_t MWriteFitsFile::ReInit(MParList *pList)
+{
+   if (fRule.Length() == 0)
+      // there is not rule defined. We keep the old file
+      return MWriteFile::ReInit(pList);
+
+   MRead *read = (MRead*)pList->FindTask("MRead");
+   if (!read)
+   {
+       *fLog << err;
+       *fLog << "ERROR: No Task 'MRead' found in the tasklist.  This task is" << endl;
+       *fLog << "  necessary to  get the filename.  Without a read-filename" << endl;
+       *fLog << "  no output-filename can be created... abort." << endl;
+       *fLog << endl;
+       return kFALSE;
+   }
+
+
+   // close the current files
+   CloseTopLevelGroup();
+   for (std::map<TString,std::ofits*>::iterator it=fFitsTables.begin(); it!=fFitsTables.end(); it++)
+   {
+       (it->second)->close();
+       delete it->second;
+   }
+   fFitsTables.clear();
+   fDataPointers.clear();
+   fTypeChars.clear();
+   fColSizes.clear();
+   fColWidth.clear();
+   fTableObjectCreated.clear();
+   fTableHeaderWritten.clear();
+   DeleteArrayHelper();
+   fClHelper.clear();
+
+   // get new filename
+   const TString readFileName = read->GetFullFileName();
+   const TString newname = MWriteRootFile::SubstituteName(fRule, readFileName)+".fits";
+
+   // create new files
+   OpenTopLevelGroup(newname.Data());
+   if (!IsFileOpen())
+      return kFALSE;
+
+   if (GetContainer(pList) == kFALSE)
+      return kFALSE;
+
+   // do, what has to be done in ReInit.
+   return MWriteFile::ReInit(pList);
+
+}
+
+void MWriteFitsFile::DeleteArrayHelper()
+{
+   map<TString, list<MArrayHelperBase *> >::iterator i_helper1 = fClHelper.begin();
+   while (i_helper1 != fClHelper.end())
+      {
+      list<MArrayHelperBase *>::iterator i_helper2 = i_helper1->second.begin();
+      while(i_helper2 != i_helper1->second.end())
+         {
+         delete *i_helper2;
+
+         i_helper2++;
+         }
+
+      i_helper1++;
+      }
+}
Index: trunk/Mars/mfileio/MWriteFitsFile.h
===================================================================
--- trunk/Mars/mfileio/MWriteFitsFile.h	(revision 14792)
+++ trunk/Mars/mfileio/MWriteFitsFile.h	(revision 14792)
@@ -0,0 +1,186 @@
+#ifndef MARS_MWreitFitsFile
+#define MARS_MWreitFitsFile
+
+#include <list>
+#include <vector>
+#include <map>
+
+#include <TClass.h>
+
+#ifndef MARS_MWriteFile
+#include "MWriteFile.h"
+#endif
+
+#include "MTopFitsGroup.h"
+#include "MFitsArray.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Information of one MParContainer, which data should be written into all or  
+// just a few columns of one FITS table                                        
+class MFitsSubTable
+{
+   // the container, which data should be written to the FITS sub-table.   
+   MParContainer  *fContainer; 
+
+   // used only if the Container is defined by its name.                   
+   // if kTRUE  must exist in the MParList of the program                  
+   // if kFALSE the container is ignored. if it is not in the              
+   //           MParList of the program                                    
+   Bool_t         fMust;
+
+public:
+   MFitsSubTable( Bool_t must)
+      : fContainer(NULL), fMust(must)
+      {}
+
+   MFitsSubTable(MParContainer * container,  Bool_t must)
+      : fContainer(container),  fMust(must)
+      {}
+
+  
+   MFitsSubTable(const MFitsSubTable & subTable)
+      : fContainer(subTable.fContainer), fMust(subTable.fMust)
+      {}
+
+   Bool_t            MustHave()           {return fMust;}
+   MParContainer *   GetContainer()       {return fContainer;}
+   void              SetContainer(MParContainer * cont)
+                                          {fContainer = cont;}
+
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// A class to write data of MParContainer into FITS files.                     
+class MWriteFitsFile : public MWriteFile
+{
+private:
+   // all (global) currently open top FITS groups.                      
+   // Note: several instances of MWriteFitsFile can write to the same   
+   //       top level FITS group (a top level FITS group corresponds to 
+   //       one ROOT file)                                              
+   static std::map<MUniqueFileId, MTopFitsGroup>    fTopFitsGroups;
+
+   // pointer to the top level FITS group of this instance              
+   std::map<MUniqueFileId, MTopFitsGroup>::iterator iTopFitsGroup;
+
+   // the key (TString) of following maps is the FITS table name, which 
+   // corresponds to one TTree                                          
+
+   // all main FITS table. Children tables to store data of             
+   // TClonesArray are not in this map.
+   //ETIENNE ofits objects cannot be copied. So store pointers instead
+   std::map<TString, std::ofits*>                       fFitsTables;
+
+   // all information needed to write data of TClonesArray to their      
+   // own FITS table. Note: one parent FTIS table may have several       
+   // children tables, each for one TClonesArray.                        
+   std::map<TString, std::list<MArrayHelperBase *> >    fClHelper;
+
+   // all information about the MParContainer, which data are stored     
+   // in the same FITS table. The key of map<TString, MFitsSubTable>     
+   // is the class name of the MParContainer                             
+   std::map<TString, std::map<TString, MFitsSubTable> > fSubTables;
+
+   std::map<TString, std::vector<void*> >    fDataPointers;
+   std::map<TString, std::vector<char> >     fTypeChars;
+   std::map<TString, std::vector<uint32_t> > fColSizes;
+   std::map<TString, std::vector<uint32_t> > fColWidth;
+   std::map<TString, bool> fTableObjectCreated;
+   std::map<TString, bool> fTableHeaderWritten;
+
+   void DeleteArrayHelper();
+
+   // rule to construct an output file-name from the input-filename      
+   TString fRule;  
+
+   TString fOpenOption; // RECREATE or NEW
+   TString fGroupName;  // name of top level group
+   TString fTitle;      // title of top level group
+
+   void OpenTopLevelGroup(const char * fname);
+   void CloseTopLevelGroup();
+
+   Bool_t InitColumns(const TString & tableName,
+                      const TString & parentVarName,
+                      std::ofits* fitsTable,
+                      void * baseAdr,
+                      TClass * classDef);
+   void InitSingleColumn(const TString& tableName,
+                         uint32_t count,
+                         const std::string& typeName,
+                         void* dataPointer,
+                         const std::string& columnName,
+                         const std::string& unit,
+                         const std::string& comment);
+   void writeOneRow(const TString& tableName);
+   void InitAttr(const char* attrName,
+                 const char* dataType,
+                 void* var,
+                 const char* unit=NULL,
+                 const char* comment=NULL,
+                 std::ofits* outFile=NULL);
+
+   // MWrite
+   Bool_t      IsFileOpen() const  
+                              {return iTopFitsGroup != fTopFitsGroups.end();}
+   Bool_t      CheckAndWrite();
+   Bool_t      GetContainer(MParList *pList);
+   const char *GetFileName() const;
+
+   Int_t       PreProcess(MParList *pList);
+   Int_t       PostProcess();
+
+   std::string Trim(const std::string &str);
+
+   // MTask
+   Bool_t ReInit(MParList *pList);
+
+   std::vector<std::string> fVetoedColumns;
+   std::map<std::string, uint32_t> fBytesPerSamples;
+
+public:
+
+   //Veto a type-mapping functions and variables
+   Bool_t VetoColumn(const std::string& colName);
+   Bool_t SetBytesPerSample(const std::string& colName, uint32_t numBytes);
+
+   enum FILE_MODE {
+      kMultiFiles,
+      kSingleFile
+      } ;
+
+    MWriteFitsFile(const char *fname,
+                   FILE_MODE fileMode = kMultiFiles,
+                   const Option_t *opt="RECREATE",
+                   const char *name=NULL,
+                   const char *title=NULL);
+    //Similar contructor to what MWriteRootFiles takes.
+    //Some of the args are not used: comp as they does not make sense in FITS
+    MWriteFitsFile(const Int_t comp,
+                   const char* rule,
+                   const Option_t* option="RECREATE",
+                   const char* fTitle="Untitled",
+                   const char* name=NULL,
+                   const char* title=NULL);
+
+   ~MWriteFitsFile();
+
+
+   void AddContainer(const char *cName,   const char *tName=NULL, Bool_t must=kTRUE);
+   void AddContainer(MParContainer *cont, const char *tName=NULL, Bool_t must=kTRUE);
+
+
+   void AddTree(const char *name, Bool_t force=kTRUE)
+   {
+       AddContainer(Form("MReport%s", name), name, force);
+       AddContainer(Form("MTime%s", name),   name, force);
+   }
+
+   ClassDef(MWriteFitsFile, 0)   
+};
+
+
+#endif
Index: trunk/Mars/mfileio/Makefile
===================================================================
--- trunk/Mars/mfileio/Makefile	(revision 14447)
+++ trunk/Mars/mfileio/Makefile	(revision 14792)
@@ -30,5 +30,8 @@
            MWriteFile.cc \
            MWriteAsciiFile.cc \
-           MWriteRootFile.cc
+           MWriteRootFile.cc \
+           MWriteFitsFile.cc \
+           MTopFitsGroup.cc \
+           MFitsArray.cc
 
 ############################################################
