#include "defines.h"
#include "guidefines.h"
#include "struct.h"
#include "stdarg.h"
#include "externalprototypes.h"

/* this code is how the server communicates with the GUI */
int  changeplayer(void);
extern int planetnumber;
extern LONG GALAXY;
extern struct MsgPort *client;
extern struct planet **planetlist;
extern struct sector   **SECTOR;
extern struct player *currentplayer;
extern ULONG signals;
extern struct MsgPort *in,*out,*dataport;
extern short chan;

extern BOOL insector(int,int,int);
BOOL   SafePutMsg(struct Message *message, STRPTR portname);
ULONG  guiinput(void);
int    guiset(struct MsgPort *,LONG datasize,LONG object,LONG method,LONG data); 
int    guiget(struct MsgPort *,LONG datasize,LONG object,LONG method,APTR data); 
int    guiDoMethod(struct MsgPort *, LONG,LONG,LONG object,ULONG data,...);
int    senddata (struct MsgPort *in, struct MsgPort *out,int length, short datatype,LONG *data);
LONG   guiRequest(LONG id); 
void   *getdata(LONG datatype);
int    imagesetup (void);
int    mapsetup(struct MsgPort *);
int    empiresetup (struct MsgPort *client);


ULONG guiinput ()
{
  return(0); /* dummy fuction */

}

int imagesetup ()
{
  return(0); /* dummy function */
}


LONG guiRequest(LONG id) {
  
  LONG *tempdata; 
  LONG length = sizeof(LONG)*4;  
  tempdata = AllocVec(length,MEMF_CLEAR);
        
  /* send data for sending */              
  
  /* 
   * put up a requestor on a client's machine 
   */
  
  if (!out) return(0);
  if (tempdata) {
    tempdata[0]  = GUI_REQUEST; /* message type */
    tempdata[1]  = sizeof(LONG);/* data length  */
    tempdata[2]  = 0;           /* no object    */
    tempdata[3]  = id;          /* actual data  */
    senddata(in,out,length,CSDATA,tempdata);
    /* release memory */
    FreeVec(tempdata);
  }

  return(0);
}


int senddata (struct MsgPort *in, struct MsgPort *out,int length, short datatype, LONG *data) {
  
  struct MuxMsg *mmsg;
  
  /*
   * send data to the IceBBS for sending to the client
   */
  
  if (!out) return(0); /* make sure port is available */
  if (mmsg = (struct MuxMsg *) AllocMem(SIZE(MuxMsg), MEMF_CLEAR)) {
     mmsg->Length = length;
     if (mmsg->Data = (UBYTE *) AllocMem(length, MEMF_CLEAR))
       {
       memcpy(&mmsg->Data[0],data,length);
       mmsg->Type = datatype;
       mmsg->priority = 0;
       mmsg->msg.mn_ReplyPort = in;
       PutMsg(out, (struct Message *) mmsg);  /** send message **/
       }
     else {
        FreeMem(mmsg,SIZE(MuxMsg));
        return(1);
     }
  }
  if (length >240) printf("sending %d bytes\n",length); 
  return(0);
}


int guiset(struct MsgPort *client,LONG datasize,LONG object,LONG method,LONG data) {

  
  LONG *tempdata; 
  LONG length =0;
  struct player *player;
  
  /* 
   * do a setAttrs on a client's machine 
   */
  
  out = client;
  if (!out) return(0);
  
  /* 
   * need to know datasize
   */
   
  switch (datasize) {
     case INT:
       length = sizeof(LONG);
       break;
     case SMALLSTRING:
       length = sizeof(char[30]);
       break;
     case LARGESTRING:
       length = sizeof(char[100]);
       break;
     case CARGO:
       length = sizeof(struct tagchar);
       break;
     case FLEET:
       length = sizeof(struct force);
       break;
     case ITEM:
       length = sizeof(struct item);
       break;
     case SHIPTAG:
       length = sizeof(struct shiptag);
       break;  
     case SHIP:
       length = sizeof(struct ship);
       break;  
  }

  tempdata = AllocVec(sizeof(LONG)*4+length,MEMF_CLEAR);
  /*
  printf("sending a guiset\n");   
  */
  /* send data for sending */              
  if (tempdata) {
    tempdata[0] = GUI_SETUPDATE;
    tempdata[1] = length;   /* data length */
    tempdata[2] = object;
    tempdata[3] = method;
    if (datasize == INT) tempdata[4] = data;
    else if (data) memcpy(&tempdata[4],data,length);
      else {
        tempdata[4] = NULL;
        tempdata[1] = sizeof(LONG);
        }
    if (out) senddata(in,out,4*sizeof(LONG)+length,CSDATA,tempdata);
    else {
        player = headplayer;
        while(player) {
           if (player->messageport) senddata(in,player->messageport,4*sizeof(LONG)+length,CSDATA,tempdata);
           player = player->next;
        }
    }
    
    /* release memory */
    FreeVec(tempdata);
  }
  
  return(0);
}  

