/*
 * This file is part of GtkSourceView
 *
 * Copyright 2007 - Johannes Schmid <jhs@gnome.org>
 *
 * GtkSourceView 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.
 *
 * GtkSourceView 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, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"

#include "gtksourcemark.h"
#include "gtksourcebuffer.h"
#include "gtksourcebuffer-private.h"

/**
 * GtkSourceMark:
 *
 * Mark object for [class@Buffer].
 *
 * A `GtkSourceMark` marks a position in the text where you want to display
 * additional info. It is based on [class@Gtk.TextMark] and thus is still valid after
 * the text has changed though its position may change.
 *
 * `GtkSourceMark`s are organized in categories which you have to set
 * when you create the mark. Each category can have a priority, a pixbuf and
 * other associated attributes. See [method@View.set_mark_attributes].
 * The pixbuf will be displayed in the margin at the line where the mark
 * residents if the [property@View:show-line-marks] property is set to %TRUE. If
 * there are multiple marks in the same line, the pixbufs will be drawn on top
 * of each other. The mark with the highest priority will be drawn on top.
 */

enum
{
	PROP_0,
	PROP_CATEGORY
};

typedef struct
{
	gchar *category;
} GtkSourceMarkPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceMark, gtk_source_mark, GTK_TYPE_TEXT_MARK)

static void
gtk_source_mark_set_property (GObject      *object,
                              guint         prop_id,
                              const GValue *value,
                              GParamSpec   *pspec)
{
	GtkSourceMark *mark = GTK_SOURCE_MARK (object);
	GtkSourceMarkPrivate *priv = gtk_source_mark_get_instance_private (mark);

	switch (prop_id)
	{
		case PROP_CATEGORY:
			g_return_if_fail (g_value_get_string (value) != NULL);
			g_free (priv->category);
			priv->category = g_value_dup_string (value);
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
							   prop_id,
							   pspec);
	}
}

static void
gtk_source_mark_get_property (GObject    *object,
                              guint       prop_id,
                              GValue     *value,
                              GParamSpec *pspec)
{
	GtkSourceMark *mark = GTK_SOURCE_MARK (object);

	switch (prop_id)
	{
		case PROP_CATEGORY:
			g_value_set_string (value,
					    gtk_source_mark_get_category (mark));
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
							   prop_id,
							   pspec);
	}
}

static void
gtk_source_mark_finalize (GObject *object)
{
	GtkSourceMark *mark = GTK_SOURCE_MARK (object);
	GtkSourceMarkPrivate *priv = gtk_source_mark_get_instance_private (mark);

	g_clear_pointer (&priv->category, g_free);

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

static void
gtk_source_mark_class_init (GtkSourceMarkClass *klass)
{
	GObjectClass *object_class;

	object_class = G_OBJECT_CLASS (klass);

	object_class->set_property = gtk_source_mark_set_property;
	object_class->get_property = gtk_source_mark_get_property;
	object_class->finalize = gtk_source_mark_finalize;

	/**
	 * GtkSourceMark:category:
	 *
	 * The category of the `GtkSourceMark`, classifies the mark and controls
	 * which pixbuf is used and with which priority it is drawn.
	 */
	g_object_class_install_property (object_class,
					 PROP_CATEGORY,
					 g_param_spec_string ("category",
							      "Category",
							      "The mark category",
							      NULL,
							      G_PARAM_READWRITE |
							      G_PARAM_CONSTRUCT_ONLY |
							      G_PARAM_STATIC_STRINGS));
}

static void
gtk_source_mark_init (GtkSourceMark *mark)
{
}

/**
 * gtk_source_mark_new:
 * @name: (nullable): Name of the #GtkSourceMark or %NULL
 * @category: is used to classify marks according to common characteristics
 *   (e.g. all the marks representing a bookmark could belong to the "bookmark"
 *   category, or all the marks representing a compilation error could belong
 *   to "error" category).
 *
 * Creates a text mark. 
 * 
 * Add it to a buffer using [method@Gtk.TextBuffer.add_mark].
 * If name is NULL, the mark is anonymous; otherwise, the mark can be retrieved
 * by name using [method@Gtk.TextBuffer.get_mark].
 * Normally marks are created using the utility function
 * [method@Buffer.create_source_mark].
 *
 * Returns: a new #GtkSourceMark that can be added using [method@Gtk.TextBuffer.add_mark].
 */
GtkSourceMark *
gtk_source_mark_new (const gchar *name,
                     const gchar *category)
{
	g_return_val_if_fail (category != NULL, NULL);

	return GTK_SOURCE_MARK (g_object_new (GTK_SOURCE_TYPE_MARK,
	                                      "category", category,
	                                      "name", name,
	                                      "left-gravity", TRUE,
	                                      NULL));
}

/**
 * gtk_source_mark_get_category:
 * @mark: a #GtkSourceMark.
 *
 * Returns the mark category.
 *
 * Returns: the category of the #GtkSourceMark.
 */
const gchar *
gtk_source_mark_get_category (GtkSourceMark *mark)
{
	GtkSourceMarkPrivate *priv = gtk_source_mark_get_instance_private (mark);

	g_return_val_if_fail (GTK_SOURCE_IS_MARK (mark), NULL);

	return priv->category;
}

/**
 * gtk_source_mark_next:
 * @mark: a #GtkSourceMark.
 * @category: (nullable): a string specifying the mark category, or %NULL.
 *
 * Returns the next `GtkSourceMark` in the buffer or %NULL if the mark
 * was not added to a buffer.
 *
 *  If there is no next mark, %NULL will be returned.
 *
 * If @category is %NULL, looks for marks of any category.
 *
 * Returns: (nullable) (transfer none): the next #GtkSourceMark, or %NULL.
 */
GtkSourceMark *
gtk_source_mark_next (GtkSourceMark *mark,
                      const gchar   *category)
{
	GtkTextBuffer *buffer;

	g_return_val_if_fail (GTK_SOURCE_IS_MARK (mark), NULL);

	buffer = gtk_text_mark_get_buffer (GTK_TEXT_MARK (mark));

	if (buffer == NULL)
	{
		return NULL;
	}

	return _gtk_source_buffer_source_mark_next (GTK_SOURCE_BUFFER (buffer),
						    mark,
						    category);
}

/**
 * gtk_source_mark_prev:
 * @mark: a #GtkSourceMark.
 * @category: a string specifying the mark category, or %NULL.
 *
 * Returns the previous `GtkSourceMark` in the buffer or %NULL if the mark
 * was not added to a buffer. 
 *
 * If there is no previous mark, %NULL is returned.
 *
 * If @category is %NULL, looks for marks of any category
 *
 * Returns: (nullable) (transfer none): the previous #GtkSourceMark, or %NULL.
 */
GtkSourceMark *
gtk_source_mark_prev (GtkSourceMark *mark,
                      const gchar   *category)
{
	GtkTextBuffer *buffer;

	g_return_val_if_fail (GTK_SOURCE_IS_MARK (mark), NULL);

	buffer = gtk_text_mark_get_buffer (GTK_TEXT_MARK (mark));

	if (buffer == NULL)
	{
		return NULL;
	}

	return _gtk_source_buffer_source_mark_prev (GTK_SOURCE_BUFFER (buffer),
						    mark,
						    category);
}

