/* sml_dev_inf.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_dev_inf.h"
#include "sml_dev_inf_enum_types.h"
#include <libsyncml/syncml.h>
#include "../sml_error_internals.h"

G_DEFINE_TYPE (SmlDevInf, sml_dev_inf, G_TYPE_OBJECT)

enum
{
	PROP_0,
	PROP_VER_DTD,
	PROP_MAN,
	PROP_MOD,
	PROP_OEM,
	PROP_FWV,
	PROP_SWV,
	PROP_HWV,
	PROP_DEV_ID,
	PROP_DEV_TYP,
	PROP_SUPPORT_UTC,
	PROP_SUPPORT_LARGE_OBJS,
	PROP_SUPPORT_NUMBER_OF_CHANGES,
	PROP_DATA_STORES,
	PROP_CTCAPS
};

struct _SmlDevInfPrivate
{
	SmlDevInfVersion ver_dtd;
	gchar*           man;
	gchar*           mod;
	gchar*           oem;
	gchar*           fwv;
	gchar*           swv;
	gchar*           hwv;
	gchar*           dev_id;
	SmlDevInfDevTyp  dev_typ;
	gboolean         support_utc;
	gboolean         support_large_objs;
	gboolean         support_number_of_changes;
	GList*           data_stores;
	GList*           ctcaps;
};

static void
sml_dev_inf_get_property (GObject    *object,
                          guint       property_id,
                          GValue     *value,
                          GParamSpec *pspec)
{
	switch (property_id) {
	case PROP_VER_DTD:
		g_value_set_enum (value, SML_DEV_INF (object)->priv->ver_dtd);
		break;
	case PROP_MAN:
		g_value_set_string (value, SML_DEV_INF (object)->priv->man);
		break;
	case PROP_MOD:
		g_value_set_string (value, SML_DEV_INF (object)->priv->mod);
		break;
	case PROP_OEM:
		g_value_set_string (value, SML_DEV_INF (object)->priv->oem);
		break;
	case PROP_FWV:
		g_value_set_string (value, SML_DEV_INF (object)->priv->fwv);
		break;
	case PROP_SWV:
		g_value_set_string (value, SML_DEV_INF (object)->priv->swv);
		break;
	case PROP_HWV:
		g_value_set_string (value, SML_DEV_INF (object)->priv->hwv);
		break;
	case PROP_DEV_ID:
		g_value_set_string (value, SML_DEV_INF (object)->priv->dev_id);
		break;
	case PROP_DEV_TYP:
		g_value_set_enum (value, SML_DEV_INF (object)->priv->dev_typ);
		break;
	case PROP_SUPPORT_UTC:
		g_value_set_boolean (value, SML_DEV_INF (object)->priv->support_utc);
		break;
	case PROP_SUPPORT_LARGE_OBJS:
		g_value_set_boolean (value, SML_DEV_INF (object)->priv->support_large_objs);
		break;
	case PROP_SUPPORT_NUMBER_OF_CHANGES:
		g_value_set_boolean (value, SML_DEV_INF (object)->priv->support_number_of_changes);
		break;
	case PROP_DATA_STORES:
		g_value_set_pointer (value, SML_DEV_INF (object)->priv->data_stores);
		break;
	case PROP_CTCAPS:
		g_value_set_pointer (value, SML_DEV_INF (object)->priv->ctcaps);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
	}
}

static void
sml_dev_inf_set_property (GObject      *object,
                          guint         property_id,
                          const GValue *value,
                          GParamSpec   *pspec)
{
	switch (property_id) {
	case PROP_VER_DTD:
		SML_DEV_INF (object)->priv->ver_dtd = g_value_get_enum (value);
		break;
	case PROP_MAN:
		g_free (SML_DEV_INF (object)->priv->man);
		SML_DEV_INF (object)->priv->man = g_strdup (g_value_get_string (value));
		break;
	case PROP_MOD:
		g_free (SML_DEV_INF (object)->priv->mod);
		SML_DEV_INF (object)->priv->mod = g_strdup (g_value_get_string (value));
		break;
	case PROP_OEM:
		g_free (SML_DEV_INF (object)->priv->oem);
		SML_DEV_INF (object)->priv->oem = g_strdup (g_value_get_string (value));
		break;
	case PROP_FWV:
		g_free (SML_DEV_INF (object)->priv->fwv);
		SML_DEV_INF (object)->priv->fwv = g_strdup (g_value_get_string (value));
		break;
	case PROP_SWV:
		g_free (SML_DEV_INF (object)->priv->swv);
		SML_DEV_INF (object)->priv->swv = g_strdup (g_value_get_string (value));
		break;
	case PROP_HWV:
		g_free (SML_DEV_INF (object)->priv->hwv);
		SML_DEV_INF (object)->priv->hwv = g_strdup (g_value_get_string (value));
		break;
	case PROP_DEV_ID:
		g_free (SML_DEV_INF (object)->priv->dev_id);
		SML_DEV_INF (object)->priv->dev_id = g_strdup (g_value_get_string (value));
		break;
	case PROP_DEV_TYP:
		SML_DEV_INF (object)->priv->dev_typ = g_value_get_enum (value);
		break;
	case PROP_SUPPORT_UTC:
		SML_DEV_INF (object)->priv->support_utc = g_value_get_boolean (value);
		break;
	case PROP_SUPPORT_LARGE_OBJS:
		SML_DEV_INF (object)->priv->support_large_objs = g_value_get_boolean (value);
		break;
	case PROP_SUPPORT_NUMBER_OF_CHANGES:
		SML_DEV_INF (object)->priv->support_number_of_changes = g_value_get_boolean (value);
		break;
	case PROP_DATA_STORES:
		SML_DEV_INF (object)->priv->data_stores = (GList *) g_value_get_pointer(value);
		break;
	case PROP_CTCAPS:
		SML_DEV_INF (object)->priv->ctcaps = (GList *) g_value_get_pointer(value);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
	}
}

static void
sml_dev_inf_finalize (GObject *object)
{
	SmlDevInf *self = (SmlDevInf *) object;
	g_free(self->priv->man);
	g_free(self->priv->mod);
	g_free(self->priv->oem);
	g_free(self->priv->fwv);
	g_free(self->priv->swv);
	g_free(self->priv->hwv);
	g_free(self->priv->dev_id);
	while(self->priv->data_stores) {
		SmlDevInfDataStore *data_store = self->priv->data_stores->data;
		self->priv->data_stores = g_list_remove(self->priv->data_stores, data_store);
		g_object_unref(data_store);
	}
	while(self->priv->ctcaps) {
		SmlDevInfCTCap *ctcap = self->priv->ctcaps->data;
		self->priv->ctcaps = g_list_remove(self->priv->ctcaps, ctcap);
		g_object_unref(ctcap);
	}
	/* all pointers must be NULL */
	self->priv->man = NULL;
	self->priv->mod = NULL;
	self->priv->oem = NULL;
	self->priv->fwv = NULL;
	self->priv->swv = NULL;
	self->priv->hwv = NULL;
	self->priv->dev_id = NULL;
	G_OBJECT_CLASS (sml_dev_inf_parent_class)->finalize (object);
}

