#include "menu.H"
#include "typecheck.H"

// event_managertype **********************************************************************
// event_managertype **********************************************************************
// event_managertype **********************************************************************
// event_managertype **********************************************************************
// event_managertype **********************************************************************
// event_managertype **********************************************************************

const char *event_managertype::headerstring="event_managertype";

event_managertype::event_managertype()
{
  parentspriteptr=NULL;
  parent=NULL;
  buffer=new strstreambuf;
  ausgabe=new ostream(buffer);
  eingabe=new istream(buffer);
  privatebuffer=1;
}

event_managertype::~event_managertype()
{
  deinit();
}

void event_managertype::set_parentspriteptr(sprite_lineartype *_parentspriteptr)
{
  parentspriteptr=_parentspriteptr;
}

void event_managertype::deinit()
{
  if (privatebuffer)
    {
      delete ausgabe;
      delete eingabe;
      delete buffer;
      privatebuffer=0;
    }
}

void event_managertype::reset_ausgabe(ostream *_ausgabe)
{
  deinit();
  ausgabe=_ausgabe;
}

int event_managertype::test_mausclick_input
(istream *ist,int32 *x,int32 *y,int32 *button)
{
  string evtype;
  streampos pos=ist->tellg();
  (*ist)>>evtype;
  int erg=1;
  if (evtype=="ButtonPress")
    {
      if ((*ist) >>*x>>*y>>*button)
	{
	  // Erfolgreich Event ausgelesen
	  erg=0;
	}
    }
  if (*ist)
    ist->seekg(pos);
  else
    fatalfehler("menu.C: test_mausclick_input(..): Got a wrong Input Stream");
  return erg;
}

int event_managertype::verarbeite_mausclick_input
(istream *ist,int32 *x,int32 *y,int32 *button)
{
  string evtype;
  streampos pos=ist->tellg();
  (*ist)>>evtype;
  if (evtype=="ButtonPress")
    {
      if ((*ist) >>*x>>*y>>*button)
	{
	  delete ist;
	  return 0;
	}
    }
  if (*ist)
    ist->seekg(pos);
  else
    fatalfehler("menu.C: verarbeite_mausclick_input(..): Got a wrong Input Stream");
  return 1;
}

istream &event_managertype::get_output()
{
  if (!privatebuffer)
    fatalfehler("event_managertype::get_output: don't have a own buffer => no istream");
  return *eingabe;
}

event_managertype *event_managertype::create(iotype *ioptr,int8 mode)
{
  if (ioptr->getmode()!=IOTYPE_READ_MODE)
    fatalfehler("event_managertype::create\n"
		"iotype isn't in read mode");

  int32 oldseek=ioptr->getpos();
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  string headerstring;
  cfgptr->read_string_check(&headerstring);
  delete cfgptr;
  ioptr->seekset(oldseek);

  // Welchen event_managertype initen *****************************************
  if (!strcmp(headerstring.c_str(),menutype::headerstring))
    {
      event_managertype *erg=new menutype;
      erg->change(ioptr,mode);
      return erg;
    }
  else if (!strcmp(headerstring.c_str(),buttontype::headerstring))
    {
      event_managertype *erg=new buttontype;
      erg->change(ioptr,mode);
      return erg;
    }
  else if (!strcmp(headerstring.c_str(),pushbuttontype::headerstring))
    {
      event_managertype *erg=new pushbuttontype;
      erg->change(ioptr,mode);
      return erg;
    }
  else if (!strcmp(headerstring.c_str(),modified_pushbuttontype::headerstring))
    {
      event_managertype *erg=new modified_pushbuttontype;
      erg->change(ioptr,mode);
      return erg;
    }
  //  else      
  cerr <<"menu.C: event_managertype::create(...): Wrong headerstring: "<<headerstring.c_str()<<endl;
  fatalfehler("see above");
#ifdef kickwarn
  return(NULL);
#endif
}


// root_event_managertype **********************************************************************
// root_event_managertype **********************************************************************
// root_event_managertype **********************************************************************
// root_event_managertype **********************************************************************
// root_event_managertype **********************************************************************

/*
int root_event_managertype::calc()
{
  istream *ist;
  while((ist=get_input()))
    {
      if (verarbeite_input(ist))
	{
	  cerr <<"menu.C: event_managertype::calc():\n"
	    "Got a unknown Event => Kill this event_managertype\n";
	  return 1;
	}
    }
  return 0;
}
*/

// menutype ***************************************************************************
// menutype ***************************************************************************
// menutype ***************************************************************************
// menutype ***************************************************************************
// menutype ***************************************************************************
// menutype ***************************************************************************