void *getdata(LONG datatype) {
  
  static int  number;
  static char smallstring[30];
  static char largestring[100];
  static struct tagchar cargotag;
  static struct force fleet;
  static struct temp displayfleet;
  static struct item item;
  static struct shiptag shiptag;
  static struct ship ship;
  struct player *player;
  LONG messagetype; 
  void *pointer1,*pointer2;
  struct MuxMsg *mmsg;
  BOOL quit=FALSE;
  LONG *message;
  ULONG mysig=NULL,portflag=NULL;
  
  /* 
   * wait for retrieved data, I need to put in a time to abort a request
   */
  
  portflag = 1L << dataport->mp_SigBit;
  
  while (!quit) {
    if (!out) return (NULL);
    mysig = Wait(portflag | SIGBREAKF_CTRL_C); /* wait for requested info */  
  
    if (mysig & portflag) { 
      while (mmsg = (struct MuxMsg *) GetMsg(dataport))
        {
           if (mmsg->msg.mn_ReplyPort == in)
           {
           if (mmsg->Data && mmsg->Length && (mmsg->Type == CSDATA)) 
             
             FreeMem(mmsg->Data, mmsg->Length);
             FreeMem(mmsg, SIZE(MuxMsg));
           }
           else if (mmsg->Type == CSDATA) {
               message = (LONG *)mmsg->Data;
               messagetype = message[0];
               pointer1 = &message[1];
               pointer2 = NULL;
               /*
               printf("received messagetype %d\n",messagetype);
               */
               if (messagetype == GUI_NULL) return (NULL);
               
               switch (datatype) {
                 case INT:
                    memcpy(&number,pointer1,sizeof(number));
                    pointer2 = (void *)number;
                    break;
                 case SMALLSTRING:
                    memcpy(smallstring,pointer1,sizeof(smallstring));
                    pointer2 = smallstring;
                    break;
                 case LARGESTRING:
                    memcpy(largestring,pointer1,sizeof(largestring));
                    pointer2 = largestring;
                    break;
                 case CARGO:
                    memcpy(&cargotag,pointer1,sizeof(cargotag));
                    pointer2 = &cargotag;
                    break;
                 case FLEET:
                    memcpy(&fleet,pointer1,sizeof(fleet));
                    pointer2 = &fleet;
                    break;
                 case TEMPFLEET:
                    memcpy(&displayfleet,pointer1,sizeof(displayfleet));
                    pointer2 = &displayfleet;
                    break;
                 case ITEM:
                    memcpy(&item,pointer1,sizeof(item));
                    pointer2 = &item;
                    break;
                 case SHIPTAG:
                    memcpy(&shiptag,pointer1,sizeof(shiptag));
                    pointer2 = &shiptag;
                    break;
                 case SHIP:
       
                    memcpy(&ship,pointer1,sizeof(ship));
                    pointer2 = &ship;
                    break;  
                 default:
                    break;
                 }
              ReplyMsg((struct Message *) mmsg);
              return(pointer2);
           }
           else if (mmsg->Type == SCKILL)
           {
             player = headplayer;
               while (player) {
                  if (player->messageport == mmsg->msg.mn_ReplyPort) {
                     player->messageport = NULL;
                     printf("player %s has disconnected\n",player->name);
                     break;
                  }
                  player = player->next;
               }
             ReplyMsg((struct Message *) mmsg);
             Delay(30L);
             return (NULL);
           }
           else if (mmsg->Type == DIENOW)
           {
             player = headplayer;
               while (player) {
                  if (player->messageport == mmsg->msg.mn_ReplyPort) {
                     player->messageport = NULL;
                     printf("player %s has unexpectedly disconnected\n",player->name);
                     break;
                  }
                  player = player->next;
               }
             ReplyMsg((struct Message *) mmsg);
             Delay(30L);
             return (NULL);
           }
         }
      }
      if (mysig & SIGBREAKF_CTRL_C) return (NULL);
  }     
  
  return(NULL);
}