static void
sml_dev_inf_class_init (SmlDevInfClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	g_type_class_add_private (klass, sizeof (SmlDevInfPrivate));

	object_class->get_property = sml_dev_inf_get_property;
	object_class->set_property = sml_dev_inf_set_property;
	object_class->finalize     = sml_dev_inf_finalize;

	/**
	 * SmlDevInf:VerDTD:
	 *
	 * The This is the protocol version of the device information. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_VER_DTD,
	                                 g_param_spec_enum ("VerDTD",
	                                                    "VersionDTD",
	                                                    "This is the protocol version of the device information.",
	                                                    SML_DEV_INF_TYPE_DEV_INF_VERSION,
	                                                    SML_DEVINF_VERSION_UNKNOWN,
	                                                    G_PARAM_READWRITE));
	/**
	 * SmlDevInf:Man:
	 *
	 * The This is the name of the manufacturer property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_MAN,
	                                 g_param_spec_string ("Man",
	                                                      "Manufacturer",
	                                                      "This is the name of the manufacturer",
	                                                      NULL,
	                                                      G_PARAM_READWRITE));
	/**
	 * SmlDevInf:Mod:
	 *
	 * The This is the name of the model. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_MOD,
	                                 g_param_spec_string ("Mod",
	                                                      "Modell",
	                                                      "This is the name of the model.",
	                                                      NULL,
	                                                      G_PARAM_READWRITE));
	/**
	 * SmlDevInf:OEM:
	 *
	 * The This is the name of the OEM. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_OEM,
	                                 g_param_spec_string ("OEM",
	                                                      "OEM",
	                                                      "This is the name of the OEM.",
	                                                      NULL,
	                                                      G_PARAM_READWRITE));
	/**
	 * SmlDevInf:FwV:
	 *
	 * The This is the version if the firmware. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_FWV,
	                                 g_param_spec_string ("FwV",
	                                                      "FirmwareVersion",
	                                                      "This is the version if the firmware.",
	                                                      NULL,
	                                                      G_PARAM_READWRITE));
	/**
	 * SmlDevInf:SwV:
	 *
	 * The This is the version of the firmware. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_SWV,
	                                 g_param_spec_string ("SwV",
	                                                      "SoftwareVersion",
	                                                      "This is the version of the firmware.",
	                                                      NULL,
	                                                      G_PARAM_READWRITE));
	/**
	 * SmlDevInf:HwV:
	 *
	 * The This is the version of the hardware. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_HWV,
	                                 g_param_spec_string ("HwV",
	                                                      "HardwareVersion",
	                                                      "This is the version of the hardware.",
	                                                      NULL,
	                                                      G_PARAM_READWRITE));
	/**
	 * SmlDevInf:DevID:
	 *
	 * The This is the identifier of the device. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_DEV_ID,
	                                 g_param_spec_string ("DevID",
	                                                      "DeviceID",
	                                                      "This is the identifier of the device.",
	                                                      NULL,
	                                                      G_PARAM_READWRITE));
	/**
	 * SmlDevInf:DevTyp:
	 *
	 * The This is the type of the device property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_DEV_TYP,
	                                 g_param_spec_enum ("DevTyp",
	                                                    "DeviceType",
	                                                    "This is the type of the device",
	                                                    SML_DEV_INF_TYPE_DEV_INF_DEV_TYP,
	                                                    SML_DEVINF_DEVTYP_UNKNOWN,
	                                                    G_PARAM_READWRITE));
	/**
	 * SmlDevInf:SupportUTC:
	 *
	 * The Does this device support UTC? property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_SUPPORT_UTC,
	                                 g_param_spec_boolean ("SupportUTC",
	                                                       "SupportUTC",
	                                                       "Does this device support UTC?",
	                                                       FALSE,
	                                                       G_PARAM_READWRITE));
	/**
	 * SmlDevInf:SupportLargeObjs:
	 *
	 * The Does this device support large objects? property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_SUPPORT_LARGE_OBJS,
	                                 g_param_spec_boolean ("SupportLargeObjs",
	                                                       "SupportLargeObjs",
	                                                       "Does this device support large objects?",
	                                                       FALSE,
	                                                       G_PARAM_READWRITE));
	/**
	 * SmlDevInf:SupportNumberOfChanges:
	 *
	 * The Does this device supports number of changes? property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_SUPPORT_NUMBER_OF_CHANGES,
	                                 g_param_spec_boolean ("SupportNumberOfChanges",
	                                                       "SupportNumberOfChanges",
	                                                       "Does this device supports number of changes?",
	                                                       FALSE,
	                                                       G_PARAM_READWRITE));
	/**
	 * SmlDevInf:DataStores:
	 *
	 * The Supported data stores. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_DATA_STORES,
	                                 g_param_spec_pointer ("DataStores",
	                                                       "DataStores",
	                                                       "Supported data stores.",
	                                                       G_PARAM_PRIVATE));
	/**
	 * SmlDevInf:CTCaps:
	 *
	 * The Supported CTCaps. property.
	 */
	g_object_class_install_property (object_class,
	                                 PROP_CTCAPS,
	                                 g_param_spec_pointer ("CTCaps",
	                                                       "CTCaps",
	                                                       "Supported CTCaps.",
	                                                       G_PARAM_PRIVATE));

}

