/* cc-format-preview.c
 *
 * Copyright (C) 2013 Red Hat, Inc.
 * 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/>.
 *
 * Written by:
 *     Matthias Clasen
 *     Ian Douglas Scott <idscott@system76.com>
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "cc-format-preview.h"

#include <errno.h>
#include <glib/gi18n.h>
#include <langinfo.h>
#include <locale.h>
#include <string.h>

struct _CcFormatPreview {
    AdwPreferencesGroup parent_instance;

    AdwActionRow *date_format_row;
    AdwActionRow *date_time_format_row;
    AdwActionRow *measurement_format_row;
    AdwActionRow *number_format_row;
    AdwActionRow *paper_format_row;
    AdwActionRow *time_format_row;

    gchar *region;
};

enum {
    PROP_0,
    PROP_REGION
};

G_DEFINE_FINAL_TYPE (CcFormatPreview, cc_format_preview, ADW_TYPE_PREFERENCES_GROUP)

static void
display_date (AdwActionRow *row, GDateTime *dt, const gchar *format)
{
    g_autofree gchar *s = g_date_time_format (dt, format);
    adw_action_row_set_subtitle (row, g_strstrip (s));
}

static void
update_format_examples (CcFormatPreview *self)
{
    const gchar *region = self->region;
    locale_t locale = 0;
    locale_t old_locale = 0;
    g_autoptr(GDateTime) dt = NULL;
    g_autofree gchar *s = NULL;
#ifdef LC_MEASUREMENT
    const gchar *fmt;
    gboolean is_us_customary = FALSE;
#endif
    g_autoptr(GtkPaperSize) paper = NULL;

    if (region == NULL || region[0] == '\0')
        return;

    locale = newlocale (LC_TIME_MASK, region, (locale_t) 0);
    if (locale == (locale_t) 0)
        g_warning ("Failed to create locale %s: %s", region, g_strerror (errno));
    else
        old_locale = uselocale (locale);

    dt = g_date_time_new_now_local ();
    display_date (self->date_format_row, dt, "%x");
    display_date (self->time_format_row, dt, "%X");
    display_date (self->date_time_format_row, dt, "%c");

    if (locale != (locale_t) 0) {
        uselocale (old_locale);
        freelocale (locale);
    }

    locale = newlocale (LC_NUMERIC_MASK, region, (locale_t) 0);
    if (locale == (locale_t) 0)
        g_warning ("Failed to create locale %s: %s", region, g_strerror (errno));
    else
        old_locale = uselocale (locale);

    s = g_strdup_printf ("%'.2f", 123456789.00);
    adw_action_row_set_subtitle (self->number_format_row, s);

    if (locale != (locale_t) 0) {
        uselocale (old_locale);
        freelocale (locale);
    }

#if 0
  locale = newlocale (LC_MONETARY_MASK, region, (locale_t) 0);
  if (locale == (locale_t) 0)
    g_warning ("Failed to create locale %s: %s", region, g_strerror (errno));
  else
    old_locale = uselocale (locale);

  num_info = localeconv ();
  if (num_info != NULL)
    adw_action_row_set_subtitle (self->currency_format_row, num_info->currency_symbol);

  if (locale != (locale_t) 0)
    {
      uselocale (old_locale);
      freelocale (locale);
    }
#endif

#ifdef LC_MEASUREMENT
    locale = newlocale (LC_MEASUREMENT_MASK, region, (locale_t) 0);
    if (locale == (locale_t) 0)
        g_warning ("Failed to create locale %s: %s", region, g_strerror (errno));
    else
        old_locale = uselocale (locale);

    fmt = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
    /* The returned pointer of nl_langinfo could be invalid after switching
       locale, so we must use it here. */
    is_us_customary = fmt && *fmt == 2;

    if (locale != (locale_t) 0) {
        uselocale (old_locale);
        freelocale (locale);
    }

    if (is_us_customary)
        /* Translators: "US Customary" refers to the measurement system as used in the USA */
        adw_action_row_set_subtitle (self->measurement_format_row, C_("measurement format", "US Customary"));
    else
        adw_action_row_set_subtitle (self->measurement_format_row, C_("measurement format", "Metric"));

#endif

#ifdef LC_PAPER
    locale = newlocale (LC_PAPER_MASK, region, (locale_t) 0);
    if (locale == (locale_t) 0)
        g_warning ("Failed to create locale %s: %s", region, g_strerror (errno));
    else
        old_locale = uselocale (locale);

    paper = gtk_paper_size_new (gtk_paper_size_get_default ());
    adw_action_row_set_subtitle (self->paper_format_row, gtk_paper_size_get_display_name (paper));

    if (locale != (locale_t) 0) {
        uselocale (old_locale);
        freelocale (locale);
    }
#endif
}

static void
cc_format_preview_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
    CcFormatPreview *self;

    self = CC_FORMAT_PREVIEW (object);

    switch (prop_id) {
    case PROP_REGION:
        cc_format_preview_set_region (self, g_value_get_string (value));
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}

static void
cc_format_preview_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
    CcFormatPreview *self;

    self = CC_FORMAT_PREVIEW (object);

    switch (prop_id) {
    case PROP_REGION:
        g_value_set_string (value, self->region);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}

static void
cc_format_preview_finalize (GObject *object)
{
    CcFormatPreview *self = CC_FORMAT_PREVIEW (object);

    g_clear_pointer (&self->region, g_free);

    G_OBJECT_CLASS (cc_format_preview_parent_class)->finalize (object);
}

void
cc_format_preview_class_init (CcFormatPreviewClass *klass)
{
    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
    GObjectClass *object_class = G_OBJECT_CLASS (klass);

    object_class->get_property = cc_format_preview_get_property;
    object_class->set_property = cc_format_preview_set_property;
    object_class->finalize = cc_format_preview_finalize;

    g_object_class_install_property (object_class, PROP_REGION,
                                     g_param_spec_string ("region", NULL, NULL, NULL, G_PARAM_READWRITE));

    gtk_widget_class_set_template_from_resource (widget_class,
                                                 "/org/gnome/control-center/system/region/cc-format-preview.ui");

    gtk_widget_class_bind_template_child (widget_class, CcFormatPreview, date_format_row);
    gtk_widget_class_bind_template_child (widget_class, CcFormatPreview, date_time_format_row);
    gtk_widget_class_bind_template_child (widget_class, CcFormatPreview, measurement_format_row);
    gtk_widget_class_bind_template_child (widget_class, CcFormatPreview, number_format_row);
    gtk_widget_class_bind_template_child (widget_class, CcFormatPreview, paper_format_row);
    gtk_widget_class_bind_template_child (widget_class, CcFormatPreview, time_format_row);

    gtk_widget_class_set_css_name (widget_class, "formatpreview");
}

void
cc_format_preview_init (CcFormatPreview *self)
{
    gtk_widget_init_template (GTK_WIDGET (self));
}

void
cc_format_preview_set_region (CcFormatPreview *self, const gchar *region)
{
    g_set_str (&self->region, region);
    update_format_examples (self);
}
