/*****************************************************************************
written by Jens Thiele in June 1996
Email:  jthiele@apollo.unterland.de
IRC:    karme
******************************************************************************/


#ifndef __IOTYPE_H
#define __IOTYPE_H
#include "allgtypedef.H"
#include "textfata.H"
#include <strstream.h>
#include <string>


/// convert any object with defined << to string
template<class X>
string any_to_string(X z)
{
  ostrstream o;
  o << z <<ends;
  char *s=o.str();
  string erg=s;
  delete [] s;
  return erg;
};



// Die choose_cfgtype Parameter (Parameter der listen load/save/change)--------
const int8 CFG_TEXT_MODE=0;
const int8 CFG_BINAER_MODE=1;
/*
#define CFG_TEXT_MODE     ((int8)0)
#define CFG_BINAER_MODE   ((int8)1)
*/

// ------------------------ Die iotype Modes ----------------------------------
const int8 IOTYPE_READ_MODE=0;
const int8 IOTYPE_WRITE_MODE=1;
/* defines sind scheisse !!
#define IOTYPE_READ_MODE  ((int8)0)
#define IOTYPE_WRITE_MODE ((int8)1)
*/

// Mehr modies koennen nur mit SEHR VIEL Aufand gemacht werden 
// => keine neuen Modies !



/******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
                       D I E    I O    K L A S S E :
*******************************************************************************
*******************************************************************************
*******************************************************************************/

// Beschreibung:
// Der iotype ist eine Art Stream. 
// Die Schreibfunktion io_write haengt die Daten an das Ende des buffers an.
// Die Lesefunktionen lesen die Daten an der Position aktpos.
// Zusaetzlich gibt es noch eine io_change_check Funktion die je nach mode 
// schreibt oder liest => laden = saven 
// spaeter ueberlegen:
// nicht immer ist die ladefunktion = der savefunktion

/// Input / Output Class
class iotype
{
public:
  static const int32 bufferbuffersize;
  // Konstruktoren
  iotype();
  iotype(int8 _mode);
  iotype(char *_buffer,int32 _buffersize);
  iotype(iotype *neu);
  ~iotype();
  
  // Allgemeine Funktionen
  
  // Setzt den Standardfehlerstring (z.b "Configfile: test.cfg :")
  void setstandardfehler(string *_standardfehler);
  // Die interne Fehlerroutine ! (fehler wird an standardfehler angehaengt !)
  void fehler(const char *fehler);
  
  // Stream Tool d.h. read=write 
  void io_change_check(char *buffer,int32 buffersize);
  
  // Mode setzen/abfragen
  void set_read_mode();
  void set_write_mode();
  int8 getmode();
  
  // Einen buffer/iotype anhaengen
  void io_write(char zeichen);
  void io_write(const char *add_buffer,int32 add_buffersize);
  void io_write(iotype *add_io_objekt);
  
  // Einen buffer/stream lesen 
  void io_read_check(char *dest,int32 anzbytes=1);
  // Bei Fehler Rueckgabewert =-1 => Ueber Buffer hinausgelesen
  int io_read(char *dest,int32 anzbytes=1);
  // Die verbleibende Buffergroesse (darf noch gereaded werden !)
  int32 getreadable();
  
  // Die Bufferposition aendern 
  int32 getpos();
  int32 seek(int32 rel);
  int32 seekset(int32 pos);
  
  // Buffer leeren
  void clear();

  char *get_buffer(){return buffer;}
  int32 get_buffersize(){return buffersize;}
protected:
  int8 mode;
private:
  // Eigentlicher Stream
  char *buffer;
  int32 buffersize;

  int32 realbuffersize;
  int32 aktpos;
  
  string standardfehler;
  
  // iotype initialiseren
  void initiotype();
  
  // Bei einer Leseaktion ueber Buffer hinausRueckgabe !=0
  int bufferende(int32 toread);
};









/******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
                       D I E    C F G    K L A S S E :
*******************************************************************************
*******************************************************************************
*******************************************************************************
******************************************************************************/

/// config file class
class cfgtype
{
public:
  cfgtype(iotype *_ioptr);

  // Lesen oder schreiben je nach mode !! ***********************************
  //  void change_string_check(stringtype *_string);
  //  void change_string_check(char **_string);
  void change(string *_string){change_string_check(_string);}
  void change_string_check(string *_string);

  void change(char *zeichen){change_char_check(zeichen);}
  void change_char_check(char *zeichen);
  void change_int8_check(int8 *zahl);
  void change_int16_check(int16 *zahl);

  void change(int32 *zahl){change_int32_check(zahl);}
  void change_int32_check(int32 *zahl);

  void change(float *zahl){change_float_check(zahl);}
  void change_float_check(float *zahl);
  // haben im Lesemode keine Auswirkung !
  void change_rem_check(char *string);
  void change_entercode_check();
  // Eine Fehlerabfangroutine: 
  // lesemodus: liest einen string der marke sein muss
  // schreibmodus: schreibt einen string der enthaelt 
  void change_marke_check(const char *marke);
  
