#include <stdio.h> //printf(), fprintf(), perror()
#include <sys/socket.h> //socket(), bind(), accept(), listen()
#include <arpa/inet.h> // struct sockaddr_in, struct sockaddr, inet_ntoa(), inet_aton()
#include <stdlib.h> //atoi(), exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <string.h> //memset(), strcmp()
#include <unistd.h> //close()

#define MSGSIZE 32768
#define BUFSIZE (MSGSIZE + 1)

#ifdef WINDOWS
#endif

#include "../../../config.h"

#ifndef TRUE
#define TRUE   -1             /* numeric value for true  */
#endif
#ifndef FALSE
#define FALSE  0             /* numeric value for false */
#endif

static int sock=0; //local socket descripter
int server;

char recvBuffer[BUFSIZE];//receive temporary buffer
char sendBuffer[BUFSIZE]; // send temporary buffer


void server_send_int(int,int);
int sendinum(DCL_INT);

/*---------------------- internal function ---------------*/
//Remove White Space from string
void rmwhsp(char* text){
  int i,slen;
  slen=strlen(text);

  for (i=1;i<slen;i++){
    if(*(text+i)==' '){
       *(text+i)='\0';
      return;	
    }
  }
  *(text+slen)='\0';
}

void getswcparam(char *name,char *val){
  char nm[1024];
  char vl[1024];
  int slen;
  
  strcpy(nm,name);
  slen=strlen(nm);
  swcget_(nm,vl,slen,1024);
  rmwhsp(vl);
  strcpy(val,vl);
  
}

void getglcparam(char *name,char *val){
  char nm[1024];
  char vl[1024];
  int slen;
  
  strcpy(nm,name);
  slen=strlen(nm);
  glcget_(nm,vl,slen,1024);
  rmwhsp(vl);
  strcpy(val,vl);
  
}

void getgliparam(char *name,int *val){
  char nm[1024];
  int slen;
  
  strcpy(nm,name);
  slen=strlen(nm);

  strcpy(nm,name);
  gliget_(nm,val,slen);
  
}
/*------------------------- Socket ------------------------*/
void opensocket(){
  int  srvport;
  char srvaddr[4096];

  char number[16];
  
//----Socke Code
    getglcparam("SCKURL",srvaddr);
    getgliparam("SCKPORT",&srvport);

    struct sockaddr_in servSockAddr; //server internet socket address
    unsigned short servPort; //server port number

    memset(&servSockAddr, 0, sizeof(servSockAddr));

    servSockAddr.sin_family = AF_INET;

    if (inet_aton(srvaddr, &servSockAddr.sin_addr) == 0) {
        fprintf(stderr, "Invalid IP Address.\n");
        exit(EXIT_FAILURE);
    }

    if ((servPort = (unsigned short) srvport) == 0) {
        fprintf(stderr, "invalid port number.\n");
        exit(EXIT_FAILURE);
    }
    servSockAddr.sin_port = htons(servPort);

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ){
        perror("socket() failed.");
        exit(EXIT_FAILURE);
    }

    if (connect(sock, (struct sockaddr*) &servSockAddr, sizeof(servSockAddr)) < 0) {
        perror("connect() failed.");
        exit(EXIT_FAILURE);
    }

    printf("connect to %s\n", inet_ntoa(servSockAddr.sin_addr));
}

/*----------From Client Struct-----*/
void server_send_short(int server,short data) {
    if (send(server, &data, 2, 0) <= 0) {
        perror("send() failed.");
        exit(EXIT_FAILURE);
    }
}


int server_receive(int server, char *buffer, int size) {
    int totalSize = 0;
    while (totalSize < size) {
        int receivedSize = recv(server, &buffer[totalSize], 1, 0);
        if (receivedSize > 0) {
            if (buffer[totalSize] == '\n'){
                return totalSize;
            }
            totalSize += receivedSize;
        } else if(receivedSize == 0){
            perror("ERR_EMPTY_RESPONSE");
            exit(EXIT_FAILURE);
        } else {
            perror("recv() failed.");
            exit(EXIT_FAILURE);
        }
    }
    return size;
}

void server_close(int server) {
    if (close(server) == 0) {
        perror("close() failed.");
        exit(EXIT_FAILURE);
    }
}

