/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
 *
 * Licensed under the GNU General Public License Version 2
 *
 * This program 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"

#include <glib/gi18n.h>
#include <libupower-glib/upower.h>

#include "egg-debug.h"
#include "egg-precision.h"

#include "gpm-upower.h"
#include "gpm-common.h"

#define GPM_UP_TIME_PRECISION			5*60
#define GPM_UP_TEXT_MIN_TIME			120

/**
 * gpm_upower_get_device_icon_index:
 * @percent: The charge of the device
 *
 * The index value depends on the percentage charge:
 *	00-10  = 000
 *	10-30  = 020
 *	30-50  = 040
 *	50-70  = 060
 *	70-90  = 080
 *	90-100 = 100
 *
 * Return value: The character string for the filename suffix.
 **/
static const gchar *
gpm_upower_get_device_icon_index (UpDevice *device)
{
	gdouble percentage;
	/* get device properties */
	g_object_get (device, "percentage", &percentage, NULL);
	if (percentage < 10)
		return "000";
	else if (percentage < 30)
		return "020";
	else if (percentage < 50)
		return "040";
	else if (percentage < 70)
		return "060";
	else if (percentage < 90)
		return "080";
	return "100";
}

/**
 * gpm_upower_get_device_icon:
 *
 * Need to free the return value
 *
 **/
gchar *
gpm_upower_get_device_icon (UpDevice *device)
{
	gchar *filename = NULL;
	const gchar *prefix = NULL;
	const gchar *index_str;
	UpDeviceKind kind;
	UpDeviceState state;
	gboolean is_present;
	gdouble percentage;

	g_return_val_if_fail (device != NULL, NULL);

	/* get device properties */
	g_object_get (device,
		      "kind", &kind,
		      "state", &state,
		      "percentage", &percentage,
		      "is-present", &is_present,
		      NULL);

	/* get correct icon prefix */
	prefix = up_device_kind_to_string (kind);

	/* get the icon from some simple rules */
	if (kind == UP_DEVICE_KIND_LINE_POWER) {
		filename = g_strdup ("gpm-ac-adapter");
	} else if (kind == UP_DEVICE_KIND_MONITOR) {
		filename = g_strdup ("gpm-monitor");
	} else if (kind == UP_DEVICE_KIND_UPS) {
		if (!is_present) {
			/* battery missing */
			filename = g_strdup_printf ("gpm-%s-missing", prefix);

		} else if (state == UP_DEVICE_STATE_FULLY_CHARGED) {
			filename = g_strdup_printf ("gpm-%s-100", prefix);

		} else if (state == UP_DEVICE_STATE_CHARGING) {
			index_str = gpm_upower_get_device_icon_index (device);
			filename = g_strdup_printf ("gpm-%s-%s-charging", prefix, index_str);

		} else if (state == UP_DEVICE_STATE_DISCHARGING) {
			index_str = gpm_upower_get_device_icon_index (device);
			filename = g_strdup_printf ("gpm-%s-%s", prefix, index_str);
		}
	} else if (kind == UP_DEVICE_KIND_BATTERY) {
		if (!is_present) {
			/* battery missing */
			filename = g_strdup_printf ("gpm-%s-missing", prefix);

		} else if (state == UP_DEVICE_STATE_EMPTY) {
			filename = g_strdup_printf ("gpm-%s-empty", prefix);

		} else if (state == UP_DEVICE_STATE_FULLY_CHARGED) {
			filename = g_strdup_printf ("gpm-%s-charged", prefix);

		} else if (state == UP_DEVICE_STATE_CHARGING) {
			index_str = gpm_upower_get_device_icon_index (device);
			filename = g_strdup_printf ("gpm-%s-%s-charging", prefix, index_str);

		} else if (state == UP_DEVICE_STATE_DISCHARGING) {
			index_str = gpm_upower_get_device_icon_index (device);
			filename = g_strdup_printf ("gpm-%s-%s", prefix, index_str);

		} else if (state == UP_DEVICE_STATE_PENDING_CHARGE) {
			index_str = gpm_upower_get_device_icon_index (device);
			/* FIXME: do new grey icons */
			filename = g_strdup_printf ("gpm-%s-%s-charging", prefix, index_str);

		} else if (state == UP_DEVICE_STATE_PENDING_DISCHARGE) {
			index_str = gpm_upower_get_device_icon_index (device);
			filename = g_strdup_printf ("gpm-%s-%s", prefix, index_str);
		} else {
			filename = g_strdup ("gpm-battery-missing");
		}

	} else if (kind == UP_DEVICE_KIND_MOUSE ||
		   kind == UP_DEVICE_KIND_KEYBOARD ||
		   kind == UP_DEVICE_KIND_PHONE) {
		if (!is_present) {
			/* battery missing */
			filename = g_strdup_printf ("gpm-%s-000", prefix);

		} else if (state == UP_DEVICE_STATE_FULLY_CHARGED) {
			filename = g_strdup_printf ("gpm-%s-100", prefix);

		} else if (state == UP_DEVICE_STATE_DISCHARGING) {
			index_str = gpm_upower_get_device_icon_index (device);
			filename = g_strdup_printf ("gpm-%s-%s", prefix, index_str);
		}
	}

	/* nothing matched */
	if (filename == NULL) {
		egg_warning ("nothing matched, falling back to default icon");
		filename = g_strdup ("dialog-warning");
	}

	egg_debug ("got filename: %s", filename);
	return filename;
}

