/*
 * Copyright (C) 2023 Purism SPC
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 *
 * Author: Alice Mikhaylenko <alice.mikhaylenko@puri.sm>
 */

#include "config.h"

#include "adw-settings-impl-private.h"

#include "adw-marshalers.h"

typedef struct
{
  gboolean has_color_scheme;
  gboolean has_high_contrast;
  gboolean has_accent_colors;

  AdwSystemColorScheme color_scheme;
  gboolean high_contrast;
  AdwAccentColor accent_color;
} AdwSettingsImplPrivate;

G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (AdwSettingsImpl, adw_settings_impl, G_TYPE_OBJECT)

enum {
  SIGNAL_PREPARE,
  SIGNAL_COLOR_SCHEME_CHANGED,
  SIGNAL_HIGH_CONTRAST_CHANGED,
  SIGNAL_ACCENT_COLOR_CHANGED,
  SIGNAL_LAST_SIGNAL,
};

static guint signals[SIGNAL_LAST_SIGNAL];

static void
adw_settings_impl_class_init (AdwSettingsImplClass *klass)
{
  signals[SIGNAL_COLOR_SCHEME_CHANGED] =
    g_signal_new ("color-scheme-changed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL,
                  adw_marshal_VOID__ENUM,
                  G_TYPE_NONE,
                  1,
                  ADW_TYPE_SYSTEM_COLOR_SCHEME);
  g_signal_set_va_marshaller (signals[SIGNAL_COLOR_SCHEME_CHANGED],
                              G_TYPE_FROM_CLASS (klass),
                              adw_marshal_VOID__ENUMv);

  signals[SIGNAL_HIGH_CONTRAST_CHANGED] =
    g_signal_new ("high-contrast-changed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL,
                  adw_marshal_VOID__BOOLEAN,
                  G_TYPE_NONE,
                  1,
                  G_TYPE_BOOLEAN);
  g_signal_set_va_marshaller (signals[SIGNAL_HIGH_CONTRAST_CHANGED],
                              G_TYPE_FROM_CLASS (klass),
                              adw_marshal_VOID__BOOLEANv);

  signals[SIGNAL_ACCENT_COLOR_CHANGED] =
    g_signal_new ("accent-color-changed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL,
                  adw_marshal_VOID__ENUM,
                  G_TYPE_NONE,
                  1,
                  ADW_TYPE_ACCENT_COLOR);
  g_signal_set_va_marshaller (signals[SIGNAL_ACCENT_COLOR_CHANGED],
                              G_TYPE_FROM_CLASS (klass),
                              adw_marshal_VOID__ENUMv);
}

static void
adw_settings_impl_init (AdwSettingsImpl *self)
{
}

gboolean
adw_settings_impl_get_has_color_scheme (AdwSettingsImpl *self)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_val_if_fail (ADW_IS_SETTINGS_IMPL (self), FALSE);

  return priv->has_color_scheme;
}

gboolean
adw_settings_impl_get_has_high_contrast (AdwSettingsImpl *self)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_val_if_fail (ADW_IS_SETTINGS_IMPL (self), FALSE);

  return priv->has_high_contrast;
}

gboolean
adw_settings_impl_get_has_accent_colors (AdwSettingsImpl *self)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_val_if_fail (ADW_IS_SETTINGS_IMPL (self), FALSE);

  return priv->has_accent_colors;
}

void
adw_settings_impl_set_features (AdwSettingsImpl *self,
                                gboolean         has_color_scheme,
                                gboolean         has_high_contrast,
                                gboolean         has_accent_colors)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_if_fail (ADW_IS_SETTINGS_IMPL (self));

  priv->has_color_scheme = !!has_color_scheme;
  priv->has_high_contrast = !!has_high_contrast;
  priv->has_accent_colors = !!has_accent_colors;
}

AdwSystemColorScheme
adw_settings_impl_get_color_scheme (AdwSettingsImpl *self)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_val_if_fail (ADW_IS_SETTINGS_IMPL (self), ADW_SYSTEM_COLOR_SCHEME_DEFAULT);

  return priv->color_scheme;
}

void
adw_settings_impl_set_color_scheme (AdwSettingsImpl      *self,
                                    AdwSystemColorScheme  color_scheme)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_if_fail (ADW_IS_SETTINGS_IMPL (self));

  if (priv->color_scheme == color_scheme)
    return;

  priv->color_scheme = color_scheme;

  if (priv->has_color_scheme)
    g_signal_emit (G_OBJECT (self), signals[SIGNAL_COLOR_SCHEME_CHANGED], 0, color_scheme);
}

gboolean
adw_settings_impl_get_high_contrast (AdwSettingsImpl *self)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_val_if_fail (ADW_IS_SETTINGS_IMPL (self), FALSE);

  return priv->high_contrast;
}

void
adw_settings_impl_set_high_contrast (AdwSettingsImpl *self,
                                     gboolean         high_contrast)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_if_fail (ADW_IS_SETTINGS_IMPL (self));

  high_contrast = !!high_contrast;

  if (priv->high_contrast == high_contrast)
    return;

  priv->high_contrast = high_contrast;

  if (priv->has_high_contrast)
    g_signal_emit (G_OBJECT (self), signals[SIGNAL_HIGH_CONTRAST_CHANGED], 0, high_contrast);
}

AdwAccentColor
adw_settings_impl_get_accent_color (AdwSettingsImpl *self)
{
  AdwSettingsImplPrivate *priv  = adw_settings_impl_get_instance_private (self);

  g_return_val_if_fail (ADW_IS_SETTINGS_IMPL (self), ADW_ACCENT_COLOR_BLUE);

  return priv->accent_color;
}

void
adw_settings_impl_set_accent_color (AdwSettingsImpl *self,
                                    AdwAccentColor   accent_color)
{
  AdwSettingsImplPrivate *priv = adw_settings_impl_get_instance_private (self);

  g_return_if_fail (ADW_IS_SETTINGS_IMPL (self));

  if (priv->accent_color == accent_color)
    return;

  priv->accent_color = accent_color;

  if (priv->has_accent_colors)
    g_signal_emit (G_OBJECT (self), signals[SIGNAL_ACCENT_COLOR_CHANGED], 0, accent_color);
}

gboolean
adw_get_disable_portal (void)
{
  const char *disable_portal = g_getenv ("ADW_DISABLE_PORTAL");

  return disable_portal && disable_portal[0] == '1';
}
