/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* vvmplayer-application.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 "vvmplayer-application"

#ifdef HAVE_CONFIG_H
# include "config.h"
# include "version.h"
#endif

#include <glib/gi18n.h>
#include <handy.h>
#include <libcallaudio.h>

#include "vvmplayer-window.h"
#include "vvmplayer-application.h"
#include "vvmplayer-log.h"
#include "vvmplayer-vvmd.h"

/**
 * SECTION: vvmplayer-application
 * @title: VvmApplication
 * @short_description: Base Application class
 * @include: "vvmplayer-application.h"
 */

struct _VvmApplication
{
  GtkApplication  parent_instance;

  int           daemon;
  int           daemon_running;

  VvmSettings  *settings;
  VvmVvmd      *backend;
  GtkWindow    *main_window;

};

G_DEFINE_TYPE (VvmApplication, vvmplayer_application, GTK_TYPE_APPLICATION)

enum {
  SIGNAL_MAIN_WINDOW_CLOSED,
  N_SIGNALS
};

static guint signals[N_SIGNALS];

static gboolean
cmd_verbose_cb (const char *option_name,
                const char *value,
                gpointer    data,
                GError    **error);

static GOptionEntry cmd_options[] = {
  {
    "quit", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL,
    N_("Quit all running instances of the application"), NULL
  },
  {
    "daemon", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL,
    N_("Whether to present the main window on startup"),
    NULL
  },
  {
    "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, cmd_verbose_cb,
    N_("Show verbose logs"), NULL
  },
  {
    "version", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL,
    N_("Show release version"), NULL
  },
  { NULL }
};

static gboolean
cmd_verbose_cb (const char *option_name,
                const char *value,
                gpointer    data,
                GError    **error)
{
  vvmplayer_log_increase_verbosity ();

  return TRUE;
}

static void
vvmplayer_application_show_help (GSimpleAction *action,
                                 GVariant      *parameter,
                                 gpointer       user_data)
{
  GtkWindow *window;
  g_autoptr(GError) error = NULL;

  window = gtk_application_get_active_window (GTK_APPLICATION (user_data));

  if (!gtk_show_uri_on_window (window, PACKAGE_HELP_URL, GDK_CURRENT_TIME, &error))
    g_warning ("Failed to launch help: %s", error->message);
}

static int
vvmplayer_application_handle_local_options (GApplication *application,
                                            GVariantDict *options)
{
  VvmApplication *self = (VvmApplication *)application;

  if (g_variant_dict_contains (options, "version"))
    {
      g_print ("%s %s\n", PACKAGE_NAME, PACKAGE_VCS_VERSION);
      return 0;
    }

  self->daemon = FALSE;
  if (g_variant_dict_contains (options, "daemon"))
    {
      if (self->main_window) {
        g_warning ("Cannot set application as a daemon"
                   " because application is already started");
        return -1;
      }

      /* Hold application only the first time daemon mode is set */
      if (!self->daemon_running) {
        g_application_hold (application);
      }

      self->daemon = TRUE;
    }
  return -1;
}

static void
vvmplayer_application_add_actions (VvmApplication *self)
{
  static const GActionEntry app_entries[] = {
    { "help", vvmplayer_application_show_help },
  };

  struct
  {
    const char *action;
    const char *accel[2];
  } accels[] = {
    { "app.help", { "F1", NULL } },
  };

  g_assert (VVMPLAYER_IS_APPLICATION (self));

  g_action_map_add_action_entries (G_ACTION_MAP (self), app_entries,
                                   G_N_ELEMENTS (app_entries), self);

  for (gsize i = 0; i < G_N_ELEMENTS (accels); i++)
    gtk_application_set_accels_for_action (GTK_APPLICATION (self),
                                           accels[i].action, accels[i].accel);
}

static void
vvmplayer_application_startup (GApplication *application)
{
  VvmApplication *self = (VvmApplication *)application;
  g_autoptr(GtkCssProvider) css_provider = NULL;

  g_info ("%s %s, git version: %s", PACKAGE_NAME,
          PACKAGE_VERSION, PACKAGE_VCS_VERSION);

  G_APPLICATION_CLASS (vvmplayer_application_parent_class)->startup (application);
  self->daemon_running = FALSE;

  hdy_init ();

  vvmplayer_application_add_actions (self);
  g_set_application_name (_("VVM Player"));
  gtk_window_set_default_icon_name (PACKAGE_ID);

  self->settings = vvm_settings_get_default ();
  self->backend = vvm_vvmd_get_default ();
  css_provider = gtk_css_provider_new ();
  gtk_css_provider_load_from_resource (css_provider,
                                       "/org/kop316/vvmplayer/css/gtk.css");

  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
                                             GTK_STYLE_PROVIDER (css_provider),
                                             GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}