  // Auslesen ***************************************************************
  //  virtual void read_string_check(stringtype *string)=0;
  //  virtual void read_string_check(char **string)=0;
  virtual void read_string_check(string *string)=0;
  virtual void read_char_check(char *zeichen)=0;
  virtual void read_int8_check(int8 *zahl)=0;
  virtual void read_int16_check(int16 *zahl)=0;
  virtual void read_int32_check(int32 *zahl)=0;
  virtual void read_float_check(float *zahl)=0;

  // Saven ******************************************************************
  //  virtual void write_string(stringtype *string)=0;
  virtual void write_string(const char *string)=0;
  virtual void write_string(string *string)=0;
  virtual void write_char(char zeichen)=0;
  virtual void write_int8(int8 zahl)=0;
  virtual void write_int16(int16 zahl)=0;
  virtual void write_int32(int32 zahl)=0;
  virtual void write_float(float zahl)=0;
  virtual void write_rem(char *string)=0;
  virtual void write_entercode()=0;
  
  iotype *ioptr;
  
protected:
  // Lies einen char aus dem iotype
  inline char getbyte_check();
};



/******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
                     D I E    C F G T E X T   K L A S S E :
*******************************************************************************
*******************************************************************************
*******************************************************************************
******************************************************************************/

/// text-mode config files
class cfg_texttype : public cfgtype
{
public:
  cfg_texttype (iotype *_ioptr);

  // Auslesen (Rueckgabewert: Bei Fehler wird -1 zurueckgeliefert ansonsten 0
  //  void read_string_check(stringtype *string);
  void read_string_check(char **string);
  void read_string_check(string *string);
  void read_char_check(char *zeichen);
  void read_int8_check(int8 *zahl);
  void read_int16_check(int16 *zahl);
  void read_int32_check(int32 *zahl);
  void read_float_check(float *zahl);

  // Saven
  //  void write_string(stringtype *string);
  void write_string(const char *string);
  void write_string(string *string);
  void write_char(char zeichen);
  void write_int8(int8 zahl);
  void write_int16(int16 zahl);
  void write_int32(int32 zahl);
  void write_float(float zahl);
  void write_rem(char *string);
  void write_entercode();
private:
  
  // Rueckgabewert: ==0 => Kein endezeichen  !=0 => Endezeichen
  int endezeichen(char zeichen);
  // Liest solange bis ein Zeichen kein Endezeichen ist 
  void ignor_endezeichen();
  // Liest bis zu einem Endezeichen
  void read_until_endezeichen(string *dest);
  // Liest bis zum stringendezeichen ( " )      Nur fuern Emacs : "
  void read_until_string_endezeichen(string *dest);
  // aktpos nach Remende 
  void seek_to_remende();
};




/******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************
                    D I E    C F G B I N A E R   K L A S S E :
*******************************************************************************
*******************************************************************************
*******************************************************************************
******************************************************************************/

/// binary-mode config files
class cfg_binaertype : public cfgtype
{
public:
  cfg_binaertype(iotype *_ioptr); 
  
  // Auslesen (Rueckgabewert: Bei Fehler wird -1 zurueckgeliefert ansonsten 0
  //  void read_string_check(stringtype *string);
  void read_string_check(char **string);
  void read_string_check(string *string);
  void read_char_check(char *zeichen);
  void read_int8_check(int8 *zahl);
  void read_int16_check(int16 *zahl);
  void read_int32_check(int32 *zahl);
  void read_float_check(float *zahl);

  // Saven
  //  void write_string(stringtype *string);
  void write_string(const char *string);
  void write_string(string *string);
  void write_char(char zeichen);
  void write_int8(int8 zahl);
  void write_int16(int16 zahl);
  void write_int32(int32 zahl);
  void write_float(float zahl);
  // haben im cfg_binaertype garkeine Auswirkung !
  void write_rem(char *string);
  void write_entercode();
};



// Zum einfachen instantiieren !!
cfgtype *choose_cfgtype(iotype *ioptr,int8 mode);



// Change STL Containers of builtin data types
template<class X>
void change_container(iotype *ioptr,int8 mode,X &cont)
{
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    {
      cont.clear();
      int32 toread;
      cfgptr->read_int32_check(&toread);
      for (int a=0;a<toread;a++)
	{
	  typename X::value_type newelem;
	  cfgptr->change(&newelem);
	  cont.push_back(newelem);
	}
    }
  else
    {
      cfgptr->write_int32(cont.size());
      typename X::iterator pos;
      for (pos=cont.begin();pos!=cont.end();++pos)
	{
	  cfgptr->change(&(*pos));
	}
    }
  delete cfgptr;
}



#endif