static void
sml_dev_inf_init (SmlDevInf *self)
{
	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
	                                          SML_TYPE_DEV_INF,
	                                          SmlDevInfPrivate);
}

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

/**
 * sml_dev_inf_get_ver_dtd:
 * @self: A #SmlDevInf
 *
 * Gets the VerDTD property.
 *
 * Return value: 
 */
SmlDevInfVersion
sml_dev_inf_get_ver_dtd (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), SML_DEVINF_VERSION_UNKNOWN);
	return self->priv->ver_dtd;
}

/**
 * sml_dev_inf_set_ver_dtd:
 * @self: A #SmlDevInf
 * @ver_dtd:
 *
 * Sets the VerDTD property.
 */
void
sml_dev_inf_set_ver_dtd (SmlDevInf *self,
                         SmlDevInfVersion ver_dtd)
{
	g_return_if_fail (SML_IS_DEV_INF (self));

	/* The version of the DTD is a minimum requirement.
	 * It is not optional.
	 */
	g_return_if_fail (ver_dtd != SML_DEVINF_VERSION_UNKNOWN);

	self->priv->ver_dtd = ver_dtd;
}

/**
 * sml_dev_inf_get_man:
 * @self: A #SmlDevInf
 *
 * Gets the Manufacturer property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_dev_inf_get_man (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return self->priv->man;
}

/**
 * sml_dev_inf_set_man:
 * @self: A #SmlDevInf
 * @man:
 *
 * Sets the Manufacturer property.
 */
