/*
 * gedit plugin for GTK+ CSS
 *
 * ©2011 Carlos Garnacho <carlosg@gnome.org>
 *
 * 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 2, 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"
#include "cossa-style-provider.h"

typedef struct _CossaStyleProviderPrivate CossaStyleProviderPrivate;

struct _CossaStyleProviderPrivate
{
  GtkCssProvider *fallback_provider;

  guint use_fallback : 1;
};

enum {
  PROP_0,
  PROP_USE_FALLBACK
};


static void cossa_style_provider_iface_init (GtkStyleProviderIface *iface);


G_DEFINE_TYPE_EXTENDED (CossaStyleProvider, cossa_style_provider, GTK_TYPE_CSS_PROVIDER, 0,
                        G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
                                               cossa_style_provider_iface_init))

static void
cossa_style_provider_init (CossaStyleProvider *provider)
{
  CossaStyleProviderPrivate *priv;

  provider->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (provider,
                                                       COSSA_TYPE_STYLE_PROVIDER,
                                                       CossaStyleProviderPrivate);

  priv->fallback_provider = gtk_css_provider_new ();
  gtk_css_provider_load_from_data (priv->fallback_provider,
                                   "* {"
                                   "  background-image: none;"
                                   "  font: none;"
                                   "  background-color: none;"
                                   "  color: none;"
                                   "  text-shadow: none;"
                                   "  border-radius: none;"
                                   "  border-style: none;"
                                   "  border-color: none;"
                                   "  border-image: none;"
                                   "  engine: none;"
                                   "  transition: none;"
                                   "}",
                                   -1, NULL);

  priv->use_fallback = TRUE;
}

static void
cossa_style_provider_finalize (GObject *object)
{
  CossaStyleProviderPrivate *priv;

  priv = COSSA_STYLE_PROVIDER (object)->priv;
  g_object_unref (priv->fallback_provider);

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

static void
cossa_style_provider_set_property (GObject      *object,
                                   guint         prop_id,
                                   const GValue *value,
                                   GParamSpec   *pspec)
{
  switch (prop_id)
    {
    case PROP_USE_FALLBACK:
      cossa_style_provider_set_use_fallback (COSSA_STYLE_PROVIDER (object),
                                             g_value_get_boolean (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
cossa_style_provider_get_property (GObject    *object,
                                   guint       prop_id,
                                   GValue     *value,
                                   GParamSpec *pspec)
{
  CossaStyleProviderPrivate *priv;

  priv = COSSA_STYLE_PROVIDER (object)->priv;

  switch (prop_id)
    {
    case PROP_USE_FALLBACK:
      g_value_set_boolean (value, priv->use_fallback);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
cossa_style_provider_class_init (CossaStyleProviderClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->get_property = cossa_style_provider_get_property;
  object_class->set_property = cossa_style_provider_set_property;
  object_class->finalize = cossa_style_provider_finalize;

  g_object_class_install_property (object_class,
				   PROP_USE_FALLBACK,
				   g_param_spec_boolean ("use-fallback",
                                                         "Use fallback",
                                                         "Use fallback",
                                                         FALSE,
                                                         G_PARAM_READWRITE));

  g_type_class_add_private (klass, sizeof (CossaStyleProviderPrivate));
}

static GtkStyleProperties *
cossa_style_provider_get_style (GtkStyleProvider *provider,
                                GtkWidgetPath    *path)
{
  GtkStyleProviderIface *parent_iface;
  CossaStyleProviderPrivate *priv;
  GtkStyleProperties *properties, *tmp;

  priv = COSSA_STYLE_PROVIDER (provider)->priv;
  properties = gtk_style_properties_new ();

  if (priv->use_fallback)
    {
      tmp = gtk_style_provider_get_style (GTK_STYLE_PROVIDER (priv->fallback_provider),
                                          path);
      gtk_style_properties_merge (properties, tmp, TRUE);
      g_object_unref (tmp);

      tmp = gtk_style_provider_get_style (GTK_STYLE_PROVIDER (gtk_css_provider_get_default ()),
                                          path);
      gtk_style_properties_merge (properties, tmp, TRUE);
      g_object_unref (tmp);
    }

  parent_iface = g_type_interface_peek_parent (GTK_STYLE_PROVIDER_GET_IFACE (provider));
  tmp = parent_iface->get_style (provider, path);

  gtk_style_properties_merge (properties, tmp, TRUE);
  g_object_unref (tmp);

  return properties;
}

static void
cossa_style_provider_iface_init (GtkStyleProviderIface *iface)
{
  iface->get_style = cossa_style_provider_get_style;
}

GtkStyleProvider *
cossa_style_provider_new (void)
{
  return g_object_new (COSSA_TYPE_STYLE_PROVIDER, NULL);
}

void
cossa_style_provider_set_use_fallback (CossaStyleProvider *provider,
                                       gboolean            use_fallback)
{
  CossaStyleProviderPrivate *priv;

  g_return_if_fail (COSSA_IS_STYLE_PROVIDER (provider));

  priv = provider->priv;

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

  priv->use_fallback = use_fallback;
  g_object_notify (G_OBJECT (provider), "use-fallback");
}

gboolean
cossa_style_provider_get_use_fallback (CossaStyleProvider *provider)
{
  CossaStyleProviderPrivate *priv;

  g_return_val_if_fail (COSSA_IS_STYLE_PROVIDER (provider), FALSE);

  priv = provider->priv;
  return priv->use_fallback;
}