const char *menutype::headerstring="menutype";

menutype::menutype()
{
  spriteptr=NULL;
}

menutype::~menutype()
{
  if (spriteptr)
    allsprites_ketteptr->delete_elementadress(spriteptr);
}

int menutype::calc()
{
  if (!parentspriteptr)
    cerr << "menutype::calc() : I should Paint me in a nonexisting parent sprite\n";
  else
    if (spriteptr)
      spriteptr->copysprite_clip(0,0,parentspriteptr);
#ifdef DEBUG_menu_H
    else 
      parentspriteptr->malerechteck_clip(-mx,-my,sx,sy,32);
#endif
  kette_calc(&childkette);
  return 0;
}

int menutype::calc(const rechtecktype &rect)
{
  if (!parentspriteptr)
    cerr << "menutype::calc() : I should Paint me in a nonexisting parent sprite\n";
  else
    if (spriteptr)
      spriteptr->copysprite_clip_to(0,0,parentspriteptr,rect);
#ifdef DEBUG_menu_H
    else 
      parentspriteptr->malerechteck_clip(-mx,-my,sx,sy,32);
#endif
  typename kette_changetype<event_managertype>::iteratortype akt;
  akt=childkette.anfang->next;
  while (akt!=childkette.ende)
    {
      if (akt->calc(rect))
	{
	  akt=akt->next;
	  childkette.delbefore(akt);
	}
      else
	akt=akt->next;
    }
  return 0;
}



void menutype::set_parentspriteptr(sprite_lineartype *_parentspriteptr)
{
  event_managertype::set_parentspriteptr(_parentspriteptr);
  event_managertype *akt=childkette.anfang->next;
  while (akt!=childkette.ende)
    {
      akt->set_parentspriteptr(_parentspriteptr);
      akt=akt->next;
    }
}
event_managertype *menutype::addmenu(const char *filename)
{
  iotype *aktioptr=make_file_to_io_check(filename);
  event_managertype *neues=event_managertype::create(aktioptr,CFG_TEXT_MODE);
  //  cout << *neues;
  addmenu(neues);
  delete aktioptr;
  return neues;
}

void menutype::addmenu(event_managertype *neu)
{
  if (!anzmenus())
    {
      mx=neu->mx;
      my=neu->my;
      sx=neu->sx;
      sy=neu->sy;
    }
  else
    addrechteck(*neu);
  childkette.zeiger_push(neu);
  neu->set_parentspriteptr(parentspriteptr);
  neu->reset_ausgabe(ausgabe);
  neu->set_parent(this);
}

