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

             T U D    S E R V E R    M O D U L

	     H E A D E R D A T E I

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


#ifndef _tudinc_server_H
#define _tudinc_server_H


#include "tudinc.H"


class einheit_server_zeigerelemtype
  : public virtual einheittype, public zeigerelemtype<einheit_server_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_server_zeigerelemtype *create(iotype *ioptr,int8 mode);

  // Berechnet eventuellen Schaden durch eine explosion !! todo  =0 !!
  virtual void shotat(vektor2_koordtype _pos,float _muehexplosion,float _explosionsradius);

  // Berechnet Einheit (Wird von der Kette automatisch aufgerufen) todo =0 !!
  virtual int calc()=0;

  // Crashcheck halt Rueckgabewert: !=0 => Crash
  int crashcheck();

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

  virtual void verarbeite_stream_msg(istream& ist);
  virtual void verarbeite_stream_msg_foreigner(istream &ist,int32 foreigner);

  // no wants to become a child of me => i hate childs => ret: no parent
  virtual einheit_server_zeigerelemtype *newchild(int32) {return NULL;}
  // no wants to tell me a waypoint (i can't drive)
  virtual void addwaypoint(const vektor2_koordtype &){return;}
  // clear waypoints (don't have any)
  virtual void clearwaypoints(){return;}

  // is this a child of me ? i don't have childs
  virtual bool is_child(int32){return false;}
  // remove child
  virtual void removechild(){return;}
 
private:

};


// einheit_server_kettetype ************************************************************
// einheit_server_kettetype ************************************************************
// einheit_server_kettetype ************************************************************


class einheit_server_kettetype : public kette_changetype<einheit_server_zeigerelemtype>
{
public:
  // Build from scratch without loading from a file
  void create(const char *_panzer_daten_dateiname,
	      vektor2_koordtype *_pos,
	      int32 _spielernummer,float _einheitdir);

  // Einheit sichtbar ?  Achtung kein Unterschied zw. eigener und feindlicher Einheit !!
  // (eigene Einheiten sind aber eigentlich immer sichtbar :-)
  int visible(einheit_server_zeigerelemtype *einheitptr,int32 spnr);

  // set the change detail (client does not need much detail)
  void setmode(einheittype::changemodetype _changemode);

  // return * to unit with number no or NULL if not available
  einheit_server_zeigerelemtype *get_unit(int32 no)
    {
      einheit_server_zeigerelemtype *laufzeiger;
      if (kette_search(this,no,laufzeiger))
	return laufzeiger;
      return NULL;
    }

};

// Dynamische Firmendaten  ****************************************************
// Dynamische Firmendaten  ****************************************************
// Dynamische Firmendaten  ****************************************************

class firma_server_zeigerelemtype
  :public firmatype, public einheit_server_zeigerelemtype, public virtual einheittype
{
public:
  firma_server_zeigerelemtype();
  firma_server_zeigerelemtype(const char *_panzer_daten_dateiname,vektor2_koordtype *_pos,
			      int32 _spielernummer,float _einheitdir,int32 _einheitnummer);

  void change(iotype *ioptr,int8 mode){firmatype::change(ioptr,mode);}
  int calc();
  void verarbeite_stream_msg(istream& ist);
private:
  // NB: 0 <=> keine Einheit in der Firma
  //   !=0 <=> sonst
  // neuer:=
  //     0     <=> kein neuer Besitzer 
  //     sonst <=> spielernummer des neuen Besitzers
  int neuerbesitzer(int *neuer);
  void stop_building(){typeof_tobuild="none";}
};

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

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

  canon_servertype(canon_datentype *_canon_datenptr, canon_kette_basetype *_canon_kette_baseptr,einheittype *_einheitptr) : canontype(_canon_datenptr,_canon_kette_baseptr,_einheitptr){}
  // Schiesse auf Einheit shotat_number 
  // NB:  1 <=> Einheit in Reichweite
  //     -1 <=> Einheit nicht in Reichweite
  //      0 <=> Einheit existiert nicht od. sie ist ein freund !
  int calc_autoshot();
  // Suche Ziel automatisch
  void calc_autoaim();
  int calc();
  // initialize (vehicle has been build during the game)
  void setmaxbereich()
  {
    relturmdir=0;
    dirhorizon=M_PI_4;
    restladedauer=0;
    shotat_number=0;
    autoshot=0;
    turmdrehen=0;
    turmfahren=0;
    schiessen=0;
  }
