/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* aspam-settings.c
 *
 * Copyright 2021 Chris Talbot <chris@talbothome.com>
 *
 * 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 3 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/>.
 *
 * Author(s):
 *   Chris Talbot <chris@talbothome.com>
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#define G_LOG_DOMAIN "aspam-settings"

#include "config.h"
#include "aspam-settings.h"

/**
 * SECTION: aspam-settings
 * @title: ASpamSettings
 * @short_description: The Application settings
 * @include: "aspam-settings.h"
 *
 * A class that handles application specific settings, and
 * to store them to disk.
 */

struct _ASpamSettings
{
  GObject    parent_instance;

  GSettings *app_settings;

  //App Settings
  int prefer_dark_theme;

  gboolean enable_aspamclient;
  gboolean allow_blocked_numbers;
  gboolean allow_callback;
  gboolean silence;
  gboolean blacklist;
  guint64 callback_timeout;
  char **match_list;
};

G_DEFINE_TYPE (ASpamSettings, aspam_settings, G_TYPE_OBJECT)

int
aspam_settings_get_dark_theme (ASpamSettings *self)
{
  return self->prefer_dark_theme;
}

static void
adw_style_manager_set_dark_theme (int prefer_dark_theme)
{
  AdwStyleManager *adw_style_manager = adw_style_manager_get_default ();

  if (prefer_dark_theme)
    adw_style_manager_set_color_scheme (adw_style_manager, ADW_COLOR_SCHEME_PREFER_DARK);
  else
    adw_style_manager_set_color_scheme (adw_style_manager, ADW_COLOR_SCHEME_DEFAULT);
}

void
aspam_settings_set_dark_theme (ASpamSettings *self,
                               int            prefer_dark_theme)
{
  self->prefer_dark_theme = prefer_dark_theme;

  /* Set the setting right away */
  g_settings_set_boolean (self->app_settings, "dark-theme", self->prefer_dark_theme);
  g_settings_apply (self->app_settings);
  adw_style_manager_set_dark_theme (self->prefer_dark_theme);
}

gboolean
aspam_settings_get_blacklist (ASpamSettings *self)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  return self->blacklist;
}

void
aspam_settings_set_blacklist (ASpamSettings *self,
                              gboolean       enable)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  self->blacklist = enable;
  g_settings_set_boolean (self->app_settings, "blacklist", self->blacklist);
  g_settings_apply (self->app_settings);
}

gboolean
aspam_settings_get_silence (ASpamSettings *self)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  return self->silence;
}

void
aspam_settings_set_silence (ASpamSettings *self,
                            gboolean       enable)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  self->silence = enable;
  g_settings_set_boolean (self->app_settings, "silence", self->silence);
  g_settings_apply (self->app_settings);
}

gboolean
aspam_settings_get_enable_aspamclient (ASpamSettings *self)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  return self->enable_aspamclient;
}

void
aspam_settings_set_enable_aspamclient (ASpamSettings *self,
                                       gboolean       enable)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  self->enable_aspamclient = enable;
  g_settings_set_boolean (self->app_settings, "enable", self->enable_aspamclient);
  g_settings_apply (self->app_settings);
}

gboolean
aspam_settings_get_allow_blocked_numbers (ASpamSettings *self)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  return self->allow_blocked_numbers;
}

void
aspam_settings_set_allow_blocked_numbers (ASpamSettings *self,
                                          gboolean       enable)
{
  g_assert (ASPAM_IS_SETTINGS (self));
  self->allow_blocked_numbers = enable;
  g_settings_set_boolean (self->app_settings, "allow-blocked-numbers", self->allow_blocked_numbers);
  g_settings_apply (self->app_settings);
}

gboolean
aspam_settings_get_allow_callback (ASpamSettings *self)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  return self->allow_callback;
}

void
aspam_settings_set_allow_callback (ASpamSettings *self,
                                   gboolean       enable)
{
  g_assert (ASPAM_IS_SETTINGS (self));
  self->allow_callback = enable;
  g_settings_set_boolean (self->app_settings, "allow-callback", self->allow_callback);
  g_settings_apply (self->app_settings);
}

