/*************************************************************************
Connection class (.cpp implementation)
***************************************************************************/

#include "openconn.h"

/*********
 Reads in a URL; then http:// or file: will be stripped off as well as
 the hostname, along with any CGI scripting information after a '?'.  The
 rest of the information will be used to access the appropriate html page
 or local file.
 NOTE: This version will not corrupt the string you pass in.
**********/
int Connection::openConnection(char *wholeurl)
{

   char *stringtok;
   char *tokenptr;
   int  port = DEFAULTPORT;
   char buf[BUFSIZE];
   char server_host[URLSIZE];
   char *url = new char[strlen(wholeurl)+1];

   struct servent       *sp;
   struct hostent       *hp;
   struct sockaddr_in   sin;
   
   fileread = -1;   

   strcpy(url,wholeurl);
   //Strips off everything after the ? in the URL (if ? exists)
   tokenptr = strtok(url,"?");
   
   //Check for a valid URL with "http://" at the beginning
   if (strncasecmp(url,HTTP_PREFIX, 7) == 0)
   {
      int no_file = (url[strlen(url) - 1] == '/');
      tokenptr = strtok(url,"/");  //removes first / after http:
      tokenptr = strtok(NULL,"/"); //removes second / after http:
      strcpy(buf,tokenptr);        //buf contains domain name and port(if one is specified)
      tokenptr = strtok(NULL,"/");
      
      //This while loop gets the location of the page requested
      strcpy(location,"/");        //starts location with a /
      while(tokenptr != NULL)
      {
         strcat(location,tokenptr);
         strcat(location,"/");
         tokenptr = strtok(NULL,"/");
      }
      if (no_file)                 //remove last '/' if file name included
        location[strlen(location)] = '\0';
      else location[strlen(location)-1] = '\0';
      tokenptr = strtok(buf,":");
      strcpy(server_host,tokenptr);  //extract domain name
      tokenptr = strtok(NULL,":");
      if (tokenptr != NULL)     // port defaults to 80 if not specified
      {
         port = atoi(tokenptr); //Some error checking will still need to be done
      }
      
      cout << "Domain: " << server_host << endl;
      cout << "Port: " << port << endl;
      cout << "File: " << location << endl;

      /* Establishing connection here */
      sd = socket(AF_INET,SOCK_STREAM,0);  // Creates socket descriptor
      hp = gethostbyname(server_host);     // get the server's host information including IP address
      if (hp == NULL)
      {
         cerr << "ERROR: Bad server name" << endl;
         delete url;
         return ERROR;
      }
      bzero((char *)&sin,sizeof(sin));  //clears sizeof(sin) bytes in the structure sin
      bcopy(hp->h_addr,(char *)&sin.sin_addr,hp->h_length);     // Copy the IP address in hp to sin
      sin.sin_port = htons(port);       // assign port ID
      sin.sin_family = hp->h_addrtype;  // specify address type
      if (connect(sd,(struct sockaddr *)&sin,sizeof(sin)) == ERROR)
      {
         cerr << "Bad connection" << endl;
         delete url;
         return ERROR;
      }
      fileread = SOCKET_TYPE;  //we are not reading from a file but a socket
      write_socket();	       //request file from server
   }
   else if (strncasecmp(url,FILE_PREFIX, 5) == 0)
   {
      tokenptr = strtok(url,":");   //strip "file:"
      tokenptr = strtok(NULL,":");
      cout << "File -> " << tokenptr << endl;
      inputFile.open(tokenptr, ios::in);
      if (!inputFile)
      {
          cerr << "ERROR: Could not open file " << tokenptr << endl;
          delete url;
          return ERROR;
      }
      fileread = FILE_TYPE;    //reading from a local file, not a socket
   }
   else
   {
      cerr << "ERROR: Invalid URL" << endl;      
      delete url;
      return ERROR;
   }
   delete url;
   return 0;
}

//sends a GET message to the server to request the file
void Connection::write_socket()
{   
   char msg[URLSIZE] = "GET ";
   strcat(msg,location);
   strcat(msg,"\n");
   write(sd,msg,strlen(msg)+1);
   write(sd,"\n",2);
}

/***********
 Everytime read_buf is called up to BUFSIZE number of bytes is read into
 buf.  The number of bytes actually read is returned. 
 NOTE: 0 is returned when EOF is reached.
************/
int Connection::read_buf(char *buf)
{
    int len;    
   
    if (fileread == SOCKET_TYPE)
    {
    	len = recv(sd,buf,BUFSIZE-1,O_NDELAY);   //read one less than max size
       if (len == ERROR) {
         len = 0;
       }
       
       buf[len] = '\0';
       return len;
    }
    else if (fileread == FILE_TYPE)
    {       
       if (inputFile.eof())
       {
          len = 0;
       }
       else
       {
          inputFile.read(buf,BUFSIZE-1);  //read one less than max size
          len = inputFile.gcount();	  //number of bytes read
          buf[len] = '\0';
       }
       return len;
    }
    else 
       return 0;
}

//must call closeConnection when done reading from each file
void Connection::closeConnection()
{
   if (fileread == SOCKET_TYPE)
   {
      close(sd);
   }
   else if (fileread == FILE_TYPE)
   {
      inputFile.close();
   }
}