/*---------------------- Socket Send ----------------------*/
int sendinum(DCL_INT data){
  //	     int server, DCL_INT data) {
  int sdata;  
  if(sock == 0){
    opensocket();
  }
  sdata=htonl((int) data);
  if (send(sock, &sdata, sizeof(int), 0) <= 0) {
        perror("send() failed.");
        exit(EXIT_FAILURE);
    }
}

int sendiary(DCL_INT* img,DCL_INT nlen){
  int image[8192];
  int i;

  for(i=0;i<nlen;i++){
    image[i]=htonl((int) *(img+i));
  }
  if (send(sock, image, sizeof(int)*nlen, 0) <= 0) {
        perror("send() failed.");
        exit(EXIT_FAILURE);
    }
}

int senddata(const char* data,int size){
  if(sock == 0){
    opensocket();
  }
  sendinum((DCL_INT) size);
  if (send(sock, data, size, 0) <= 0) {
    perror("send() failed.");
    exit(EXIT_FAILURE);
  }
}

int sendrnum(float num){
  char number[17];
  if(sock == 0){
    opensocket();
  }
  sprintf(number,"%f ",num);
  senddata(number,strlen(number));
}

int recvint(int *idat){
  int data;
  int recvMsgSize;
  if ((recvMsgSize = recv(sock, &data, sizeof(int), 0)) < 0) {
    perror("recv() failed.");
    exit(EXIT_FAILURE);
  }else if(recvMsgSize == 0){
    fprintf(stderr, "connection closed by foreign host.\n");
    exit(1);
  }else{
    *idat=ntohl(data); 
  }
}

int recvstr(char* buff,int dlen){
  int recvMsgSize;
  
  if ((recvMsgSize = recv(sock, buff, dlen, 0)) < 0) {
    perror("recv() failed.");
    exit(EXIT_FAILURE);
  }else if(recvMsgSize == 0){
    fprintf(stderr, "connection closed by foreign host.\n");
    exit(1);
  }else{
  }
}

int recvrnum(float* fdat){
  char fdatbuff[80];
  int  fstrlen;
  double ddat;
  recvint(&fstrlen);
  recvstr(fdatbuff,fstrlen);
  ddat=atof(fdatbuff);
  *fdat=(float) ddat;
}


int recvdata(int sock){
  //recvBuffe youisutu
  int byteRcvd  = 0;
    int byteIndex = 0;
        while (byteIndex < MSGSIZE) {
	  //            byteRcvd = recv(sock, &recvBuffer[byteIndex], 1, 0);
            if (byteRcvd > 0) {
	      //                if (recvBuffer[byteIndex] == '\n'){
	      //                    recvBuffer[byteIndex] = '\0';
	      //             if (strcmp(recvBuffer, "quit") == 0) {
	      // close(sock);
			//          return EXIT_SUCCESS;
	      //    } else {
	      //        break;
			//    }
	      // }
                byteIndex += byteRcvd;
            } else if(byteRcvd == 0){
                perror("ERR_EMPTY_RESPONSE");
                exit(EXIT_FAILURE);
            } else {
                perror("recv() failed.");
                exit(EXIT_FAILURE);
            }
        }
        printf("server return: %s\n", recvBuffer);
}

/*---------------------- parameter set --------------------*/
#ifndef WINDOWS
void zglset_(char pmname[],int *pl,DCL_INT* value)
#else
void ZGLSET(char pmname[],int *pl,DCL_INT* value)
#endif
{
  int i;
  char senddat[8];

  senddata("ZGLSET ",7);

  for(i=0;i<*pl;i++){
    senddat[i]=pmname[i];
  }
  senddat[*pl]='\0';
  senddata(senddat,*pl);
  sendinum(*value);
}

#ifndef WINDOWS
void zgiset_(char pmname[],int *pl,DCL_INT* value)
#else
void ZGISET(char pmname[],int *pl,DCL_INT* value)
#endif
{
  int i;
  char senddat[8];
  senddata("ZGISET ",7);
  for(i=0;i<*pl;i++){
    senddat[i]=pmname[i];
  }
  senddat[*pl]='\0';
  senddata(senddat,*pl);
  sendinum(*value);

}

