/*
 * Copyright (C) 2016, Sam Thursfield <sam@afuera.me.uk>
 *
 * 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.
 */

#include "tracker-resource-helpers.h"

#include "tracker-extract-info.h"
#include "tracker-guarantee.h"

/**
 * SECTION:tracker-resource-helpers
 * @title: Resource Helpers
 * @short_description: Helpers for describing certain common kinds of resource.
 * @stability: Stable
 * @include: libtracker-extract/tracker-extract.h
 *
 * Some common patterns for resources used in Tracker extractors have helper
 * functions defined in this module.
 */

/**
 * tracker_extract_new_music_artist:
 * @name: the name of the artist
 *
 * Create a new nmm:Artist resource. The URI will be set based on the URI, so
 * there will only be one resource representing the artist in the Tracker store.
 *
 * Returns: a newly allocated #TrackerResource instance, of type nmm:Artist.
 *
 * Since: 1.10
 */
TrackerResource *
tracker_extract_new_artist (const char *name)
{
	TrackerResource *artist;
	gchar *uri;

	g_return_val_if_fail (name != NULL, NULL);

	uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", name);

	artist = tracker_resource_new (uri);

	tracker_resource_set_uri (artist, "rdf:type", "nmm:Artist");
	tracker_guarantee_resource_utf8_string (artist, "nmm:artistName", name);

	g_free (uri);

	return artist;
}

/**
 * tracker_extract_new_contact:
 * @fullname: the full name of the contact
 *
 * Create a new nco:Contact resource. The URI is based on @fullname, so only
 * one instance will exist in the Tracker store.
 *
 * This is used for describing people or organisations, and can be used with
 * many fields including nco:artist, nco:creator, nco:publisher, and
 * nco:representative.
 *
 * Returns: a newly allocated #TrackerResource instance, of type nco:Contact
 *
 * Since: 1.10
 */
TrackerResource *
tracker_extract_new_contact (const char *fullname)
{
	TrackerResource *publisher;
	gchar *uri;

	g_return_val_if_fail (fullname != NULL, NULL);

	uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", fullname);

	publisher = tracker_resource_new (uri);

	tracker_resource_set_uri (publisher, "rdf:type", "nco:Contact");
	tracker_guarantee_resource_utf8_string (publisher, "nco:fullname", fullname);

	g_free (uri);

	return publisher;
}

/**
 * tracker_extract_new_equipment:
 * @make: (allow none): the manufacturer of the equipment, or %NULL
 * @model: (allow none): the model name of the equipment, or %NULL
 *
 * Create a new nfo:Equipment resource. The URI is based on @make and @model,
 * so only one instance will exist in the Tracker store. At least one of @make
 * and @model must be non-%NULL.
 *
 * This is useful for describing equipment used to create something, for
 * example the camera that was used to take a photograph.
 *
 * Returns: a newly allocated #TrackerResource instance, of type nfo:Equipment
 *
 * Since: 1.10
 */
TrackerResource *
tracker_extract_new_equipment (const char *make,
                               const char *model)
{
	TrackerResource *equipment;
	gchar *equip_uri;

	g_return_val_if_fail (make != NULL || model != NULL, NULL);

	equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:", make ? make : "", model ? model : "");

	equipment = tracker_resource_new (equip_uri);
	tracker_resource_set_uri (equipment, "rdf:type", "nfo:Equipment");

	if (make) {
		tracker_guarantee_resource_utf8_string (equipment, "nfo:manufacturer", make);
	}

	if (model) {
		tracker_guarantee_resource_utf8_string (equipment, "nfo:model", model);
	}

	g_free (equip_uri);

	return equipment;
}

/**
 * tracker_extract_new_external_reference:
 * @source_uri: the source uri of the external reference
 * @identifier: the identifier of the external reference
 * @uri: (allow-none): URI of the resource (leave blank to generate one).
 *
 * Create a new tracker:ExternalReference resource and set its source and its
 * identifier. Both @source and @identifer must be non-%NULL.
 *
 * External references link local data to online resources where apps can fetch
 * more metadata. One example is MusicBrainz, an open database of music releases.
 * Here is an example of creating a tracker:ExternalResource that could be used
 * to link the music artist 'Pulp' to the corresponding Musicbrainz data:
 *
 * <example>
 * <programlisting>
 *     TrackerResource *mb_artist = tracker_extract_new_external_reference (
 *         "https://musicbrainz.org/doc/Artist", "76b2e842-5e85-4c97-ab62-d5bc315595b5",
 *         "https://musicbrainz.org/artist/76b2e842-5e85-4c97-ab62-d5bc315595b5");
 * </programlisting>
 * </example>
 *
 * Returns: a newly allocated #TrackerResource instance, of type tracker:ExternalReference
 *
 * Since: 2.3.0
 */
