/**
 * Files : Palindrome_client.cc 
 * Name  : Edison Chindrawaly
 * Class : CSCI 3780 Spring 2001
 * HW    : #3
 */

#include "MyHeader.h"

char* askIP(char *);
char* askPort(char *);
void processIt(char* , char* );
int openConnection(char *, char *);
void closeConnection(int);
int sendAll(int, char *);
int receiveAll(int, char *);

//interact with user
int getUserChoice(void);
void getUserFile(int );
void getUserInput(int );


void main(int argc, char **argv)
{
 char* tempAdd;
 char* IP_add = strdup(askIP(tempAdd));     
 char* Host_port = strdup(askPort(tempAdd));
 processIt(IP_add, Host_port);
 exit(0);
}

/**
 * askIP's method is to ask user for the host IP add
 * @param  char* tAdd 
 * @return char* IP address
 */
char* askIP(char* tAdd)
{
 char temp[16+1];
 cout<<"Enter the hostname (e.g. csp04) : "<<flush;
 cin.getline(temp,17);
 strcpy(tAdd,temp);
 return tAdd;
}

/**
 * askPort's method is to ask user for the host port number.
 * The host port number has a max of 6 digits
 * @param  char* taAdd
 * @return char* the port number of user.
 */
char* askPort(char* tAdd)
{
  char temp[5+1];
  cout<<"Enter the host port: "<<flush;
  cin.getline(temp,6);
  strcpy(tAdd,temp);
  return tAdd;
}

/**
 * openConnection's method is to open connection to host server
 * with the given IP address and the given port number. Once the
 * server accepts the connection, openConnection's method will
 * return the sockfd of the accepted/rejected connection.
 * @param  char* ipAdd contains host IP address
 *         char* hostPort contains host port number
 * @return int sockfd contains the sock descriptor of the accepted
           or rejected connection(-1)
 */
int openConnection(char* ipAdd, char* hostPort)
{
 int sockfd;
 struct hostent *hosten;
 struct sockaddr_in serv_addr;

 if((hosten = gethostbyname(ipAdd)) == NULL)
 {
  perror("Error: need hostname! ");
  exit(1);
 }
 if((sockfd=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP))==-1)
 {
   perror("socket error");
   exit(1);
 }
 serv_addr.sin_family = AF_INET;
 serv_addr.sin_port   = htons(atoi(hostPort));
 serv_addr.sin_addr   = *((struct in_addr *)hosten->h_addr);
 bzero(&(serv_addr.sin_zero),8);

 if(connect(sockfd,(struct sockaddr *)&serv_addr,
    sizeof(struct sockaddr))==-1)
 {
   perror("connect error");
   exit(1);
 }

 return sockfd;
}

/**
 * processIt's method is to process the part of 
 * getting user input and send the user input [palindrome]
 * to the server to be process by the server. It turns
 * the server will return array contains answer to
 * the user input.
 * @param  char* ipAdd contains host ip address
 *         char* hostPort contains host port number
 * @return none
 */
void processIt(char* ipAdd, char* hostPort)
{
 int sockfd = openConnection(ipAdd,hostPort);
 int numbytes;
 char buffer[MAXSIZE];

 if((numbytes=recv(sockfd, buffer, MAXSIZE, 0)) == -1)
 {
   perror("recv error");
   closeConnection(sockfd);
   exit(1);
 }

 buffer[numbytes] = '\0';
 printf("Received: %s", buffer);
 strcpy(buffer,"reply to server: hello server\n");
 send(sockfd,buffer,strlen(buffer),0);

 int respond = 0;
 do
 {
  respond = getUserChoice();
  switch(respond)
  {
   case 1:
           getUserInput(sockfd);
           break;
   case 2:
           getUserFile(sockfd);
          
   case 3: break;
  }
 } while(respond != 3);
 closeConnection(sockfd);
}

/**
 * closeConnection's method is to close the socket
 * @param  int sockfd contains the connection socket
 * @return none
 */
void closeConnection(int sockfd)
{
 close(sockfd);
}

/**
 * getUserChoice's method is to get user choice whether
 * the user wants to input from keyboard or file
 * @param  none
 * @return choice = 1 to enter from keyboard
 *         choice = 2 to enter from file
 *         choice = 3 to exit
 */
