#include <6170.h>
#include "ps5/http_server.h"
#include "ps5/http_response.h"
#include "ps5/error_response.h"
#include "ps5/server.h"


#include <strstream.h>
#include <unistd.h>
#include <ctype.h>

http_server::http_server(int port_, web_node *root__) {
    serv = new server(port_);
    root_ = root__;
    debugging = false;
}

static string trim_crud(string x) {
// remove leading and trailing whitespace
    int l = 0, r = x.length() - 1;
    while (l <= r && isspace(x[l])) l++;
    while (r >= l && isspace(x[r])) r--;
    return x.substring(l, r - l + 1);
}

void http_server::handle_one() {
    int s = serv->accept();
    fstream st = s;
    istream &in = st;
    ostream &out = st;
    bool http_10 = false;

    string method, url, proto;
    extensions *ext = new extensions;

    if ((in >> method ))
        {
	    
	    if ((method == "GET" || method == "POST") &&
	in >> url &&
	url[0] == '/') {
	if (!read_line(in, proto)) goto close;
    } else goto close;
	}
    else goto close;
    if (debugging) {
	cerr << method << ' ' << url << proto << '\n';
    }
    proto = trim_crud(proto);
    if (proto == "HTTP/1.0") {
	http_10 = true;
	// skip over headers
	string hdr, val;
        for (;;) {
	    if (!read_line(in, hdr)) goto close;
	    if (hdr == "\r" || hdr.length() == 0) break;
	    int index;
	    if (!hdr.find_char(':', 0, index)) {
		strstream s;
		s << "Invalid header line: \"" << trim_crud(hdr) << "\"\n";
		if (debugging) cerr << s.str();
	        error_response(http_response::BAD_REQUEST, s.str()).send(out);
		goto close;
	    }
	    string n = hdr.substring(0, index);
	    index++;
	    if (index < hdr.length()) {
		val = trim_crud(hdr.substring(index, hdr.length() - index));
	    } else {
		val = "";
	    }
	    string oldval;
	    if (ext->find(n, oldval)) {
		ext->store(n, oldval + " " + val);
	    } else {
		ext->store(n, val);
	    }
	    if (debugging) cerr << hdr << '\n';
	}
    } else if (proto == "") {
	http_10 = false;
    } else  {
	strstream s;
	s << "<b>Don't know how to handle protocol \"" << proto << "\"</b>\n";
	error_response(http_response::NOT_IMPLEMENTED, s.str()).send(out);
	if (debugging) cerr << s.str();
	goto close;
    }
    {
	http_response *hr = root_->get(url, ext);
	if (http_10) hr->send(out);
	else hr->body(out);
	if (debugging) cerr << hr->code() << ' ' <<
	    result_description(hr->code()) << '\n';
    }
close:
    out.flush();
    st.close();
    
    
}

int http_server::file_descriptor() {
    return serv->file_descriptor();
}

void http_server::close() {
    serv->close();
}

void http_server::debug(bool d) {
    debugging = d;
}
