/*
 * This file is part of budgie-desktop
 *
 * Copyright (C) 2015-2016 Ikey Doherty <ikey@solus-project.com>
 *
 * 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.
 */

#include "applet-info.h"
#include <libpeas/peas.h>

enum { PROP_ICON = 1,
       PROP_NAME,
       PROP_DESCRIPTION,
       PROP_UUID,
       PROP_ALIGNMENT,
       PROP_POSITION,
       PROP_SETTINGS,
       PROP_APPLET,
       N_PROPS };

struct _BudgieAppletInfoPrivate {
        BudgieApplet *applet;
        GSettings *settings;
        char *icon;
        char *name;
        char *description;
        char *uuid;
        char *alignment;
        int position;
};

static void budgie_applet_info_bind_settings(BudgieAppletInfo *info);
static void budgie_applet_info_unbind_settings(BudgieAppletInfo *info);

#define UPDATE_STRING_PROPERTY(x, y)                                                               \
        {                                                                                          \
                if (self->priv->x) {                                                               \
                        g_free(self->priv->x);                                                     \
                        self->priv->x = NULL;                                                      \
                }                                                                                  \
                self->priv->x = g_value_dup_string(y);                                             \
        }

#define FREE_IF_SET(x)                                                                             \
        {                                                                                          \
                if (self->priv->x) {                                                               \
                        g_free(self->priv->x);                                                     \
                        self->priv->x = NULL;                                                      \
                }                                                                                  \
        }

G_DEFINE_TYPE_WITH_PRIVATE(BudgieAppletInfo, budgie_applet_info, G_TYPE_OBJECT)

static GParamSpec *obj_properties[N_PROPS] = {
        NULL,
};

static void budgie_applet_info_get_property(GObject *object, guint id, GValue *value,
                                            GParamSpec *spec)
{
        BudgieAppletInfo *self = BUDGIE_APPLET_INFO(object);

        switch (id) {
        case PROP_ICON:
                g_value_set_string((GValue *)value, self->priv->icon);
                break;
        case PROP_NAME:
                g_value_set_string((GValue *)value, self->priv->name);
                break;
        case PROP_DESCRIPTION:
                g_value_set_string((GValue *)value, self->priv->description);
                break;
        case PROP_UUID:
                g_value_set_string((GValue *)value, self->priv->uuid);
                break;
        case PROP_ALIGNMENT:
                g_value_set_string((GValue *)value, self->priv->alignment);
                break;
        case PROP_POSITION:
                g_value_set_int((GValue *)value, self->priv->position);
                break;
        case PROP_SETTINGS:
                g_value_set_pointer((GValue *)value, g_object_ref(self->priv->settings));
                break;
        case PROP_APPLET:
                if (!self->priv->applet) {
                        g_value_set_pointer((GValue *)value, NULL);
                } else {
                        g_value_set_pointer((GValue *)value, g_object_ref(self->priv->applet));
                }
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID(object, id, spec);
                break;
        }
}

static void budgie_applet_info_set_property(GObject *object, guint id, const GValue *value,
                                            GParamSpec *spec)
{
        BudgieAppletInfo *self = BUDGIE_APPLET_INFO(object);
        BudgieApplet *applet = NULL;

        switch (id) {
        case PROP_ICON:
                UPDATE_STRING_PROPERTY(icon, value);
                break;
        case PROP_NAME:
                UPDATE_STRING_PROPERTY(name, value);
                break;
        case PROP_DESCRIPTION:
                UPDATE_STRING_PROPERTY(description, value);
                break;
        case PROP_UUID:
                UPDATE_STRING_PROPERTY(uuid, value);
                break;
        case PROP_ALIGNMENT:
                UPDATE_STRING_PROPERTY(alignment, value);
                break;
        case PROP_POSITION:
                self->priv->position = g_value_get_int((GValue *)value);
                break;
        case PROP_SETTINGS:
                if (self->priv->settings) {
                        budgie_applet_info_unbind_settings(self);
                }
                GSettings *settings = g_value_get_pointer((GValue *)value);
                if (!settings) {
                        break;
                }
                self->priv->settings = g_object_ref(settings);
                budgie_applet_info_bind_settings(self);
                break;
        case PROP_APPLET:
                applet = g_value_get_pointer((GValue *)value);
                if (!applet) {
                        break;
                }
                if (self->priv->applet) {
                        g_object_unref(self->priv->applet);
                }
                self->priv->applet = g_object_ref(applet);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID(object, id, spec);
                break;
        }
}

