/* sml_map_item.c
 *
 * Copyright (C) 2009 Michael Bell <michael.bell@opensync.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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 "sml_map_item_internals.h"
#include "../sml_error_internals.h"
#include <string.h>

G_DEFINE_TYPE (SmlMapItem, sml_map_item, G_TYPE_OBJECT)

enum
{
	PROP_0,
	PROP_REMOTE,
	PROP_LOCAL
};

struct _SmlMapItemPrivate
{
	SmlLocation*  remote;
	SmlLocation*  local;
};

static void
sml_map_item_get_property (GObject    *object,
                           guint       property_id,
                           GValue     *value,
                           GParamSpec *pspec)
{
	switch (property_id) {
	case PROP_REMOTE:
		g_value_set_object (value, SML_MAP_ITEM (object)->priv->remote);
		break;
	case PROP_LOCAL:
		g_value_set_object (value, SML_MAP_ITEM (object)->priv->local);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
	}
}

static void
sml_map_item_set_property (GObject      *object,
                           guint         property_id,
                           const GValue *value,
                           GParamSpec   *pspec)
{
	switch (property_id) {
	case PROP_REMOTE:
        	if (SML_MAP_ITEM (object)->priv->remote)
        		g_object_unref (SML_MAP_ITEM (object)->priv->remote);
		SML_MAP_ITEM (object)->priv->remote = SML_LOCATION (value);
		g_object_ref(SML_MAP_ITEM (object)->priv->remote);
		break;
	case PROP_LOCAL:
        	if (SML_MAP_ITEM (object)->priv->local)
        		g_object_unref (SML_MAP_ITEM (object)->priv->local);
		SML_MAP_ITEM (object)->priv->local = SML_LOCATION (value);
		g_object_ref(SML_MAP_ITEM (object)->priv->local);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
	}
}

static void
sml_map_item_finalize (GObject *object)
{
	SmlMapItem *self = (SmlMapItem *) object;
	g_object_unref(self->priv->remote);
	g_object_unref(self->priv->local);
	/* all pointers must be NULL */
	self->priv->remote = NULL;
	self->priv->local = NULL;
	G_OBJECT_CLASS (sml_map_item_parent_class)->finalize (object);
}

