#ifndef _tudinc_client_H
#define _tudinc_client_H_

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

                    T U D    C L I E N T  -  M O D U L

                    H E A D E R D A T E I

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


#include "tudinc.H"
#include "scrX11.H"
#include "menu.H"
#include "yyysound_client_noexception.H"

// Hat hier eigentlich nix verloren !!! spaeter todo
class transformtype
{
public:
  transformtype(spieler_zeigerelemtype *_ich);
  void scr_to_spr(int32 scrx,int32 scry,int32 *sprx,int32 *spry);
  void spr_to_scr(int32 sprx,int32 spry,int32 *scrx,int32 *scry);
  void calc();
  void rotate(float _winkel_to)
  {
    winkel_to=_winkel_to;
  }
  void turnleft()
  {
    winkel_to-=M_PI_4/2;
  }
  void turnright()
  {
    winkel_to+=M_PI_4/2;
  }
  void scroll(int32 _tx,int32 _ty)
  {
    tx_to=_tx;
    ty_to=_ty;
  }
  void scrollup()
    {
       ty_to-=ftoi(float(40)/vzoom);
    }
  void scrolldown()
    {
      ty_to+=ftoi(float(40)/vzoom);
    }
  void scrollleft()
    {
      tx_to-=ftoi(float(40)/vzoom);
    }
  void scrollright()
    {
      tx_to+=ftoi(float(40)/vzoom);
    }

  
  void zoomto(float _zoom_to)
  {
    zoom_to=_zoom_to;
  }
  void zoomin()
  {
    zoom_to+=0.1;
  }
  void zoomout()
  {
    zoom_to-=0.1;
  }
  int transforming();

  int32 tx()
  {
    return vtx;
  }
  int32 ty()
  {
    return vty;
  }
  float winkel()
  {
    return vwinkel;
  }
  float zoom()
  {
    return vzoom;
  }
private:
  int32 vtx,vty;
  float vwinkel,vzoom;

  int totransform();
  void incfloat(float &aktvalue,const float incvalue,const float incspeed) const;

  float winkel_to,zoom_to;
  int transformed;
  int32 tx_to,ty_to;
  float akttx,aktty;
};


class bardiag_type : public rechtecktype
{
public:
  bardiag_type(int _mx,int _my,int _sx,int _sy,char _fcolor,char _bcolor,sprite_lineartype *_spr) : rechtecktype(_mx,_my,_sx,_sy)
    {
      fcolor=_fcolor;
      bcolor=_bcolor;
      spr=_spr;
      oldv=0;
      setvalue(1.0);
      /*
      int tx1=-300,ty1=100,tsx=300,tsy=40;
      spr->malerechteck_flaeche_clip(tx1,ty1,tsx,tsy,fcolor);
      rechtecktype rect(-tx1,-ty1,tsx,tsy);
      spr->malerechteck(tx1,ty1,tsx,tsy,fcolor);
      spr->map(rect);
      ty1+=tsy;
      spr->malerechteck_flaeche_clip(tx1,ty1,tsx,tsy,bcolor);
      spr->malerechteck(tx1,ty1,tsx,tsy,bcolor);
      rect=rechtecktype(-tx1,-ty1,tsx,tsy);
      spr->map(rect);
      spr->kreis(0,0,200,32);
      spr->kreis(0,0,210,allsprites_ketteptr->paletteptr->white());
      spr->map();
      */
    }
  void setvalue(float v)
    {
      if (v<0.0)
	v=0.0;
      else if (v>1.0)
	v=1.0;
      int newv=ftoi(float(sx)*v);
      if (newv>oldv)
	{
	  spr->malerechteck_flaeche_clip(-mx+oldv,-my,newv-oldv,sy,fcolor);
	  rechtecktype rect(mx-oldv,my,newv-oldv,sy);
	  spr->map(rect);
	  oldv=newv;
	}
      else if (newv<oldv)
	{
	  spr->malerechteck_flaeche_clip(-mx+newv,-my,oldv-newv,sy,bcolor);
	  rechtecktype rect(mx-newv,my,oldv-newv,sy);
	  spr->map(rect);
	  oldv=newv;
	}
    }
private:
  char fcolor;
  char bcolor;
  int oldv;
  sprite_lineartype *spr;
};