guint64
aspam_settings_get_callback_timeout (ASpamSettings *self)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  return self->callback_timeout;
}

void
aspam_settings_set_callback_timeout (ASpamSettings *self,
                                     guint64        timeout)
{
  g_assert (ASPAM_IS_SETTINGS (self));
  self->callback_timeout = timeout;
  g_settings_set_uint64 (self->app_settings, "callback-timeout", self->callback_timeout);
  g_settings_apply (self->app_settings);
}


char **
aspam_settings_get_match_list (ASpamSettings *self)
{
  g_assert (ASPAM_IS_SETTINGS (self));

  return self->match_list;
}

char
*aspam_settings_make_csv_match_list (char **match_list)
{
  guint match_list_length = 0;
  GString *new_csv_string;

  match_list_length = g_strv_length (match_list);
  new_csv_string = g_string_new (NULL);
  for (guint i = 0; i < match_list_length; i++)
    if (match_list[i] != NULL && match_list[i][0] != '\0')
      {
        new_csv_string = g_string_append (new_csv_string, match_list[i]);
        if (i + 1 != match_list_length)
          new_csv_string = g_string_append (new_csv_string, ",");
      }

  if (new_csv_string->str[new_csv_string->len - 1] == ',')
    g_string_truncate (new_csv_string, new_csv_string->len - 1);

  return g_string_free (new_csv_string, FALSE);
}

void
aspam_settings_set_match_list (ASpamSettings *self,
                               char         **match_list)
{
  g_auto(GStrv) new_match_list = NULL;
  g_autoptr(GError) error = NULL;
  g_autofree char *csv = NULL;
  g_autoptr(GFile) whitelist_file = NULL;

  int size = 0;


  g_assert (ASPAM_IS_SETTINGS (self));

  csv = aspam_settings_make_csv_match_list (match_list);

  if (csv)
    size = strlen (csv);
  else
    return;

  whitelist_file = g_file_new_build_filename (g_get_user_config_dir (),
                                              "phoshantispam",
                                              "whitelist.csv",
                                              NULL);

  if (!g_file_replace_contents (whitelist_file, csv, size, NULL, FALSE,
                                G_FILE_CREATE_NONE, NULL, NULL, &error))
    {
      g_warning ("Failed to write to file %s: %s",
                 g_file_peek_path (whitelist_file), error->message);
      return;
    }

  g_strfreev (self->match_list);
  self->match_list = g_strsplit (csv, ",", -1);
  return;
}

void
aspam_settings_delete_match (ASpamSettings *self,
                             const char    *match)
{
  g_auto(GStrv) new_match_list = NULL;
  g_autofree char *new_csv = NULL;
  GString *new_csv_string;
  guint match_list_length;

  g_assert (ASPAM_IS_SETTINGS (self));

  match_list_length = g_strv_length (self->match_list);
  new_csv_string = g_string_new (NULL);
  for (guint i = 0; i < match_list_length; i++)
    if (g_strcmp0 (self->match_list[i], match) != 0)
      {
        new_csv_string = g_string_append (new_csv_string, self->match_list[i]);
        if (i + 1 != match_list_length)
          new_csv_string = g_string_append (new_csv_string, ",");
      }

  new_csv = g_string_free (new_csv_string, FALSE);

  new_match_list = g_strsplit (new_csv, ",", -1);
  aspam_settings_set_match_list (self,
                                 new_match_list);
  return;
}

void
aspam_settings_add_match (ASpamSettings *self,
                          const char    *match)
{
  g_autofree char *csv = NULL;
  g_autofree char *new_csv = NULL;
  g_auto(GStrv) new_match_list = NULL;

  g_assert (ASPAM_IS_SETTINGS (self));

  if (!match || !*match)
    return;

  csv = g_strjoinv (",", self->match_list);
  if (!*csv)
    new_csv = g_strdup_printf ("%s", match);
  else
    new_csv = g_strdup_printf ("%s,%s", csv, match);

  new_match_list = g_strsplit (new_csv, ",", -1);
  aspam_settings_set_match_list (self,
                                 new_match_list);
  return;
}

