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

#include "iotype.H"




/******************************************************************************
*******************************************************************************
*******************************************************************************
*******************************************************************************

                       D I E    I O    K L A S S E

*******************************************************************************
*******************************************************************************
*******************************************************************************
******************************************************************************/

// Konstruktoren
iotype::iotype()
{
    initiotype();
    mode=IOTYPE_WRITE_MODE;
}

iotype::iotype(int8 _mode)
{
    initiotype();
    if ((mode==IOTYPE_READ_MODE)||(mode==IOTYPE_WRITE_MODE))
	mode=_mode;
    else
	fatalfehler("iotype::iotype(int8 _mode):\n"
		    "Sie wollten einen unzulaessigen mode setzen !");
}

iotype::iotype(char *_buffer,int32 _buffersize)
{
    initiotype();
    buffer=_buffer;
    buffersize=_buffersize;
    realbuffersize=buffersize;
    mode=IOTYPE_READ_MODE;
}
    
iotype::iotype(iotype *neu)
{
    initiotype();
    io_write(neu);
    mode=IOTYPE_READ_MODE;
}

iotype::~iotype()
{
    delete buffer;
}

// Mode setzen/abfragen
void iotype::set_read_mode()
{
    mode=IOTYPE_READ_MODE;
}

void iotype::set_write_mode()
{
    mode=IOTYPE_WRITE_MODE;
}
 
int8 iotype::getmode()
{
    return(mode);
}


// Allgemeine Funktionen ******************************************************
void iotype::setstandardfehler(string *_standardfehler)
{
    standardfehler=*_standardfehler;
}

void iotype::io_change_check(char *buffer,int32 buffersize)
{
    if (mode==IOTYPE_READ_MODE)
	{
	    io_read_check(buffer,buffersize);
	    return;
	}
    io_write(buffer,buffersize);
}

const int32 iotype::bufferbuffersize=50;

void iotype::io_write(char zeichen)
{
    int32 oldsize=buffersize;
    buffersize++;
    if (buffersize>realbuffersize)
      {
	realbuffersize+=bufferbuffersize;
	char * newb=new char[realbuffersize];
	if (oldsize)
	  {
	    memcpy(newb,buffer,oldsize);
	    delete buffer;
	  }
	buffer=newb;
      }
    *(buffer+oldsize)=zeichen;
}

void iotype::io_write(const char *add_buffer,int32 add_buffersize)
{
    int32 oldsize=buffersize;
    buffersize+=add_buffersize;
    if (buffersize>realbuffersize)
      {
	realbuffersize+=bufferbuffersize+add_buffersize;
	char * newb=new char[realbuffersize];
	if (oldsize)
	  {
	    memcpy(newb,buffer,oldsize);
	    delete buffer;
	  }
	buffer=newb;
      }
    memcpy(buffer+oldsize,add_buffer,add_buffersize);
}

void iotype::io_write(iotype *add_io_objekt)
{
    io_write(add_io_objekt->buffer,add_io_objekt->buffersize);
}

void iotype::io_read_check(char *dest,int32 anzbytes)
{
    if (bufferende(anzbytes))
	{
	    fehler("Ueber Buffer hinausgelesen");
	}
    memcpy(dest,buffer+aktpos,anzbytes);
    aktpos+=anzbytes;
}

int iotype::io_read(char *dest,int32 anzbytes)
{
    if (bufferende(anzbytes))
	{
	    return(-1);
	}
    memcpy(dest,buffer+aktpos,anzbytes);
    aktpos+=anzbytes;
    return(0);
}

int32 iotype::getreadable()
{
    return(buffersize-aktpos);
}

int32 iotype::getpos()
{
  return aktpos;
}

int32 iotype::seek(int32 rel)
{
    return aktpos+=rel;
}

int32 iotype::seekset(int32 pos)
{
  if ((pos<0)||(pos>=buffersize))
    fehler("iotype::seekset: zeiger ausserhalb des buffers positioniert !");
  return (aktpos=pos);
}

void iotype::clear()
{
  if (buffersize)
    delete buffer;
  buffer=NULL;
  aktpos=0;
  buffersize=0;
  realbuffersize=0;
}

// Private Funktionen *********************************************************
void iotype::initiotype()
{
	buffer=NULL;
	buffersize=0;
	clear();
}

void iotype::fehler(const char *fehler)
{
    string aktfehler(standardfehler);
    aktfehler+=fehler;
    fatalfehler(aktfehler.c_str());
}

int iotype::bufferende(int32 toread)
{
    return(aktpos+toread>buffersize);
}







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


cfgtype::cfgtype(iotype *_ioptr)
{
    ioptr=_ioptr;
}