#ifndef WINDOWS
void zgrset_(char pmname[],int *pl,DCL_REAL *value)
#else
void ZGRSET(char pmname[],int *pl,DCL_REAL *value)
#endif
{
  int i;
  char senddat[8];
  senddata("ZGRSET ",7);
  for(i=0;i<*pl;i++){
    senddat[i]=pmname[i];
  }
  senddat[*pl]='\0';
  senddata(senddat,*pl);
  sendinum(*value);

}

/*---------------------- transformation -------------------*/
#ifndef WINDOWS
void zgfint_(DCL_REAL *wx, DCL_REAL *wy, DCL_INT *iwx, DCL_INT *iwy)
#else
void ZGFINT(DCL_REAL *wx, DCL_REAL *wy, DCL_INT *iwx, DCL_INT *iwy)
#endif
{
  senddata("ZGFINT ",7);
  sendrnum(*wx);
  sendrnum(*wy);
  recvint(iwx);
  recvint(iwy);
  
}

#ifndef WINDOWS
void zgfrel_(DCL_REAL *wx, DCL_REAL *wy, DCL_REAL *rwx, DCL_REAL *rwy)
#else
void ZGFREL(DCL_REAL *wx, DCL_REAL *wy, DCL_REAL *rwx, DCL_REAL *rwy)
#endif
{
  senddata("ZGFREL ",7);
  sendrnum(*wx);
  sendrnum(*wy);
  recvrnum(rwx);
  recvrnum(rwy);
}

#ifndef WINDOWS
void zgiint_(DCL_INT *iwx, DCL_INT *iwy, DCL_REAL *wx, DCL_REAL *wy)
#else
void ZGIINT(DCL_INT *iwx, DCL_INT *iwy, DCL_REAL *wx, DCL_REAL *wy)
#endif
{
  senddata("ZGIINT ",7);
  sendinum(*iwx);
  sendinum(*iwy);
  recvrnum(wx);
  recvrnum(wy);
}
/*------------------------- device ------------------------*/
#ifndef WINDOWS
void zgdopn_(DCL_INT *dev_type,
             DCL_INT *width, DCL_INT *height, DCL_INT *iposx, DCL_INT *iposy, DCL_INT *idmpdgt,
             DCL_INT *ibgpage,DCL_REAL *rlwfact,
             DCL_INT *lwait, DCL_INT *lwait0, DCL_INT *lwait1, DCL_INT *lalt , DCL_INT *lstdot,
             DCL_INT *lkey, DCL_INT *ldump, DCL_INT *lwnd, DCL_INT *lfgbg, DCL_INT *lsep, DCL_INT *ifln,
             char cimgfmt[], DCL_REAL *rimgcmp, char clrmap[], char cbmmap[], char file[], char title[]
             )
#else
void ZGDOPN(DCL_INT *dev_type,
            DCL_INT *width, DCL_INT *height, DCL_INT *iposx, DCL_INT *iposy, DCL_INT *idmpdgt,
            DCL_INT *ibgpage, DCL_REAL *rlwfact,
            DCL_INT *lwait, DCL_INT *lwait0, DCL_INT *lwait1, DCL_INT *lalt,DCL_INT *lstdot,
            DCL_INT *lkey, DCL_INT *ldump, DCL_INT *lwnd, DCL_INT *lfgbg, DCL_INT *lsep, DCL_INT *ifln,
            char cimgfmt[], DCL_REAL *rimgcmp, char clrmap[], char cbmmap[], char file[], char title[]
            )
#endif
{
  if(sock == 0){
    opensocket();
  }

    senddata("ZGDOPN ",7);
    sendinum(*dev_type);
    sendinum(*width);
    sendinum(*height);
    sendinum(*iposx);
    sendinum(*iposy);
    sendinum(*idmpdgt);
    sendinum(*ibgpage);
    sendrnum(*rlwfact);
    sendinum(*lwait);
    sendinum(*lwait0);
    sendinum(*lwait1);
    sendinum(*lalt);
    sendinum(*lstdot);
    sendinum(*lkey);
    sendinum(*ldump);
    sendinum(*lwnd);
    sendinum(*lfgbg);
    sendinum(*lsep);
    sendinum(*ifln);
    senddata(cimgfmt,strlen(cimgfmt));
    sendrnum(*rimgcmp);
    senddata(clrmap,strlen(clrmap));
    senddata(cbmmap,strlen(cbmmap));
    senddata(file,strlen(file));
    senddata(title,strlen(title));

    return;

}

