#include "stdarg.h"
#include "guidefines.h"
#include "defines.h"
#include "struct.h"
#include <envoy/nipc.h>
#include <envoy/errors.h>
#include <clib/nipc_protos.h>
#include <pragmas/nipc_pragmas.h>

struct MyMsg 
{
  struct Message msg;
  ULONG  Type;
  ULONG  Length;            
  UBYTE  *Data;
};



extern struct WBStartup *WBenchMsg;
struct Library *NIPCBase=NULL;
ULONG bitnumber=0;

int processdata(struct Transaction *trans,struct MuxMsg *mmsg, struct MsgPort *in,struct Entity *myentity,struct Entity *sourceentity,struct MsgPort *,struct MsgPort *); 
struct MsgPort *startserver (struct MyStartMsg *startupmsg);
int setport(struct MuxMsg  *mmsg, struct MsgPort *in,struct MsgPort *muxport, struct MsgPort **dataport, struct MsgPort **serverport);
int empire_talk(struct MsgPort *myport,struct Entity *myentity,struct MsgPort *serverport,struct MsgPort *dataport);


  
int empire_talk(struct MsgPort *in,struct Entity *myentity,struct MsgPort *serverport,struct MsgPort *dataport) {
          
  short quit = FALSE;
  struct MuxMsg *mmsg;
  struct Transaction *trans;
  struct Entity *sourceentity=NULL;
  
  while(!quit)
      {
      while (mmsg = (struct MuxMsg *) GetMsg(in))
      {
        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) processdata(NULL,(struct Message *) mmsg,in,myentity,sourceentity,serverport,dataport);
        else if (mmsg->Type == CSKILL)
        {
          quit = TRUE;          
          processdata(NULL,(struct Message *) mmsg,in,myentity,sourceentity,serverport,dataport);
          Delay(30L);
        }
        else if (mmsg->Type == DIENOW)
        {
          quit = TRUE;
          processdata(NULL,(struct Message *) mmsg,in,myentity,sourceentity,serverport,dataport);
          Delay(30L);
        }
      }
      while (trans = GetTransaction(myentity))
      {
        if (trans->trans_Type != TYPE_RESPONSE) sourceentity = trans->trans_SourceEntity;
        else FreeTransaction(trans);
        
        if (trans->trans_Command == CSDATA) 
           processdata(trans,NULL,in,myentity,sourceentity,serverport,dataport);
        else if (trans->trans_Command == CSKILL)
        { 
          quit = TRUE;
          processdata(trans,NULL,in,myentity,sourceentity,serverport,dataport);
        }
        else if (trans->trans_Command == DIENOW)
        {
          quit = TRUE;
          processdata(trans,NULL,in,myentity,sourceentity,serverport,dataport);
        }
      }
      if (!quit) Wait((1L << in->mp_SigBit) | (1L << bitnumber));

    } /** end while true do **/
  return(1);
}

long main(argc, argv)
int argc;
char *argv[];
{
  
  char name[30];
  struct MsgPort *serverport,*dataport,*myport,*parent;
  struct Entity *myentity;
  struct Library *SvcBase;
  struct MyMsg *msg;
  BOOL foo = TRUE;
  
  parent = FindPort("MUIEmpire_service.port");
  if (!parent) exit(0);
  
  myport = CreateMsgPort();
  
  /* get entity name */
  if (msg = (struct MyMsg *)AllocVec(sizeof(struct MyMsg),MEMF_CLEAR|MEMF_ANY)) {
     msg->msg.mn_ReplyPort = myport;
     msg->Length = 30;
     msg->Type   = 1;
     if (msg->Data = AllocVec(msg->Length,MEMF_CLEAR|MEMF_ANY)) {                      
       PutMsg(parent, (struct Message *)msg); /* forward message to library */   
     }
     else {
        FreeVec(msg);
        DeletePort(myport);
        exit(0);
     }
  }
  
  while (foo) {
     while (msg = (struct MyMsg *)GetMsg(myport)) {
        if (msg->Data) {
           memcpy(name,msg->Data,msg->Length);
           FreeVec(msg->Data);
        }
        FreeVec(msg);
        foo = FALSE;
     }
     if (foo) WaitPort (myport);
  }
  foo = TRUE;
    
  if(NIPCBase = OpenLibrary("nipc.library",37L)) {
    if(SvcBase = OpenLibrary("MUIEmpire.service", 0L)) {
      if (myentity = CreateEntity(ENT_AllocSignal, &bitnumber,
                                ENT_Name,name,
                                ENT_Public, TRUE,
                                TAG_DONE)) {
           /* inform the library the we are ready */
           if (msg = (struct MyMsg *)AllocVec(sizeof(struct MyMsg),MEMF_CLEAR|MEMF_ANY)) {
              msg->msg.mn_ReplyPort = myport;
              msg->Length = 0L;
              msg->Type   = 2;
              PutMsg(parent, (struct Message *)msg); /* forward message to library */   
              }
           /* wait for the reply and free the message */
           while (foo) {
              while (msg = (struct MyMsg *)GetMsg(myport)) {
                 if (msg->Data) FreeVec(msg->Data);
                 FreeVec(msg);
                 foo = FALSE;
              }
              if (foo) WaitPort (myport);
           }
           serverport = FindPort("EmpireServer");
           dataport = FindPort("EmpireServerData");
           if ((dataport && serverport) && myport) empire_talk(myport,myentity,serverport,dataport);
           DeleteEntity(myentity);
           printf("Quiting The Simpe Empire Envoy Server\n");
       }
       CloseLibrary(SvcBase);
    }  
    CloseLibrary(NIPCBase);
  }
  
  DeletePort(myport);     
  exit(0);
}