void menutype::change(iotype *ioptr,int8 mode)
{
  if (ioptr->getmode()==IOTYPE_WRITE_MODE)
    fatalfehler("menu.C: menutype::change: write mode not yet implemented");
  check_or_save_header(this,ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_string_check(&spritename);
  int32 anzmenues;
  cfgptr->change_int32_check(&anzmenues);
  for (int32 akt=0;akt<anzmenues;akt++)
    {
      string filename;
      cfgptr->change_string_check(&filename);
      addmenu(filename.c_str());
    }
  cfgptr->change_marke_check("ende");
  cfgptr->change_string_check(&defaultout);
  delete cfgptr;
  if (ioptr->getmode()==IOTYPE_READ_MODE)
    init();
}

int menutype::verarbeite_input(istream *ist)
{
  int32 _x,_y,_button;
  if (test_mausclick_input(ist,&_x,&_y,&_button))
    {
      // War kein Mausclick
      cerr << "menu.C: menutype::verarbeite_input(...) : Got a unknown Event\n";
      delete ist;
      return 0;
    }
  // Wer kriegt den Event jetzt ?
  event_managertype *akt=childkette.anfang->next;
  while (akt!=childkette.ende)
    {
      if (akt->punktinrechteck(_x,_y))
	{
	  //	  cout << "menutype::verarbeite_input: Event forwarded\n";
	  return akt->verarbeite_input(ist);
	}
      //      cout << "mx my sx sy :"<<akt->mx<<" "<<akt->my<<" "<<akt->sx<<" "<<akt->sy<<endl;
      akt=akt->next;
    }
  if (defaultout=="")
    cout << "menutype::verarbeite_input: kicked Event x: "<<_x<<" y: "<<_y<<endl;
  else 
    {
      cout << "menutype::verarbeite_input: Send msg. "<<defaultout<<endl;
      *ausgabe <<defaultout<<endl;
    }
  delete ist;
  return 0;
}

void menutype::reset_ausgabe(ostream *_ausgabe)
{
  event_managertype::reset_ausgabe(_ausgabe);
  event_managertype *akt=childkette.anfang->next;
  while (akt!=childkette.ende)
    {
      akt->reset_ausgabe(ausgabe);
      akt=akt->next;
    }
}

void menutype::init()
{
  if (strcmp("",spritename.c_str()))
    spriteptr=allsprites_ketteptr->make_elementadress(spritename.c_str());
  event_managertype *akt=childkette.anfang->next;
  while (akt!=childkette.ende)
    {
      akt->reset_ausgabe(ausgabe);
      akt=akt->next;
    }
}


void menutype::killmenus()
{
  childkette.clear();
}

void menutype::killmenu(event_managertype *menu)
{
  rechtecktype rect(*menu);
  childkette.del(menu);
  calc(rect);
}

uint32 menutype::anzmenus()
{
  return childkette.anzzeigerelem;
}



// buttontype ************************************************************
// buttontype ************************************************************
// buttontype ************************************************************
// buttontype ************************************************************
// buttontype ************************************************************

const char *buttontype::headerstring="buttontype";

int buttontype::calc()
{
  // Male Dich !! => brauche ein Parent Sprite !!
  if (!parentspriteptr)
    cerr << "buttontype::calc() : I should Paint me in a nonexisting parent sprite\n";
  else if (spriteptr)
    {
      if (!maxpect)
	spriteptr->copysprite_clip(posx,posy,parentspriteptr);
      else
	spriteptr->copysprite_maxpect_to(parentspriteptr,*((rechtecktype *)this));
    }
#ifdef DEBUG_menu_H
  else 
    parentspriteptr->malerechteck_clip(-mx,-my,sx,sy,32);
#endif    
  return 0;
}
int buttontype::calc(const rechtecktype &rect)
{
  // Male Dich !! => brauche ein Parent Sprite !!
  if (!parentspriteptr)
    cerr << "buttontype::calc() : I should Paint me in a nonexisting parent sprite\n";
  else if (spriteptr)
    {
      if (!maxpect)
	spriteptr->copysprite_clip_to(posx,posy,parentspriteptr,rect);
      else
	// todo  this does not !! clip against rect yet !!
	spriteptr->copysprite_maxpect_to(parentspriteptr,*((rechtecktype *)this));
    }
#ifdef DEBUG_menu_H
  else 
    parentspriteptr->malerechteck_clip(-mx,-my,sx,sy,32);
#endif
  return 0;
}


void buttontype::change(iotype *ioptr,int8 mode)
{
  check_or_save_header(this,ioptr,mode);
  rechtecktype::change(ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_string_check(&msg);
  delete cfgptr;
}

int buttontype::verarbeite_input(istream *ist)
{
  // todo muss gucken ob es ein clickevent ist !
  int32 _x,_y,_button;
  if (verarbeite_mausclick_input(ist,&_x,&_y,&_button))
    {
      cerr << "menu.C: buttontype::verarbeite_input(...) : Got a unknown Event\n";
      delete ist;
      return 0;
    }
  *ausgabe <<msg<<endl; 
  return 0;
}


// pushbuttontype **********************************************************************
// pushbuttontype **********************************************************************
// pushbuttontype **********************************************************************
// pushbuttontype **********************************************************************
// pushbuttontype **********************************************************************
// pushbuttontype **********************************************************************

const char *pushbuttontype::headerstring="pushbuttontype";

pushbuttontype::pushbuttontype()
{
  spriteptr=NULL;
}

pushbuttontype::~pushbuttontype()
{
  if (spriteptr)
    allsprites_ketteptr->delete_elementadress(spriteptr);
}

void pushbuttontype::ipaint(int _x,int _y)
{
  if (!parentspriteptr)
    cerr << "pushbuttontype::paint() : I should Paint me in a nonexisting parent sprite\n";
  else
    {
      spriteptr->copysprite_clip(_x,_y,parentspriteptr,aktindex);
      //      cout <<"aktindex: "<<aktindex<<endl;
    }
}
void pushbuttontype::ipaint(int _x,int _y,const rechtecktype &rect)
{
  if (!parentspriteptr)
    cerr << "pushbuttontype::paint() : I should Paint me in a nonexisting parent sprite\n";
  else
    {
      spriteptr->copysprite_clip_to(_x,_y,parentspriteptr,rect,aktindex);
    }
}

int pushbuttontype::calc()
{
  // Male Dich !! => brauche ein Parent Sprite !!
  ipaint(0,0);
  return 0;
}
int pushbuttontype::calc(const rechtecktype &rect)
{
  // Male Dich !! => brauche ein Parent Sprite !!
  ipaint(0,0,rect);
  return 0;
}
void pushbuttontype::setindex(int32 _index)
{
  int a=0;
  string_zeigerelemtype *akt=messages.anfang->next;
  while (akt!=messages.ende)
    {
      if (a==_index)
	{
	  aktmessage=akt;
	  aktindex=_index;
	  return;
	}
      akt=akt->next;
      a++;
    }
  cout << "pushbuttontype::setindex(): illegal index !\n";
  return;
}

void pushbuttontype::change(iotype *ioptr,int8 mode)
{
  check_or_save_header(this,ioptr,mode);
  messages.change(ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_string_check(&spritename);
  delete cfgptr;
  if (ioptr->getmode()==IOTYPE_READ_MODE)
      init();
}

int pushbuttontype::verarbeite_input(istream *ist)
{
  // todo muss gucken ob es ein clickevent ist !
  int32 _x,_y,_button;
  if (verarbeite_mausclick_input(ist,&_x,&_y,&_button))
    {
      cerr << "menu.C: pushbuttontype::verarbeite_input(...) : Got a unknown Event\n";
      delete ist;
      return 0;
    }
  *ausgabe << (string)*aktmessage<<endl; //todo geht das noch ??
  //  cout <<"Angekommen"<<endl;
  if (aktmessage->next!=messages.ende)
    {
      aktmessage=aktmessage->next;
      aktindex++;
      //  cout <<"Erhoeht\n";
    }
  else
    {
      aktmessage=messages.anfang->next;
      aktindex=0;
    }
  // todo Alter Hintergrund
  if ((spriteptr)&&(parentspriteptr))
    paintparent(rechtecktype(*this));
  // Neues Sprite malen
  calc();
  parentspriteptr->map(rechtecktype(*this));
  return 0;
}

void pushbuttontype::init()
{
  spriteptr=allsprites_ketteptr->make_elementadress(spritename.c_str());
  if (messages.anzzeigerelem!=1)
    {
      // todo muss nicht unbedingt sein aber ist ok so
      if (strcmp(spriteptr->getheaderstring(),"sprite_indextype"))
	fatalfehler("menu.C: pushbuttontype::init(): sprite must be a sprite_indextype when using multiple messages");
      sprite_indextype *testit=(sprite_indextype *)spriteptr;
      if (testit->anzsprites()!=messages.anzzeigerelem)
	fatalfehler("menu.C: pushbuttontype::init():\n"
		    "sprite_indextype must have as much sprites as the button messages");
    }
  mx=spriteptr->mx;
  my=spriteptr->my;
  sx=spriteptr->sx;
  sy=spriteptr->sy;
  aktindex=0;
  aktmessage=messages.anfang->next;
}





// modified_pushbuttontype ******************************************************************
// modified_pushbuttontype ******************************************************************
// modified_pushbuttontype ******************************************************************
// modified_pushbuttontype ******************************************************************
// modified_pushbuttontype ******************************************************************
const char *modified_pushbuttontype::headerstring="modified_pushbuttontype";
// Relikt aus vergangenen Zeiten ;-)
// todo weg damit
modified_pushbuttontype::modified_pushbuttontype
(const char *filename,const char *_prefix,int32 _relx,int32 _rely)
{
  iotype *ioptr=make_file_to_io_check(filename);
  pushbuttontype::change(ioptr,CFG_TEXT_MODE);
  delete ioptr;
  prefix=_prefix;
  // todo net so gut eigentlich !!
  mx-=_relx;
  my-=_rely;
  relx=_relx;
  rely=_rely;
}
int modified_pushbuttontype::verarbeite_input(istream *ist)
{
  *ausgabe << prefix;
  pushbuttontype::verarbeite_input(ist);
  //    *ausgabe << endl;
  // todo was ist wenn der pushbutton nen falschen event kriegt !!
  return 0;
}

void modified_pushbuttontype::change(iotype *ioptr,int8 mode)
{
  check_or_save_header(this,ioptr,mode);
  pushbuttontype::change(ioptr,mode);
  cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
  cfgptr->change_string_check(&prefix);
  cfgptr->change_int32_check(&relx);
  cfgptr->change_int32_check(&rely);
  delete cfgptr;
  // todo net so gut eigentlich !! - Warum ??
  mx-=relx;
  my-=rely;
}

int modified_pushbuttontype::calc()
{
  ipaint(relx,rely);
  return 0;
}

int modified_pushbuttontype::calc(const rechtecktype &rect)
{
  ipaint(relx,rely,rect);
  return 0;
}



