/**
 * gpm_upower_get_device_summary:
 **/
gchar *
gpm_upower_get_device_summary (UpDevice *device)
{
	const gchar *kind_desc = NULL;
	gchar *description = NULL;
	guint time_to_full_round;
	guint time_to_empty_round;
	gchar *time_to_full_str;
	gchar *time_to_empty_str;
	UpDeviceKind kind;
	UpDeviceState state;
	gdouble percentage;
	gboolean is_present;
	gint64 time_to_full;
	gint64 time_to_empty;

	/* get device properties */
	g_object_get (device,
		      "kind", &kind,
		      "state", &state,
		      "percentage", &percentage,
		      "is-present", &is_present,
		      "time-to-full", &time_to_full,
		      "time-to-empty", &time_to_empty,
		      NULL);

	if (!is_present)
		return NULL;

	kind_desc = gpm_device_kind_to_localised_text (kind, 1);

	/* don't display all the extra stuff for keyboards and mice */
	if (kind == UP_DEVICE_KIND_MOUSE ||
	    kind == UP_DEVICE_KIND_KEYBOARD ||
	    kind == UP_DEVICE_KIND_PDA)
		return g_strdup_printf ("%s (%.1f%%)", kind_desc, percentage);

	/* we care if we are on AC */
	if (kind == UP_DEVICE_KIND_PHONE) {
		if (state == UP_DEVICE_STATE_CHARGING || !state == UP_DEVICE_STATE_DISCHARGING) {
			/* TRANSLATORS: a phone is charging */
			return g_strdup_printf (_("%s charging (%.1f%%)"), kind_desc, percentage);
		}
		return g_strdup_printf ("%s (%.1f%%)", kind_desc, percentage);
	}

	/* precalculate so we don't get Unknown time remaining */
	time_to_full_round = egg_precision_round_down (time_to_full, GPM_UP_TIME_PRECISION);
	time_to_empty_round = egg_precision_round_down (time_to_empty, GPM_UP_TIME_PRECISION);

	/* we always display "Laptop battery 16 minutes remaining" as we need to clarify what device we are refering to */
	if (state == UP_DEVICE_STATE_FULLY_CHARGED) {

		if (kind == UP_DEVICE_KIND_BATTERY && time_to_empty_round > GPM_UP_TEXT_MIN_TIME) {
			time_to_empty_str = gpm_get_timestring (time_to_empty_round);
			/* TRANSLATORS: The laptop battery is fully charged, and we know a time */
			description = g_strdup_printf (_("Battery is fully charged.\nProvides %s laptop runtime"),
							time_to_empty_str);
			g_free (time_to_empty_str);
		} else {
			/* TRANSLATORS: the device is fully charged */
			description = g_strdup_printf (_("%s is fully charged"), kind_desc);
		}

	} else if (state == UP_DEVICE_STATE_DISCHARGING) {

		if (time_to_empty_round > GPM_UP_TEXT_MIN_TIME) {
			time_to_empty_str = gpm_get_timestring (time_to_empty_round);
			/* TRANSLATORS: the device is discharging, and we have a time remaining */
			description = g_strdup_printf (_("%s %s remaining (%.1f%%)"),
							kind_desc, time_to_empty_str, percentage);
			g_free (time_to_empty_str);
		} else {
			/* TRANSLATORS: the device is discharging, but we only have a percentage */
			description = g_strdup_printf (_("%s discharging (%.1f%%)"),
							kind_desc, percentage);
		}

	} else if (state == UP_DEVICE_STATE_CHARGING) {

		if (time_to_full_round > GPM_UP_TEXT_MIN_TIME &&
		    time_to_empty_round > GPM_UP_TEXT_MIN_TIME) {

			/* display both discharge and charge time */
			time_to_full_str = gpm_get_timestring (time_to_full_round);
			time_to_empty_str = gpm_get_timestring (time_to_empty_round);

			/* TRANSLATORS: the device is charging, and we have a time to full and empty */
			description = g_strdup_printf (_("%s %s until charged (%.1f%%)\nProvides %s battery runtime"),
							kind_desc, time_to_full_str, percentage, time_to_empty_str);
			g_free (time_to_full_str);
			g_free (time_to_empty_str);

		} else if (time_to_full_round > GPM_UP_TEXT_MIN_TIME) {

			/* display only charge time */
			time_to_full_str = gpm_get_timestring (time_to_full_round);

			/* TRANSLATORS: device is charging, and we have a time to full and a percentage */
			description = g_strdup_printf (_("%s %s until charged (%.1f%%)"),
						kind_desc, time_to_full_str, percentage);
			g_free (time_to_full_str);
		} else {

			/* TRANSLATORS: device is charging, but we only have a percentage */
			description = g_strdup_printf (_("%s charging (%.1f%%)"),
						kind_desc, percentage);
		}

	} else if (state == UP_DEVICE_STATE_PENDING_DISCHARGE) {

		/* TRANSLATORS: this is only shown for laptops with multiple batteries */
		description = g_strdup_printf (_("%s waiting to discharge (%.1f%%)"),
						kind_desc, percentage);

	} else if (state == UP_DEVICE_STATE_PENDING_CHARGE) {

		/* TRANSLATORS: this is only shown for laptops with multiple batteries */
		description = g_strdup_printf (_("%s waiting to charge (%.1f%%)"), kind_desc, percentage);

	} else {
		egg_warning ("in an undefined state we are not charging or "
			     "discharging and the batteries are also not charged");
		description = g_strdup_printf ("%s (%.1f%%)", kind_desc, percentage);
	}
	return description;
}