gboolean
sml_dev_inf_set_man (SmlDevInf *self,
                     const gchar* man,
                     GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDevInf object.");

	/* normalize the man */
	if (man && strlen(man) == 0)
		man = NULL;

	g_free (self->priv->man);
	self->priv->man = g_strdup (man);
	sml_return_val_error_if_fail (!man || self->priv->man, FALSE, error, SML_ERROR_GENERIC, "Cannot copy the manufacturer - out of memory.");

	return TRUE;
}

/**
 * sml_dev_inf_get_mod:
 * @self: A #SmlDevInf
 *
 * Gets the Modell property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_dev_inf_get_mod (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return self->priv->mod;
}

/**
 * sml_dev_inf_set_mod:
 * @self: A #SmlDevInf
 * @mod:
 *
 * Sets the Modell property.
 */
gboolean
sml_dev_inf_set_mod (SmlDevInf *self,
                     const gchar* mod,
                     GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDevInf object.");

	/* normalize the mod */
	if (mod && strlen(mod) == 0)
		mod = NULL;

	g_free (self->priv->mod);
	self->priv->mod = g_strdup (mod);
	sml_return_val_error_if_fail (!mod || self->priv->mod, FALSE, error, SML_ERROR_GENERIC, "Cannot copy the model - out of memory.");

	return TRUE;
}

/**
 * sml_dev_inf_get_oem:
 * @self: A #SmlDevInf
 *
 * Gets the OEM property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_dev_inf_get_oem (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return self->priv->oem;
}

/**
 * sml_dev_inf_set_oem:
 * @self: A #SmlDevInf
 * @oem:
 *
 * Sets the OEM property.
 */