private:
};

class canon_kette_servertype :public canon_kettetype<canon_servertype>
{
public:
  void verarbeite_stream_msg(istream &ist)
  {
    string befehl;
    if (ist>>befehl)
      {
	if (befehl=="priorityaim")
	  ist >> priorityaim;
	else if (befehl=="autoaim")
	  ist >> autoaim;
      }
    else
      cerr <<"canon_kette_servertype: Got a wrong msg\n";
  }
};




// Dynamische Panzerdaten  ****************************************************
// Dynamische Panzerdaten  ****************************************************
// Dynamische Panzerdaten  ****************************************************

class panzer_server_zeigerelemtype 
  : public panzertype, public einheit_server_zeigerelemtype, public virtual einheittype
{
public:
  canon_kette_servertype canon_kette_server;
protected:
  // Die Daten, die nur der Server kennt,
  // und sonst niemand zu kennen braucht !
  struct{
    // Position
    float oldposx,oldposy;
    float oldpanzdir;
    
    // Untergrundcheck:
    float aktspeedfaktor;
    float aktdestroyfaktor;
    char inbewegung;
    char oldinbewegung;
    // Explosionen bei Panzertod in regelmaessigen abstaenden
    float todtimer;
  }server;
  
  // Routinen !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  // Ändert relturmdir und turmdir und turmdrehen
  void chkrelturmdirbereich();
  
  // Ueberprueft ob die Aktuellen Daten dem panzer_datentype entsprechen
  void checkbereich();

  // Setzt die Daten auf das Maximum (angegeben im panzer_datentype)
  void setmaxbereich();

  // Liefert !=0 wenn das Fahrzeug auserhalb der Landschaft ist
  int untergrundcheck(float *speedfaktor,float *destroyfaktor);
  
public:  
  // Berechnet Einheit (Wird von der Kette automatisch aufgerufen)
  int calc();
  void change(iotype *ioptr,int8 mode);
  void verarbeite_stream_msg(istream& ist);

  // Objekt "umwandeln" brauch ich wohl doch net !
  //  void export(panzer_client_zeigerelemtype *objptr){}
  //  void export(panzer_besitzer_client_zeigerelemtype *objptr){}
  
  // Einheit erstellen
  panzer_server_zeigerelemtype();
  panzer_server_zeigerelemtype(const char *_panzer_daten_dateiname,vektor2_koordtype *_pos,
			       int32 _spielernummer,float _einheitdir,int32 _einheitnummer);

  //  panzer_server_zeigerelemtype(iotype *ioptr,int8 mode);
  // Einheit löschen
  ~panzer_server_zeigerelemtype();
private:
  void init();
  // drive to pos Pos.  NB: 1 <=> noch yet reached   | 0 <=> reached
  int calc_driveto(const vektor2_koordtype &topos);
  // follow unit with no.  autofollow_number   ret:  new autodrive mode
  int calc_autofollow();
  // drive from waypoint to waypoint in waypoint list
  void calc_waypointdrive();
  // get my follower ret: NULL isn't available
  //  einheit_server_zeigerelemtype *get_follower()

  // clear waypoints (tell it my child if i have one
  void clearwaypoints();
  // add a waypoint and tell it my child if i have one
  void addwaypoint(const vektor2_koordtype &v);
  // Is this a child of me ?
  bool is_child(int32 no);
  // i want to a have another parent 
  void newparent(int32 no);
  // remove my parent
  void removeparent();
  // no wants to become a child of me , I return the parent it gets
  einheit_server_zeigerelemtype *newchild(int32 no);
  // remove child
  void removechild();
  // have a child
  bool havechild(){return (besitz.eingabe.follower!=-1);}
  // have a parent
  bool haveparent(){return (besitz.eingabe.autofollow_number!=-1);}
  
};





// Schussobjekt (Server)   ****************************************************
// Schussobjekt (Server)   ****************************************************
// Schussobjekt (Server)   ****************************************************

class schuss_server_zeigerelemtype : public schusstype,
				     public zeigerelem_changetype<schuss_server_zeigerelemtype>
{
public:
  schuss_server_zeigerelemtype(){}
  //  schuss_server_zeigerelemtype(iotype *ioptr,int8 mode);
  schuss_server_zeigerelemtype(vektor2_koordtype _pos,float _dir,float _speed,
				  float _restzeit,float _muehexplosion,float _explosionsradius,const char *_sound);
  int calc();
  inline void change(iotype *ioptr,int8 mode){schusstype::change(ioptr,mode);}
};

