/**
 * vim: sw=4:ts=4:
 *
 * GNOME Apt dependency check class
 *
 * 	(C) 2003 Filip Van Raemdonck <mechanix@debian.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * 	$Id$
 *
 **/

#include "depresolver.h"

#define GAPT_PAD 6
#define UNICODE_BULLET "•"

#ifndef _
#if ENABLE_NLS
#define _(x) gettext(x)
#else
#define _(x) (x)
#endif
#endif

static RDepMap
get_broken (GAptCache* cache) {
	RDepMap rmap;

	if (!cache || !cache->BrokenCount()) {
		return rmap;
	}

	pkgCache::PkgIterator i = cache->PkgBegin();
	while (!i.end()) {
		if (!(*cache)[i].InstBroken()) {
			++i;
			continue;
		}

		if ((*cache)[i].InstVerIter (*cache).end()) {
			/* No currently installed version */
			/* FIXME: shouldn't the candidate version be checked? */
			++i;
			continue;
		}

		pkgCache::DepIterator d = (*cache)[i].InstVerIter (*cache).DependsList();

		while (!d.end()) {
			pkgCache::DepIterator start, end;
			d.GlobOr (start, end);

			if (!cache->IsImportantDep (end) ||
			      ((*cache)[end] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall) {
				continue;
			}

			gchar *needver = NULL, *newver = NULL;

			pkgCache::PkgIterator pkg = end.TargetPkg();
			if (!pkg->ProvidesList) {
				pkgCache::VerIterator ver = (*cache)[pkg].InstVerIter (*cache);
				if (ver.end()) {
					/* virtual package (which */
				} else {
					/* version mismatch */
					/* Actually this is the prospective rather than the current version */
					newver = g_strdup (ver.VerStr());
				}
			}
			/* else: virtual package */

			/* end.TargetVer() is empty for unversioned dependencies */
			if (end.TargetVer()) {
				needver = g_strdup_printf ("%s %s", end.CompType(), end.TargetVer());
			}

			/* FIXME: free needver, newver - somewhere */
			DepInfo tmp = { end.DepType(), i.Name(), needver, newver };
			rmap.insert (RDepMap::value_type (end.TargetPkg().Name(), tmp));
		}

		++i;
	}

	return rmap;
}

static const gchar* titles[] = {
	_("Package"), _("Version needed"), _("Version to be installed")
};

static gboolean
needs_listing (RDepMap::iterator i, RDepMap* rmap) {
	RDepMap::iterator next = i;

	++next;
	if (next == rmap->end()) {
		return TRUE;
	}

	if (g_ascii_strcasecmp ((*i).first.c_str(), (*next).first.c_str()) ||
	      g_ascii_strcasecmp ((*i).second.deptype, (*next).second.deptype)) {
		return TRUE;
	}

	if ((*i).second.newver) {
		if (!(*next).second.newver ||
		      g_ascii_strcasecmp ((*i).second.newver, (*next).second.newver)) {
			return TRUE;
		}
	} else {	/* !(*i).second.newver */
		if ((*next).second.newver) {
			return TRUE;
		}
	}

	if ((*i).second.needver) {
		if (!(*next).second.needver ||
		      g_ascii_strcasecmp ((*i).second.needver, (*next).second.needver)) {
			return TRUE;
		}
	} else {	/* !(*i).second.needver */
		if ((*next).second.needver) {
			return TRUE;
		}
	}

	return FALSE;
}

GtkWidget*
GAptDepResolver::depview (void) {
	if (!g_cache) {
		return NULL;
	}

	GtkListStore* store = gtk_list_store_new (3,
	      G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);

	GtkWidget* tree = GTK_WIDGET (red_list_view_new());
	gtk_tree_view_set_model (GTK_TREE_VIEW (tree), GTK_TREE_MODEL (store));
	gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)), GTK_SELECTION_NONE);

	for (int a = 0; a < 3; a++) {
		GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
		GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes (
			titles[a], renderer, "text", a, NULL);
		gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
	}

	GtkTreeIter iter;

	RDepMap rmap = get_broken (g_cache);
	RDepMap::iterator i = rmap.begin();
	int j = 0;
	while (i != rmap.end()) {
		const gchar* cur = (*i).first.c_str();
		static string deps;

		RDepMap::iterator old = i;
		if (needs_listing (i, &rmap)) {
			gtk_list_store_append (store, &iter);
			gtk_list_store_set (store, &iter,
			      C_PACKAGE, cur, C_NEWVER, (*i).second.newver, C_NEEDVER, (*i).second.needver, -1);
			++j;
		}

		if (deps.size()) {
			deps = deps + ", " + (*i).second.name;
		} else {
			deps = (*i).second.name;
		}
		const gchar* prev = cur;
		++i;

		/* Hackety, hack... */
		if (i != rmap.end()) {
			cur = (*i).first.c_str();
		} else {
			cur = NULL;
		}

		if (!cur || g_ascii_strcasecmp (prev, cur)) {
			gtk_list_store_append (store, &iter);
			gtk_list_store_set (store, &iter, -1); /* empty row */

			GtkCellRenderer* cell = gtk_cell_renderer_text_new();

			/* FIXME: free msg */
			gchar* msg = g_strdup_printf (_("<i>"UNICODE_BULLET" needed by <b>%s</b></i>"), deps.c_str());

			if (!g_ascii_strcasecmp ((*old).second.deptype, "Conflicts")) {
				g_free (msg);
				msg = g_strdup_printf (_("<i>"UNICODE_BULLET" conflicts with <b>%s</b></i>"), deps.c_str());
			}

			g_object_set (G_OBJECT (cell), "markup", msg, NULL);
			red_list_view_add_spanner (RED_LIST_VIEW (tree), j, 1, -1, cell);

			deps.clear();
			++j;
		}
	}

	GtkWidget* vbox = gtk_vbox_new (FALSE, GAPT_PAD);

	GtkWidget* sw = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);

	gtk_container_add (GTK_CONTAINER (sw), tree);

	return vbox;
}