static int
vvmplayer_application_command_line (GApplication            *application,
                                    GApplicationCommandLine *command_line)
{
  GVariantDict *options;

  options = g_application_command_line_get_options_dict (command_line);

  /*
   * NOTE: g_application_quit() is almost always a bad idea.
   * This simply kills the application.  So active process like
   * Saving file will get stopped midst the process.  If you
   * find it bad, find your luck with g_application_release()
   */
  if (g_variant_dict_contains (options, "quit"))
    {
      g_application_quit (application);
      return 0;
    }

  g_application_activate (application);

  return 0;
}

gboolean
on_widget_deleted(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  VvmApplication *self = (VvmApplication *)data;
  g_autoptr (GError) error = NULL;
  gboolean hide_on_del = FALSE;
  gboolean ret;

  /* If we are not running in daemon mode, hide the window and reset speaker button */
  if (self->daemon) {
    hide_on_del = gtk_widget_hide_on_delete (widget);
    vvmplayer_window_set_speaker_button (VVMPLAYER_WINDOW (self->main_window), FALSE);
  }

  g_signal_emit_by_name (self, "main-window-closed", 0);

  g_debug ("Setting audio profile to back to default");
  ret = call_audio_select_mode (CALL_AUDIO_MODE_DEFAULT, &error);

  if (!ret && error)
    g_warning ("Failed to switch profile: %s", error->message);

  return hide_on_del;
}

static void
vvmplayer_application_activate (GApplication *application)
{
  VvmApplication *self = (VvmApplication *)application;


  if (!self->main_window) {
    self->main_window = GTK_WINDOW (vvmplayer_window_new (GTK_APPLICATION (self), self->settings));
    g_object_add_weak_pointer (G_OBJECT (self->main_window), (gpointer *)&self->main_window);

    g_signal_connect(G_OBJECT(self->main_window),
        "delete-event", G_CALLBACK(on_widget_deleted), application);
  }

  if ((!self->daemon && !self->daemon_running) || (self->daemon_running)) {
    GtkSettings *gtk_settings = gtk_settings_get_default ();
    int prefer_dark_theme;
    int default_dark_theme_pref;

    self->main_window = gtk_application_get_active_window (GTK_APPLICATION (self));


    g_object_get (gtk_settings, "gtk-application-prefer-dark-theme", &default_dark_theme_pref, NULL);
    vvmplayer_settings_set_default_dark_theme_pref (self->settings,
                                                    default_dark_theme_pref);

    if (vvmplayer_settings_get_override_global_appearence_pref (self->settings)) {
      prefer_dark_theme = vvmplayer_settings_get_dark_theme (self->settings);
      g_object_set (gtk_settings, "gtk-application-prefer-dark-theme", prefer_dark_theme, NULL);
    }

    gtk_window_present (GTK_WINDOW (self->main_window));
  } else {
    self->daemon_running = TRUE;
  }
}

static void
vvmplayer_application_finalize (GObject *object)
{
  VvmApplication *self = (VvmApplication *)object;

  VVMPLAYER_TRACE_MSG ("disposing application");

  g_clear_object (&self->settings);
  g_clear_object (&self->backend);

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

static void
vvmplayer_application_class_init (VvmApplicationClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GApplicationClass *application_class = G_APPLICATION_CLASS (klass);

  signals [SIGNAL_MAIN_WINDOW_CLOSED] =
    g_signal_new ("main-window-closed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0, NULL, NULL, NULL,
                  G_TYPE_NONE, 0);

  object_class->finalize = vvmplayer_application_finalize;

  application_class->handle_local_options = vvmplayer_application_handle_local_options;
  application_class->startup = vvmplayer_application_startup;
  application_class->command_line = vvmplayer_application_command_line;
  application_class->activate = vvmplayer_application_activate;
}

static void
vvmplayer_application_init (VvmApplication *self)
{
  g_application_add_main_option_entries (G_APPLICATION (self), cmd_options);
}

VvmApplication *
vvmplayer_application_new (void)
{
  return g_object_new (VVMPLAYER_TYPE_APPLICATION,
                       "application-id", PACKAGE_ID,
                       "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
                       "register-session", TRUE,
                       NULL);
}