#ifndef WINDOWS
void zgdcls_(void)
#else
void ZGDCLS(void)
#endif
{
  /* device closing proc. */ 
  senddata("ZGDCLS ",7);
}

/*------------------------- page --------------------------*/

#ifndef WINDOWS
void zgpopn_(void)
#else
void ZGPOPN(void)
#endif
{
  senddata("ZGPOPN ",7);
}

#ifndef WINDOWS
void zgpcls_(void)
#else
void ZGPCLS(void)
#endif
{
  senddata("ZGPCLS ",7);
}

#ifndef WINDOWS
void zgflash_()
#else
void ZGFLASH()
#endif
{
  senddata("ZGFLASH ",8);
}

/*------------------------- object ------------------------*/

#ifndef WINDOWS
void zgoopn_(char *objname, char *comment)
#else
void ZGOOPN(char *objname, char *comment)
#endif
{
  /* for long-type message? */
  senddata("ZGOOPN ",7);
  senddata(objname,strlen(objname));
  senddata(comment,strlen(comment));
}

#ifndef WINDOWS
void zgocls_(char *objname)
#else
void ZGOCLS(char *objname)
#endif
{
  senddata("ZGOCLS ",7);
  senddata(objname,strlen(objname));
}

/*------------------------- line --------------------------*/

#ifndef WINDOWS
void zgswdi_(DCL_INT *iwdidx)
#else
void ZGSWDI(DCL_INT *iwdidx)
#endif
{
  senddata("ZGSWDI ",7);
  sendinum(*iwdidx);
}

#ifndef WINDOWS
void zgscli_(DCL_INT *iclidx)
#else
void ZGSCLI(DCL_INT *iclidx)
#endif
{
  senddata("ZGSCLI ",7);
  sendinum(*iclidx);
}

#ifndef WINDOWS
void zggopn_(void)
#else
void ZGGOPN(void)
#endif
{
  senddata("ZGGOPN ",7);
}

#ifndef WINDOWS
void zggmov_(DCL_REAL *wx, DCL_REAL *wy)
#else
void ZGGMOV(DCL_REAL *wx, DCL_REAL *wy)
#endif
{
  senddata("ZGGMOV ",7);
  sendrnum(*wx);
  sendrnum(*wy);
}

#ifndef WINDOWS
void zgqtxw_(char* text, DCL_INT *len, DCL_REAL *wxch, DCL_REAL *wych)
#else
void ZGQTXW(char* text, DCL_INT *len, DCL_REAL *wxch, DCL_REAL *wych)
#endif
{
  int slen;
  
  recvint(&slen);
  senddata("ZGQTXW ",7);
  recvstr(text,slen);
  recvint(len);
  recvrnum(wxch);
  recvrnum(wych);
}

#ifndef WINDOWS
void zgclip_(DCL_REAL *xmin,DCL_REAL *xmax,DCL_REAL *ymin,DCL_REAL *ymax)
#else
void ZGCLIP(DCL_REAL *xmin,DCL_REAL *xmax,DCL_REAL *ymin,DCL_REAL *ymax)
#endif
{
  senddata("ZGCLIP ",7);
  sendrnum(*xmin);
  sendrnum(*xmax);
  sendrnum(*ymin);
  sendrnum(*ymax);
}

#ifndef WINDOWS
void zgrclp_()
#else
void ZGRCLP()
#endif
{
  senddata("ZGRCLP ",7);
}

#ifndef WINDOWS
void zgtxt_(DCL_REAL *wx, DCL_REAL *wy, DCL_REAL *size, char* text, DCL_INT *len, DCL_REAL *irota, DCL_INT *icentz)
#else
void ZGTXT(DCL_REAL *wx, DCL_REAL *wy, DCL_REAL *size, char* text, DCL_INT *len, DCL_REAL *irota, DCL_INT *icentz)
#endif
{
  senddata("ZGTXT ",6);
  sendrnum(*wx);
  sendrnum(*wy);
  sendrnum(*size);
  senddata(text,strlen(text));
  sendinum(*len);
  sendrnum(*irota);
  sendinum(*icentz);
}