int setport(struct MuxMsg  *mmsg, struct MsgPort *in,struct MsgPort *muxport, struct MsgPort **dataport, struct MsgPort **serverport)
  {
  
  LONG *temp;
  STRPTR name;

  if (mmsg->Data) temp = (LONG *) mmsg->Data;
  else temp = NULL;
  
  if (temp) {
    if (temp[0] == GUI_SEND) {
      if (temp[1] == ID_PLAYGAME) {
        if (name = AllocVec(50,MEMF_CLEAR|MEMF_ANY)) {
          strmfe(name,"EmpireServer",&temp[2]);
          printf("portname %s\n",name);
          *serverport = FindPort(name);
        }
        if (*serverport) {
           strmfe(name,"EmpireServerData",&temp[2]);
           printf("dataportname %s\n",name);
           *dataport = FindPort(name); 
        }
        FreeVec(name); 
      }
    }   
  }
  if (!(*dataport) || !(*serverport)) {
     printf("failed to find ports!\n");
     return(1);
  }
  return (0);
}

int processdata (struct Transaction *trans,struct MuxMsg *mmsg, struct MsgPort *in,struct Entity *myentity,struct Entity *sourceentity, struct MsgPort *serverport, struct MsgPort *dataport) {
  
  LONG *temp;
  struct MuxMsg *tempMuxMsg;
  struct Transaction *temptrans;
  
  /* message from client for server */
  if (trans) {
     if (tempMuxMsg = (struct MuxMsg *)AllocMem(sizeof(struct MuxMsg),MEMF_CLEAR|MEMF_ANY)) {
        tempMuxMsg->Type = trans->trans_Command;
        tempMuxMsg->msg.mn_ReplyPort = in;
        tempMuxMsg->Length = trans->trans_ReqDataActual;
        if (temp = AllocMem(tempMuxMsg->Length,MEMF_CLEAR|MEMF_ANY)) {                     
           memcpy(&temp[0],trans->trans_RequestData,trans->trans_ReqDataActual);
           tempMuxMsg->Data = (UBYTE *)temp;
           if ((temp[0] == GUI_SEND) || (temp[0] == GUI_PLANET)) 
              PutMsg(serverport, (struct Message *) tempMuxMsg); /* forward message to server */
           else PutMsg(dataport, (struct Message *) tempMuxMsg); /* forward message to server */
        }
        else PutMsg(serverport, (struct Message *) tempMuxMsg); /* forward message to server */   
     }
     ReplyTransaction(trans);
  }
  
  /* message from server for client */
  if (mmsg) {
     if (temptrans = AllocTransaction(TRN_AllocReqBuffer,mmsg->Length,
                                                TAG_DONE)) {
        temptrans->trans_Command       = mmsg->Type;
        temptrans->trans_ReqDataActual = mmsg->Length;
        if (mmsg->Length) memcpy(temptrans->trans_RequestData,mmsg->Data,mmsg->Length);
        BeginTransaction(sourceentity,myentity,temptrans);    /* forward message to envoy */   
     }
     ReplyMsg((struct Message *) mmsg);
  }
  return (0); 
}