int guiget(struct MsgPort *client,LONG datasize,LONG object,LONG method,APTR data) {


APTR *temp;
LONG *tempdata;
LONG length =0;
  
  out = client;
  if (!out) return(0);
  switch (datasize) {
     case INT:
       length = sizeof(LONG);
       break;
     case SMALLSTRING:
       length = sizeof(char[30]);
       break;
     case LARGESTRING:
       length = sizeof(char[100]);
       break;
     case CARGO:
       length = sizeof(struct tagchar);
       break;
     case FLEET:
       length = sizeof(struct force);
       break;
     case ITEM:
       length = sizeof(struct item);
       break;
     case SHIPTAG:
       length = sizeof(struct shiptag);
       break;
     case SHIP:
       length = sizeof(struct ship);
       break;
       
  }

  tempdata = AllocVec(sizeof(LONG)*5,MEMF_CLEAR);
  /* send data for sending */              
  if (tempdata) {
    tempdata[0] = GUI_GET;
    tempdata[1] = length;
    tempdata[2] = object;
    tempdata[3] = method;
    tempdata[4] = (LONG)data;
    senddata(in,out,5*sizeof(LONG),CSDATA,tempdata);
    temp = (APTR *)(data);
    FreeVec(tempdata);
    *temp = getdata(datasize);
    }
             
/*
  if (data = getdata(CHAR));
*/
  return (0);
} 

int guiDoMethod(struct MsgPort *client, LONG message, LONG datatype,LONG object,ULONG data,...) {

LONG length=0;
LONG *tempdata;
va_list argptr;
APTR *temp;

  
  va_start(argptr,data); /* intialize var args */
  out = client; 
  if (!out) return(0);
  switch (datatype) {
     case INT:
       length = sizeof(LONG);
       break;
     case SMALLSTRING:
       length = sizeof(char[30]);
       break;
     case LARGESTRING:
       length = sizeof(char[100]);
       break;
     case CARGO:
       length = sizeof(struct tagchar);
       break;
     case FLEET:
       length = sizeof(struct force);
       break;
     case TEMPFLEET:
       length = sizeof(struct temp);
       break;
     case ITEM:
       length = sizeof(struct item);
       break;
     case SHIPTAG:
       length = sizeof(struct shiptag);
       break;
     case SHIP:
       length = sizeof(struct ship);
       break;  
     default:
       length = 0;
       break;
  }
  
  switch (message) {
     case GUI_DOMETHODGET3:
     /* if data length is 0, just pass message, if data = 1, then
        we expect data back */
        /* make memory for transfer of stack data */
        tempdata = AllocVec(sizeof(LONG)*5,MEMF_CLEAR);
        
        /* send data for sending */              
        if (tempdata) {
          tempdata[0] = GUI_DOMETHODGET3;
          tempdata[1] = length;
          tempdata[2] = object;
          tempdata[3] = data;
          tempdata[4] = va_arg(argptr,LONG);
          senddata(in,out,5*sizeof(LONG),CSDATA,tempdata);
          temp = (APTR *)tempdata[4];
          FreeVec(tempdata);
          if (length) {
            *temp = getdata(datatype);
            }
          }
        break;
        
     case GUI_DOMETHODGET4:
        /* need info and message reply is needed */
        /* make memory for transfer of stack data */
        tempdata = AllocVec(sizeof(LONG)*6,MEMF_CLEAR);
        /* send data for sending */              
        if (tempdata) {
          tempdata[0] = GUI_DOMETHODGET4;
          tempdata[1] = length;
          tempdata[2] = object;
          tempdata[3] = data;
          tempdata[4] = va_arg(argptr,LONG);
          tempdata[5] = va_arg(argptr,LONG);
          senddata(in,out,6*sizeof(LONG),CSDATA,tempdata);
          temp = (APTR *)tempdata[5];
          *temp = getdata(datatype);
          if (!*temp) temp = NULL; 
          FreeVec(tempdata);
        }
        break;
     
     case GUI_DOMETHODGET5:
        /* inserting data, no return is needed */
        tempdata = AllocVec(sizeof(LONG)*7+length,MEMF_CLEAR);
        /* send data for sending */              
        if (tempdata) {
          tempdata[0] = GUI_DOMETHODGET5;
          tempdata[1] = length;
          tempdata[2] = object;
          tempdata[3] = data;
          tempdata[4] = va_arg(argptr,LONG);
          tempdata[5] = va_arg(argptr,LONG);
          tempdata[6] = va_arg(argptr,LONG);
          if (datatype != INT) memcpy(&tempdata[7],*(LONG *)tempdata[4],length);
          else memcpy(&tempdata[7],&tempdata[4],length);
          senddata(in,out,7*sizeof(LONG)+length,CSDATA,tempdata);
          FreeVec(tempdata);
        }
        break;

  }
  va_end(argptr); /* end macro */
  return (0);
  
}

