/*
 * 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 <config.h>

#include <string.h>

#include "interface.h"
#include "path.h"
#include "props.h"
#include "search.h"

gchar *dls_search_translate_search_string(GHashTable *filter_map,
					  const gchar *search_string)
{
	GRegex *reg;
	gchar *retval = NULL;
	GMatchInfo *match_info = NULL;
	gchar *prop = NULL;
	gchar *op = NULL;
	gchar *value = NULL;
	const gchar *translated_value;
	gchar *translated_type_ex;
	dls_prop_map_t *prop_map;
	GString *str;
	gint start_pos;
	gint end_pos;
	gint old_end_pos = 0;
	unsigned int skipped;
	unsigned int search_string_len = strlen(search_string);
	gchar *root_path;
	gchar *id;

	reg = g_regex_new("(\\w+)\\s+(=|!=|<|<=|>|>|contains|doesNotContain|"\
			  "derivedfrom|exists)\\s+"\
			  "(\"[^\"]*\"|true|false)",
			  0, 0, NULL);
	str = g_string_new("");

	g_regex_match(reg, search_string, 0, &match_info);
	while (g_match_info_matches(match_info)) {
		prop = g_match_info_fetch(match_info, 1);
		if (!prop)
			goto on_error;

		op = g_match_info_fetch(match_info, 2);
		if (!op)
			goto on_error;

		value = g_match_info_fetch(match_info, 3);
		if (!value)
			goto on_error;

		/* Handle special cases where we need to translate
		   value as well as property name */

		if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE)) {
			/* Skip the quotes */

			value[strlen(value) - 1] = 0;
			translated_value = dls_props_media_spec_to_upnp_class(
				value + 1);
			if (!translated_value)
				goto on_error;
			g_free(value);
			value = g_strdup_printf("\"%s\"", translated_value);
		} else if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE_EX)) {
			/* Skip the quotes */

			value[strlen(value) - 1] = 0;
			translated_type_ex =
				dls_props_media_spec_ex_to_upnp_class(
					value + 1);
			if (!translated_type_ex)
				goto on_error;
			g_free(value);
			value = g_strdup_printf("\"%s\"", translated_type_ex);
			g_free(translated_type_ex);
		} else if (!strcmp(prop, DLS_INTERFACE_PROP_PARENT) ||
			   !strcmp(prop, DLS_INTERFACE_PROP_PATH)) {
			value[strlen(value) - 1] = 0;
			if (!dls_path_get_path_and_id(value + 1, &root_path,
						      &id, NULL))
				goto on_error;
			g_free(root_path);
			g_free(value);
			value = g_strdup_printf("\"%s\"", id);
			g_free(id);
		}

		prop_map = g_hash_table_lookup(filter_map, prop);
		if (!prop_map)
			goto on_error;

		if (!prop_map->searchable)
			goto on_error;

		if (!g_match_info_fetch_pos(match_info, 0, &start_pos,
					    &end_pos))
			goto on_error;

		skipped = start_pos - old_end_pos;
		if (skipped > 0)
			g_string_append_len(str, &search_string[old_end_pos],
					    skipped);
		g_string_append_printf(str, "%s %s %s",
				       prop_map->upnp_prop_name, op, value);
		old_end_pos = end_pos;

		g_free(value);
		g_free(prop);
		g_free(op);

		value = NULL;
		prop = NULL;
		op = NULL;

		g_match_info_next(match_info, NULL);
	}

	skipped = search_string_len - old_end_pos;
	if (skipped > 0)
		g_string_append_len(str, &search_string[old_end_pos],
				    skipped);

	retval = g_string_free(str, FALSE);
	str = NULL;

on_error:

	g_free(value);
	g_free(prop);
	g_free(op);

	if (match_info)
		g_match_info_free(match_info);

	if (str)
		g_string_free(str, TRUE);

	g_regex_unref(reg);

	return retval;
}