class einheit_client_zeigerelemtype 
  : public virtual einheittype, public zeigerelem_changetype<einheit_client_zeigerelemtype>
{
public:
  // Spezial routine um objekte mit abgeleiteten virtuellen routinen einheitlich zu erstellen !!
  // wird in listen2.H verwendet (kette_iqtype)
  // erstellt einen einheit_server_zeigerelemtype aus einem stream 
  // (und erkennt anhand eines headerstrings was fuer eine einheit es ist)
  static einheit_client_zeigerelemtype *create(iotype *ioptr,int8 mode);

  // Einzelkomponenten von calc !
  void calcsprite();
  void calcflag();
  // Malt Einheit (Wird von der Kette automatisch aufgerufen) 
  virtual int calc();

  // Laden speichern
  virtual void change(iotype *ioptr,int8 mode){einheittype::change(ioptr,mode);}

  // paint icon into rectangular window in sprite spr
  virtual void paintto(sprite_lineartype *spr,const rechtecktype &rect);

  // update all displays of selected unit
  virtual void update_displays();
  // update displays depend on contents
  virtual void update_displays_depend_contents(); 
  // update bar diag
  void paint_substanz();
  // update volume display
  void paint_volume();
  // update lend from display
  void paint_lendfrom();
  // update lend to and give menu and actplayer picture
  void update_lend_give();

  /// All that is related to the state screen
  // einheit selected => prepare status menu
  virtual void status_activate(menutype *_tud_menuptr);
  // create status submenus
  //  virtual void status_addmenus();
  // remove status menu (einheit isn't selected any more)
  virtual void status_deactivate();
  bool is_active() const {return active;}

  einheit_client_zeigerelemtype();
  virtual ~einheit_client_zeigerelemtype();

  // Wegen Reload
  int reloaded;

  // active player rectangle
  static rechtecktype actplayer_rect;
protected:
  // Damit nicht immer neu rotated werden muss
  // => Altes rotated sprite merken !
  spritetype *oldsprite;
  float oldwinkel;
  float oldzoom;

  // Status 
  menutype *tud_menuptr;
  menutype *status_menuptr;

  bool active;

  // Substanz display
  bardiag_type *box;
  bardiag_type *volume_box;
  //lend from display
  rechtecktype lendfrom_rect;
  buttontype *lendfrom_menuptr;

  //lend and give menus
  buttontype *lendto_menuptr;
  buttontype *give_menuptr;
};

class einheit_client_kettetype 
  : public kette_changetype<einheit_client_zeigerelemtype>
{
public:
  // NB: beste einheit mit kontakt oder NULL
  einheit_client_zeigerelemtype *best_near(einheit_client_zeigerelemtype *akt);
  void change(iotype *ioptr,int8 mode);
  // Sortiert die Liste so wie die Einheiten nacheinander dargestellt werden sollen
  // todo sind sie nicht doch schon richtig sortiert ? vom server her ?
  void zeiger_insert_sorted(einheit_client_zeigerelemtype *neues);
  // find first vehicle of player no (NULL there is none)
  einheit_client_zeigerelemtype *find_first_of(int32 spielernummer)
  {
    einheit_client_zeigerelemtype *akt=anfang->next;
    while (akt!=ende)
      {
	if (akt->spielernummer==spielernummer)
	  return akt;
	akt=akt->next;
      }
    return NULL;
  }
};

// Dynamische Firmendaten des Klienten ****************************************************
// Dynamische Firmendaten des Klienten ****************************************************
// Dynamische Firmendaten des Klienten ****************************************************

