Index: trunk/FACT++/src/Fits.cc
===================================================================
--- trunk/FACT++/src/Fits.cc	(revision 10367)
+++ trunk/FACT++/src/Fits.cc	(revision 10367)
@@ -0,0 +1,265 @@
+// **************************************************************************
+/** @class FactFits
+
+@brief FITS writter for the FACT project. 
+
+The FactFits class is able to open, manage and update FITS files. 
+
+The file columns should be given to the class before the file is openned. Once
+a file has been created, the structure of its columns cannot be changed. Only
+row can be added.
+
+This class relies on the CCfits and CFitsIO packages.
+
+*/
+// **************************************************************************
+#include "Fits.h"
+
+#include "Time.h"
+#include "Converter.h"
+
+using namespace std;
+
+// --------------------------------------------------------------------------
+//
+//! This gives a standard variable to the file writter. 
+//! This variable should not be related to the DIM service being logged. 
+//! @param desc the description of the variable to add
+//! @param dataFormat the FITS data format corresponding to the variable to add.
+//! @param dataPointer the memory location where the variable is stored
+//! @param numDataBytes the number of bytes taken by the variable
+//
+void Fits::AddStandardColumn(Description& desc, std::string dataFormat, void* dataPointer, long unsigned int numDataBytes)
+{
+	fStandardColDesc.push_back(desc);
+	fStandardFormats.push_back(dataFormat);
+	fStandardPointers.push_back(dataPointer);
+	fStandardNumBytes.push_back(numDataBytes);
+}
+// --------------------------------------------------------------------------
+//
+//! This gives the file writter access to the DIM data
+//! @param desc a vector containing the description of all the columns to log
+//! @param dataFormat a vector containing the FITS data format of all the columsn to log
+//! @param dataPointer the memory location where the DIM data starts
+//! @param numDataBytes the number of bytes taken by the DIM data. 
+//	
+void Fits::InitDataColumns(std::vector<Description> desc, std::vector<std::string>& dataFormat, void* dataPointer, int numDataBytes)
+{//we will copy this information here. It duplicates the data, which is not great, but it is the easiest way of doing it right now
+	if (desc.size() == dataFormat.size())
+	{
+	 	fDataColDesc = desc;
+	}
+	else
+	{
+		for (unsigned int i=0;i<dataFormat.size();i++)
+		{
+			std::stringstream stt;
+			stt << "Data" << i;
+			fDataColDesc.push_back(Description(stt.str(), "unit", "comment"));	
+		}
+	}		
+	fDataFormats = dataFormat;
+	fDataPointer = dataPointer;
+	fDataNumBytes = numDataBytes; 	
+}
+// --------------------------------------------------------------------------
+//
+//! This opens the FITS file (after the columns have been passed)
+//! @param fileName the filename with complete or relative path of the file to open
+//! @param tableName the name of the table that will receive the logged data.
+//
+void Fits::Open(const std::string& fileName, const std::string& tableName)
+{		
+	try
+	{
+		fFile = new FITS(fileName, RWmode::Write);
+	}
+	catch (FITS::CantOpen)
+	{
+		std::ostringstream err;
+		err << "Could not open " << fileName << ".Skipping it.";
+		throw runtime_error(err.str());	
+	}	
+	//concatenate the standard and data columns
+	//do it the inneficient way first: its easier and faster to code.
+	std::vector<std::string> allNames;
+	std::vector<std::string> allDataTypes;
+	std::vector<std::string> allUnits;
+	fTotalNumBytes = 0;
+	for (unsigned int i=0;i<fStandardColDesc.size();i++)
+	{
+		allNames.push_back(fStandardColDesc[i].name);
+		allDataTypes.push_back(fStandardFormats[i]);
+		allUnits.push_back(fStandardColDesc[i].unit);
+		fTotalNumBytes += fStandardNumBytes[i];
+	}
+	//for (int i=static_cast<int>(fDataColDesc.size())-1;i>=0;i--)
+	for (int i=0; i< static_cast<int>(fDataColDesc.size()); i++)
+	{
+		if (fDataColDesc[i].name != "")
+			allNames.push_back(fDataColDesc[i].name);
+		else 
+		{
+			std::stringstream stt;
+			stt << "Data" << i;
+			allNames.push_back(stt.str());
+		}
+		allDataTypes.push_back(fDataFormats[i]);
+		allUnits.push_back(fDataColDesc[i].unit);	
+	}
+	fTotalNumBytes += fDataNumBytes;
+	
+	bool updating = false;
+	try
+	{
+		fTable = fFile->addTable(tableName, 0, allNames, allDataTypes, allUnits);
+		fCopyBuffer = new unsigned char[fTotalNumBytes]; 
+		fNumRows = fTable->rows();
+		if (fNumRows !=0)
+		{//If the file already existed, then we must load its data to memory before writing to it.
+			std::vector<std::string> tableNameString;
+			tableNameString.push_back(tableName);
+			fFile->read(tableNameString);	
+			std::map<std::string, Column*> cMap = fTable->column();
+			std::map<std::string, Column*>::iterator cMapIt;
+			for (cMapIt = cMap.begin(); cMapIt != cMap.end(); cMapIt++)
+			{
+				//TODO this only works for scalar columns I assume. upgrade it to fully read vector columns
+				cMapIt->second->readData(1, fNumRows);		
+			}	
+			updating = true;
+		}
+	}
+	catch(CCfits::FitsError e)
+	{
+		std::ostringstream err;
+		err << "Error when adding table " << tableName << " : " << e.message();
+		throw runtime_error(err.str());
+	}
+			
+	fEndMjD = * static_cast<double*>(fStandardPointers[0]);
+	if (!updating)
+		WriteHeaderKeys();
+}
+// --------------------------------------------------------------------------
+//
+//! This writes the standard header 
+//
+void Fits::WriteHeaderKeys()
+{
+	std::string name;
+	std::string comment;
+	
+	float floatValue;
+	double doubleValue;
+	std::string stringValue;
+			
+	name = "EXTREL";
+	comment = "Release Number";
+	floatValue = 1.0f;
+	fTable->addKey(name, floatValue, comment);
+			
+	name = "BASETYPE";
+	comment = "Base class that wrote this file";
+	stringValue = "CCFits_table";
+	fTable->addKey(name, stringValue, comment);
+			
+	name = "TELESCOP";
+	comment = "Telescope that acquired this data";
+	stringValue = "FACT";
+	fTable->addKey(name, stringValue, comment);
+			
+	name = "ORIGIN";
+	comment = "Institution that wrote the file";
+	stringValue = "ISDC";
+	fTable->addKey(name, stringValue, comment);
+			
+	name = "CREATOR";
+	comment = "Program that wrote this file";
+	stringValue = "FACT++_DataLogger";
+	fTable->addKey(name, stringValue, comment);
+			
+	name = "DATE";
+	stringValue = Time().GetAsStr();
+	stringValue[10] = 'T';
+	comment = "File creation date";
+	fTable->addKey(name, stringValue, comment);
+			
+	name = "TIMEREF";
+	stringValue = "UTC";
+	comment = "Time reference system";
+	fTable->addKey(name, stringValue, comment);
+			
+	name = "TSTART";
+	doubleValue = fEndMjD;
+	comment = "Time of the first received data";
+	fTable->addKey(name, doubleValue, comment);
+			
+	//More ?
+}
+// --------------------------------------------------------------------------
+//
+//! This writes one line of data to the file.
+//! @param conv the converter corresponding to the service being logged
+//
+void Fits::Write(Converter* conv)
+{
+	try
+	{
+		fTable->insertRows(fNumRows);
+	}
+	catch(CCfits::FitsError e)
+	{
+		std::ostringstream err;
+		err << "Error when inserting a row: " << e.message();
+		throw runtime_error(err.str());
+	}
+	fNumRows++;
+			
+	//the first standard variable is the current MjD
+	fEndMjD = * static_cast<double*>(fStandardPointers[0]);
+			
+	//first copy the standard variables to the copy buffer
+	int shift = 0;
+
+	for (unsigned int i=0;i<fStandardNumBytes.size();i++)
+	{
+		for (int j=0; j<fStandardNumBytes[i]; j++)
+			fCopyBuffer[shift+j] = static_cast<char*>(fStandardPointers[i])[fStandardNumBytes[i]-(j+1)];
+		shift+= fStandardNumBytes[i];	
+	}
+
+	//now take care of the DIM data. The Converter is here for that purpose
+	conv->ToFits(static_cast<void*>(&fCopyBuffer[shift]), fDataPointer, fDataNumBytes);
+			 
+	//data copied to buffer, can write to fits
+	int status = 0;
+	//TODO check the status after the write operation
+   	fits_write_tblbytes(fFile->fitsPointer(), fNumRows, 1, fTotalNumBytes, fCopyBuffer, &status);
+
+	//This forces the writting of each row to the disk. Otherwise all rows are written when the file is closed.
+	fFile->flush();
+}
+// --------------------------------------------------------------------------
+//
+//! This closes the currently openned FITS file. 
+//! it also updates the header to reflect the time of the last logged row
+//	
+void Fits::Close() 
+{
+//WARNING: do NOT delete the table as it gets deleted by the fFile object
+//			if (fTable != NULL)
+//				delete fTable;
+	std::string name = "TEND";
+	double doubleValue = fEndMjD;
+	std::string comment = "Time of the last received data";
+	fTable->addKey(name, doubleValue, comment);
+
+	if (fFile != NULL)
+		delete fFile;
+	fFile = NULL;
+	if (fCopyBuffer != NULL)
+		delete [] fCopyBuffer;
+	fCopyBuffer = NULL;
+}
Index: trunk/FACT++/src/Fits.h
===================================================================
--- trunk/FACT++/src/Fits.h	(revision 10367)
+++ trunk/FACT++/src/Fits.h	(revision 10367)
@@ -0,0 +1,87 @@
+#ifndef FACT_Fits
+#define FACT_Fits
+
+#include <CCfits/CCfits>
+#include <vector>
+
+#include "Description.h"
+
+using namespace CCfits;
+
+class Converter;
+
+class Fits
+{
+	private:
+		///The CCfits object to the FITS file
+		FITS* fFile;
+		///The CCfits Table
+		Table* fTable;
+		///The current number of Rows in the table
+		int fNumRows;
+		///Name of the "standard", i.e. data found in every fits file
+		///TODO make these variable static so that they are shared by every object.
+		///TODO add also a static boolean to initialize these only once
+		std::vector<Description> fStandardColDesc;
+		///Format of the standard columns.
+		std::vector<std::string> fStandardFormats;
+		///the pointers to the standard variables
+		std::vector<void*> fStandardPointers;
+		///the number of bytes taken by each standard variable
+		std::vector<int> fStandardNumBytes;
+		///the vector of data column names
+		std::vector<Description> fDataColDesc;
+		///the data format of the data columns
+		std::vector<std::string> fDataFormats;
+		///the pointer to the contiguous memory location where the data is stored (i.e. the dim data pointer)
+		void* fDataPointer;
+		///the size of the data, in bytes.
+		int fDataNumBytes;
+		///the copy buffer. Required to put the standard and data variable in contguous memory 
+		unsigned char* fCopyBuffer;
+		///the total number of bytes per FITS row
+		int fTotalNumBytes;
+		///to keep track of the time of the latest written entry (to update the header when closing the file)
+		double fEndMjD;
+		///Write the FITS header keys
+		void WriteHeaderKeys();
+		
+	public:
+		
+		Fits() : fFile(NULL), 
+					 fTable(NULL), 
+					 fNumRows(0), 
+					 fDataPointer(NULL), 
+					 fDataNumBytes(0), 
+					 fCopyBuffer(NULL), 
+					 fTotalNumBytes(0),
+					 fEndMjD(0.0)
+		 {}
+		
+		virtual ~Fits() 
+		{
+			if (IsOpen())
+				Close();
+		}
+		///returns wether or not the file is currently open or not
+		bool IsOpen() {return fFile != NULL;}
+		
+		///Adds a column that exists in all FITS files
+		void AddStandardColumn(Description& desc, std::string dataFormat, void* dataPointer, long unsigned int numDataBytes);
+		
+		///Adds columns specific to the service being logged.
+		void InitDataColumns(std::vector<Description> desc, std::vector<std::string>& dataFormat, void* dataPointer, int numDataBytes);
+
+		///Opens a FITS file
+		void Open(const std::string& fileName, const std::string& tableName);
+
+		///Write one line of data. Use the given converter.
+		void Write(Converter* conv);
+		
+		///Close the currently opened file.
+		void Close();
+
+};//Fits
+
+#endif /*FITS_H_*/
+