TrackerResource *
tracker_extract_new_external_reference (const char *source_uri,
				        const char *identifier,
				        const char *uri)
{
	TrackerResource *external_reference;
	g_autofree gchar *generated_uri = NULL;

	g_return_val_if_fail (source_uri != NULL && identifier != NULL, NULL);

	if (uri == NULL) {
		uri = generated_uri = tracker_sparql_escape_uri_printf ("urn:ExternalReference:%s:%s", source_uri, identifier);
	}

	external_reference = tracker_resource_new (uri);
	tracker_resource_set_uri (external_reference, "rdf:type", "tracker:ExternalReference");
	tracker_resource_set_uri (external_reference, "tracker:referenceSource", source_uri);
	tracker_resource_set_string (external_reference, "tracker:referenceIdentifier", identifier);

	return external_reference;
}

void
tracker_extract_merge_location (TrackerResource *location,
                                const char      *street_address,
                                const char      *state,
                                const char      *city,
                                const char      *country,
                                const char      *gps_altitude,
                                const char      *gps_latitude,
                                const char      *gps_longitude)
{
	tracker_resource_set_uri (location, "rdf:type", "slo:GeoLocation");

	if (street_address || state || country || city) {
		TrackerResource *address;

		address = tracker_resource_get_first_relation (location, "slo:postalAddress");

		if (!address) {
			g_autofree char *addruri = NULL;

			addruri = tracker_sparql_get_uuid_urn ();
			address = tracker_resource_new (addruri);
			tracker_resource_set_take_relation (location, "slo:postalAddress", address);
		}

		tracker_resource_set_uri (address, "rdf:type", "nco:PostalAddress");

		if (street_address) {
			tracker_guarantee_resource_utf8_string (address, "nco:streetAddress", street_address);
		}

		if (state) {
			tracker_guarantee_resource_utf8_string (address, "nco:region", state);
		}

		if (city) {
			tracker_guarantee_resource_utf8_string (address, "nco:locality", city);
		}

		if (country) {
			tracker_guarantee_resource_utf8_string (address, "nco:country", country);
		}
	}

	if (gps_altitude) {
		gdouble val;

		val = g_strtod (gps_altitude, NULL);
		tracker_resource_set_double (location, "slo:altitude", val);
	}

	if (gps_latitude) {
		gdouble val;

		val = g_strtod (gps_latitude, NULL);
		tracker_resource_set_double (location, "slo:latitude", val);
	}

	if (gps_longitude) {
		gdouble val;

		val = g_strtod (gps_longitude, NULL);
		tracker_resource_set_double (location, "slo:longitude", val);
	}
}

TrackerResource *
tracker_extract_new_location (const char *street_address,
                              const char *state,
                              const char *city,
                              const char *country,
                              const char *gps_altitude,
                              const char *gps_latitude,
                              const char *gps_longitude)
{
	TrackerResource *location;

	location = tracker_resource_new (NULL);
	tracker_extract_merge_location (location,
	                                street_address, state, city, country,
	                                gps_altitude, gps_latitude, gps_longitude);

	return location;
}

/**
 * tracker_extract_new_music_album_disc:
 * @album_title: title of the album
 * @album_artist: (allow none): a #TrackerResource for the album artist, or %NULL
 * @disc_number: disc number of this disc (the first / only disc in a set should be 1, not 0)
 * @date: (allow none):The release date, or %NULL
 *
 * Create new nmm:MusicAlbumDisc and nmm:MusicAlbum resources. The resources are
 * given fixed URIs based on @album_title and @disc_number, so they will be
 * merged with existing entries when serialized to SPARQL and sent to the
 * Tracker store.
 *
 * You can get the album resource from the disc resource by calling:
 *
 *     tracker_resource_get_first_relation (album_disc, "nmm:albumDiscAlbum");
 *
 * Returns: a newly allocated #TrackerResource instance, of type nmm:MusicAlbumDisc
 *
 * Since: 1.10
 */
