/*
 * dLeyna
 *
 * Copyright (C) 2012-2017 Intel Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Mark Ryan <mark.d.ryan@intel.com>
 *
 */

#include <stdio.h>
#include <string.h>

#include <libdleyna/core/error.h>

#include "path.h"
#include "server.h"

gboolean dls_path_get_non_root_id(const gchar *object_path,
				  const gchar **slash_before_id)
{
	gboolean retval = FALSE;
	unsigned int offset = strlen(DLEYNA_SERVER_PATH) + 1;

	if (!g_str_has_prefix(object_path, DLEYNA_SERVER_PATH "/"))
		goto on_error;

	if (!object_path[offset])
		goto on_error;

	*slash_before_id = strchr(&object_path[offset], '/');
	retval = TRUE;

on_error:

	return retval;
}

static gchar *prv_object_name_to_id(const gchar *object_name)
{
	gchar *retval = NULL;
	unsigned int object_len = strlen(object_name);
	unsigned int i;
	gint hex;
	gchar byte;

	if (object_len & 1)
		goto on_error;

	retval = g_malloc((object_len >> 1) + 1);

	for (i = 0; i < object_len; i += 2) {
		hex = g_ascii_xdigit_value(object_name[i]);

		if (hex == -1)
			goto on_error;

		byte = hex << 4;
		hex = g_ascii_xdigit_value(object_name[i + 1]);

		if (hex == -1)
			goto on_error;

		byte |= hex;
		retval[i >> 1] = byte;
	}
	retval[i >> 1] = 0;

	return retval;

on_error:

	g_free(retval);

	return NULL;
}

gboolean dls_path_get_path_and_id(const gchar *object_path, gchar **root_path,
				  gchar **id, GError **error)
{
	const gchar *slash;
	gchar *coded_id;

	if (!dls_path_get_non_root_id(object_path, &slash))
		goto on_error;

	if (!slash) {
		*root_path = g_strdup(object_path);
		*id = g_strdup("0");
	} else {
		if (!slash[1])
			goto on_error;

		coded_id = prv_object_name_to_id(slash + 1);

		if (!coded_id)
			goto on_error;

		*root_path = g_strndup(object_path, slash - object_path);
		*id = coded_id;
	}

	return TRUE;

on_error:
	if (error)
		*error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_PATH,
				     "object path is badly formed.");

	return FALSE;
}

static gchar *prv_id_to_object_name(const gchar *id)
{
	gchar *retval;
	unsigned int i;
	unsigned int data_len = strlen(id);

	retval = g_malloc((data_len << 1) + 1);
	retval[0] = 0;

	for (i = 0; i < data_len; i++)
		sprintf(&retval[i << 1], "%0x", (guint8) id[i]);

	return retval;
}

gchar *dls_path_from_id(const gchar *root_path, const gchar *id)
{
	gchar *coded_id;
	gchar *path;

	if (!strcmp(id, "0")) {
		path = g_strdup(root_path);
	} else {
		coded_id = prv_id_to_object_name(id);
		path = g_strdup_printf("%s/%s", root_path, coded_id);
		g_free(coded_id);
	}

	return path;
}