gboolean
sml_dev_inf_set_oem (SmlDevInf *self,
                     const gchar* oem,
                     GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDevInf object.");

	/* normalize the oem */
	if (oem && strlen(oem) == 0)
		oem = NULL;

	g_free (self->priv->oem);
	self->priv->oem = g_strdup (oem);
	sml_return_val_error_if_fail (!oem || self->priv->oem, FALSE, error, SML_ERROR_GENERIC, "Cannot copy the OEM - out of memory.");

	return TRUE;
}

/**
 * sml_dev_inf_get_fwv:
 * @self: A #SmlDevInf
 *
 * Gets the FirmwareVersion property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_dev_inf_get_fwv (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return self->priv->fwv;
}

/**
 * sml_dev_inf_set_fwv:
 * @self: A #SmlDevInf
 * @fwv:
 *
 * Sets the FirmwareVersion property.
 */
gboolean
sml_dev_inf_set_fwv (SmlDevInf *self,
                     const gchar* fwv,
                     GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDevInf object.");

	/* normalize the fwv */
	if (fwv && strlen(fwv) == 0)
		fwv = NULL;

	g_free (self->priv->fwv);
	self->priv->fwv = g_strdup (fwv);
	sml_return_val_error_if_fail (!fwv || self->priv->fwv, FALSE, error, SML_ERROR_GENERIC, "Cannot copy the firmware version - out of memory.");

	return TRUE;
}

/**
 * sml_dev_inf_get_swv:
 * @self: A #SmlDevInf
 *
 * Gets the SoftwareVersion property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_dev_inf_get_swv (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return self->priv->swv;
}

/**
 * sml_dev_inf_set_swv:
 * @self: A #SmlDevInf
 * @swv:
 *
 * Sets the SoftwareVersion property.
 */
gboolean
sml_dev_inf_set_swv (SmlDevInf *self,
                     const gchar* swv,
                     GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDevInf object.");

	/* normalize the swv */
	if (swv && strlen(swv) == 0)
		swv = NULL;

	g_free (self->priv->swv);
	self->priv->swv = g_strdup (swv);
	sml_return_val_error_if_fail (!swv || self->priv->swv, FALSE, error, SML_ERROR_GENERIC, "Cannot copy the software version - out of memory.");

	return TRUE;
}

/**
 * sml_dev_inf_get_hwv:
 * @self: A #SmlDevInf
 *
 * Gets the HardwareVersion property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_dev_inf_get_hwv (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return self->priv->hwv;
}

/**
 * sml_dev_inf_set_hwv:
 * @self: A #SmlDevInf
 * @hwv:
 *
 * Sets the HardwareVersion property.
 */
gboolean
sml_dev_inf_set_hwv (SmlDevInf *self,
                     const gchar* hwv,
                     GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDevInf object.");

	/* normalize the hwv */
	if (hwv && strlen(hwv) == 0)
		hwv = NULL;

	g_free (self->priv->hwv);
	self->priv->hwv = g_strdup (hwv);
	sml_return_val_error_if_fail (!hwv || self->priv->hwv, FALSE, error, SML_ERROR_GENERIC, "Cannot copy the hardware version - out of memory.");

	return TRUE;
}

/**
 * sml_dev_inf_get_dev_id:
 * @self: A #SmlDevInf
 *
 * Gets the DeviceID property.
 *
 * Return value: 
 */
G_CONST_RETURN gchar*
sml_dev_inf_get_dev_id (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return self->priv->dev_id;
}

/**
 * sml_dev_inf_set_dev_id:
 * @self: A #SmlDevInf
 * @dev_id:
 *
 * Sets the DeviceID property.
 */