static void budgie_applet_info_dispose(GObject *g_object)
{
        BudgieAppletInfo *self = BUDGIE_APPLET_INFO(g_object);

        FREE_IF_SET(icon);
        FREE_IF_SET(name);
        FREE_IF_SET(description);
        FREE_IF_SET(uuid);
        FREE_IF_SET(alignment);

        if (self->priv->applet) {
                g_object_unref(self->priv->applet);
                self->priv->applet = NULL;
        }

        budgie_applet_info_unbind_settings(self);

        G_OBJECT_CLASS(budgie_applet_info_parent_class)->dispose(g_object);
}

static void budgie_applet_info_class_init(BudgieAppletInfoClass *klazz)
{
        GObjectClass *obj_class = G_OBJECT_CLASS(klazz);

        obj_class->get_property = budgie_applet_info_get_property;
        obj_class->set_property = budgie_applet_info_set_property;
        obj_class->dispose = budgie_applet_info_dispose;

        obj_properties[PROP_ICON] = g_param_spec_string("icon",
                                                        "Applet icon",
                                                        "Set the applet icon",
                                                        NULL,
                                                        G_PARAM_READWRITE);

        obj_properties[PROP_NAME] = g_param_spec_string("name",
                                                        "Applet name",
                                                        "Set the applet name",
                                                        NULL,
                                                        G_PARAM_READWRITE);

        obj_properties[PROP_DESCRIPTION] = g_param_spec_string("description",
                                                               "Applet description",
                                                               "Set the applet description",
                                                               NULL,
                                                               G_PARAM_READWRITE);

        obj_properties[PROP_UUID] = g_param_spec_string("uuid",
                                                        "Applet UUID",
                                                        "Set the applet UUID",
                                                        NULL,
                                                        G_PARAM_READWRITE);

        obj_properties[PROP_ALIGNMENT] = g_param_spec_string("alignment",
                                                             "Applet alignment",
                                                             "Set the applet alignment",
                                                             "start",
                                                             G_PARAM_READWRITE);

        obj_properties[PROP_POSITION] = g_param_spec_int("position",
                                                         "Applet position",
                                                         "Set the applet position",
                                                         -1000,
                                                         1000,
                                                         0,
                                                         G_PARAM_READWRITE);

        /**
         * BudgieAppletInfo:settings: (type GSettings)
         */
        obj_properties[PROP_SETTINGS] = g_param_spec_pointer("settings",
                                                             "Applet Settings",
                                                             "Set the applet GSettings",
                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT);

        /**
         * BudgieAppletInfo:applet: (type BudgieApplet)
         */
        obj_properties[PROP_APPLET] = g_param_spec_pointer("applet",
                                                           "Applet instance",
                                                           "Set the applet instance",
                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT);

        g_object_class_install_properties(obj_class, N_PROPS, obj_properties);
}

static void budgie_applet_info_bind_settings(BudgieAppletInfo *self)
{
        if (!self || !self->priv->settings) {
                return;
        }

        g_settings_bind(self->priv->settings,
                        BUDGIE_APPLET_KEY_NAME,
                        self,
                        "name",
                        G_SETTINGS_BIND_DEFAULT);
        g_settings_bind(self->priv->settings,
                        BUDGIE_APPLET_KEY_POS,
                        self,
                        "position",
                        G_SETTINGS_BIND_DEFAULT);
        g_settings_bind(self->priv->settings,
                        BUDGIE_APPLET_KEY_ALIGN,
                        self,
                        "alignment",
                        G_SETTINGS_BIND_DEFAULT);
}

static void budgie_applet_info_unbind_settings(BudgieAppletInfo *self)
{
        if (!self || !self->priv->settings) {
                return;
        }

        g_settings_unbind(self, "name");
        g_settings_unbind(self, "position");
        g_settings_unbind(self, "alignment");
        g_object_unref(self->priv->settings);
        self->priv->settings = NULL;
}

static void budgie_applet_info_init(BudgieAppletInfo *self)
{
        self->priv = budgie_applet_info_get_instance_private(self);
}

BudgieAppletInfo *budgie_applet_info_new(PeasPluginInfo *plugin_info, const char *uuid,
                                         BudgieApplet *applet, GSettings *settings)
{
        if (plugin_info) {
                return g_object_new(BUDGIE_TYPE_APPLET_INFO,
                                    "icon",
                                    peas_plugin_info_get_icon_name(plugin_info),
                                    "name",
                                    peas_plugin_info_get_name(plugin_info),
                                    "description",
                                    peas_plugin_info_get_description(plugin_info),
                                    "uuid",
                                    uuid,
                                    "applet",
                                    applet,
                                    "settings",
                                    settings,
                                    NULL);
        } else {
                return g_object_new(BUDGIE_TYPE_APPLET_INFO,
                                    "uuid",
                                    uuid,
                                    "applet",
                                    applet,
                                    "settings",
                                    settings,
                                    NULL);
        }
}
