#include <glib.h>
#include <libsoup/soup.h>
#include <string.h> /* strchr */
#include <stdio.h> /* sscanf */

#define TESTURL "http://www.gnome.org/~jstowers/conduit_test_data/Image.png"

#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))

static const char *months[] = {
	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

/* Parse date string. RFC 822, updated by RFC 1123.
 * Stores timeval in destination of GTimeVal pointer.
 * Returns boolean indicating if parseing was successful.
 */
gboolean
g_time_val_from_rfc1123 (const char *text, GTimeVal *tv)
{
	int i;
	int DD, MM, YYYY, hh, mm, ss;
	char tmp[25];

	/* validate input string formatting */
	g_return_val_if_fail (text != NULL, FALSE);
	g_return_val_if_fail (strlen (text) == 29, FALSE);

	i = sscanf (text, "%*3s, %d %s %d %d:%d:%d GMT",
			&DD, tmp, &YYYY, &hh, &mm, &ss);
	g_return_val_if_fail (i = 7, FALSE);

	MM = 0;
	for (i = ARRAY_SIZE (months) - 1; i > 0; i--) {
		if (strcmp (tmp, months[i]) == 0) {
			MM = i + 1;
			break;
		}
	}
	g_return_val_if_fail (MM != 0, FALSE);

	sprintf (tmp, "%04d-%02d-%02dT%02d:%02d:%02dZ",
			YYYY, MM, DD, hh, mm, ss);

	g_debug ("%s - %s", __FUNCTION__, tmp);

	return g_time_val_from_iso8601 (tmp, tv);
}

/* Parse date string. RFC 850, obsoleted by RFC 1036
 * Stores timeval in destination of GTimeVal pointer.
 * Returns boolean indicating if parseing was successful.
 */
gboolean
g_time_val_from_rfc850 (const char *text, GTimeVal *tv)
{
	int i;
	int DD, MM, YYYY, hh, mm, ss;
	char tmp[25];

	/* validate input string formatting */
	g_return_val_if_fail (text != NULL, FALSE);

	i = sscanf (text, "%*s %d-%3s-%d %d:%d:%d GMT", &DD, tmp, &YYYY,
			&hh, &mm, &ss);

	g_return_val_if_fail (i == 6, FALSE);

	MM=0;
	for (i = ARRAY_SIZE (months) - 1; i > 0; i--) {
		if (strcmp (tmp, months[i]) == 0) {
			MM = i + 1;
			break;
		}
	}
	g_return_val_if_fail (MM != 0, FALSE);

	/* year, 0-68 = 20xx, 69-99 = 19xx */
	YYYY += 1900;
	if (YYYY < 1969)
		YYYY += 100;


	sprintf (tmp, "%04d-%02d-%02dT%02d:%02d:%02dZ", YYYY, MM, DD,
			hh, mm, ss);

	g_debug ("%s - %s\n", __FUNCTION__, tmp);

	return g_time_val_from_iso8601 (tmp, tv);
}

/* Parse date string. Format as returned by asctime().
 * Stores timeval in destination of GTimeVal pointer.
 * Returns boolean indicating if parseing was successful.
 */
gboolean
g_time_val_from_asctime (const char *text, GTimeVal *tv)
{
	const char *pos;
	char tmp[25];
	size_t len;
	int i;
	int DD, MM, YYYY, hh, mm, ss;

	g_return_val_if_fail (text != NULL, FALSE);
	len = strlen (text);

	/* wkday */
	g_return_val_if_fail (text[3] == ' ', FALSE);

	pos = text+3;
	while (*pos == ' ')
		pos++;
	
	/* month */
	g_return_val_if_fail ((pos+4 < text+len) && pos[4] == ' ', FALSE);

	memcpy (tmp, pos, 3);
	tmp[3] = '\0';

	MM=0;
	for (i = ARRAY_SIZE (months) - 1; i > 0; i--) {
		if (strcmp (tmp, months[i]) == 0) {
			MM = i + 1;
			break;
		}
	}
	g_return_val_if_fail (MM != 0, FALSE);

	pos += 4;

	while (*pos == ' ')
		pos++;

	/* day */
	i=0;
	while (*pos != '\0' && *pos != ' ') {
		tmp[i] = *pos;
		pos++;
		i++;
	}
	tmp[i] = '\0';

	g_return_val_if_fail (*pos != '\0', FALSE);

	DD = atoi (tmp);

	while (*pos == ' ')
		pos++;

	/* time */
	g_return_val_if_fail (pos+8 < text+len, FALSE);
	g_return_val_if_fail (pos[2] == ':', FALSE);
	g_return_val_if_fail (pos[5] == ':', FALSE);
	g_return_val_if_fail (pos[8] == ' ', FALSE);

	g_return_val_if_fail (sscanf (pos, "%d:%d:%d", &hh, &mm, &ss) == 3,
			FALSE);

	while (*pos != '\0' && *pos != ' ')
		pos++;
	
	g_return_val_if_fail (*pos != '\0', FALSE);

	while (*pos == ' ')
		pos++;

	YYYY = atoi (pos);

	sprintf (tmp, "%04d-%02d-%02dT%02d:%02d:%02dZ", YYYY, MM, DD,
			hh, mm, ss);

	g_debug ("%s - %s\n", __FUNCTION__, tmp);

	return g_time_val_from_iso8601 (tmp, tv);
}

/* Parsing time string based on the syntax specified at:
 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
 */
gboolean
g_time_val_from_httpdate (const char *text, GTimeVal *tv)
{
	g_return_val_if_fail(text != NULL, FALSE);
	g_return_val_if_fail(strlen(text) > 10, FALSE);

	if (text[3] == ',')
		return g_time_val_from_rfc1123(text, tv);
	else if (text[6] == ',' || text[7] == ',' ||
			text[8] == ',' || text[9] == ',')
		return g_time_val_from_rfc850(text, tv);
	else
		return g_time_val_from_asctime(text, tv);
}

void parse_time(const char *text)
{
	GTimeVal tv;

	g_debug("Time: %s\n", text);

	if (g_time_val_from_httpdate (text, &tv)) {
		g_debug("Parsed time successfully: %s\n",
				g_time_val_to_iso8601(&tv));
	} else {
		g_debug("ERROR: Parsing time failed.\n");
	}
	
}

int main(int argc, char **argv)
{
    SoupSession * soup_session;
	SoupMessage *msg;

    g_type_init();
    g_thread_init(NULL);

#if 1
    soup_session = soup_session_sync_new();
	msg = soup_message_new ("GET", TESTURL);
    soup_session_send_message(soup_session, msg);

    if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) 
	{
        const char *text;
        text = soup_message_headers_get (msg->response_headers,"Last-Modified");
        g_debug("Last Modified: %s", text);
	parse_time(text);
    }
    else
        g_debug("BROKE");
#else
	parse_time("Tue, 04 Dec 2007 09:36:32 GMT");
	parse_time("Tuesday, 04-Dec-07 09:36:32 GMT");
	parse_time("Tue Dec   4 09:36:32 2007");
#endif
}
