// Posix is for wimps, clearly.
#define _GNU_SOURCE 

#include <debian-installer.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

#ifndef PACKAGES
# define PACKAGES "/var/cache/system-integrity-check/Packages"
#endif

#ifndef PKGLIST
# define PKGLIST "/var/cache/system-integrity-check/pkglist"
#endif

#ifndef OUTLIST
# define OUTLIST "/var/cache/system-integrity-check/outlist"
#endif

#ifndef DEBIANARCH
# error "dude.. gimme a break eh?"
#endif

#define DEBIANARCH_DEB DEBIANARCH ".deb\n"

int main() {
	FILE *packages_fd;
	FILE *pkglist_fd;
	FILE *outlist_fd;
	char *package_line = 0;
	char *pkglist_line = 0;
	size_t len;
	ssize_t read;
	di_hash_table *hashtable;

	packages_fd=fopen(PACKAGES, "r");
	if (packages_fd == NULL) {
		printf("cannot open %s: %s\n", PACKAGES, strerror(errno));
		return 1;
	}

	pkglist_fd=fopen(PKGLIST, "r");
	if (pkglist_fd == NULL) {
		printf("cannot open %s: %s\n", PKGLIST, strerror(errno));
		return 1;
	}

	outlist_fd=fopen(OUTLIST, "w+");
	if (outlist_fd == NULL) {
		printf("cannot open %s: %s\n", OUTLIST, strerror(errno));
		return 1;
	}

/* here start the dance :) */

	// TODO: initialize the hash table before we hit algo.

	// di_hash_table_new by default eats keys or values, but
	// won't ever free them.  You have to make sure there are no dups,
	// and that you don't ever care if they're freed or not.
	// Since we care about such things, we'll use di_hash_table_new_full.
	hashtable = di_hash_table_new(di_rstring_hash, di_rstring_equal);
	
	/* algorithm:  (however it's spelled) */
	// Note: We need a unique key to lookup.  The Package file
	// will contain alot of data we don't care about.  What we DO
	// care about is *our* arch, and arch: all.  We have the promise
	// that there we never be a conflcit with these two values different.
	// Is there a promise that there's only one version in the pool list? no.
	// the problem is that sometimes pkgs move between main/universe. We don't want
	// to spend time to track that, because we don't care. so you might have more
	// than one result for the same pkg/version but they are supposed to be exactly
	// the same (and they are) so we keep the first and stop.
	//
	// Given this, we will encode the hash string as PACKAGE_VERSION.  Having 
	// _ in a package name is (IIRC) illegal in Debian, so this gives us
	// a non conflicting string.  It also means we never have to parse the
	// version out.

	// For each line in Packages:
	while ((read = getline(&package_line, &len, packages_fd)) != -1) {

		char *package, *arch;
		di_rstring *key;
	//   Parse out the package and version.  
	//   The packages file is in the format:
	//   (noise/)+PACKAGE_VERSION_ARCH\.deb
	//   Given that / is illegal, find the last / and start from there
	//   and construct the hash key.
		package = rindex(package_line, '/');
		package++;
		arch = rindex(package_line, '_');
		arch++;

		//   Discard those that don't match our arch or any.

		if ((strcmp(arch,"all.deb\n") != 0) &&
			(strcmp(arch,DEBIANARCH_DEB) != 0)) {
			continue;
		}

		// This gets sent into the hashtable
		// annoying as being assfucked we need to allocate each struct
		key = malloc(sizeof(struct di_rstring));
		key->string = strndup(package, (arch - package - 1));
		key->size = strlen(key->string);

		//   Load the string read in from Packages into the hashtable.
		//   still more annoying as being assfucked we need to copy the package_line again.
		di_hash_table_insert(hashtable, key, strdup(package_line));

		//   If there's a conflict, that's okay.  There is a promise that
		//   if a given package/arch/version exists in multiple places, that it's
		//   the exactly same file.
	
		//   Clean up.
		if (package_line) {
			free(package_line);
			package_line = 0;
		}
	}

	while ((read = getline(&pkglist_line, &len, pkglist_fd)) != -1) {

		char *out=0;
		char *pkg=0;
		char *ver=0;
		char *epoch=0;
		di_rstring realkey;

	// For each line in pkglist:
	//   Parse pkg ver to create the key. Remember to strip epoch from ver!
		pkg = strndup(pkglist_line,(index(pkglist_line, ' ') - pkglist_line));
		ver = strdup((index(pkglist_line, ' ') + 1));

	//   Start writing to the file
		fwrite(pkglist_line, strlen(pkglist_line), 1, outlist_fd);
	//   Hack around epoch
		if(index(ver, ':')) {
			epoch = strdup((index(ver, ':') + 1));
			free(ver);
			ver = epoch;
			epoch = 0;
		}

	//   Create the key
		asprintf(&realkey.string, "%s_%s", pkg,ver);
		realkey.size = (strlen(realkey.string) - 1);

	//   Retrieve the stored value from the hash.
		out = di_hash_table_lookup(hashtable, &realkey);

	//   Print the stored string to a file
	//   (NOTE for fabio: remember case in which there is no match
	//   must return error to d-i somehow)
		if (out) {
			fwrite(out, strlen(out), 1, outlist_fd);
		} else {
			fwrite("\n", 1, 1, outlist_fd);
		}

		free(realkey.string);
		free(ver);
		free(pkg);
		out = 0;
		pkglist_line = 0;
	}

/* and here it should finish :) */
	fclose(outlist_fd);
	return 0; 
}