/**
 * gpm_upower_get_device_description:
 **/
gchar *
gpm_upower_get_device_description (UpDevice *device)
{
	GString	*details;
	const gchar *text;
	gchar *time_str;
	UpDeviceKind kind;
	UpDeviceState state;
	UpDeviceTechnology technology;
	gdouble percentage;
	gdouble capacity;
	gdouble energy;
	gdouble energy_full;
	gdouble energy_full_design;
	gdouble energy_rate;
	gboolean is_present;
	gint64 time_to_full;
	gint64 time_to_empty;
	gchar *vendor = NULL;
	gchar *serial = NULL;
	gchar *model = NULL;

	g_return_val_if_fail (device != NULL, NULL);

	/* get device properties */
	g_object_get (device,
		      "kind", &kind,
		      "state", &state,
		      "percentage", &percentage,
		      "is-present", &is_present,
		      "time-to-full", &time_to_full,
		      "time-to-empty", &time_to_empty,
		      "technology", &technology,
		      "capacity", &capacity,
		      "energy", &energy,
		      "energy-full", &energy_full,
		      "energy-full-design", &energy_full_design,
		      "energy-rate", &energy_rate,
		      "vendor", &vendor,
		      "serial", &serial,
		      "model", &model,
		      NULL);

	details = g_string_new ("");
	text = gpm_device_kind_to_localised_text (kind, 1);
	/* TRANSLATORS: the type of data, e.g. Laptop battery */
	g_string_append_printf (details, "<b>%s</b> %s\n", _("Product:"), text);

	if (!is_present) {
		/* TRANSLATORS: device is missing */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Status:"), _("Missing"));
	} else if (state == UP_DEVICE_STATE_FULLY_CHARGED) {
		/* TRANSLATORS: device is charged */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Status:"), _("Charged"));
	} else if (state == UP_DEVICE_STATE_CHARGING) {
		/* TRANSLATORS: device is charging */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Status:"), _("Charging"));
	} else if (state == UP_DEVICE_STATE_DISCHARGING) {
		/* TRANSLATORS: device is discharging */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Status:"), _("Discharging"));
	}

	if (percentage >= 0) {
		/* TRANSLATORS: percentage */
		g_string_append_printf (details, "<b>%s</b> %.1f%%\n", _("Percentage charge:"), percentage);
	}
	if (vendor) {
		/* TRANSLATORS: manufacturer */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Vendor:"), vendor);
	}
	if (technology != UP_DEVICE_TECHNOLOGY_UNKNOWN) {
		text = gpm_device_technology_to_localised_string (technology);
		/* TRANSLATORS: how the battery is made, e.g. Lithium Ion */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Technology:"), text);
	}
	if (serial) {
		/* TRANSLATORS: serial number of the battery */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Serial number:"), serial);
	}
	if (model) {
		/* TRANSLATORS: model number of the battery */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Model:"), model);
	}
	if (time_to_full > 0) {
		time_str = gpm_get_timestring (time_to_full);
		/* TRANSLATORS: time to fully charged */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Charge time:"), time_str);
		g_free (time_str);
	}
	if (time_to_empty > 0) {
		time_str = gpm_get_timestring (time_to_empty);
		/* TRANSLATORS: time to empty */
		g_string_append_printf (details, "<b>%s</b> %s\n", _("Discharge time:"), time_str);
		g_free (time_str);
	}
	if (capacity > 0) {
		const gchar *condition;
		if (capacity > 99) {
			/* TRANSLATORS: Excellent, Good, Fair and Poor are all related to battery Capacity */
			condition = _("Excellent");
		} else if (capacity > 90) {
			condition = _("Good");
		} else if (capacity > 70) {
			condition = _("Fair");
		} else {
			condition = _("Poor");
		}
		/* TRANSLATORS: %.1f is a percentage and %s the condition (Excellent, Good, ...) */
		g_string_append_printf (details, "<b>%s</b> %.1f%% (%s)\n",
					_("Capacity:"), capacity, condition);
	}
	if (kind == UP_DEVICE_KIND_BATTERY) {
		if (energy > 0) {
			/* TRANSLATORS: current charge */
			g_string_append_printf (details, "<b>%s</b> %.1f Wh\n",
						_("Current charge:"), energy);
		}
		if (energy_full > 0 &&
		    energy_full_design != energy_full) {
			/* TRANSLATORS: last full is the charge the battery was seen to charge to */
			g_string_append_printf (details, "<b>%s</b> %.1f Wh\n",
						_("Last full charge:"), energy_full);
		}
		if (energy_full_design > 0) {
			/* Translators:  */
			/* TRANSLATORS: Design charge is the amount of charge the battery is designed to have when brand new */
			g_string_append_printf (details, "<b>%s</b> %.1f Wh\n",
						_("Design charge:"), energy_full_design);
		}
		if (energy_rate > 0) {
			/* TRANSLATORS: the charge or discharge rate */
			g_string_append_printf (details, "<b>%s</b> %.1f W\n",
						_("Charge rate:"), energy_rate);
		}
	}
	if (kind == UP_DEVICE_KIND_MOUSE ||
	    kind == UP_DEVICE_KIND_KEYBOARD) {
		if (energy > 0) {
			/* TRANSLATORS: the current charge for CSR devices */
			g_string_append_printf (details, "<b>%s</b> %.0f/7\n",
						_("Current charge:"), energy);
		}
		if (energy_full_design > 0) {
			/* TRANSLATORS: the design charge for CSR devices */
			g_string_append_printf (details, "<b>%s</b> %.0f/7\n",
						_("Design charge:"), energy_full_design);
		}
	}
	/* remove the last \n */
	g_string_truncate (details, details->len-1);

	g_free (vendor);
	g_free (serial);
	g_free (model);
	return g_string_free (details, FALSE);
}

