/* cc-brightness-scale.c
 *
 * Copyright (C) 2010 Red Hat, Inc
 * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
 * Copyright (C) 2010,2015 Richard Hughes <richard@hughsie.com>
 * Copyright (C) 2020 System76, Inc.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include <glib/gi18n.h>

#include "cc-battery-row.h"

struct _CcBatteryRow {
  GtkListBoxRow parent_instance;

  GtkBox       *battery_box;
  GtkLabel     *details_label;
  GtkImage     *icon;
  GtkLevelBar  *levelbar;
  GtkLabel     *name_label;
  GtkLabel     *percentage_label;
  GtkBox       *primary_bottom_box;
  GtkLabel     *primary_percentage_label;

  UpDeviceKind  kind;
  gboolean      primary;
};

G_DEFINE_TYPE (CcBatteryRow, cc_battery_row, GTK_TYPE_LIST_BOX_ROW)

static void
cc_battery_row_class_init (CcBatteryRowClass *klass)
{
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/power/cc-battery-row.ui");

  gtk_widget_class_bind_template_child (widget_class, CcBatteryRow, battery_box);
  gtk_widget_class_bind_template_child (widget_class, CcBatteryRow, details_label);
  gtk_widget_class_bind_template_child (widget_class, CcBatteryRow, icon);
  gtk_widget_class_bind_template_child (widget_class, CcBatteryRow, levelbar);
  gtk_widget_class_bind_template_child (widget_class, CcBatteryRow, name_label);
  gtk_widget_class_bind_template_child (widget_class, CcBatteryRow, percentage_label);
  gtk_widget_class_bind_template_child (widget_class, CcBatteryRow, primary_bottom_box);
  gtk_widget_class_bind_template_child (widget_class, CcBatteryRow, primary_percentage_label);
}

static void
cc_battery_row_init (CcBatteryRow *self)
{
  gtk_widget_init_template (GTK_WIDGET (self));
}

static gchar *
get_timestring (guint64 time_secs)
{
  gchar* timestring = NULL;
  gint  hours;
  gint  minutes;

  /* Add 0.5 to do rounding */
  minutes = (int) ( ( time_secs / 60.0 ) + 0.5 );

  if (minutes == 0)
    return g_strdup (_("Unknown time"));

  if (minutes < 60)
    return timestring = g_strdup_printf (ngettext ("%i minute",
                                         "%i minutes",
                                         minutes), minutes);

  hours = minutes / 60;
  minutes = minutes % 60;

  if (minutes == 0)
    return timestring = g_strdup_printf (ngettext (
                                         "%i hour",
                                         "%i hours",
                                         hours), hours);

  /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes"
   * Swap order with "%2$s %2$i %1$s %1$i if needed */
  return timestring = g_strdup_printf (_("%i %s %i %s"),
                                       hours, ngettext ("hour", "hours", hours),
                                       minutes, ngettext ("minute", "minutes", minutes));
}

static gchar *
get_details_string (gdouble percentage, UpDeviceState state, guint64 time)
{
  g_autofree gchar *details = NULL;

  if (time > 0)
    {
      g_autofree gchar *time_string = NULL;

      time_string = get_timestring (time);
      switch (state)
        {
          case UP_DEVICE_STATE_CHARGING:
            /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */
            details = g_strdup_printf (_("%s until fully charged"), time_string);
            break;
          case UP_DEVICE_STATE_DISCHARGING:
          case UP_DEVICE_STATE_PENDING_DISCHARGE:
            if (percentage < 20)
              {
                /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */
                details = g_strdup_printf (_("Caution: %s remaining"), time_string);
              }
            else
              {
                /* TRANSLATORS: %1 is a time string, e.g. "1 hour 5 minutes" */
                details = g_strdup_printf (_("%s remaining"), time_string);
              }
            break;
          case UP_DEVICE_STATE_FULLY_CHARGED:
            /* TRANSLATORS: primary battery */
            details = g_strdup (_("Fully charged"));
            break;
          case UP_DEVICE_STATE_PENDING_CHARGE:
            /* TRANSLATORS: primary battery */
            details = g_strdup (_("Not charging"));
            break;
          case UP_DEVICE_STATE_EMPTY:
            /* TRANSLATORS: primary battery */
            details = g_strdup (_("Empty"));
            break;
          default:
            details = g_strdup_printf ("error: %s", up_device_state_to_string (state));
            break;
        }
    }
  else
    {
      switch (state)
        {
          case UP_DEVICE_STATE_CHARGING:
            /* TRANSLATORS: primary battery */
            details = g_strdup (_("Charging"));
            break;
          case UP_DEVICE_STATE_DISCHARGING:
          case UP_DEVICE_STATE_PENDING_DISCHARGE:
            /* TRANSLATORS: primary battery */
            details = g_strdup (_("Discharging"));
            break;
          case UP_DEVICE_STATE_FULLY_CHARGED:
            /* TRANSLATORS: primary battery */
            details = g_strdup (_("Fully charged"));
            break;
          case UP_DEVICE_STATE_PENDING_CHARGE:
            /* TRANSLATORS: primary battery */
            details = g_strdup (_("Not charging"));
            break;
          case UP_DEVICE_STATE_EMPTY:
            /* TRANSLATORS: primary battery */
            details = g_strdup (_("Empty"));
            break;
          default:
            details = g_strdup_printf ("error: %s",
                                       up_device_state_to_string (state));
            break;
        }
    }

  return g_steal_pointer (&details);
}

