#include "a.h"

// This code is almost certainly wrong.

typedef struct Icache Icache;
struct Icache
{
	char *url;
	HTTPHeader hdr;
	char *tmpfile;
	int fd;
	Icache *next;
	Icache *prev;
	Icache *hash;
};

enum {
	NHASH = 128,
	MAXCACHE = 128,
};
static struct {
	Icache *hash[NHASH];
	Icache *head;
	Icache *tail;
	int n;
} icache;

static Icache*
icachefind(char *url)
{
	int h;
	Icache *ic;
	
	h = hash(url) % NHASH;
	for(ic=icache.hash[h]; ic; ic=ic->hash){
		if(strcmp(ic->url, url) == 0){
			/* move to front */
			if(ic->prev) {
				ic->prev->next = ic->next;
				if(ic->next)
					ic->next->prev = ic->prev;
				else
					icache.tail = ic->prev;
				ic->prev = nil;
				ic->next = icache.head;
				icache.head->prev = ic;
				icache.head = ic;
			}
			return ic;
		}
	}
	return nil;
}

static Icache*
icacheinsert(char *url, HTTPHeader *hdr, char *file, int fd)
{
	int h;
	Icache *ic, **l;

	if(icache.n == MAXCACHE){
		ic = icache.tail;
		icache.tail = ic->prev;
		if(ic->prev)
			ic->prev->next = nil;
		else
			icache.head = ic->prev;
		h = hash(ic->url) % NHASH;
		for(l=&icache.hash[h]; *l; l=&(*l)->hash){
			if(*l == ic){
				*l = ic->hash;
				goto removed;
			}
		}
		sysfatal("cannot find ic in cache");
	removed:
		free(ic->url);
		close(ic->fd);
		remove(ic->file);
		free(ic->file);
	}else{
		ic = emalloc(sizeof *ic);
		icache.n++;
	}
	
	ic->url = estrdup(url);
	ic->fd = dup(fd, -1);
	ic->file = estrdup(file);
	ic->hdr = *hdr;
	h = hash(url) % NHASH;
	ic->hash = icache.hash[h];
	icache.hash[h] = ic;
	ic->prev = nil;
	ic->next = icache.head;
	if(ic->next)
		ic->next->prev = ic;
	else
		icache.tail = ic;
	return ic;
}

void
icacheflush(char *substr)
{
	Icache **l, *ic;
	
	for(l=&icache.head; (ic=*l); ) {
		if(substr == nil || strstr(ic->url, substr)) {
			icache.n--;
			*l = ic->next;
			free(ic->url);
			close(ic->fd);
			remove(ic->file);
			free(ic->file);
			free(ic);
		}else
			l = &ic->next;
	}
	
	if(icache.head) {
		icache.head->prev = nil;
		for(ic=icache.head; ic; ic=ic->next){
			if(ic->next)
				ic->next->prev = ic;
			else
				icache.tail = ic;
		}
	}else
		icache.tail = nil;
}

int
urlfetch(char *url, HTTPHeader hdr)
{
	Icache *ic;
	char buf[50], *host, *path, *p;
	int fd, len;

	ic = icachefind(url);
	if(ic != nil){
		*hdr = ic->hdr;
		return dup(ic->fd, -1);
	}

	if(memcmp(url, "http://", 7) != 0){
		werrstr("non-http url");
		return -1;
	}
	p = strchr(url+7, '/');
	if(p == nil)
		p = url+strlen(url);
	len = p - (url+7);
	host = emalloc(len+1);
	memmove(host, url+7, len);
	host[len] = 0;
	if(*p == 0)
		p = "/";

	strcpy(buf, "/var/tmp/smugfs.XXXXXX");
	fd = opentemp(buf, ORDWR|ORCLOSE);
	if(fd < 0)
		return -1;
	if(httptofile(http, host, req, &hdr, fd) < 0){
		free(host);
		return -1;
	}
	free(host);
	icacheinsert(url, &hdr, buf, fd);
	return fd;
}