/*
 * dselect - Debian package maintenance user interface
 * pkgdisplay.cc - package list display
 *
 * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
 * Copyright © 2006, 2008-2015 Guillem Jover <guillem@debian.org>
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This 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, see <https://www.gnu.org/licenses/>.
 */

#include <config.h>
#include <compat.h>

#include <string.h>
#include <stdio.h>

#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>

#include "dselect.h"
#include "pkglist.h"

// These MUST be in the same order as the corresponding enums in dpkg-db.h.
const char *const wantstrings[] = {
	N_("new package"),
	N_("install"),
	N_("hold"),
	N_("remove"),
	N_("purge"),
	nullptr,
};

/*
 * TRANSLATORS: The space is a trick to work around gettext which uses
 * the empty string to store information about the translation. DO NOT
 * CHANGE THAT IN A TRANSLATION! The code really relies on that being
 * a single space.
 */
const char *const eflagstrings[] = {
	N_(" "),
	N_("REINSTALL"),
	nullptr,
};

const char *const statusstrings[] = {
	N_("not installed"),
	N_("removed (configs remain)"),
	N_("half installed"),
	N_("unpacked (not set up)"),
	N_("half configured (config failed)"),
	N_("awaiting trigger processing"),
	N_("triggered"),
	N_("installed"),
	nullptr,
};

const char *const prioritystrings[] = {
	N_("Required"),
	N_("Important"),
	N_("Standard"),
	N_("Optional"),
	N_("Extra"),
	N_("Unclassified"),
	nullptr,
};

const char *const relatestrings[] = {
	N_("suggests"),
	N_("recommends"),
	N_("depends on"),
	N_("pre-depends on"),
	N_("breaks"),
	N_("conflicts with"),
	N_("provides"),
	N_("replaces"),
	N_("enhances"),
	nullptr,
};

const char *const priorityabbrevs[] = {
	N_("Req"),
	N_("Imp"),
	N_("Std"),
	N_("Opt"),
	N_("Xtr"),
	N_("bUG"),
	N_("?"),
};

const char statuschars[] = " -IUCWt*";
const char eflagchars[] = " R";
const char wantchars[] = "n*=-_";

// These MUST be in the same order as the corresponding enums in pkglist.h.
const char *const ssaabbrevs[] = {
	N_("Broken"),
	N_("New"),
	N_("Upgradable"),
	N_("Obsolete/local"),
	N_("Installed"),
	N_("Available"),
	N_("Removed"),
};
const char *const ssastrings[] = {
	N_("Brokenly installed packages"),
	N_("Newly available packages"),
	N_("Upgradable packages"),
	N_("Obsolete and locally created packages"),
	N_("Installed packages"),
	N_("Available not installed packages"),
	N_("Removed and no longer available packages"),
};

const char *const sssstrings[] = {
	N_("Brokenly installed packages"),
	N_("Installed packages"),
	N_("Removed packages (configuration still present)"),
	N_("Purged packages and those never installed"),
};
const char *const sssabbrevs[] = {
	N_("Broken"),
	N_("Installed"),
	N_("Removed"),
	N_("Purged"),
};

static int
maximumstring(const char *const *array)
{
	int maxlen = 0;

	while (*array) {
		int l = strlen(gettext(*array));
		const char *p = strchr(*array, '(');

		if (p && p > *array && *--p == ' ')
			l = p - *array;
		if (l > maxlen)
			maxlen = l;
		array++;
	}

	return maxlen;
}