class firma_client_zeigerelemtype
  : public firmatype, public einheit_client_zeigerelemtype
{
public:
  firma_client_zeigerelemtype() : iconrect(372,-22,55,50)
  {
    firma_menuptr=NULL;
  }
  
  ~firma_client_zeigerelemtype()
  {
    //    if (status_activated)
    //status_deactivate();
  }


  int calc();
  void change(iotype *ioptr,int8 mode){firmatype::change(ioptr,mode);}
  
  // Status
  void update_displays();
  void status_activate(menutype *_tud_menuptr);
  void status_addmenus();
  void status_deactivate();
  void paint_build_icon();
  void paint_buildbox();
  void update_displays_depend_contents()
    {
      einheit_client_zeigerelemtype::update_displays_depend_contents();
      make_buildable_buttons();
    }
  void make_buildable_buttons();

  //  int verarbeite_input(istream *ist);

private:
  // NB: 1 <=> min. eine Einheit ist in der Firma
  //     0 <=> keine Einheit ist in der Firma
  int einheit_in_firma();
  int oldoffen;

  // Status
  string oldtobuild;
  product_datentype *status_product_datenptr;
  rechtecktype iconrect;
  // building display
  bardiag_type *buildbox;
  // build menus
  menutype *firma_menuptr;


  /*
  int status_activated;
  int state_details;
  int status_buildmenu;
  strstreambuf *status_buffer;
  ostream *ausgabe;
  ostream *status_ausgabe;
  istream *status_eingabe;
  string status_tobuildtype;
  product_datentype *status_newproduct_datenptr;
  string_zeigerelemtype *status_aktobj;
  string_zeigerelemtype *status_aktveh;
  menutype *status_firma_menuptr;*/
};


// Dynamische canondaten  ****************************************************
// Dynamische canondaten  ****************************************************
// Dynamische canondaten  ****************************************************

class canon_clienttype : public canontype, public zeigerelemtype<canon_clienttype>
{
public:
  static canon_clienttype *create(iotype *ioptr,int8 mode,canon_datentype *_canon_datenptr, canon_kette_basetype *_canon_kette_baseptr,einheittype *_einheitptr)
  {
    canon_clienttype *erg=new canon_clienttype(_canon_datenptr,_canon_kette_baseptr,_einheitptr);
    erg->change(ioptr,mode);
    return erg;
  }

  canon_clienttype(canon_datentype *_canon_datenptr, canon_kette_basetype *_canon_kette_baseptr,einheittype *_einheitptr) : canontype(_canon_datenptr,_canon_kette_baseptr,_einheitptr)
  {
    roldsprite=NULL;
  }
  ~canon_clienttype()
  {
    delete roldsprite;
  }
  int calc();
private:
  float roldwinkel;
  spritetype *roldsprite;
  float oldzoom;
};

typedef canon_kettetype<canon_clienttype> canon_kette_clienttype;


// Dynamische Panzerdaten des Klienten ****************************************************
// Dynamische Panzerdaten des Klienten ****************************************************
// Dynamische Panzerdaten des Klienten ****************************************************

class panzer_client_zeigerelemtype 
  : public panzertype, public einheit_client_zeigerelemtype
{
public:
  canon_kette_clienttype canon_kette_client;

  // Einheit erstellen
  panzer_client_zeigerelemtype();
  //  panzer_client_zeigerelemtype(iotype *ioptr,int8 mode);
  ~panzer_client_zeigerelemtype();
  // Routinen !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  int calc();
  void change(iotype *ioptr,int8 mode);
private:
  // Damit nicht immer neu rotated werden muss
  // => Altes rotated sprite merken !
  spritetype *oldsprite;
  float oldwinkel;
  float oldzoom;
};


// einheit_statustype **********************************************************************
// einheit_statustype **********************************************************************
// einheit_statustype **********************************************************************
// einheit_statustype **********************************************************************

