#include <iostream>
#include <string>
#include <cstdlib>
#include <map>
#include <iterator>
#include <algorithm>

std::string PlusToSpace(const std::string s)
{
  std::string result;
  
  for (int i = 0; i < s.length(); i++)
    result += s[i] == '+' ? ' ' : s[i];
  
  return result;
}

char X2C(char c1, char c2)
{
  unsigned char digit;
  
  digit = c1 >= 'A' ? (c1 & 0xdf) - 'A' + 10 : c1 - '0';
  digit *= 16;
  digit += c2 >= 'A' ? (c2 & 0xdf) - 'A' + 10 : c2 - '0';

  return digit;
}

std::string UnescapeURL(const std::string s)
{
  std::string result;
  
  for (int i = 0; i < s.length(); i++)
    if (s[i] != '%' || i + 2 >= s.length())
      result += s[i];
    else {
      result += X2C(s[i + 1], s[i + 2]);
      i += 2;
    }
  
  return result;
}

std::map<std::string, std::string> ParseQuery(const std::string input)
{
  std::map<std::string, std::string> result;

  std::string::const_iterator i = input.begin();
  while (i != input.end()) {
    // Ignore leading separators.
    i = std::find_if(i, input.end(), std::bind2nd(std::not_equal_to<char>(), '&'));

    // Find end of next block.
    std::string::const_iterator j = std::find(i, input.end(), '&');
    
    //std::cout << std::string(i, j) << std::endl;
    std::string entry = UnescapeURL(PlusToSpace(std::string(i, j)));

    std::string::iterator k = std::find(entry.begin(), entry.end(), '=');
    
    if (k == entry.end()) {
      std::cout << "Malformed entry (" << entry << "): missing '=' separator." << std::endl;
      exit(1);
    }
    
    //std::cout << std::string(entry.begin(), k) << " - " << std::string(k + 1, entry.end()) << std::endl;
    result[std::string(entry.begin(), k)] = std::string(k + 1, entry.end());
    
    i = j;
  }
  
  return result;
}

int main (int argc, char * const argv[]) {
  std::cout << "Content-type: text/html" << std::endl << std::endl;
  
  char *requestMethod = getenv("REQUEST_METHOD");
  if (!requestMethod || std::string(requestMethod) != "POST") {
    std::cout << "This script should be referenced with a METHOD of POST." << std::endl << "If you don't understand this, see this <A HREF=\"http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html\">forms overview</A>." << std::endl;
    exit(1);
  }
  
  char *contentType = getenv("CONTENT_TYPE");
  if (!contentType || std::string(contentType) != "application/x-www-form-urlencoded") {
    std::cout << "This script can only be used to decode form results." << std::endl;
    exit(1);
  }
  
  int contentLength = atoi(getenv("CONTENT_LENGTH"));
  //std::cout << "Content length = " << cl << std::endl;
  
  std::string input;
  char c;
  while (std::cin.get(c))
    input += c;
  
  //std::cout << "Input:" << std::endl << input;
  //std::cout << "Input length = " << input.length() << std::endl;
  if (contentLength != input.length()) {
    std::cout << "CONTENT_LENGTH contains incorrect value." << std::endl;
    exit(1);
  }
  
  std::map<std::string, std::string> query = ParseQuery(input);
  
  std::cout << "<H1>Query Results</H1>";
  std::cout << "You submitted the following name/value pairs:<p>" << std::endl;
  std::cout << "<ul>" << std::endl;
  
  for (std::map<std::string, std::string>::iterator p = query.begin(); p != query.end(); p++)
    std::cout << "<li> <code>" << (*p).first << " = " << (*p).second << "</code>" << std::endl;
  
  std::cout << "</ul>" << std::endl;

  return 0;
}