static void
sml_map_item_class_init (SmlMapItemClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	g_type_class_add_private (klass, sizeof (SmlMapItemPrivate));

	object_class->get_property = sml_map_item_get_property;
	object_class->set_property = sml_map_item_set_property;
	object_class->finalize     = sml_map_item_finalize;

	/**
	 * SmlMapItem:remote:
	 *
	 * The remote property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_REMOTE,
	                                 g_param_spec_object ("remote",
	                                                      "remote",
	                                                      "remote",
	                                                      G_TYPE_OBJECT,
	                                                      G_PARAM_READWRITE));
	/**
	 * SmlMapItem:local:
	 *
	 * The local property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_LOCAL,
	                                 g_param_spec_object ("local",
	                                                      "local",
	                                                      "local",
	                                                      G_TYPE_OBJECT,
	                                                      G_PARAM_READWRITE));

}

static void
sml_map_item_init (SmlMapItem *self)
{
	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
	                                          SML_TYPE_MAP_ITEM,
	                                          SmlMapItemPrivate);
}

/**
 * sml_map_item_new:
 *
 * Creates a new instance of #SmlMapItem.
 *
 * Return value: the newly created #SmlMapItem instance
 */
SmlMapItem*
sml_map_item_new (void)
{
	return g_object_new (SML_TYPE_MAP_ITEM, NULL);
}

/**
 * sml_map_item_get_remote:
 * @self: A #SmlMapItem
 *
 * Gets the remote property.
 *
 * Return value: 
 */
SmlLocation*
sml_map_item_get_remote (SmlMapItem *self)
{
	g_return_val_if_fail (SML_IS_MAP_ITEM (self), NULL);
	return self->priv->remote;
}

/**
 * sml_map_item_get_remote_uri:
 * @self: A #SmlMapItem
 *
 * Gets the remote URI property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_map_item_get_remote_uri (SmlMapItem *self)
{
	g_return_val_if_fail (SML_IS_MAP_ITEM (self), NULL);
	if (!self->priv->remote)
		return NULL;
	return sml_location_get_uri(self->priv->remote);
}

/**
 * sml_map_item_set_remote:
 * @self: A #SmlMapItem
 * @remote:
 *
 * Sets the remote property.
 */
gboolean
sml_map_item_set_remote (SmlMapItem *self,
                         SmlLocation* remote,
                         GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_MAP_ITEM (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlMapItem object.");
	sml_return_val_error_if_fail (SML_IS_LOCATION (remote), FALSE, error, SML_ERROR_GENERIC, "There must be a remote SmlLocation object.");
	sml_return_val_error_if_fail (sml_location_get_uri(remote), FALSE, error, SML_ERROR_GENERIC, "There must be a remote URI.");
	sml_return_val_error_if_fail (strlen(sml_location_get_uri(remote)) > 0, FALSE, error, SML_ERROR_GENERIC, "The remote URI cannot be the empty string.");
	sml_return_val_error_if_fail (sml_location_get_name(remote) == NULL, FALSE, error, SML_ERROR_GENERIC, "The remote name must not be set.");
	sml_return_val_error_if_fail (sml_location_get_parent_uri(remote) == NULL, FALSE, error, SML_ERROR_GENERIC, "The remote parent URI must not be set.");

	if (self->priv->remote)
		g_object_unref (self->priv->remote);
	self->priv->remote = remote;
	g_object_ref (remote);
	return TRUE;
}

/**
 * sml_map_item_get_local:
 * @self: A #SmlMapItem
 *
 * Gets the local property.
 *
 * Return value: 
 */
SmlLocation*
sml_map_item_get_local (SmlMapItem *self)
{
	g_return_val_if_fail (SML_IS_MAP_ITEM (self), NULL);
	return self->priv->local;
}

/**
 * sml_map_item_get_local_uri:
 * @self: A #SmlMapItem
 *
 * Gets the local URI property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_map_item_get_local_uri (SmlMapItem *self)
{
	g_return_val_if_fail (SML_IS_MAP_ITEM (self), NULL);
	if (!self->priv->local)
		return NULL;
	return sml_location_get_uri(self->priv->local);
}

/**
 * sml_map_item_set_local:
 * @self: A #SmlMapItem
 * @local:
 *
 * Sets the local property.
 */
gboolean
sml_map_item_set_local (SmlMapItem *self,
                        SmlLocation* local,
                        GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_MAP_ITEM (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlMapItem object.");
	sml_return_val_error_if_fail (SML_IS_LOCATION (local), FALSE, error, SML_ERROR_GENERIC, "There must be a local SmlLocation object.");
	sml_return_val_error_if_fail (sml_location_get_uri(local), FALSE, error, SML_ERROR_GENERIC, "There must be a local URI.");
	sml_return_val_error_if_fail (strlen(sml_location_get_uri(local)) > 0, FALSE, error, SML_ERROR_GENERIC, "The local URI cannot be the empty string.");
	sml_return_val_error_if_fail (sml_location_get_name(local) == NULL, FALSE, error, SML_ERROR_GENERIC, "The local name must not be set.");
	sml_return_val_error_if_fail (sml_location_get_parent_uri(local) == NULL, FALSE, error, SML_ERROR_GENERIC, "The local parent URI must not be set.");

	if (self->priv->local)
		g_object_unref (self->priv->local);
	self->priv->local = local;
	g_object_ref (local);
	return TRUE;
}

/**
 * sml_map_item_is_compliant:
 * @self: A #SmlMapItem
 *
 * Checks the compliance with the OMA specifications for mappings.
 */
gboolean
sml_map_item_is_compliant (SmlMapItem *self,
                           GError **error)
{
	sml_return_val_error_if_fail (SML_IS_MAP_ITEM (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlMapItem object.");

	SmlLocation *remote = self->priv->remote;
	sml_return_val_error_if_fail (remote, FALSE, error, SML_ERROR_GENERIC, "There must be a remote URI.");
	sml_return_val_error_if_fail (SML_IS_LOCATION (remote), FALSE, error, SML_ERROR_GENERIC, "There must be a remote SmlLocation object.");
	sml_return_val_error_if_fail (sml_location_get_uri(remote), FALSE, error, SML_ERROR_GENERIC, "There must be a remote URI.");
	sml_return_val_error_if_fail (strlen(sml_location_get_uri(remote)) > 0, FALSE, error, SML_ERROR_GENERIC, "The remote URI cannot be the empty string.");
	sml_return_val_error_if_fail (sml_location_get_name(remote) == NULL, FALSE, error, SML_ERROR_GENERIC, "The remote name must not be set.");
	sml_return_val_error_if_fail (sml_location_get_parent_uri(remote) == NULL, FALSE, error, SML_ERROR_GENERIC, "The remote parent URI must not be set.");

	SmlLocation *local = self->priv->local;
	sml_return_val_error_if_fail (local, FALSE, error, SML_ERROR_GENERIC, "There must be a local URI.");
	sml_return_val_error_if_fail (SML_IS_LOCATION (local), FALSE, error, SML_ERROR_GENERIC, "There must be a local SmlLocation object.");
	sml_return_val_error_if_fail (sml_location_get_uri(local), FALSE, error, SML_ERROR_GENERIC, "There must be a local URI.");
	sml_return_val_error_if_fail (strlen(sml_location_get_uri(local)) > 0, FALSE, error, SML_ERROR_GENERIC, "The local URI cannot be the empty string.");
	sml_return_val_error_if_fail (sml_location_get_name(local) == NULL, FALSE, error, SML_ERROR_GENERIC, "The local name must not be set.");
	sml_return_val_error_if_fail (sml_location_get_parent_uri(local) == NULL, FALSE, error, SML_ERROR_GENERIC, "The local parent URI must not be set.");

	return TRUE;
}