/*
todo wegmachen

class einheit_statustype : public menutype
{
public:
  einheit_statustype(einheit_client_zeigerelemtype *_einheitptr);
  // s.h. menu.H
  virtual int calc();
protected:
  einheit_client_zeigerelemtype *einheitptr;
};

*/




// Schussobjekt (Client)   ****************************************************
// Schussobjekt (Client)   ****************************************************
// Schussobjekt (Client)   ****************************************************

class schuss_client_zeigerelemtype : public schusstype,
				     public zeigerelem_changetype<schuss_client_zeigerelemtype>
{
public:
  schuss_client_zeigerelemtype(){}
  //  schuss_client_zeigerelemtype(iotype *ioptr,int8 mode);
  int calc();
  inline void change(iotype *ioptr,int8 mode){schusstype::change(ioptr,mode);}
};

machekette_changetype(schuss_client)




// Explosionsobjekt **********************************************************
// Explosionsobjekt **********************************************************
// Explosionsobjekt **********************************************************

class explosions_client_zeigerelemtype : public explosionstype,
					 public zeigerelem_changetype<explosions_client_zeigerelemtype>
{
public:
  explosions_client_zeigerelemtype();
  ~explosions_client_zeigerelemtype();
  //  explosions_client_zeigerelemtype(iotype *ioptr,int8 mode);
  int calc();
  void change(iotype *ioptr,int8 mode);
private:
  sprite_movietype *sprite_movieptr;
};

machekette_changetype(explosions_client);



// contentscreen ************************************************************************
class contentscreentype : public menutype
{
public:
  // Typeinfo -Achtung statisch wird nicht vererbt !!! =>benutze getheaderstring() muss aber public sein!
  static const char *headerstring;
  const char *getheaderstring(){return headerstring;}

  contentscreentype();
  virtual ~contentscreentype();
  void paint(einheit_client_zeigerelemtype *unit);
  bool calc_iconmap(einheit_client_zeigerelemtype *unit);
private:
  int *zahlen;
  int anzz;
  einheit_client_zeigerelemtype *oldother;
};



// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************
// Scrollscreen **************************************************************************

class scrollscreentype : public event_managertype
{
public:
  scrollscreentype(spieler_zeigerelemtype *_ichptr,int _mx,int _my,int _sx,int _sy) 
    : transform(_ichptr)
  {
    mx=_mx;
    my=_my;
    sx=_sx;sy=_sy;
    //    cout <<"scrollscreentype(...) called!\n";
    //    cout << rechtecktype(_mx,_my,_sx,_sy);
    //    cout << mx << " " <<my<<" jetzt stand\n";
    //    *this=rechtecktype(_mx,_my,_sx,_sy);
    //    cout << mx << " " <<my<<" jetzt stand nach =\n";
    painting=1;
    ichptr=_ichptr;
    maskspriteptr=new sprite_linear_transparenttype(_sx,_sy,mx,my,255);
  }
  ~scrollscreentype()
  {
    delete maskspriteptr;
  }

  // Nothing (normally it should paint)
  int calc();
  //  Already defined in menu.H
  //  int calc(cons rechtecktype &rect);

  // This is a special menu => paint paints not calc
  void paint();

  // s.h. menu.H
  int verarbeite_input(istream *ist);

  // in the moment useless because first the big window has to resizeable 
  //   void resize(int32 x,int32 y);
 
  

  void paintsprite(float x,float y,spritetype *sprite);

  // Soll ich malen ?
  int painting;
  // Zeiger auf den Spieler
  spieler_zeigerelemtype *ichptr;
  // Transform, scroll , zoom
  transformtype transform;
private:
  // Berechnet abhaengig von den eigenen Einheiten das masksprite !!
  void calc_masksprite();
  void paint_masksprite();