void
packagelist::setwidths()
{
	debug(dbg_general, "packagelist[%p]::setwidths()", this);

	col_cur_x = 0;

	if (verbose) {
		add_column(col_status_hold, _("Error"), 9);
		add_column(col_status_status, _("Installed?"),
		           maximumstring(statusstrings));
		add_column(col_status_old_want, _("Old mark"),
		           maximumstring(wantstrings));
		add_column(col_status_new_want, _("Marked for"),
		           maximumstring(wantstrings));
	} else {
		add_column(col_status, _("EIOM"), 4);
	}

	if (sortorder == so_section)
		add_column(col_section, _("Section"), 8);
	add_column(col_priority, _("Priority"), verbose ? 8 : 3);
	if (sortorder != so_section)
		add_column(col_section, _("Section"), 8);

	add_column(col_package, _("Package"), verbose ? 16 : 12);

	switch (archdisplayopt) {
	case ado_none:
		col_archinstalled.blank();
		col_archavailable.blank();
		break;
	case ado_available:
		col_archinstalled.blank();
		add_column(col_archavailable, _("Avail.arch"),
		           verbose ? 14 : 10);
		break;
	case ado_both:
		add_column(col_archinstalled, _("Inst.arch"),
		           verbose ? 14 : 10);
		add_column(col_archavailable, _("Avail.arch"),
		           verbose ? 14 : 10);
		break;
	default:
		internerr("unknown archdisplayopt %d", archdisplayopt);
	}

	switch (versiondisplayopt) {
	case vdo_none:
		col_versioninstalled.blank();
		col_versionavailable.blank();
		break;
	case vdo_available:
		col_versioninstalled.blank();
		add_column(col_versionavailable, _("Avail.ver"), 11);
		break;
	case vdo_both:
		add_column(col_versioninstalled, _("Inst.ver"), 11);
		add_column(col_versionavailable, _("Avail.ver"), 11);
		break;
	default:
		internerr("unknown versiondisplayopt %d", versiondisplayopt);
	}

	end_column(col_description, _("Description"));
}

void
packagelist::redrawtitle()
{
	if (!title_height)
		return;

	int x, y DPKG_ATTR_UNUSED;

	mywerase(titlewin);
	mvwaddnstr(titlewin, 0, 0,
	           recursive ? _("dselect - recursive package listing") :
	           modstatdb_get_status() == msdbrw_readonly ?
	                       _("dselect - inspection of package states") :
	                       _("dselect - main package listing"),
	           xmax);
	getyx(titlewin, y, x);
	if (x < xmax) {
		switch (sortorder) {
		case so_section:
			switch (statsortorder) {
			case sso_unsorted:
				waddnstr(titlewin, _(" (by section)"), xmax - x);
				break;
			case sso_avail:
				waddnstr(titlewin, _(" (avail., section)"), xmax - x);
				break;
			case sso_state:
				waddnstr(titlewin, _(" (status, section)"), xmax - x);
				break;
			default:
				internerr("bad statsort %d on so_section", statsortorder);
			}
			break;
		case so_priority:
			switch (statsortorder) {
			case sso_unsorted:
				waddnstr(titlewin, _(" (by priority)"), xmax - x);
				break;
			case sso_avail:
				waddnstr(titlewin, _(" (avail., priority)"), xmax - x);
				break;
			case sso_state:
				waddnstr(titlewin, _(" (status, priority)"), xmax - x);
				break;
			default:
				internerr("bad statsort %d on so_priority", statsortorder);
			}
			break;
		case so_alpha:
			switch (statsortorder) {
			case sso_unsorted:
				waddnstr(titlewin, _(" (alphabetically)"), xmax - x);
				break;
			case sso_avail:
				waddnstr(titlewin, _(" (by availability)"), xmax - x);
				break;
			case sso_state:
				waddnstr(titlewin, _(" (by status)"), xmax - x);
				break;
			default:
				internerr("bad statsort %d on so_priority", statsortorder);
			}
			break;
		case so_unsorted:
			break;
		default:
			internerr("bad sort %d", sortorder);
		}
	}

	const char *helpstring;
	if (modstatdb_get_status() == msdbrw_write)
		helpstring = (verbose ? _(" mark:+/=/- terse:v help:?")
		                      : _(" mark:+/=/- verbose:v help:?"));
	else
		helpstring = (verbose ? _(" terse:v help:?")
		                      : _(" verbose:v help:?"));

	int l = strlen(helpstring);
	getyx(titlewin, y, x);
	if (xmax - l > 0) {
		mvwaddstr(titlewin, 0, xmax - l, helpstring);
	}
	wnoutrefresh(titlewin);
}
