/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  GThumb
 *
 *  Copyright (C) 2009 Free Software Foundation, Inc.
 *
 *  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 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/>.
 */

#include <config.h>
#include <glib.h>
#include <gthumb.h>
#include "gth-comment.h"
#include "gth-metadata-provider-comment.h"


struct _GthMetadataProviderCommentPrivate {
	GHashTable *checked_folders;
};


G_DEFINE_TYPE_WITH_CODE (GthMetadataProviderComment,
			 gth_metadata_provider_comment,
			 GTH_TYPE_METADATA_PROVIDER,
			 G_ADD_PRIVATE (GthMetadataProviderComment))


static gboolean
gth_metadata_provider_comment_can_read (GthMetadataProvider  *base,
					GthFileData          *file_data,
					const char           *mime_type,
					char                **attribute_v)

{
	GthMetadataProviderComment *self = GTH_METADATA_PROVIDER_COMMENT (base);
	gboolean                    can_read;

	can_read = _g_file_attributes_matches_any_v ("comment::*,"
						     "general::datetime,"
						     "general::title,"
						     "general::description,"
						     "general::location,"
						     "general::tags,"
						     "general::rating",
						     attribute_v);

	if (! can_read)
		return FALSE;

	if (file_data != NULL) {
		GFile    *comment_file;
		GFile    *comment_folder;
		gboolean  comment_folder_exists;
		gpointer  value;

		comment_file = gth_comment_get_comment_file (file_data->file);
		if (comment_file == NULL)
			return FALSE;

		comment_folder = g_file_get_parent (comment_file);
		if (comment_folder == NULL)
			return FALSE;

		value = g_hash_table_lookup (self->priv->checked_folders, comment_folder);
		if (value == NULL) {
			comment_folder_exists = g_file_query_exists (comment_folder, NULL);
			g_hash_table_insert (self->priv->checked_folders,
					     g_object_ref (comment_folder),
					     GINT_TO_POINTER (comment_folder_exists ? 1 : 2));
		}
		else
			comment_folder_exists = GPOINTER_TO_INT (value) == 1;

		can_read = comment_folder_exists;

		g_object_unref (comment_folder);
		g_object_unref (comment_file);
	}

	return can_read;
}


static gboolean
gth_metadata_provider_comment_can_write (GthMetadataProvider  *self,
				         const char           *mime_type,
				         char                **attribute_v)
{
	return _g_file_attributes_matches_any_v ("comment::*,"
						 "general::datetime,"
						 "general::title,"
						 "general::description,"
						 "general::location,"
						 "general::tags,"
						 "general::rating",
					         attribute_v);
}


static void
gth_metadata_provider_comment_read (GthMetadataProvider *self,
				    GthFileData         *file_data,
				    const char          *attributes,
				    GCancellable        *cancellable)
{
	GthComment *comment;
	const char *value;
	GPtrArray  *categories;
	char       *comment_time;

	comment = gth_comment_new_for_file (file_data->file, cancellable, NULL);
	g_file_info_set_attribute_boolean (file_data->info, "comment::no-comment-file", (comment == NULL));

	if (comment == NULL)
		return;

	value = gth_comment_get_note (comment);
	if (value != NULL)
		g_file_info_set_attribute_string (file_data->info, "comment::note", value);

	value = gth_comment_get_caption (comment);
	if (value != NULL)
		g_file_info_set_attribute_string (file_data->info, "comment::caption", value);

	value = gth_comment_get_place (comment);
	if (value != NULL)
		g_file_info_set_attribute_string (file_data->info, "comment::place", value);

	if (gth_comment_get_rating (comment) > 0)
		g_file_info_set_attribute_int32 (file_data->info, "comment::rating", gth_comment_get_rating (comment));
	else
		g_file_info_remove_attribute (file_data->info, "comment::rating");

	categories = gth_comment_get_categories (comment);
	if (categories->len > 0) {
		GthStringList *list;
		GthMetadata   *metadata;

		list =  gth_string_list_new_from_ptr_array (categories);
		metadata = gth_metadata_new_for_string_list (list);
		g_file_info_set_attribute_object (file_data->info, "comment::categories", G_OBJECT (metadata));

		g_object_unref (metadata);
		g_object_unref (list);
	}
	else
		g_file_info_remove_attribute (file_data->info, "comment::categories");

	comment_time = gth_comment_get_time_as_exif_format (comment);
	if (comment_time != NULL) {
		GTimeVal  time_;
		char     *formatted;

		if (_g_time_val_from_exif_date (comment_time, &time_))
			formatted = _g_time_val_strftime (&time_, "%x %X");
		else
			formatted = g_strdup (comment_time);
		set_attribute_from_string (file_data->info, "comment::time", comment_time, formatted);

		g_free (formatted);
		g_free (comment_time);
	}
	else
		g_file_info_remove_attribute (file_data->info, "comment::time");

	gth_comment_update_general_attributes (file_data);

	g_object_unref (comment);
}