TrackerResource *
tracker_extract_new_music_album_disc (const char      *album_title,
                                      TrackerResource *album_artist,
                                      int              disc_number,
                                      const char      *date)
{
	GString *album_uri, *disc_uri, *shared;
	const gchar *album_artist_name = NULL;
	gchar *tmp_album_uri, *tmp_disc_uri;

	TrackerResource *album, *album_disc;

	g_return_val_if_fail (album_title != NULL, NULL);

	if (album_artist)
		album_artist_name = tracker_resource_get_first_string (album_artist,
		                                                       "nmm:artistName");
	shared = g_string_new (NULL);

	g_string_append (shared, album_title);

	if (album_artist_name)
		g_string_append_printf (shared, ":%s", album_artist_name);

	if (date) {
		g_string_append_c (shared, ':');

		/* Only use date from ISO8601 string */
		if (strlen (date) > 10)
			g_string_append_len (shared, date, 10);
		else
			g_string_append (shared, date);
	}

	album_uri = g_string_new ("urn:album:");
	g_string_append (album_uri, shared->str);
	tmp_album_uri = tracker_sparql_escape_uri (album_uri->str);
	album = tracker_resource_new (tmp_album_uri);

	tracker_resource_set_uri (album, "rdf:type", "nmm:MusicAlbum");
	tracker_resource_set_string (album, "nie:title", album_title);

	if (album_artist)
		tracker_resource_add_relation (album, "nmm:albumArtist", album_artist);

	disc_uri = g_string_new ("urn:album-disc:");
	g_string_append_printf (disc_uri, "%s:Disc%d", shared->str, disc_number);

	tmp_disc_uri = tracker_sparql_escape_uri (disc_uri->str);
	album_disc = tracker_resource_new (tmp_disc_uri);

	tracker_resource_set_uri (album_disc, "rdf:type", "nmm:MusicAlbumDisc");
	tracker_resource_set_int (album_disc, "nmm:setNumber", disc_number > 0 ? disc_number : 1);
	tracker_resource_set_relation (album_disc, "nmm:albumDiscAlbum", album);

	g_free (tmp_album_uri);
	g_free (tmp_disc_uri);
	g_string_free (album_uri, TRUE);
	g_string_free (disc_uri, TRUE);
	g_string_free (shared, TRUE);

	g_object_unref (album);

	return album_disc;
}

/**
 * tracker_extract_new_tag:
 * @label: the label of the tag
 *
 * Create a new nao:Tag resource. The URI will be set based on the tag label,
 * so there will only be one resource representing the tag in the Tracker store.
 *
 * Returns: a newly allocated #TrackerResource instance, of type nao:Tag.
 *
 * Since: 1.10
 */
TrackerResource *
tracker_extract_new_tag (const char *label)
{
	TrackerResource *tag;
	char *uri;

	uri = tracker_sparql_escape_uri_printf ("urn:tag:%s", label);
	tag = tracker_resource_new (uri);

	tracker_resource_set_uri (tag, "rdf:type", "nao:Tag");
	tracker_guarantee_resource_utf8_string (tag, "nao:prefLabel", label);

	g_free (uri);
	return tag;
}

TrackerResource *
tracker_extract_new_tv_series (const char *name)
{
	TrackerResource *tv_series;
	g_autofree char *uri = NULL;

	uri = tracker_sparql_escape_uri_printf ("urn:tvseries:%s", name);
	tv_series = tracker_resource_new (uri);
	tracker_resource_set_uri (tv_series, "rdf:type", "nmm:TVSeries");
	tracker_resource_set_string (tv_series, "nie:title", name);

	return tv_series;
}

TrackerResource *
tracker_extract_new_tv_season (const char      *name,
                               int              number,
                               TrackerResource *tv_series)
{
	TrackerResource *tv_season;
	g_autofree char *uri = NULL;

	uri = tracker_sparql_escape_uri_printf ("urn:tvseason:%s-S%2d",
	                                        name, number);
	tv_season = tracker_resource_new (uri);

	tracker_resource_set_uri (tv_season, "rdf:type", "nmm:TVSeason");
	tracker_resource_set_int (tv_season, "nmm:seasonNumber", number);

	if (tv_series) {
		tracker_resource_set_uri (tv_season, "nmm:seasonOf",
		                          tracker_resource_get_identifier (tv_series));
		tracker_resource_add_uri (tv_series, "nmm:hasSeason", uri);
	}

	return tv_season;
}
