#ifndef CONFIGCACHE_H
#define CONFIGCACHE_H

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <ostream>

#include "datread.h"

#define CACHE_MODE_OO 0
#define CACHE_MODE_RO 1
#define CACHE_MODE_WO 2
#define CACHE_MODE_RW 3

using namespace std;

struct parameter{
  string id;
  double val;
};

struct infiledesc {
  string filename;
  int nequi;
  int nskip;
  bool extended;
  bool superextended;
};

class configcache{
 public:
  ~configcache();
  configcache(const string& cacheid, const int& nequi, const int& nskip, const string& datadir, char **configmem, const int& configMemSize, 
	      const int& cachemode=CACHE_MODE_RW, ostream *_log=NULL);
  void readConfig(bool *readnewconfig, int *nequileft, vector<unsigned long> *excludeFileHashes=NULL);
  void writeConfig(int actnequi);
  void addPara(const string& parid, const double& val=0);
  void setPara(const string& parid, const double& value);
  void writeHeader(const string& headerid, const char *header, long unsigned int size, int actnequi);
  void * getHeader(const string& headerid);
  string getOutFileName() { return outFileName.str(); }
  string getInFileName() { return DATADIR + "/" + openFileDesc.filename; }
  static unsigned long hash(const string& str);
  void closeInFile() { dataReader->closeFile(); }
  int inFilesLeft() { return inFiles.size(); }
  char* getConfigMem() { return configMem; }
  int getConfigSize() { return configSize; }
  bool isOutFileOpen () { return outFile.is_open(); }
  void finishOutFile();

 private:
  struct iobuffers;
  iobuffers *ioBuffers;

  ostream* log;
  infiledesc openFileDesc;
  int getParIndex(const string& parid);
  int NEQUI;
  int NSKIP;
  string DATADIR;
  string CACHEID;
  int MODE;
  string getFileId(int actnequi, const bool& superextended=true, const bool& shortid=false);

  ofstream outFile;

  stringstream outFileName;

  int readnum;

  int inSize;

  int configSize;
  char *configMem;
  char *tmpConfig;

  bool refetchDataFiles;

  void fetchDataFiles();
  
  bool isValidInFile(const string& infile, infiledesc *filedesc);

  vector<infiledesc> inFiles;

  vector<parameter> Paras;

  void openOutFile(int actnequi);

  int readHeader();

  bool headerWritten;

  bool readAllHeaders();

  vector<infiledesc>::iterator getNextInfile(vector<unsigned long> *excludeFileHashes);

  int nequileft_internal;

  bool doVirtualEquilibration, firstUsedConfig;

  string paraString();

  datread *dataReader;
};

#endif