gboolean
sml_dev_inf_set_dev_id (SmlDevInf *self,
                        const gchar* dev_id,
                        GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There must be a SmlDevInf object.");
	sml_return_val_error_if_fail (dev_id, FALSE, error, SML_ERROR_GENERIC, "The device ID is a required element.");
	sml_return_val_error_if_fail (strlen(dev_id) > 0, FALSE, error, SML_ERROR_GENERIC, "The device ID cannot be the empty word.");

	g_free (self->priv->dev_id);
	self->priv->dev_id = g_strdup (dev_id);
	sml_return_val_error_if_fail (self->priv->dev_id, FALSE, error, SML_ERROR_GENERIC, "Cannot copy the device ID - out of memory.");

	return TRUE;
}

/**
 * sml_dev_inf_get_dev_typ:
 * @self: A #SmlDevInf
 *
 * Gets the DeviceType property.
 *
 * Return value: 
 */
SmlDevInfDevTyp
sml_dev_inf_get_dev_typ (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), SML_DEVINF_DEVTYP_UNKNOWN);
	return self->priv->dev_typ;
}

/**
 * sml_dev_inf_set_dev_typ:
 * @self: A #SmlDevInf
 * @dev_typ:
 *
 * Sets the DeviceType property.
 */
void
sml_dev_inf_set_dev_typ (SmlDevInf *self,
                         SmlDevInfDevTyp dev_typ)
{
	g_return_if_fail (SML_IS_DEV_INF (self));

	/* The device ID is a minimum requirement.
	 * It is not optional.
	 */
	g_return_if_fail (dev_typ != SML_DEVINF_DEVTYP_UNKNOWN);

	self->priv->dev_typ = dev_typ;
}

/**
 * sml_dev_inf_get_support_utc:
 * @self: A #SmlDevInf
 *
 * Gets the SupportUTC property.
 *
 * Return value: 
 */
gboolean
sml_dev_inf_get_support_utc (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), FALSE);

	/* enforce SyncML 1.0 specification */
	if (self->priv->ver_dtd == SML_DEVINF_VERSION_10)
		return FALSE;

	return self->priv->support_utc;
}

/**
 * sml_dev_inf_set_support_utc:
 * @self: A #SmlDevInf
 * @support_utc:
 *
 * Sets the SupportUTC property.
 */
void
sml_dev_inf_set_support_utc (SmlDevInf *self,
                             gboolean support_utc)
{
	g_return_if_fail (SML_IS_DEV_INF (self));
	self->priv->support_utc = support_utc;
}

/**
 * sml_dev_inf_get_support_large_objs:
 * @self: A #SmlDevInf
 *
 * Gets the SupportLargeObjs property.
 *
 * Return value: 
 */
gboolean
sml_dev_inf_get_support_large_objs (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), FALSE);

	/* enforce SyncML 1.0 specification */
	if (self->priv->ver_dtd == SML_DEVINF_VERSION_10)
		return FALSE;

	return self->priv->support_large_objs;
}

/**
 * sml_dev_inf_set_support_large_objs:
 * @self: A #SmlDevInf
 * @support_large_objs:
 *
 * Sets the SupportLargeObjs property.
 */
void
sml_dev_inf_set_support_large_objs (SmlDevInf *self,
                                    gboolean support_large_objs)
{
	g_return_if_fail (SML_IS_DEV_INF (self));
	self->priv->support_large_objs = support_large_objs;
}

/**
 * sml_dev_inf_get_support_number_of_changes:
 * @self: A #SmlDevInf
 *
 * Gets the SupportNumberOfChanges property.
 *
 * Return value: 
 */
gboolean
sml_dev_inf_get_support_number_of_changes (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), FALSE);

	/* enforce SyncML 1.0 specification */
	if (self->priv->ver_dtd == SML_DEVINF_VERSION_10)
		return FALSE;

	return self->priv->support_number_of_changes;
}

/**
 * sml_dev_inf_set_support_number_of_changes:
 * @self: A #SmlDevInf
 * @support_number_of_changes:
 *
 * Sets the SupportNumberOfChanges property.
 */