static void
aspam_settings_dispose (GObject *object)
{
  ASpamSettings *self = (ASpamSettings *)object;

  g_info ("Disposing Settings");

  g_settings_set_boolean (self->app_settings, "dark-theme", self->prefer_dark_theme);
  g_settings_set_string (self->app_settings, "version", PACKAGE_VERSION);
  g_settings_apply (self->app_settings);
  g_strfreev (self->match_list);

  G_OBJECT_CLASS (aspam_settings_parent_class)->dispose (object);
}

static void
aspam_settings_class_init (ASpamSettingsClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->dispose = aspam_settings_dispose;
}

static void
aspam_settings_init (ASpamSettings *self)
{
  g_autofree char *version = NULL;
  g_autofree char *contents = NULL;
  g_autoptr(GFile) whitelist_file = NULL;
  g_autoptr(GFile) whitelist_dir = NULL;
  g_autoptr(GError) error = NULL;
  gsize length = 0;

  whitelist_dir = g_file_new_build_filename (g_get_user_config_dir (),
                                             "phoshantispam",
                                             NULL);

  if (!g_file_make_directory_with_parents (whitelist_dir, NULL, &error))
    {
      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
        {
          g_debug ("Directory exists, skipping error...");
          g_clear_error (&error);
        }
      else if (error)
        {
          g_warning ("Error creating Directory: %s", error->message);
          g_clear_error (&error);
        }
    }

  whitelist_file = g_file_new_build_filename (g_get_user_config_dir (),
                                              "phoshantispam",
                                              "whitelist.csv",
                                              NULL);

  g_file_load_contents (whitelist_file,
                        NULL,
                        &contents,
                        &length,
                        NULL,
                        &error);

  if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
    {
      g_auto(GStrv) new_match_list = NULL;
      g_debug ("There is no CSV File! Making a blank one.");
      new_match_list = g_strsplit ("", ",", -1);
      aspam_settings_set_match_list (self, new_match_list);
      g_clear_error (&error);
    }
  else if (error)
    {
      g_warning ("Error loading CSV File: %s. Making a blank one.", error->message);
      g_clear_error (&error);
    }
  else {
      g_debug ("File Contents %s", contents);
      /* Sometimes there are */
      g_strdelimit (contents, "\r\n", ' ');
      g_strstrip (contents);
      g_debug ("File Contents %s", contents);
      self->match_list = g_strsplit (contents, ",", -1);
    }

  self->app_settings = g_settings_new (PACKAGE_ID);
  version = g_settings_get_string (self->app_settings, "version");

  self->enable_aspamclient = g_settings_get_boolean (self->app_settings, "enable");
  self->allow_blocked_numbers = g_settings_get_boolean (self->app_settings, "allow-blocked-numbers");
  self->allow_callback = g_settings_get_boolean (self->app_settings, "allow-callback");
  self->callback_timeout = g_settings_get_uint64 (self->app_settings, "callback-timeout");
  self->silence = g_settings_get_boolean (self->app_settings, "silence");
  self->blacklist = g_settings_get_boolean (self->app_settings, "blacklist");
  self->prefer_dark_theme = g_settings_get_boolean (self->app_settings, "dark-theme");

  adw_style_manager_set_dark_theme (self->prefer_dark_theme);

  g_settings_delay (self->app_settings);
}

/**
 * aspam_settings_get_default:
 *
 * Create a new #ASpamSettings
 *
 * Returns: (transfer full): A #ASpamSettings.
 * Free with g_object_unref().
 */
ASpamSettings *
aspam_settings_get_default (void)
{
  static ASpamSettings *self;

  if (!self)
    {
      self = g_object_new (ASPAM_TYPE_SETTINGS, NULL);
      g_object_add_weak_pointer (G_OBJECT (self), (gpointer *)&self);
    }
  return self;
}
