/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
 *
 * Copyright © 2017 Endless Mobile, Inc.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Authors:
 *  - Philip Withnall <withnall@endlessm.com>
 */

#pragma once

#include <gio/gio.h>
#include <glib.h>
#include <glib-object.h>

G_BEGIN_DECLS

/**
 * GSS_SERVICE_ERROR:
 *
 * Error domain for #GssServiceError.
 *
 * Since: 0.1.0
 */
#define GSS_SERVICE_ERROR gss_service_error_quark ()
GQuark gss_service_error_quark (void);

/**
 * GssServiceError:
 * @GSS_SERVICE_ERROR_SIGNALLED: Process was signalled with `SIGINT` or
 *    `SIGTERM`.
 * @GSS_SERVICE_ERROR_INVALID_OPTIONS: Invalid command line options.
 * @GSS_SERVICE_ERROR_NAME_UNAVAILABLE: Bus or well-known name unavailable.
 * @GSS_SERVICE_ERROR_INVALID_ENVIRONMENT: Runtime environment is insecure or
 *    otherwise invalid for running the daemon.
 * @GSS_SERVICE_ERROR_TIMEOUT: Inactivity timeout reached.
 *
 * Errors from running a service.
 *
 * Since: 0.1.0
 */
typedef enum
{
  GSS_SERVICE_ERROR_SIGNALLED,
  GSS_SERVICE_ERROR_INVALID_OPTIONS,
  GSS_SERVICE_ERROR_NAME_UNAVAILABLE,
  GSS_SERVICE_ERROR_INVALID_ENVIRONMENT,
  GSS_SERVICE_ERROR_TIMEOUT,
} GssServiceError;

int gss_service_error_to_exit_status (GssServiceError error);

#define GSS_TYPE_SERVICE gss_service_get_type ()
G_DECLARE_DERIVABLE_TYPE (GssService, gss_service, GSS, SERVICE, GObject)

/**
 * GssServiceClass:
 * @get_main_option_entries: (nullable): Get a %NULL-terminated array of
 *    #GOptionEntrys to add to the main option group for the service. If
 *    implemented, this must return a non-%NULL value.
 * @startup_async: (not nullable): Asynchronous service startup implementation.
 *    This should start performing the startup for the service, when called by
 *    gss_service_run(). @startup_finish will be called to complete the startup,
 *    and a #GMainContext will be iterated between the two. This method must be
 *    implemented. If gss_service_exit() is called during startup_async(), the
 *    exit return value (success or error) will be returned from
 *    gss_service_run().
 * @startup_finish: (not nullable): Finish asynchronous startup started with
 *    @startup_async. This method must be implemented.
 * @shutdown: (not nullable): Synchronous service shutdown implementation. This
 *    should perform all shutdown for the service, and is called from
 *    gss_service_run() once the service shutdown is triggered. This method must
 *    be implemented.
 *
 * Class structure for a #GssService implementation.
 *
 * All services must implement @startup_async, @startup_finish and @shutdown,
 * which are called by gss_service_run() to start up and shut down the service.
 *
 * If your service needs to support additional command line options in the main
 * group, implement @get_main_option_entries; otherwise leave it unimplemented.
 *
 * Since: 0.1.0
 */
struct _GssServiceClass
{
  GObjectClass parent_class;

  GOptionEntry *(*get_main_option_entries) (GssService *service);

  void (*startup_async)  (GssService          *service,
                          GCancellable        *cancellable,
                          GAsyncReadyCallback  callback,
                          gpointer             user_data);
  void (*startup_finish) (GssService          *service,
                          GAsyncResult        *result,
                          GError             **error);
  void (*shutdown)       (GssService          *service);

  /*< private >*/
  gpointer padding[12];
};

void        gss_service_add_option_group (GssService    *self,
                                          GOptionGroup  *group);

void        gss_service_run              (GssService    *self,
                                          int            argc,
                                          char         **argv,
                                          GError       **error);
void        gss_service_exit             (GssService    *self,
                                          const GError  *error,
                                          int            signum);

GDBusConnection *gss_service_get_dbus_connection (GssService *self);
int              gss_service_get_exit_signal     (GssService *self);

guint gss_service_get_inactivity_timeout (GssService *self);
void  gss_service_set_inactivity_timeout (GssService *self,
                                          guint       timeout_ms);

GDebugController *gss_service_get_debug_controller (GssService *self);

void  gss_service_hold    (GssService *self);
void  gss_service_release (GssService *self);

G_END_DECLS