void
sml_dev_inf_set_support_number_of_changes (SmlDevInf *self,
                                           gboolean support_number_of_changes)
{
	g_return_if_fail (SML_IS_DEV_INF (self));
	self->priv->support_number_of_changes = support_number_of_changes;
}

/**
 * sml_dev_inf_num_data_stores:
 * @self: A #SmlDevInf
 *
 * 
 */
gsize
sml_dev_inf_num_data_stores (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), 0);
	return g_list_length(self->priv->data_stores);
}

/**
 * sml_dev_inf_get_nth_data_store:
 * @self: A #SmlDevInf
 *
 * 
 */
SmlDevInfDataStore*
sml_dev_inf_get_nth_data_store (SmlDevInf *self,
                                gsize n)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return (SmlDevInfDataStore *)g_list_nth_data(self->priv->data_stores, n);
}

/**
 * sml_dev_inf_add_data_store:
 * @self: A #SmlDevInf
 *
 * 
 */
gboolean
sml_dev_inf_add_data_store (SmlDevInf *self,
                            SmlDevInfDataStore *data_store,
                            GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There is no SmlDevInf object.");
	sml_return_val_error_if_fail (data_store, FALSE, error, SML_ERROR_GENERIC, "The SmlDevInfDataStore object is missing.");
	sml_return_val_error_if_fail (SML_IS_DEV_INF_DATA_STORE (data_store), FALSE, error, SML_ERROR_GENERIC, "The data store parameter must be a SmlDevInfDataStore object.");

	g_object_ref(data_store);
	self->priv->data_stores = g_list_append(self->priv->data_stores, data_store);
	sml_return_val_error_if_fail (self->priv->data_stores, FALSE, error, SML_ERROR_GENERIC, "Cannot add data store to data store list of device information.");

	return TRUE;
}

/**
 * sml_dev_inf_get_ctcap:
 * @self: A #SmlDevInf
 *
 * 
 */
SmlDevInfCTCap*
sml_dev_inf_get_ctcap (SmlDevInf *self,
                       SmlDevInfContentType* ct)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), 0);
	g_return_val_if_fail (SML_IS_DEV_INF_CONTENT_TYPE (ct), 0);

	GList *h;
	for (h = self->priv->ctcaps; h; h = h->next)
	{
		SmlDevInfCTCap *ctcap = h->data;
		/* check that the content type matches */
		if (!strcmp(sml_dev_inf_content_type_get_cttype(ct),
		            sml_dev_inf_content_type_get_cttype(sml_dev_inf_ctcap_get_content_type(ctcap))) &&
		     !strcmp(sml_dev_inf_content_type_get_verct(ct),
		             sml_dev_inf_content_type_get_verct(sml_dev_inf_ctcap_get_content_type(ctcap))))
		{
			return ctcap;
		}
	}
	return NULL;
}

/**
 * sml_dev_inf_num_ctcaps:
 * @self: A #SmlDevInf
 *
 * 
 */
gsize
sml_dev_inf_num_ctcaps (SmlDevInf *self)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), 0);
	return g_list_length(self->priv->ctcaps);
}

/**
 * sml_dev_inf_get_nth_ctcap:
 * @self: A #SmlDevInf
 *
 * 
 */
SmlDevInfCTCap*
sml_dev_inf_get_nth_ctcap (SmlDevInf *self,
                           gsize n)
{
	g_return_val_if_fail (SML_IS_DEV_INF (self), NULL);
	return (SmlDevInfCTCap *)g_list_nth_data(self->priv->ctcaps, n);
}

/**
 * sml_dev_inf_add_ctcap:
 * @self: A #SmlDevInf
 *
 * 
 */
