#include <6170.h>
#include "ps5/url_ops.h"
#include <ctype.h>

// $Header: /mit/6.170/groups/se01/.cvsroot/src/ps5/url_ops.C,v 1.16 1995/12/11 18:52:48 rgmisra Exp $

string extract_pathname(string URL) {
    int index;
    if (!URL.find_char('?', 0, index)) {
	index = URL.length();
    }
    int start = 0;
    while (start < URL.length() && URL[start] == '/') start++;
    return URL.substring(start, index - start);
}

string extract_query(string URL) {
    int index;
    if (!URL.find_char('?', 0, index)) return string();
    return URL.substring(index + 1, URL.length() - (index + 1));
}

static void split_path(string URL, int &start, int &end) {
    // effects: the location of the first character of first component is
    // placed in "start", and the location of the last character of that
    // component, plus one, is placed in "end". If there is no first component,
    // 0 is placed in both.
    start = 0;
    while (start < URL.length() && URL[start] == '/') start++;
    if (start == URL.length()) {
	start = 0;
	end = 0;
	return;
    }
    end = start + 1;
    while (end < URL.length() && URL[end] != '/') end++;
}

string first_component(string URL) {
    int start, next;
    split_path(URL, start, next);
    return extract_pathname(URL.substring(start, next - start));
}

string rest_components(string URL) {
    int start, next;
    split_path(URL, start, next);
    while (next < URL.length() && URL[next] == '/') next++;
    return URL.substring(next, URL.length() - next);
}

string last_component(string URL) {
    int last = URL.length() - 1;
    while (last >= 0 && URL[last] == '/') last--;
    last++;
    int first = last-1;
    while (first >= 0 && URL[first] != '/') first--;
    first++;
    if (first < last) return URL.substring(first, last - first);
    else return "";
}

string extension(string pathname) {
    int end = pathname.length() - 1;
    while (end > 0 && pathname[end] == '/') end--;
    int last = end - 1;
    while (last > 0 &&
	   pathname[last] != '/' &&
	   pathname[last] != '.') last--;
    if (last >= 0 && pathname[last] == '.') {
	return pathname.substring(last + 1, end - last);
    } else {
	return "";
    }
}

static int hex_to_nibble (char c)
// Effects: returns a nibble between 0 and 15
// Requires: c be in 0-9 a-f A-F
{
    switch (toupper(c))  {
    case '0':
	return 0;
    case '1': return 1;
    case '2': return 2;
    case '3': return 3;
    case '4': return 4;
    case '5': return 5;
    case '6': return 6;
    case '7': return 7;
    case '8': return 8;
    case '9': return 9;
    case 'A': return 10;
    case 'B': return 11;
    case 'C': return 12;
    case 'D': return 13;
    case 'E': return 14;
    case 'F': return 15;
    default: check(false, "hex_to_nibble passed non hex digit");
    }
    return 0; // Never ever reached.
}

bool unescape_uri(string in, string &out) {
    

    class unescaping_generator : public generator <char> {
    public:
	// Overview: Returns the characters of the string given to the
	// constructor replacing %xx (where xx is two hex digits) with the
	// appropriate unescaped character as per RFC 1738.


	unescaping_generator (string in ) {
	    s = in;
	    l = in.length();
	    broken_string = false;
	    i = 0;
    }

	bool get (char &c) {
	    if (i == l)
		return false;
	    if ( s[i] == '%') {
		if ((i+2  < l)&& (isxdigit(s[i+1]))&&(isxdigit(s[i+2]))) {
		    unsigned char ch = 16*hex_to_nibble(s[i+1])+hex_to_nibble(s[i+2]);
		    c = ch;
		    i += 3;
		    return true;
		}
		broken_string = true;
		i = l;
		    return false;
	    }
	    else {
		c = s[i++];
		return true;
	    }
	}

	bool broken() {return broken_string;
	}

    private:
	bool broken_string;
	int i,l;
	string s;
    } gen(in);
    string newstr(&gen);
    if ( gen.broken())
	return false;
    out = newstr;
    return true;
}

string escape_uri (string s) {
    return s; // Not quite long-term solution
}


map <string,string> *parse_query (string q) {
    map <string, string> *m = new map <string,string>;
    bool finding_value = false;		// If true, we are finding a value else a name.
    string fname;		// Generic string for field names
    int start = 0;			// 

    int lc;
    
    for ( lc = 0; lc < q.length(); lc++) {
	if (q[lc] == '='){
	    if (finding_value)
		return 0;		// We have an = in the middle of a field name.
	    finding_value = true;
	    if (!unescape_uri(q.substring(start,lc-start),fname))
		return 0;			//won't unescape
	    start = lc+1;
	}
	else if ((q[lc] == '&') || (lc == q.length())) {
	    if (!finding_value)
		return 0;	//  bogus: & in a field name.
	    string value;
	    if (!unescape_uri(q.substring(start,lc-start), value))
		return 0;	// unable to unescape value
	    if (value.length() != 0)
m->add(fname,value);
	    start = lc+1;
finding_value = false;
	}
    }
    if (finding_value) {
	    string value;
	    if (!unescape_uri(q.substring(start,lc-start), value))
		return 0;	// unable to unescape value
	    if (value.length() != 0)
m->add(fname,value);
}      
return m;
}

// string safeify_filename(string s) {
// int i;
// if (s.find_char('/',0,i))
// return "invalid_fil";
// return s;
// }

	
// string safeify_filename(string s) {
//    int i;
//    string fixed_name;
//  
//    for (i = 0; i < s.length(); i++)
//	if (s[i] != '/')
//	    fixed_name.append(s[i]);
//    return fixed_name;
//}

string safeify_filename(string s) {
  int curr, last = 0;
  string fixed_name = s;

  while (fixed_name.find_char('/', last, curr)) {
    fixed_name = fixed_name.substring(0, curr) + fixed_name.substring(curr+1, fixed_name.length()-curr-1);
  }
  return fixed_name;
}
