/*Povides services to access the network, i.e. access romote procedure.
  It links client.c to access functions sum and product.*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include "service.h"

int sock;
struct sockaddr_in serv_addr;
extern char dispatcher[100];
extern int port;
int status;

/*The function helps client to connect dispatcher first, find out which server
  (IP address,port number) provides the servies it needed. Then the client
  connects the dispatcher directly,sending operands to it, and finally get
  result from the server. It returns the value of status, if sth wrong happened
  during the connection to dispatcher, status will be i, if sth wrong happened 
  during the connection to server, staturs will be -1. Otherwise,0 is returned.*/
int operation(char *op,int a,int b,int *c)
{
 char feedback[100];
 char dest[60];
 int destport;
 int delay=RETRY_DELAY;
 int retries=1;
 char message[100];

 printf("Connectting to the dispatcher......"); 
 status=10;

 /*Client will try MAX_RETRIES times to connect to dispatcher.*/
 while(retries<=MAX_RETRIES)
   { 
     char request[100]="client "; /*request will be send to dispatcher.*/
     strcat(request,op);
     sleep(delay);
     delay *=2;
     retries ++;

     /*NOW BEGINE TO CONNECT TO DISPATCHER.*/
   
     /*if connection to dispatcher succeeds,status will be 0,otherwise 1.*/
     if((status=DISP*connect_remote(dispatcher,port,&sock,&serv_addr))!=0)
       {printf("status is %d\n",status); 
       continue;
       }

     printf("Sending request to the dispatcher ......");
     
     /* send request to dispatcher,declare it is a client and also the service
       it needed. If send fails, status will be 1.*/
     if(send(sock,request,strlen(request)+1,0)==-1)
       {
	 printf("Unable to send the request to dispatcher.\n");
         status++;
         continue;
       }
     printf("Done!\n");
   
     printf("Reciveing server info from the dispatcher......");
     
     /*if recv from dispatcher fails, status will be 1.*/
     if(recv(sock,feedback,100,0)==-1) 
       {
	 printf("Unable to receive respond from dispatcher.\n");
         status++;
	 continue;
       }
     
     /*dispatcher informs client that there is no server available to 
       provide the service client needed.*/
     if(strcmp(feedback,"Not Available.")==0) 
       {
	 printf("The server is not working now.\n");
         status++;
	 continue;
       }

     printf("Done!\n");
     strtok(feedback," "); /*feedback contains the ip address and port number
			     of the available server.*/
     strcpy(dest,feedback);    
     destport=atoi(strtok(0," "));
     break;
   }
 
  /*Client will try MAX_RETRIES times to connect to dispatcher.*/
     if(retries>MAX_RETRIES) 
       {
        printf("Tried enough time.The dispatcher is not cooperative.Give up.\n");
        close(sock);
        return status;
       }
 close(sock);

  
  /*NOW BEGINE TO CONNECT TO SERVER.*/
   printf("Connecting to the server ......");
   
   /*if connect succeeds, status will become 0,otherwise -1.*/
   if((status=DEST*connect_remote(dest,destport,&sock,&serv_addr))!=0) 
     {
       printf("The server is not reachable.\n");
      return status;
     }
   /*  message[0]='\0';*/

   /*message will be sent to server, containing the service requested and the
     according operands.*/
  sprintf(message,"%s %d %d",op,a,b);

  printf("Sending the operands to server %s at port %d......",dest,destport);
 
  /*if send fails, return -1.*/
  if(send(sock,message,strlen(message)+1,0)==-1) 
   return --status;
  printf("Done!\n");
  printf("Receiving the result from the server %s......",dest);
  
  /*if recv fails, return -1,otherwise receive the calculation result from
    server in result.*/
  if(recv(sock,feedback,100,0)==-1)  return --status;
  printf("Done!\n");

  /*put the result in c.*/
  *c=atoi(feedback);
  close(sock);

  return status;
}


/*A small function named sum, just call function operation to do all the things
  for it.*/
int sum(int a,int b,int *c)
  {
   status=operation("sum",a,b,c);
   return status;
  }

/*A small function named sum, just call function operation to do all the things
  for it.*/
int product(int a,int b,int *c)
  {
   status=0;
   status=operation("product",a,b,c);
   return status;
  }