// -*- C++ -*-
#ifndef LOGFILE_H
#define LOGFILE_H

#include <cstdio>
#include <unistd.h>
#include <map>
#include <list>
#include <string>
#include <ctime>
#include <iostream>
#include <sstream>

/// \ingroup baseclasses

/**
   Logs values for arbitrary defined channels.
   T can be std::string or int or anything else supports the << of streams.
   (It is used as name for a channel.)
*/

template <class T> class LogFile{
protected:
    FILE* f;
    typedef std::map<T, double> data_map;
    typedef std::list<T> names_list;    
    data_map data;
    names_list names;
    std::string filename;
    std::string info;
    std::string separator;
    int line_counter;
    bool _print_names_list;
public:
    LogFile(const std::string& filename="",const std::string& info="",const std::string& separator="\t")
	:filename(filename),info(info),separator(separator),line_counter(0),_print_names_list(false){
	f=NULL;
    };
    ~LogFile(){
	if(f)fclose(f);
    };
    void setInfo(const std::string& info){
	this->info=info;
    };
    void addChannel(const T& name){
	names.push_back(name);
    };
    void putData(const T& channel, double value){
	data[channel]=value;
    }; 
    /** print comment line in file 
	format is "#%d: %s"
    */
    void comment(const std::string& text){
	init();
	fprintf(f,"#%d: %s\n",line_counter,text.data());
	fflush(f);
    };

    /** print numbered names list in file header
    */
    void print_names_list(){
	_print_names_list=true;
    };
    /** print data line in file 
	format is "%5.3f%s" * number of channels
	%s is the separator string usually "\t"
    */
    void print(){
	if(names.empty())return;
	init();
	bool first=true;
	for(typename names_list::iterator i=names.begin();i!=names.end();++i){
	    if(first) first=false;
	    else fprintf(f,"%s",separator.data());
	    fprintf(f,"%f", data[(*i)]);
	}
	fprintf(f,"\n");
	fflush(f);
	line_counter++;
    };
protected:
    void init(){
	if(f!=NULL)return;

	time_t t=time(NULL);
    	if(filename!="")	
	    f=fopen(filename.data(),"w");
	else {
	    char* time_str=ctime(&t);
	    if(time_str[strlen(time_str)-1]='\n')
		time_str[strlen(time_str)-1]='\0';
	    f=fopen(time_str,"w");
	}

	bool first=true;
	// print info
	fprintf(f,"# created at %s",ctime(&t));
	fprintf(f,"#\n");
	fprintf(f,"#"); // insert comment char
	for(typename std::string::iterator s=info.begin();s!=info.end();++s){
	    fprintf(f,"%c",*s);
	    if(*s == '\n') // line ending found
	        fprintf(f,"#"); // insert comment char
	}
	fprintf(f,"#\n");

	// collect names
	std::ostringstream headline_str;
	std::ostringstream names_str;
	int counter=1;
	names_str << "# list of channels\n#\n";
	for(typename names_list::iterator i=names.begin();i!=names.end();++i,counter++){
	    if(first) {
		first=false;
		headline_str << "#";
	    } else 
		headline_str << separator;

	    headline_str << (*i);
	    names_str << "#  " << counter << ": " << (*i) << std::endl;
	}	
	names_str << "#\n" << std::ends;
	headline_str << std::endl << std::ends;
	// print names list
	if(_print_names_list)
	    fprintf(f,"%s",names_str.str().data());
	// print column headers
	fprintf(f,"%s",headline_str.str().data());
    }

};

#endif