static const char *
kind_to_description (UpDeviceKind kind)
{
  switch (kind)
    {
      case UP_DEVICE_KIND_MOUSE:
        /* TRANSLATORS: secondary battery */
        return N_("Wireless mouse");
      case UP_DEVICE_KIND_KEYBOARD:
        /* TRANSLATORS: secondary battery */
        return N_("Wireless keyboard");
      case UP_DEVICE_KIND_UPS:
        /* TRANSLATORS: secondary battery */
        return N_("Uninterruptible power supply");
      case UP_DEVICE_KIND_PDA:
        /* TRANSLATORS: secondary battery */
        return N_("Personal digital assistant");
      case UP_DEVICE_KIND_PHONE:
        /* TRANSLATORS: secondary battery */
        return N_("Cellphone");
      case UP_DEVICE_KIND_MEDIA_PLAYER:
        /* TRANSLATORS: secondary battery */
        return N_("Media player");
      case UP_DEVICE_KIND_TABLET:
        /* TRANSLATORS: secondary battery */
        return N_("Tablet");
      case UP_DEVICE_KIND_COMPUTER:
        /* TRANSLATORS: secondary battery */
        return N_("Computer");
      case UP_DEVICE_KIND_GAMING_INPUT:
        /* TRANSLATORS: secondary battery */
        return N_("Gaming input device");
      default:
        /* TRANSLATORS: secondary battery, misc */
        return N_("Battery");
    }

  g_assert_not_reached ();
}

CcBatteryRow*
cc_battery_row_new (UpDevice *device,
                    gboolean  primary)
{
  g_autofree gchar *details = NULL;
  gdouble percentage;
  UpDeviceKind kind;
  UpDeviceState state;
  g_autofree gchar *s = NULL;
  g_autofree gchar *icon_name = NULL;
  const gchar *name;
  CcBatteryRow *self;
  guint64 time_empty, time_full, time;
  gdouble energy_full, energy_rate;
  gboolean is_kind_battery;
  UpDeviceLevel battery_level;

  self = g_object_new (CC_TYPE_BATTERY_ROW, NULL);

  g_object_get (device,
                "kind", &kind,
                "state", &state,
                "model", &name,
                "percentage", &percentage,
                "icon-name", &icon_name,
                "time-to-empty", &time_empty,
                "time-to-full", &time_full,
                "energy-full", &energy_full,
                "energy-rate", &energy_rate,
                "battery-level", &battery_level,
                NULL);
  if (state == UP_DEVICE_STATE_DISCHARGING)
    time = time_empty;
  else
    time = time_full;

  is_kind_battery = (kind == UP_DEVICE_KIND_BATTERY || kind == UP_DEVICE_KIND_UPS);

  /* Name label */
  if (is_kind_battery)
    {
      if (g_object_get_data (G_OBJECT (device), "is-main-battery") != NULL)
        name = C_("Battery name", "Main");
      else
        name = C_("Battery name", "Extra");
    }
  else if (name == NULL || name[0] == '\0')
    {
      name = _(kind_to_description (kind));
    }
  gtk_label_set_text (self->name_label, name);

  /* Icon */
  if (is_kind_battery && icon_name != NULL && icon_name[0] != '\0')
    {
      gtk_image_set_from_icon_name (self->icon, icon_name);
      gtk_widget_show (GTK_WIDGET (self->icon));
    }
  else
    gtk_widget_hide (GTK_WIDGET (self->icon));

  /* Percentage label */
  if (battery_level == UP_DEVICE_LEVEL_NONE)
  {
    s = g_strdup_printf ("%d%%", (int)percentage);
    gtk_label_set_text (self->percentage_label, s);
    gtk_label_set_text (self->primary_percentage_label, s);
  }

  /* Level bar */
  gtk_level_bar_set_value (self->levelbar, percentage / 100.0);

  /* Details label (primary only) */
  details = get_details_string (percentage, state, time);
  gtk_label_set_text (self->details_label, details);

  /* Handle "primary" row differently */
  gtk_widget_set_visible (GTK_WIDGET (self->battery_box), !primary);
  gtk_widget_set_visible (GTK_WIDGET (self->percentage_label), !primary);
  gtk_widget_set_visible (GTK_WIDGET (self->primary_bottom_box), primary);
  /*
  gtk_accessible_update_relation (GTK_ACCESSIBLE (self->levelbar),
                                  GTK_ACCESSIBLE_RELATION_LABELLED_BY, primary ? self->primary_percentage_label
                                                                               : self->percentage_label,
                                  NULL);
   */

  self->kind = kind;
  self->primary = primary;

  return self;
}



void
cc_battery_row_set_level_sizegroup (CcBatteryRow *self,
                                    GtkSizeGroup *sizegroup)
{
  gtk_size_group_add_widget (sizegroup, GTK_WIDGET (self->levelbar));
}

void
cc_battery_row_set_row_sizegroup (CcBatteryRow *self,
                                  GtkSizeGroup *sizegroup)
{
  gtk_size_group_add_widget (sizegroup, GTK_WIDGET (self));
}

void
cc_battery_row_set_charge_sizegroup (CcBatteryRow *self,
                                     GtkSizeGroup *sizegroup)
{
  gtk_size_group_add_widget (sizegroup, GTK_WIDGET (self->percentage_label));
}

void
cc_battery_row_set_battery_sizegroup (CcBatteryRow *self,
                                      GtkSizeGroup *sizegroup)
{
  gtk_size_group_add_widget (sizegroup, GTK_WIDGET (self->battery_box));
}

gboolean
cc_battery_row_get_primary (CcBatteryRow *self)
{
  return self->primary;
}

UpDeviceKind
cc_battery_row_get_kind (CcBatteryRow *self)
{
  return self->kind;
}
