#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>

#define K	1024

#define min(a,b)	((a) < (b)? (a) : (b))

struct url {
  char *host;
  uint16_t port;
  char *path;
};

/*
 * wget.c: 10 points
 *   A program to connect to a server and receive data into a file.  This file
 * is mearly a guide to how to do this assignment, you may do it differently if
 * you are able.
 *  The bottom of this page has example HTTP/1.1 response headers you may use
 * as a reference.
 */

/*
 * http://<host>[:<port>][/<path>]
 */
struct url *processurl(char *str)
{
  static struct url *u;
  char buf[K], *s;
  int i;

  // A valid URL in our case only uses the http protocol.  If it's not http://
  // then return a NULL


  
  // Use malloc to allocate a new url structure:


  // Scan forward starting at character 7 of the string "str" and go until we
  // encounter either a) the end of the string ('\0'), a colon (':') or a slash
  // ('/').  Put each character found in buf.



  // Null terminal buf and duplicate buf into the host field of the url structure:



  // If we encountered a : above, then parse out the port number, otherwise set
  // the port to 80 by default.




  // If we hit a '/' save the rest of the url as the path in the url structure:
  // otherwise make "/" the default path.


  return u;
}

// A function to free a url structure:
void freeurl(struct url *u)
{
  free(u->host);
  free(u->path);
  free(u);
}

// Opens a socket to a web server using the information in a url structure, uses
// fdopen() on the socket so we can return a FILE stream.  This function should
// return NULL on any error (after printing an error message).
FILE *webopen(struct url *u)
{
  struct sockaddr_in server;
  struct hostent *he;
  FILE *sock;
  int sfd;

  // Create a SOCK_STREAM internet socket:




  // Setup the severs address, use gethostbyname() to get the address:








  // Use connect() to connect to the server:



  // Use fdopen to make a stream descriptor for the socket, and return it.



  return sock;
}

// Reads the header from a HTTP/1.1 request, setting the status and clen
// (content-length)  Headers this function should check are:
// HTTP/1.1 (for the status)
// Location: (for the redirect URL)
// Content-Length: (for the content length, if present)
// Transfer-Encoding: (if this is "chunked" set clen to -2 and ignore any
//   subsequent Content-Length.
// Return a new URL structure if Location is present and the url in it resolves
//   properly.
struct url *getheader(FILE *sock, int *status, int *clen)
{
  char buf[K], *s;
  struct url *u = NULL;

  *clen = -1;

  // Read lines from sock, using fgets() into buf:

    // Use strtok() to split out the first word in buf.  Use " \r\n" for the
    // deliminator. If strtok() returns NULL for the first word, exit the loop.


    // Use strncasecmp() to check the first word against the above headers.
    // use another call to strtok() to get the second word out of the line
    // and use as appropriate to the header.
    
    
      // handle HTTP/1.1:
      
      
    
      // handle Location:
      
      
    
      // handle Content-Length:
      
      
      
    
      // handle Transfer-Encoding:
      
      
      

  return u;
}

// Reads a "chunk" (len) of data from the server (sock), saving it in the file
// given (fd).  Returns -1 on error, 0 on success.
int readchunk(FILE *sock, int fd, int len)
{
  char buf[K];
  int w;

  // a while len > 0 loop:
  
    // read min of K or len bytes from sock:

    // Return -1 if read above returns 0;

    // write to file the number of bytes read, return -1 if there is an error
    // on write:

    // subtract number of bytes read from len:
    
  
  return 0;
}

// Saves the file, based on the context length:
void save(FILE *sock, char *file, int clen)
{
  char buf[K];
  int fd, w = 0;

  // Open "file" for writing, create it if it doesn't exist and truncate if it
  // does.  Remember to set the mode.  Print a message and exit on error.

  
  

  switch(clen) {
    case -2:	// Chunked data transfer
      // do-while sock not end of file or error (feof()/ferror()):

	// Get the hex encoded length of next chunk (fgets()):

	// use strtol() with a base of 16 to process string into a number:

	// break if chunk size <= 0:

	// call readchunk to read and save the data chunk:

	// use fgets() again to eat newline at the end of the chunk.


      break;
    case -1:	// No content-length, so read until EOF on the sock stream:
      // Use fread() to read from the socket K sized blocks of data and write
      // that to fd until feof() or ferror() on the socket is true:




      break;
    default:	// Read clen bytes and thats it (one chunk):
      readchunk(sock, fd, clen);
      break;
  }
  close(fd);
}

int main(int argc, char *argv[])
{
  struct url *u;
  FILE *sock;
  char buf[K];
  int status, clen;

  if (argc < 3) {
    fprintf(stderr,"Usage: wget <URL> <filename>\n");
    return 0;
  }

  u = processurl(argv[1]);

  do {
    if ((sock = webopen(u)) == NULL) exit(1);

    fprintf(sock, "GET %s HTTP/1.1\nHost: %s\n\n", u->path, u->host);
    freeurl(u);

    u = getheader(sock, &status, &clen);
    switch(status) {
      case 404:
	fprintf(stderr,"Error 404 File not found.\n");
	break;
      case 200:
	save(sock, argv[2], clen);
	break;
      default:
	break;
    }
    fclose(sock);
  } while(u);

  return 0;
}

/*
Example headers:

Example OK (200) header:
=======================
HTTP/1.1 200 OK
Date: Mon, 15 Feb 2016 18:34:30 GMT
Server: Apache/2.4.17 (Unix) OpenSSL/1.0.2f PHP/5.6.17
Last-Modified: Tue, 02 Feb 2016 21:27:46 GMT
ETag: "a88-52ad02c32abea"
Accept-Ranges: bytes
Content-Length: 2696
Content-Type: text/html

Example redirect (302) header:
=============================
HTTP/1.1 302 Found
Date: Mon, 15 Feb 2016 18:31:11 GMT
Server: Apache/2.4.17 (Unix) OpenSSL/1.0.2f PHP/5.6.17
X-Powered-By: PHP/5.6.17
Location: http://cs.indstate.edu/info/
Content-Length: 0
Content-Type: text/html; charset=UTF-8

Chunked transfer header:
=======================
HTTP/1.1 200 OK
Date: Tue, 16 Feb 2016 17:35:16 GMT
Server: Apache/2.4.17 (Unix) OpenSSL/1.0.2f PHP/5.6.17
Accept-Ranges: bytes
Transfer-Encoding: chunked
Content-Type: text/html

297a
...

*/