int empiresetup (struct MsgPort *client) {

  struct Empires newempire;
  struct player *player;
  struct computerplayer *computerplayer;
  LONG *data;
  LONG message[3];
  
  message[0] = GUI_EMPIRECLEAR;
  senddata(in,client,3*sizeof(LONG),CSDATA,&message[0]);    
  
  player = headplayer;
  while (player) {
     strcpy(newempire.name,player->empire);
     newempire.id = player->id;
     
     data = AllocVec(sizeof(struct Sector)+sizeof(LONG),MEMF_CLEAR|MEMF_ANY);
     if (data) {
        data[0] = GUI_EMPIRE;
        memcpy(&data[1],&newempire,sizeof(struct Empires));      
        senddata(in,client,sizeof(struct Empires)+sizeof(LONG),CSDATA,data);
        FreeVec(data); 
     }
     player = player->next;
  }
  
  computerplayer = headcomputerplayer;
  while (computerplayer) {
     strcpy(newempire.name,computerplayer->empire);
     newempire.id = computerplayer->id;
     
     data = AllocVec(sizeof(struct Sector)+sizeof(LONG),MEMF_CLEAR|MEMF_ANY);
     if (data) {
        data[0] = GUI_EMPIRE;
        memcpy(&data[1],&newempire,sizeof(struct Empires));      
        senddata(in,client,sizeof(struct Empires)+sizeof(LONG),CSDATA,data);
        FreeVec(data); 
     }
     computerplayer = computerplayer->next;
  }
    
  return(0);
}

int mapsetup (struct MsgPort *client) {

      int n,m;
      BOOL enemy=FALSE,friendly=FALSE,send = FALSE;
      struct force *fleet;
      struct TagItem *tag;
      struct Sector newsector;
      LONG *data;
      LONG message[3];
      
      message[0] = GUI_MAPCLEAR;
      senddata(in,client,3*sizeof(LONG),CSDATA,&message[0]);    
      
      if (!currentplayer) return(0);
        for (n=0;n<GALAXY;n++) {
          for (m=0;m<GALAXY;m++) {
            send                    = FALSE;
            newsector.planet        = FALSE;
            
            if (SECTOR[n][m].PLANET) {
               send = TRUE;
               newsector.x             = n;
               newsector.y             = m;
               newsector.friendlyfleet = FALSE;
               newsector.enemyfleet    = FALSE;
               newsector.planet        = TRUE;
               newsector.item          = FALSE;
               newsector.text          = planetlist[currentplayer->id][SECTOR[n][m].PLANET->ID].textattribute;      
               if (currentplayer->id == planetlist[0][SECTOR[n][m].PLANET->ID].id) newsector.planetowner = FRIENDLYPLANET;
               else if (planetlist[currentplayer->id][SECTOR[n][m].PLANET->ID].id == 0) newsector.planetowner = NEUTRALPLANET;
               else newsector.planetowner = ENEMYPLANET;
               memcpy(&newsector.planetname,&planetlist[currentplayer->id][SECTOR[n][m].PLANET->ID].name,sizeof(char [30]));      
            }
          
            if (insector(currentplayer->id,n,m)) {
              send        = TRUE;
              newsector.x = n;
              newsector.y = m;

              tag = SECTOR[n][m].TAGITEM;
              if (NextTagItem(&tag)) newsector.item = TRUE;
              else  newsector.item = FALSE;  
            
              fleet = SECTOR[n][m].FLEET;
              friendly = enemy = FALSE;
              while (fleet) {
                if (fleet->id == currentplayer->id) friendly = TRUE;
                else enemy = TRUE;
                fleet = fleet->sectornext;
              }
              if (friendly) newsector.friendlyfleet = TRUE;
                else newsector.friendlyfleet = FALSE;
              if (enemy)    newsector.enemyfleet = TRUE;
                else  newsector.enemyfleet = FALSE; 
          }
          if (send) {
           data = AllocVec(sizeof(struct Sector)+sizeof(LONG),MEMF_CLEAR|MEMF_ANY);
           if (data)
             data[0] = GUI_MAP;
             memcpy(&data[1],&newsector,sizeof(struct Sector));      
             senddata(in,client,sizeof(struct Sector)+sizeof(LONG),CSDATA,data);
             FreeVec(data); 
           }
        }
      }
  
  return(0);
}