  // Wählt einen Panzer aus
  // gibt 0 zurueck wenn an der pos x y kein panzer ist ansonsten einen pointer auf die einheit!
  einheit_client_zeigerelemtype *choose_tank(int32 x,int32 y);
  // todo resize !!!
  sprite_linear_transparenttype *maskspriteptr;
};


/// The Tud Main Screen 
class tudscreentype : public sprite_linear_nontransparent_screentype
{
public:
  tudscreentype(spieler_zeigerelemtype *_ichptr,int _x,int _y,int _sx,int _sy,
		   char *_palette=NULL,char *_scrname=NULL,char *_dpyname=NULL);

  ~tudscreentype();

  // s.a. menu.H 
  int calc();

  // s.a. menu.H
  int verarbeite_input(istream *ist);

  // new active unit
  void neweinheit(int32 _einheitnummer);
  // new nearest unit (contacted unit) to active unit
  void newnearest(einheit_client_zeigerelemtype *near);
  // Activate all displays for special select (you selected a unit that isn't directly yours)
  void new_special_select(einheit_client_zeigerelemtype *unit);
  bool special_selected(){return (special_select_menuptr);}
  // Get unit that is specially selected (NULL=not available)
  einheit_client_zeigerelemtype *get_specialselect_einheitptr();

  // deactivate all displays and menus of special select
  void delete_special_select();

  // unit not anymore in the received list (you can't see it anymore or it was killed)
  void einheit_killed(int32 _nr)
    {
      if ((_nr==geteinheitnummer())||((special_selected())&&(_nr==specialselect_einheitno)))
	{
	  neweinheit(-1);
	}
    }

  // update player list
  void update_spielermenu();
  void paint_all()
    {
      menuptr->calc();
    }

  // Pointer to player
  spieler_zeigerelemtype *ichptr;
  int32 geteinheitnummer() const {if (einheitptr) return einheitptr->einheitnummer; else return -1;}
  einheit_client_zeigerelemtype *geteinheitptr() const {return einheitptr;}
  einheit_client_zeigerelemtype *getnearestptr()const {return nearestptr;}
  int32 getnearest() const {if (nearestptr) return nearestptr->einheitnummer; else return -1;}
  void set_activeplayer(int32 pl);
  int32 get_activeplayer(){return activeplayer;}
private:
  // aktive player for lend and give
  int32 activeplayer;
  // Aktuelle Einheit
  einheit_client_zeigerelemtype *einheitptr;
  einheit_client_zeigerelemtype *nearestptr;
  rechtecktype selection_rect;

  //scrollscreentype *scrollscreenptr;
  menutype *spieler_menuptr;
  contentscreentype *contentscreenptr;
  menutype *menuptr;

  // Special select (I lent this unit to someone) 
  buttontype *special_select_menuptr;
  rechtecktype special_rect;
  int32 specialselect_einheitno;
};

// Landscreen **********************************************************************
// Landscreen **********************************************************************
// Landscreen **********************************************************************
// Landscreen **********************************************************************
// Landscreen **********************************************************************

/// Pseudo 3D-View (45 degree) of the landscape (not in use)
class landscreentype : public sprite_linear_nontransparent_screentype
{
public:
  landscreentype(int _x,int _y,int _sx,int _sy,
		 char *_palette=NULL,char *_scrname=NULL,char *_dpyname=NULL);
  ~landscreentype()
  {
  }

  // s.h. menu.H 
  //  int calc();
  int verarbeite_input(istream *ist);
  void calc_paint();
  void paint();

private:
  inline void transform_to_land(int32 scrx,int32 scry,int32 &lx,int32 &ly);
  inline void transform_to_scr(int32 lx,int32 ly,int32 &scrx,int32 &scry);

  float winkel;
  float tx;
  float ty;
  // Outzoom !!!
  float zoom;
};



// ****************************************************************************
// ****************************************************************************
//                     K O M M U N I K A T I O N 
// ****************************************************************************
// ****************************************************************************