/**
 * gpm_device_kind_to_localised_text:
 **/
const gchar *
gpm_device_kind_to_localised_text (UpDeviceKind kind, guint number)
{
	const gchar *text = NULL;
	switch (kind) {
	case UP_DEVICE_KIND_LINE_POWER:
		/* TRANSLATORS: system power cord */
		text = ngettext ("AC adapter", "AC adapters", number);
		break;
	case UP_DEVICE_KIND_BATTERY:
		/* TRANSLATORS: laptop primary battery */
		text = ngettext ("Laptop battery", "Laptop batteries", number);
		break;
	case UP_DEVICE_KIND_UPS:
		/* TRANSLATORS: battery-backed AC power source */
		text = ngettext ("UPS", "UPSs", number);
		break;
	case UP_DEVICE_KIND_MONITOR:
		/* TRANSLATORS: a monitor is a device to measure voltage and current */
		text = ngettext ("Monitor", "Monitors", number);
		break;
	case UP_DEVICE_KIND_MOUSE:
		/* TRANSLATORS: wireless mice with internal batteries */
		text = ngettext ("Mouse", "Mice", number);
		break;
	case UP_DEVICE_KIND_KEYBOARD:
		/* TRANSLATORS: wireless keyboard with internal battery */
		text = ngettext ("Keyboard", "Keyboards", number);
		break;
	case UP_DEVICE_KIND_PDA:
		/* TRANSLATORS: portable device */
		text = ngettext ("PDA", "PDAs", number);
		break;
	case UP_DEVICE_KIND_PHONE:
		/* TRANSLATORS: cell phone (mobile...) */
		text = ngettext ("Cell phone", "Cell phones", number);
		break;
#if UP_CHECK_VERSION(0,9,5)
	case UP_DEVICE_KIND_MEDIA_PLAYER:
		/* TRANSLATORS: media player, mp3 etc */
		text = ngettext ("Media player", "Media players", number);
		break;
	case UP_DEVICE_KIND_TABLET:
		/* TRANSLATORS: tablet device */
		text = ngettext ("Tablet", "Tablets", number);
		break;
	case UP_DEVICE_KIND_COMPUTER:
		/* TRANSLATORS: tablet device */
		text = ngettext ("Computer", "Computers", number);
		break;
#endif
	default:
		egg_warning ("enum unrecognised: %i", kind);
		text = up_device_kind_to_string (kind);
	}
	return text;
}