/*
void cfgtype::change_string_check(stringtype *_string)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	read_string_check(_string);
    else
	write_string(_string);
}

void cfgtype::change_string_check(char **_string)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	read_string_check(_string);
    else
	write_string(*_string);
}
*/

void cfgtype::change_string_check(string *_string)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	read_string_check(_string);
    else
	write_string(_string);
}

void cfgtype::change_char_check(char *zeichen)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	read_char_check(zeichen);
    else
	write_char(*zeichen);
}

void cfgtype::change_int8_check(int8 *zahl)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	read_int8_check(zahl);
    else
	write_int8(*zahl);
}

void cfgtype::change_int16_check(int16 *zahl)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	read_int16_check(zahl);
    else
	write_int16(*zahl);
}

void cfgtype::change_int32_check(int32 *zahl)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	read_int32_check(zahl);
    else
	write_int32(*zahl);
}

void cfgtype::change_float_check(float *zahl)
{
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	read_float_check(zahl);
    else
	write_float(*zahl);
}

void cfgtype::change_rem_check(char *_string)
{
    if (ioptr->getmode()==IOTYPE_WRITE_MODE)
	write_rem(_string);
}

void cfgtype::change_entercode_check()
{
    if (ioptr->getmode()==IOTYPE_WRITE_MODE)
	write_entercode();
}

void cfgtype::change_marke_check(const char *marke)
{
    string endestring;
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	{
	    read_string_check(&endestring);
	    if (endestring!=string(marke))
		{
		  string fehlerstring("cfgtype::change_marke_check:\n\"");
		  fehlerstring+=marke;
		  fehlerstring+="\"-Mark not found !\n read instead : \"";
		  fehlerstring+=endestring;
		  fehlerstring+='\"'; // for emacs "
		  ioptr->fehler(fehlerstring.c_str());
		}
#ifdef DEBUG_iotype_H	    
	    cout <<"Mark found :"<<marke<<endl;
#endif
	}
    else
      {
	write_string(marke);
      }    
}

inline char cfgtype::getbyte_check()
{
    char zeichen;
    if (ioptr->io_read(&zeichen))
	ioptr->fehler("cfgtype::getbyte_check() : Ueber Bufferende hinausgelesen !");
    return(zeichen);
}







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


cfg_texttype::cfg_texttype (iotype *_ioptr) : cfgtype (_ioptr)
{
};

void cfg_texttype::read_string_check(string *_string)
{
  *_string="";
  ignor_endezeichen();
  char zeichen=getbyte_check();
  while (zeichen=='#')
    {
      seek_to_remende();
      ignor_endezeichen();
      zeichen=getbyte_check();
    }
  if (zeichen=='\"') // fuern emacs "
    {
      read_until_string_endezeichen(_string);
    }
  else
    {
      ioptr->seek(-1);
      read_until_endezeichen(_string);
    }
}

void cfg_texttype::read_char_check(char *zeichen)
{
    string neuer;
    read_string_check(&neuer);
    *zeichen=neuer[0];
}

void cfg_texttype::read_int8_check(int8 *zahl)
{
    string neuer;
    read_string_check(&neuer);
    *zahl=atoi(neuer.c_str());
}

void cfg_texttype::read_int16_check(int16 *zahl)
{
    string neuer;
    read_string_check(&neuer);
    *zahl=atoi(neuer.c_str());
}

void cfg_texttype::read_int32_check(int32 *zahl)
{
    string neuer;
    read_string_check(&neuer);
    *zahl=atoi(neuer.c_str());
}

void cfg_texttype::read_float_check(float *zahl)
{
    string neuer;
    read_string_check(&neuer);
    *zahl=atof(neuer.c_str());
}

void cfg_texttype::write_string(string *_string)
{
    string schuster("\""); // fuern emacs "
    schuster+=*_string;
    schuster+='"';         // fuern emacs "
    ioptr->io_write(schuster.c_str(),schuster.length());
}

void cfg_texttype::write_string(const char *_string)
{
    string neuer(_string);
    write_string(&neuer);
}

void cfg_texttype::write_char(char zeichen)
{
    ioptr->io_write(zeichen);
    ioptr->io_write(';');
}

void cfg_texttype::write_int8(int8 zahl)
{
    string neuer(any_to_string(zahl));
    neuer+=';';
    ioptr->io_write(neuer.c_str(),neuer.length());
}

void cfg_texttype::write_int16(int16 zahl)
{
    string neuer(any_to_string(zahl));
    neuer+=';';
    ioptr->io_write(neuer.c_str(),neuer.length());
}

void cfg_texttype::write_int32(int32 zahl)
{
    string neuer(any_to_string(zahl));
    neuer+=';';
    ioptr->io_write(neuer.c_str(),neuer.length());
}