int changeplayer() {
  
  int x,n,m;
  char *p;
  struct TagItem *tag,*tstate;
  struct ship *tempship;
  struct player *player;
  struct tagchar *cargo = NULL,cargotag;
  
  if (!currentplayer) return(0);
  out = currentplayer->messageport;
    
  if ((playernumber > 1) && (client == 0)) {
    guiset(out,INT,WI_MOVEMENT,MUIA_Window_Open,FALSE);
    guiset(out,INT,WI_FLEETCARGO,MUIA_Window_Open,FALSE);
  }
  currentplayer->currentfleet = currentfleet = currentplayer->nextfleet;
  guiDoMethod(out,GUI_DOMETHODGET3,0,LV3,MUIM_List_Clear,TRUE);

  for (x=0;x<planetnumber;x++) {
    n=planetlist[currentplayer->id][x].x;
    m=planetlist[currentplayer->id][x].y;
    p = planetlist[currentplayer->id][x].name;
    SECTOR[n][m].PLANET=&planetlist[currentplayer->id][x];
    guiDoMethod(out,GUI_DOMETHODGET5,SMALLSTRING,LV3,MUIM_List_Insert,&p,1,MUIV_List_Insert_Bottom);
  }
  x = findplanet(-1,1);
  currentplayer->planet = x;
  displayplanet(x);
  selectplanets();
  if (x>=0) guiset(out,INT,BT_PURCHASE,MUIA_Disabled,FALSE);
  else guiset(out,INT,BT_PURCHASE,MUIA_Disabled,TRUE);
  
  purchase(x);
  currentplayer->currentplanet = &planetlist[currentplayer->id][x];
  selectplanets();
  empiresetup(out);
  mapsetup(out);
  display(currentplayer);
  fleetlist(currentplayer->nextfleet);
  displayfleet(currentplayer->nextfleet);
  displaymessages(currentplayer);
  /* insert ship information */
  tstate = currentplayer->fleettag;
  guiDoMethod(out,GUI_DOMETHODGET3,0,LV11,MUIM_List_Clear,TRUE); 
  while (tag = NextTagItem (&tstate)) {
    tempship = (struct ship *) tag->ti_Data;
    guiDoMethod(out,GUI_DOMETHODGET5,SHIP,LV11,MUIM_List_Insert,&tempship,1,MUIV_List_Insert_Top);
    } 
  
  guiset(out,INT,LV18,MUIA_List_Quiet,TRUE);
  guiDoMethod(out,GUI_DOMETHODGET3,0,LV18,MUIM_List_Clear,TRUE);
  player = headplayer;
  while (player) {
     if (currentplayer->id != player->id) {
       strcpy(cargotag.name,player->empire);
       cargotag.tagdata = player->id;
       cargotag.tagname = (ULONG) player;
       cargo = &cargotag;
       guiDoMethod(out,GUI_DOMETHODGET5,CARGO,LV18,MUIM_List_Insert,&cargo,1,MUIV_List_Insert_Bottom);
     }
     player = player->next;  
  }
  guiset(out,INT,LV18,MUIA_List_Quiet,FALSE);
  if(!currentfleet) guiset(out,INT,BT_MOVEMENT,MUIA_Disabled,TRUE);
  else guiset(out,INT,BT_MOVEMENT,MUIA_Disabled,FALSE);
  
  setdisplay();
  guiset(out,INT,WI_MAINWINDOW,MUIA_Window_Open,TRUE);
  guiset(out,INT,WI_MESSAGES,MUIA_Window_Open,TRUE);
  guiRequest(9);

  return(0);
}