machekette_changetype(schuss_server)



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

class explosions_server_zeigerelemtype : public explosionstype,
					 public zeigerelem_changetype<explosions_server_zeigerelemtype>
{
public:
  explosions_server_zeigerelemtype(){}
  //  explosions_server_zeigerelemtype(iotype *ioptr,int8 mode);
  explosions_server_zeigerelemtype(vektor2_koordtype _pos,float _muehexplosion,float _explosionsradius, const char *_sound);
  inline void change(iotype *ioptr,int8 mode){explosionstype::change(ioptr,mode);}
};

machekette_changetype(explosions_server)













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

class servermsg_zeigerelemtype 
  : public tud_streamtype,
    public zeigerelemtype<servermsg_zeigerelemtype>
{
public:
  // Spielerdaten !
  spieler_zeigerelemtype *spielerptr;
  // Zum vergleichen werden die Spielernummern genommen
  int compare(int32 ges_sp_nr){return (spielerptr->spielernummer==ges_sp_nr);}

  eventmasktype eventmask;
  servermsg_zeigerelemtype(){} // Wegen change ??
  servermsg_zeigerelemtype(verbindungstype *verbindung);
  ~servermsg_zeigerelemtype();
  int calc(){return(communication_streamtype::calc());}    
  //  void change(iotype *ioptr,int8 mode);
  void verarbeitemsg(char *msg,int32 laenge,int32 msgart);

  // send msgs
  float send_ping_msg();            // Achtung: Wartet ewig auf eine Antwort !! todo ?
  void send_spieleranz_msg();
  void send_landsname_msg();
  void send_panzer_kette_msg();
  void send_panzer_kette_msg(int32 x1,int32 y1,int32 x2,int32 y2);
  void send_explosion_kette_msg();
  void send_spielerkette_msg();

  // Verschicke Events an die die sie wollen   !! todo wann wird dieser Event verschickt !! 
  // Im Moment grober Fehler: es kann auch ein Noname verschickt werden !!!!! TODO !!!
  void send_event_spieler_kette_msg();

  // verarbeite Msgs
  // 1.Requests
  void verarbeite_req_spielerdatei_msg(char *dateiname);
  void verarbeite_req_spielerplatz_msg(char *msg,int32 laenge);    
  void verarbeite_req_freespielerdatei_msg();
  void verarbeite_req_freespielerplatz_msg();
  void verarbeite_req_panzer_kette_msg(char *msg,int32 laenge);

  // 2.Sonstige
  void verarbeite_eingabe_msg(char *msg,int32 laenge);
  void verarbeite_eventmask_msg(char *msg,int32 laenge);
  void verarbeite_stream_msg(char *msg,int32 laenge);
private:
  // Alter Bereich
  int32 x1_old,y1_old,x2_old,y2_old;
};

typedef server_kettetype<servermsg_zeigerelemtype> servermsg_kettetype;


class leveltype
{
public:
  // Im Prinzip gehoeren all diese Variablen in den Leveltype
  // spaeter mal !!
  string landsname;
  //  int32 maxspieler;

  //  landschafttype *landscapeptr;
  //  einheit_server_kettetype *einheit_server_ketteptr;
  // schuss_server_kettetype *schuss_server_ketteptr;
  // explosions_server_kettetype *explosions_server_ketteptr;
  // servermsg_kettetype* servermsg_ketteptr;

  leveltype();
  ~leveltype();
  void change(iotype *ioptr,int8 mode);
  int calc();
  void ladelevel(const char *name);
  void savelevel(const char *name);
};








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

           T Y P E N   D I E   N U R   I M   S E R V E R   S I N D

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




// Maximale Anzahl der Spieler im Level
extern int32 maxspieler; 

// Globale Leveldaten
extern string levelname;

// Setupdaten:
extern float wunschti;
extern float muehmineexplosion;
extern float mineexplosionsradius;
  
// Kommunikationsverbindungen !
extern servermsg_kettetype *servermsg_ketteptr;

// Level
extern leveltype *levelptr;

extern einheit_server_kettetype *einheit_server_ketteptr;
extern schuss_server_kettetype *schuss_server_ketteptr;
extern explosions_server_kettetype *explosions_server_ketteptr;
#endif