void cfg_texttype::write_float(float zahl)
{
    string neuer(any_to_string(zahl));
    neuer+=';';
    ioptr->io_write(neuer.c_str(),neuer.length());
}

void cfg_texttype::write_rem(char *str)
{
    string rem("#");
    rem+=str;
    write_string(&rem);
    write_entercode();
}

void cfg_texttype::write_entercode()
{
    ioptr->io_write('\n');
}






// PRIVATE FUNKTIONEN *********************************************************



int cfg_texttype::endezeichen(char zeichen)
{
    return( (zeichen==';')||(zeichen=='\n')||(zeichen==' ') );
}

void cfg_texttype::ignor_endezeichen()
{
    char zeichen;
    do
	{
	    zeichen=getbyte_check();
	}
    while (endezeichen(zeichen));
    ioptr->seek(-1);
}

void cfg_texttype::read_until_endezeichen(string *dest)
{
    char zeichen;
    for(;;)
    {
	zeichen=getbyte_check();
	if (endezeichen(zeichen))
	    break;
	(*dest)+=zeichen;
    }
}

void cfg_texttype::read_until_string_endezeichen(string *dest)
{
    char zeichen;
    for(;;)
	{
	    zeichen=getbyte_check();
	    if (zeichen=='\"') // fuern emacs "
		break;
	    (*dest)+=zeichen;
	}
}

void cfg_texttype::seek_to_remende()
{
    while(getbyte_check()!='\n');
}





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


cfg_binaertype::cfg_binaertype(iotype *_ioptr) : cfgtype (_ioptr)
{
}
void cfg_binaertype::read_string_check(string *str)
{
  *str="";
  char zeichen;
  for(;;)
    {
      zeichen=getbyte_check();
      if (!zeichen)
	break;
      (*str)+=zeichen;
    }
}
/*
void cfg_binaertype::read_string_check(char **string)
{
    string neuer;
    read_string_check(&neuer);
    neuer.make_charptrptr(string);
}
*/

void cfg_binaertype::read_char_check(char *zeichen)
{
    *zeichen=getbyte_check();
}

void cfg_binaertype::read_int8_check(int8 *zahl)
{
    if (ioptr->io_read((char *)zahl,sizeof(*zahl)))
	ioptr->fehler("cfg_binaertype::read_int8_check(): "
		      "Ueber Bufferende hinausgelesen !");
}

void cfg_binaertype::read_int16_check(int16 *zahl)
{
    if (ioptr->io_read((char *)zahl,sizeof(*zahl)))
	ioptr->fehler("cfg_binaertype::read_int16_check(): "
		    "Ueber Bufferende hinausgelesen !");
}

void cfg_binaertype::read_int32_check(int32 *zahl)
{
    if (ioptr->io_read((char *)zahl,sizeof(*zahl)))
	ioptr->fehler("cfg_binaertype::read_int32_check(): "
		    "Ueber Bufferende hinausgelesen !");
}

void cfg_binaertype::read_float_check(float *zahl)
{
    if (ioptr->io_read((char *)zahl,sizeof(*zahl)))
	ioptr->fehler("cfg_binaertype::read_float_check() : Ueber Bufferende hinausgelesen !");
}


void cfg_binaertype::write_string(const char *string)
{
    ioptr->io_write(string,strlen(string)+1);
}

void cfg_binaertype::write_string(string *string)
{
  ioptr->io_write(string->c_str(),strlen(string->c_str())+1);
}

void cfg_binaertype::write_char(char zeichen)
{
    ioptr->io_write(zeichen);
}

void cfg_binaertype::write_int8(int8 zahl)
{
    ioptr->io_write((char*)&zahl,sizeof(zahl));
}

void cfg_binaertype::write_int16(int16 zahl)
{
    ioptr->io_write((char*)&zahl,sizeof(zahl));
}

void cfg_binaertype::write_int32(int32 zahl)
{
    ioptr->io_write((char*)&zahl,sizeof(zahl));
}

void cfg_binaertype::write_float(float zahl)
{
    ioptr->io_write((char*)&zahl,sizeof(zahl));
}

void cfg_binaertype::write_rem(char *)
{
}

void cfg_binaertype::write_entercode()
{
}








// ***************************************************************************
// ***************************************************************************
// ***************************************************************************
//             Zum einfachen instantiieren
// ***************************************************************************
// ***************************************************************************
// ***************************************************************************

cfgtype *choose_cfgtype(iotype *ioptr,int8 mode)
{
  if (mode==CFG_TEXT_MODE)
    return( (cfgtype *)(new cfg_texttype(ioptr)) );
  else 
    if (mode==CFG_BINAER_MODE)
      return( (cfgtype *)(new cfg_binaertype(ioptr)) );
  fatalfehler("choose_cfgtype : Diesen cfgtype gibt es nicht !");
  return(NULL);
}