int getUserChoice()
{
 int choice = 0;
 do
 {
  cout<<"Would you like to: "<<endl;
  cout<<"1. Enter the words manually."<<endl;
  cout<<"2. Enter the words from the file."<<endl;
  cout<<"3. Exit."<<endl;
  cout<<"NOTE: max length of word = 128 characters.\n"<<endl;
  cout<<"Your choice : "<<flush;
  cin>>choice;
  if((choice == 1) || (choice == 2) || (choice == 3))
    return choice;
  cout<<"Invalid choice!"<<endl;
 } while(1);
}

/**
 * getUserInput's method is to getUserInput from keyboard
 * It uses array of char with MAXSIZE of 128 words. The
 * process of reading user input will end when user type END
 * or the count has reach 127 [MAXSIZE-1].
 * @param  char[] msgbuffer contains nothing
 * @return msgbuffer[] contain users input
 */
void getUserInput(int sockfd)
{
 int count = 0;
 char buf[MAXSIZE];
 cout<<"Enter the words you want to enter(max length=128)\n";
 cout<<"Type END to end the process\n";
 do
 {
  buf[0]='\0';
  cout<<"word : "<<flush;
  cin.getline(buf,MAXSIZE);
  if(strcasecmp(buf,"END") == 0)
    break;   
  if(sendAll(sockfd,buf) < 0) 
  {
   perror("send error\n");
   closeConnection(sockfd);
   exit(0);
  }
  if(receiveAll(sockfd,buf) < 0)
  {
   perror("receive error\n");
   closeConnection(sockfd);
   exit(0);
  }
 }while(true);
}

/**
 * getUserFile's method is to get user input from the
 * given file (user determine the file.) This method
 * assumed that the file is in the current directory.
 * @param  char* msgBuffer contains empty string
 * @return char* the result of the reading user input
 */
void getUserFile(int sockfd)
{
 char buffer[MAXSIZE];
 char filename[20+1]; 
 cout<<"Enter the file name: "<<flush;
 cin>>filename;
 if(strlen(filename)<1)
 {
  cout<<"You need to enter the filename"<<endl;
  exit(0);
 }
 ifstream readfile(filename);
 if(!readfile.is_open())
 {
  cout<<"Unable to open the file: "<<filename<<endl;
  exit(0);
 }
 while(!readfile.eof())
 {
  readfile.getline(buffer,MAXSIZE);
  if(sendAll(sockfd,buffer) < 0) 
  {
   perror("send error\n");
   closeConnection(sockfd);
   readfile.close();
   exit(0);
  }
  if(receiveAll(sockfd,buffer) < 0)
  {
   perror("receive error\n");
   closeConnection(sockfd);
   readfile.close();
   exit(0);
  }
 }
 readfile.close();
}

/**
 * sendAll's method is to send string with the
 * given socket file descriptor to the host.
 * @param  int sockfd contains socket descriptor
 *         char* buffer contains the string to send
 * @return int = 0 if successful else -1
 */
int sendAll(int sockfd, char* buffer)
{
  int sendBytes = 0;
  int total = 0;
  int length = strlen(buffer);
  int bytesleft = length;
 
  while(total < length)
  {
    sendBytes = send(sockfd, buffer+total, bytesleft, 0);
    if(sendBytes == -1)
       break;
    total += sendBytes;
    bytesleft -= sendBytes;
  }
  length = total;
  return sendBytes==-1? -1:0;      
}

/**
 * receiveAll's method is to receive message of 0 & 1
 * 0 means not palindrome. 1 means palindrome.
 * @param  int sockfd contains socket descriptor
 *         char* original contains original string
 * @return int -1 if it fails else return 0 if successfull
 */
int receiveAll(int sockfd, char* original)
{
 char buffer[MAXSIZE];
 int numbytes = 0;

 if((numbytes=recv(sockfd,buffer,MAXSIZE,0))<0)
 {
   perror("received error from server\n");
   return -1;
 }
 buffer[numbytes] = '\0';
 if(buffer[0] == '0')
   printf("The word %s is not a palindrome.\n",original);
 else if(buffer[0] == '1')
   printf("The word %s is a palindrome.\n",original);
 return 0;

}
 

1