#ifndef WINDOWS
void zgselectfont_(char* selected_font){
#else
void ZGSELECTFONT(char* selected_font){
#endif
  int slen;
  senddata("ZGSELECTFONT ",13);

  recvint(&slen);
  recvstr(selected_font,slen);
}
 

#ifndef WINDOWS
void zgftfc_(char* family)
#else
void ZGFTFC(char* family)
#endif
{
  senddata("ZGFTFC ",7);
  senddata(family,strlen(family));
}

#ifndef WINDOWS
void zgsfw_(DCL_INT *weight)
#else
void ZGSFW(DCL_INT *weight)
#endif
{
  senddata("ZGSFW ",6);
  sendinum(*weight);
}

#ifndef WINDOWS
void zgnumfonts_(DCL_INT *fntnum)
#else
void ZGNUMFONTS(DCL_INT *fntnum)
#endif
{
  senddata("ZGNUMFONT ",10);
  sendinum(*fntnum);
}

// cf. http://www.lemoda.net/pango/list-fonts/
#ifndef WINDOWS
void zglistfonts_()
#else
void ZGLISTFONTS()
#endif
{
  senddata("ZGLISTFONT ",11);
}

#ifndef WINDOWS
void zgfontname_(DCL_INT *n, char* string, DCL_INT *nmax)
#else
void ZGFONTNAME(DCL_INT *n, char* string, DCL_INT *nmax)
#endif
{
  senddata("ZGFONTNAME ",11);
  sendinum(*n);
  senddata(string,strlen(string));
  sendinum(*nmax);
}

#ifndef WINDOWS
void zggplt_(DCL_REAL *wx, DCL_REAL *wy)
#else
void ZGGPLT(DCL_REAL *wx, DCL_REAL *wy)
#endif
{
  senddata("ZGGPLT ",7);
  sendrnum(*wx);
  sendrnum(*wy);
}

#ifndef WINDOWS
void zggcls_(void)
#else
void ZGGCLS(void)
#endif
{
  senddata("ZGGCLS ",7);
}

/*------------------------- tone --------------------------*/

#ifndef WINDOWS
void zggton_(DCL_INT *np, DCL_REAL wpx[], DCL_REAL wpy[], DCL_INT *itpat)
#else
void ZGGTON(DCL_INT *np, DCL_REAL wpx[], DCL_REAL wpy[], DCL_INT *itpat)
#endif
{
  int i;
  senddata("ZGGTON ",7);
  sendinum(*np);
  for(i=0;i<*np;i++){
    sendrnum(wpx[i]);
  }
  for(i=0;i<*np;i++){
    sendrnum(wpy[i]);
  }
  sendinum(*itpat);
  ///realarray
  
}

/*------------------------- image -------------------------*/

#ifndef WINDOWS
void zgiopn_(DCL_INT *iwx, DCL_INT *iwy, DCL_INT *iwidth, DCL_INT *iheight)
#else
void ZGIOPN(DCL_INT *iwx, DCL_INT *iwy, DCL_INT *iwidth, DCL_INT *iheight)
#endif
{
  senddata("ZGIOPN ",7);
  sendinum(*iwx);
  sendinum(*iwy);
  sendinum(*iwidth);
  sendinum(*iheight);

}

#ifndef WINDOWS
void zgidat_(DCL_INT image[], DCL_INT *nlen)
#else
void ZGIDAT(DCL_INT image[], DCL_INT *nlen)
#endif
{

  int i;
  int img[8192];

  senddata("ZGIDAT ",7);


  for(i=0;i<*nlen;i++){
    img[i]=*(image+i);
  }
  sendinum(*nlen);

}

#ifndef WINDOWS
void zgicls_(void)
#else
void ZGICLS(void)
#endif
{
  senddata("ZGICLS ",7);
}

/*------------------------- mouse -------------------------*/

#ifndef WINDOWS
void zgqpnt_(DCL_REAL *wx, DCL_REAL *wy, DCL_INT *mb)
#else
void ZGQPNT(DCL_REAL *wx, DCL_REAL *wy, DCL_INT *mb)
#endif
{
  senddata("ZGQPNT ",7);
  recvrnum(wx);
  recvrnum(wy);
  recvint(mb);
}

/*------------------------- inquiry -----------------------*/

#ifndef WINDOWS
void zgqwdc_(DCL_INT *lwdatr)
#else
void ZGQWDC(DCL_INT *lwdatr)
#endif
{
  senddata("ZGQWDC ",7);
  recvint(lwdatr);
}

#ifndef WINDOWS
void zgqclc_(DCL_INT *lclatr)
#else
void ZGQCLC(DCL_INT *lclatr)
#endif
{
  senddata("ZGQCLC ",7);
  recvint(lclatr);
}

#ifndef WINDOWS
void zgqtnc_(DCL_INT *ltnatr)
#else
void ZGQTNC(DCL_INT *ltnatr)
#endif
{
  senddata("ZGQTNC ",7);
  recvint(ltnatr);
}

#ifndef WINDOWS
void zgqimc_(DCL_INT *limatr)
#else
void ZGQIMC(DCL_INT *limatr)
#endif
{
  senddata("ZGQIMC ",7);
  recvint(limatr);
}

#ifndef WINDOWS
void zgqptc_(DCL_INT *lptatr)
#else
void ZGQPTC(DCL_INT *lptatr)
#endif
{
  senddata("ZGQPTC ",7);
  recvint(lptatr);
}

#ifndef WINDOWS
void zgqrct_(DCL_REAL *wsxmn, DCL_REAL *wsxmx, DCL_REAL *wsymn, DCL_REAL *wsymx, DCL_REAL *fact)
#else
void ZGQRCT(DCL_REAL *wsxmn, DCL_REAL *wsxmx, DCL_REAL *wsymn, DCL_REAL *wsymx, DCL_REAL *fact)
#endif
{
  float fdat;
  
  senddata("ZGQRCT ",7);
  recvrnum(&fdat);
  *wsxmn=(DCL_REAL)fdat;
  recvrnum(&fdat);
  *wsxmx=(DCL_REAL)fdat;
  recvrnum(&fdat);
  *wsymn=(DCL_REAL)fdat;
  recvrnum(&fdat);
  *wsymx=(DCL_REAL)fdat;
  recvrnum(&fdat);
  *fact=(DCL_REAL)fdat;

}

#ifndef WINDOWS
void zgsrot_(DCL_INT *iwtrot)
#else
void ZGSROT(DCL_INT *iwtrot)
#endif
{
  senddata("ZGSROT ",7);
  sendinum(*iwtrot);  
}

// New function for Fullcolor
#ifndef WINDOWS
void zgsfcm_(DCL_INT *lfc)
#else
void ZGSFCM(DCL_INT *lfc)
#endif
{
  senddata("ZGSFCM ",7);
  sendinum(*lfc);
}

#ifndef WINDOWS
void zgslcl_(DCL_INT *icolor)
#else
void ZGSLCL(DCL_INT *icolor)
#endif
{
  senddata("ZGSLCL ",7);
  sendinum(*icolor);
}

#ifndef WINDOWS
void zgstcl_(DCL_INT *icolor)
#else
void ZGSTCL(DCL_INT *icolor)
#endif
{
  senddata("ZGSTCL ",7);
  sendinum(*icolor);
}

#ifndef WINDOWS
void zgiclr_(DCL_INT *image,DCL_INT *nlen)
#else
void ZGICLR(DCL_INT *image,DCL_INT *nlen)
#endif
{
  int i;
  int img[8192];

  for(i=0;i<*nlen;i++){
    img[i]=*(image+i);
  }

  senddata("ZGICLR ",7);
  sendinum(*nlen);
  sendiary(img,*nlen);
}

#ifndef WINDOWS
void zgclini_(char clrmap[], DCL_INT *lfgbg)
#else
void ZGCLINI(char clrmap[], DCL_INT *lfgbg)
#endif
{
  senddata("ZGCLINI ",8);
  senddata(clrmap,strlen(clrmap));
  sendinum(*lfgbg);
}