class clientmsgtype : public tud_streamtype
{
public:
  clientmsgtype(){}
  clientmsgtype(verbindungstype *verbindung) 
    : tud_streamtype (verbindung){}
  void verarbeitemsg(char *msg,int32 laenge,int32 msgart);

  // Send Requests
  void req_spieleranz_msg(){sendmsg(NULL,0,REQ_SPIELERANZ_MSG);}
  void req_landsname_msg(){sendmsg(NULL,0,REQ_LANDSNAME_MSG);}
  inline void req_spieler_kette_msg();
  void req_freespielerdatei_msg(){sendmsg(NULL,0,REQ_FREESPIELERDATEI_MSG);}
  void req_freespielerplatz_msg(){sendmsg(NULL,0,REQ_FREESPIELERPLATZ_MSG);}
  void req_spielerdatei_msg(const char *name){sendmsg(name,strlen(name)+1,REQ_SPIELERDATEI_MSG);}
  void req_panzer_kette_msg();
  void req_panzer_kette_msg(int32 x1,int32 y1,int32 x2,int32 y2);


  // Send Msgs
  void send_eventmask_msg(eventmasktype *eventmask);
  void send_eingabe_msg(int einheitnummer,eingabetype *eingabe);

  // Incoming Msgs
  void verarbeite_panzer_kette_msg(char *msg,int32 laenge);
  void verarbeite_explosion_kette_msg(char *msg,int32 laenge);
  void verarbeite_spieler_kette_msg(char *msg,int32 laenge);

  // Msgs to wait for
  void wait_ping_msg();
  int32 wait_spieleranz_msg();
  string wait_landsname_msg();
  string wait_freespielerdatei_msg();
  int32 wait_freespielerplatz_msg();
};

// CLIENTMSG_KETTE_ITERATORTYPE **********************************************

class clientmsg_zeigerelemtype 
    : public clientmsgtype ,
      public zeigerelemtype<clientmsg_zeigerelemtype>
{
public:
    clientmsg_zeigerelemtype (verbindungstype *verbindung) 
	: clientmsgtype (verbindung) {};
  clientmsg_zeigerelemtype(){}
};

// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************
// The Game **********************************************************************


class gametype
{
public:
  gametype(const string &server,string spielerfilename,const string &setupfilename);

  ~gametype();
  int calc();
  void prepare_exit();

  //  spieler_kette_screentype *spieler_kette_screenptr;
  //einheit_screentype *einheit_screenptr;
  float getwunschti() const {return wunschti;}
  float getavgti() const {return avgti;}
  spieler_zeigerelemtype *get_ich()
  {
    return &ich;
  }
  int32 maskmode;
private:
  int verarbeite_befehl(istream &ist);
  void help();

  char ende;
  
  // Realtime !!!
  timeval zeit;
  timeval oldzeit;    
  float minti;
  float maxti;
  float avgti;
  float anztakte;
  float wunschti;
  float timeavailable;
  
  clientmsgtype *streamptr;
  eventmasktype eventmask;

  spieler_zeigerelemtype ich;

  //  statusscreentype *statusscreenptr;
  landscreentype *landscreenptr;

  // Berechne minimales Rechteck
  void calc_new_rechteck();
  // Minimales Rechteck des Scrollscreens in der Landschaft
  int32 x1,y1,x2,y2;
  // Sound on ?
  int32 sound;
};



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

            T Y P E N   D I E   N U R   I M   C L I E N T   S I N D

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



// Abbildung  Bildschirm <-> Landschaft
// extern transformtype transform; now in scrollscreentype
extern einheit_client_kettetype *einheit_client_ketteptr;
extern schuss_client_kettetype *schuss_client_ketteptr;
extern explosions_client_kettetype *explosions_client_ketteptr;
extern int showflags;
extern gametype *gameptr;
extern yyysound_client_noexception *soundptr;
#endif