static void
gth_metadata_provider_comment_write (GthMetadataProvider   *self,
				     GthMetadataWriteFlags  flags,
				     GthFileData           *file_data,
				     const char            *attributes,
				     GCancellable          *cancellable)
{
	GthComment    *comment;
	GthMetadata   *metadata;
	const char    *text;
	char          *data;
	gsize          length;
	GthStringList *categories;
	GFile         *comment_file;
	GFile         *comment_folder;

	comment = gth_comment_new ();

	/* caption */

	text = NULL;
	metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::title");
	if (metadata != NULL)
		text = gth_metadata_get_raw (metadata);
	gth_comment_set_caption (comment, text);

	/* comment */

	text = NULL;
	metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::description");
	if (metadata != NULL)
		text = gth_metadata_get_raw (metadata);
	gth_comment_set_note (comment, text);

	/* location */

	text = NULL;
	metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::location");
	if (metadata != NULL)
		text = gth_metadata_get_raw (metadata);
	gth_comment_set_place (comment, text);

	/* time */

	text = NULL;
	metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::datetime");
	if (metadata != NULL)
		text = gth_metadata_get_raw (metadata);
	gth_comment_set_time_from_exif_format (comment, text);

	/* keywords */

	metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::tags");
	categories = gth_metadata_get_string_list (metadata);
	if (categories != NULL) {
		GList *list;
		GList *scan;

		list = gth_string_list_get_list (categories);
		for (scan = list; scan; scan = scan->next)
			gth_comment_add_category (comment, (char *) scan->data);
	}

	/* rating */

	metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::rating");
	if (metadata != NULL) {
		int rating;

		sscanf (gth_metadata_get_raw (metadata), "%d", &rating);
		gth_comment_set_rating (comment, rating);
	}

	data = gth_comment_to_data (comment, &length);
	comment_file = gth_comment_get_comment_file (file_data->file);
	comment_folder = g_file_get_parent (comment_file);

	g_file_make_directory (comment_folder, NULL, NULL);
	_g_file_write (comment_file, FALSE, 0, data, length, cancellable, NULL);

	g_object_unref (comment_folder);
	g_object_unref (comment_file);
	g_free (data);
	g_object_unref (comment);
}


static void
gth_metadata_provider_comment_finalize (GObject *object)
{
	GthMetadataProviderComment *self;

	g_return_if_fail (object != NULL);
	g_return_if_fail (GTH_IS_METADATA_PROVIDER_COMMENT (object));

	self = GTH_METADATA_PROVIDER_COMMENT (object);
	g_hash_table_unref (self->priv->checked_folders);

	/* Chain up */
	G_OBJECT_CLASS (gth_metadata_provider_comment_parent_class)->finalize (object);
}


static void
gth_metadata_provider_comment_class_init (GthMetadataProviderCommentClass *klass)

{
	GObjectClass             *gobject_class;
	GthMetadataProviderClass *mp_class;

	gobject_class = G_OBJECT_CLASS (klass);
	gobject_class->finalize = gth_metadata_provider_comment_finalize;

	mp_class = GTH_METADATA_PROVIDER_CLASS (klass);
	mp_class->can_read = gth_metadata_provider_comment_can_read;
	mp_class->can_write = gth_metadata_provider_comment_can_write;
	mp_class->read = gth_metadata_provider_comment_read;
	mp_class->write = gth_metadata_provider_comment_write;
}


static void
gth_metadata_provider_comment_init (GthMetadataProviderComment *self)
{
	self->priv = gth_metadata_provider_comment_get_instance_private (self);
	self->priv->checked_folders = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, NULL);
}
