#include <apt-pkg/acquire-item.h>
#include <apt-pkg/cachefile.h>
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/init.h>
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/progress.h>
#include <apt-pkg/sourcelist.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>

using std::cerr;
using std::cout;
using std::endl;

typedef pkgCache::VerIterator VerIterator;
typedef pkgCache::VerFileIterator VerFileIterator;
#define NotSource pkgCache::Flag::NotSource
#define NotAutomatic pkgCache::Flag::NotAutomatic

VerIterator getHighestVersion(pkgCache &cache, pkgCache::PkgIterator pkg) {
	VerIterator last(cache, 0);

	for (VerIterator i = pkg.VersionList(); !i.end(); i++) {
		for (VerFileIterator j = i.FileList(); !j.end(); j++) {
			if ((j.File()->Flags & NotSource) != 0) {
				continue;
			}
			if ((j.File()->Flags & NotAutomatic) != 0) {
				if (last.end()) {
					last = i;
				}
				continue;
			}
			return i;
		}
	}

	return last;
}

bool downloadPackages(int test, int argc, char **argv) {
	pkgCacheFile cache;
	OpTextProgress prog(*_config);
	if (!cache.Open(prog, false))
		return false;

	pkgRecords rec(cache);
	if (_error->PendingError())
		return false;

	FileFd Lock;
	if (!_config->FindB("Debug::NoLocking",false)) {
		Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") +
				"lock"));
		if (_error->PendingError())
			return _error->Error(
				"Unable to lock the download directory");
	}

	pkgAcquire fetcher;

	pkgSourceList list;
	if (!list.ReadMainList())
		return _error->Error("The list of sources could not be read.");

	string *filenames = new string[argc];
	for (int i = 0; i < argc; i++) {
		pkgCache::PkgIterator pkg = cache->FindPkg(argv[i]);
		if (pkg.end()) {
			cerr << "Couldn't find package " << argv[i] << endl;
			continue;
		}
		VerIterator candidateVer = getHighestVersion(cache, pkg);
		if (candidateVer == 0) {
			cerr << "Couldn't find package " << argv[i] << endl;
			continue;
		}
		new pkgAcqArchive(&fetcher, &list, &rec, candidateVer,
				  filenames[i]);
	}

	if (test) {
		pkgAcquire::UriIterator i = fetcher.UriBegin();
		for (; i != fetcher.UriEnd(); i++) {
			cout << i->URI << endl;
		}
		return true;
	}

	if (fetcher.Run() == pkgAcquire::Failed)
		return false;

	return true;
}

static void usage(const char *name) {
	cerr << "usage: " << name << " [-t] pkg..." << endl;
	exit(1);
}

int main(int argc, char **argv) {
	int test = 0;
	const char *progname = argv[0];

	int c;
	while ((c = getopt(argc, argv, "t")) != -1) {
		switch (c) {
		case 't':
			test = 1;
			break;
		default:
			usage(progname);
		}
	}
	argc -= optind;
	argv += optind;
	if (!*argv) {
		usage(progname);
	}

	pkgInitConfig(*_config);
	pkgInitSystem(*_config, _system);
	if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
		_config->Set("quiet","1");

	downloadPackages(test, argc, argv);

	if (!_error->empty()) {
		bool Errors = _error->PendingError();
		_error->DumpErrors();
		return Errors ? 100 : 0;
	}
	return 0;   
}