gboolean
sml_dev_inf_add_ctcap (SmlDevInf *self,
                       SmlDevInfCTCap *ctcap,
                       GError **error)
{
	CHECK_ERROR_REF
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There is no SmlDevInf object.");
	sml_return_val_error_if_fail (ctcap, FALSE, error, SML_ERROR_GENERIC, "The SmlDevInfCTCap object is missing.");
	sml_return_val_error_if_fail (SML_IS_DEV_INF_CTCAP (ctcap), FALSE, error, SML_ERROR_GENERIC, "The ctcap parameter must be a SmlDevInfCTCap object.");

	g_object_ref(ctcap);
	self->priv->ctcaps = g_list_append(self->priv->ctcaps, ctcap);
	sml_return_val_error_if_fail (self->priv->ctcaps, FALSE, error, SML_ERROR_GENERIC, "Cannot add CTCap to CTCap list of device information.");

	return TRUE;
}

/**
 * sml_dev_inf_is_compliant:
 * @self: A #SmlDevInfDataStore
 * @error: A #GError
 * 
 * This is the only function of this class where you have not to provide a pointer to the error parameter.
 * If you only want to know if the data store is already compliant
 * then you can ignore the error.
 *
 * Return value: 
 */
gboolean
sml_dev_inf_is_compliant (SmlDevInf *self,
                          GError **error)
{
	sml_return_val_error_if_fail (SML_IS_DEV_INF (self), FALSE, error, SML_ERROR_GENERIC, "There is no SmlDevInf object.");

	/* Common SyncML requirements */

	sml_return_val_error_if_fail (self->priv->ver_dtd != SML_DEVINF_VERSION_UNKNOWN, FALSE, error, SML_ERROR_GENERIC, "The VerDTD must be set.");
	sml_return_val_error_if_fail (self->priv->dev_id != NULL, FALSE, error, SML_ERROR_GENERIC, "The device ID must be set.");
	sml_return_val_error_if_fail (self->priv->dev_typ != SML_DEVINF_DEVTYP_UNKNOWN, FALSE, error, SML_ERROR_GENERIC, "The device type must be set.");
	sml_return_val_error_if_fail (self->priv->data_stores != NULL, FALSE, error, SML_ERROR_GENERIC, "There must be at minimum one data store.");

	/* SyncML 1.0 requirements */

	/* SyncML 1.0 does not support UTC, SupportLargeObjs and SupportNumberOfChanges.
	 * Nevertheless this is no problem because the getter functions of these
	 * properties simply return FALSE if SyncML 1.0 is used.
	 */

	/* SyncML 1.2 requirements */

	if (self->priv->ver_dtd >= SML_DEVINF_VERSION_12) {
		sml_return_val_error_if_fail (self->priv->man != NULL, FALSE, error, SML_ERROR_GENERIC, "The manufacturer must be set.");
		sml_return_val_error_if_fail (self->priv->mod != NULL, FALSE, error, SML_ERROR_GENERIC, "The model must be set.");
		sml_return_val_error_if_fail (self->priv->fwv != NULL, FALSE, error, SML_ERROR_GENERIC, "The firmware version must be set.");
		sml_return_val_error_if_fail (self->priv->swv != NULL, FALSE, error, SML_ERROR_GENERIC, "The software version must be set.");
		sml_return_val_error_if_fail (self->priv->hwv != NULL, FALSE, error, SML_ERROR_GENERIC, "The hardware version must be set.");
	}

	/* SyncML server requirements (except of SyncML 1.0) */

	if (self->priv->dev_typ == SML_DEVINF_DEVTYP_SERVER &&
	    self->priv->ver_dtd >= SML_DEVINF_VERSION_11) {
		sml_return_val_error_if_fail (self->priv->support_utc, FALSE, error, SML_ERROR_GENERIC, "A server must support UTC.");
		sml_return_val_error_if_fail (self->priv->support_large_objs, FALSE, error, SML_ERROR_GENERIC, "A server must support large objects.");
		sml_return_val_error_if_fail (self->priv->support_number_of_changes, FALSE, error, SML_ERROR_GENERIC, "A server must support number of changes.");
	}

	return TRUE;
}