/**
 * gpm_device_kind_to_icon:
 **/
const gchar *
gpm_device_kind_to_icon (UpDeviceKind kind)
{
	const gchar *icon = NULL;
	switch (kind) {
	case UP_DEVICE_KIND_LINE_POWER:
		icon = "gpm-ac-adapter";
		break;
	case UP_DEVICE_KIND_BATTERY:
		icon = "battery";
		break;
	case UP_DEVICE_KIND_UPS:
		icon = "network-wired";
		break;
	case UP_DEVICE_KIND_MONITOR:
		icon = "application-certificate";
		break;
	case UP_DEVICE_KIND_MOUSE:
		icon = "input-mouse";
		break;
	case UP_DEVICE_KIND_KEYBOARD:
		icon = "input-keyboard";
		break;
	case UP_DEVICE_KIND_PDA:
		icon = "pda";
		break;
	case UP_DEVICE_KIND_PHONE:
		icon = "phone";
		break;
#if UP_CHECK_VERSION(0,9,5)
	case UP_DEVICE_KIND_MEDIA_PLAYER:
		icon = "multimedia-player";
		break;
	case UP_DEVICE_KIND_TABLET:
		icon = "input-tablet";
		break;
	case UP_DEVICE_KIND_COMPUTER:
		icon = "computer-apple-ipad";
		break;
#endif
	default:
		egg_warning ("enum unrecognised: %i", kind);
		icon = "gtk-help";
	}
	return icon;
}

/**
 * gpm_device_technology_to_localised_string:
 **/
const gchar *
gpm_device_technology_to_localised_string (UpDeviceTechnology technology_enum)
{
	const gchar *technology = NULL;
	switch (technology_enum) {
	case UP_DEVICE_TECHNOLOGY_LITHIUM_ION:
		/* TRANSLATORS: battery technology */
		technology = _("Lithium Ion");
		break;
	case UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER:
		/* TRANSLATORS: battery technology */
		technology = _("Lithium Polymer");
		break;
	case UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE:
		/* TRANSLATORS: battery technology */
		technology = _("Lithium Iron Phosphate");
		break;
	case UP_DEVICE_TECHNOLOGY_LEAD_ACID:
		/* TRANSLATORS: battery technology */
		technology = _("Lead acid");
		break;
	case UP_DEVICE_TECHNOLOGY_NICKEL_CADMIUM:
		/* TRANSLATORS: battery technology */
		technology = _("Nickel Cadmium");
		break;
	case UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE:
		/* TRANSLATORS: battery technology */
		technology = _("Nickel metal hydride");
		break;
	case UP_DEVICE_TECHNOLOGY_UNKNOWN:
		/* TRANSLATORS: battery technology */
		technology = _("Unknown technology");
		break;
	default:
		g_assert_not_reached ();
		break;
	}
	return technology;
}

/**
 * gpm_device_state_to_localised_string:
 **/
const gchar *
gpm_device_state_to_localised_string (UpDeviceState state)
{
	const gchar *state_string = NULL;

	switch (state) {
	case UP_DEVICE_STATE_CHARGING:
		/* TRANSLATORS: battery state */
		state_string = _("Charging");
		break;
	case UP_DEVICE_STATE_DISCHARGING:
		/* TRANSLATORS: battery state */
		state_string = _("Discharging");
		break;
	case UP_DEVICE_STATE_EMPTY:
		/* TRANSLATORS: battery state */
		state_string = _("Empty");
		break;
	case UP_DEVICE_STATE_FULLY_CHARGED:
		/* TRANSLATORS: battery state */
		state_string = _("Charged");
		break;
	case UP_DEVICE_STATE_PENDING_CHARGE:
		/* TRANSLATORS: battery state */
		state_string = _("Waiting to charge");
		break;
	case UP_DEVICE_STATE_PENDING_DISCHARGE:
		/* TRANSLATORS: battery state */
		state_string = _("Waiting to discharge");
		break;
	default:
		g_assert_not_reached ();
		break;
	}
	return state_string;
}