/**
 * @file oval_resultSystem.c
 * \brief Open Vulnerability and Assessment Language
 *
 * See more details at http://oval.mitre.org/
 */

/*
 * Copyright 2009--2013 Red Hat Inc., Durham, North Carolina.
 * All Rights Reserved.
 *
 * 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
 *
 * Authors:
 *      "David Niemoller" <David.Niemoller@g2-inc.com>
 *      "Peter Vrabec" <pvrabec@redhat.com>
 *      Šimon Lukašík
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

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

#include "oval_definitions.h"
#include "oval_agent_api.h"
#include "oval_agent_api_impl.h"
#include "results/oval_results_impl.h"
#include "adt/oval_collection_impl.h"
#include "adt/oval_smc_impl.h"
#include "adt/oval_smc_iterator_impl.h"
#include "adt/oval_string_map_impl.h"
#include "oval_parser_impl.h"

#include "common/debug_priv.h"
#include "common/_error.h"
#include "common/util.h"
#include "common/list.h"

typedef struct oval_result_system {
	struct oval_results_model *model;
	struct oval_smc *definitions;			///< Map contains lists of oval_result_definition
	struct oval_smc *tests;				///< Map contains lists of oval_result_test
	struct oval_syschar_model *syschar_model;
} oval_result_system_t;


static void _oval_result_system_scan_criteria_for_references(struct oval_result_criteria_node *node, 
							     struct oval_smc *testmap);

static void _oval_result_system_scan_entity_for_references(struct oval_syschar_model *syschar_model, 
							   struct oval_entity *entity,
							   struct oval_string_map *objmap,
							   struct oval_string_map *sttmap, 
							   struct oval_string_map *varmap, 
							   struct oval_string_map *sysmap);

static void _oval_result_system_scan_set_for_references(struct oval_syschar_model *syschar_model, 
							struct oval_setobject *set,
							struct oval_string_map *objmap,
							struct oval_string_map *sttmap, 
							struct oval_string_map *varmap, 
							struct oval_string_map *sysmap);

static void _oval_result_system_scan_object_for_references(struct oval_syschar_model *syschar_model, 
							struct oval_object *object,
							struct oval_string_map *objmap,
							struct oval_string_map *sttmap, 
							struct oval_string_map *varmap, 
							struct oval_string_map *sysmap);
static void _oval_result_system_scan_state_for_references(struct oval_syschar_model *syschar_model, 
							struct oval_state *state,
							struct oval_string_map *objmap,
							struct oval_string_map *sttmap, 
							struct oval_string_map *varmap, 
							struct oval_string_map *sysmap);

static void _oval_result_system_scan_component_for_references(struct oval_syschar_model *syschar_model, 
							struct oval_component *component,	
							struct oval_string_map *objmap,
							struct oval_string_map *sttmap, 
							struct oval_string_map *varmap, 
							struct oval_string_map *sysmap);

static bool _oval_result_system_resolve_syschar(struct oval_syschar *syschar, struct oval_string_map *sysmap);





struct oval_result_system *oval_result_system_new(struct oval_results_model *model,
						  struct oval_syschar_model *syschar_model)
{
	__attribute__nonnull__(model);
	oval_result_system_t *sys;

	sys = (oval_result_system_t *) malloc(sizeof(oval_result_system_t));
	if (sys == NULL)
		return NULL;

	sys->definitions = oval_smc_new();
	sys->tests = oval_smc_new();
	sys->syschar_model = syschar_model;
	sys->model = model;

	oval_results_model_add_system(model, sys);

	return sys;
}

struct oval_result_system *oval_result_system_clone(struct oval_results_model *new_model,
						    struct oval_result_system *old_system)
{
	__attribute__nonnull__(old_system);

	struct oval_result_system *new_system =
	    oval_result_system_new(new_model, oval_result_system_get_syschar_model(old_system));

	oval_smc_free0(new_system->definitions);
	oval_smc_free0(new_system->tests);
	new_system->definitions = oval_smc_clone_user(old_system->definitions, (oval_smc_user_clone_func) oval_result_definition_clone, new_system);
	new_system->tests = oval_smc_clone_user(old_system->tests, (oval_smc_user_clone_func) oval_result_test_clone, new_system);

	return new_system;
}

void oval_result_system_free(struct oval_result_system *sys)
{
	__attribute__nonnull__(sys);

	oval_smc_free(sys->definitions, (oscap_destruct_func) oval_result_definition_free);
	oval_smc_free(sys->tests, (oscap_destruct_func) oval_result_test_free);

	sys->definitions = NULL;
	sys->syschar_model = NULL;
	sys->tests = NULL;

	free(sys);
}

bool oval_result_system_iterator_has_more(struct oval_result_system_iterator *sys) {
	return oval_collection_iterator_has_more((struct oval_iterator *)sys);
}

struct oval_result_system *oval_result_system_iterator_next(struct oval_result_system_iterator *sys) {
	return (struct oval_result_system *)
	    oval_collection_iterator_next((struct oval_iterator *)sys);
}

void oval_result_system_iterator_free(struct oval_result_system_iterator *sys) {
	oval_collection_iterator_free((struct oval_iterator *)sys);
}

struct oval_result_definition_iterator *oval_result_system_get_definitions(struct oval_result_system *sys) {
	__attribute__nonnull__(sys);

	return oval_result_definition_iterator_new(sys->definitions);
}

struct oval_result_test_iterator *oval_result_system_get_tests(struct oval_result_system *sys) {
	__attribute__nonnull__(sys);

	return oval_result_test_iterator_new(sys->tests);
}

struct oval_result_definition *oval_result_system_get_definition(struct oval_result_system *sys, const char *id) {
	__attribute__nonnull__(sys);

	// Previously, this structure used to hold only one result_definition per given ID.
	// Now we need to return the very last one from a list.
	return oval_smc_get_last(sys->definitions, id);
}

struct oval_result_test *oval_result_system_get_test(struct oval_result_system *sys, char *id) {
	__attribute__nonnull__(sys);

	// Previously, this structure used to hold only one result_test per given ID.
	// Now we need to return the very last one from a list.
	return oval_smc_get_last(sys->tests, id);
}

struct oval_result_definition *oval_result_system_get_new_definition
    (struct oval_result_system *sys, struct oval_definition *oval_definition, int variable_instance) {

	return oval_result_system_get_new_definition_with_check(sys, oval_definition, NULL, variable_instance);

}

struct oval_result_definition *oval_result_system_get_new_definition_with_check
		(struct oval_result_system *sys, struct oval_definition *oval_definition, struct oscap_list *visited_definitions, int variable_instance)
{
	// This function is used from multiple different places which might not be sustainable.
	// variable_instance=0 means that caller has no special preference for variable_instance
	// 	and the very last definition shall be returned. Additionally, we should create
	// 	new result_definition when the variable_instance_hint does not match.
	// variable_instance!=0 means that we should find result_definition with given instance
	struct oval_result_definition *rslt_definition = NULL;
	if (oval_definition) {
		char *id = oval_definition_get_id(oval_definition);
		rslt_definition = oval_result_system_get_definition(sys, id);
		if (rslt_definition == NULL) {
			rslt_definition = make_result_definition_from_oval_definition(sys, oval_definition, visited_definitions,
				variable_instance ? variable_instance : 1);
			if (rslt_definition == NULL)
				return NULL;
			oval_result_system_add_definition(sys, rslt_definition);
		}
		else if (oval_result_definition_get_variable_instance_hint(rslt_definition) != oval_result_definition_get_instance(rslt_definition)) {
			int hint = oval_result_definition_get_variable_instance_hint(rslt_definition);
			dI("Creating another result-definition for id=%s based on variable_instance: %d", id, hint);
			rslt_definition = make_result_definition_from_oval_definition(sys, oval_definition, visited_definitions, hint);
			if (rslt_definition == NULL)
				return NULL;
			oval_result_system_add_definition(sys, rslt_definition);
		}
	}
	return rslt_definition;
}

struct oval_result_test *oval_result_system_get_new_test(struct oval_result_system *sys, struct oval_test *oval_test, int variable_instance) {
	char *id = oval_test_get_id(oval_test);
	struct oval_result_test *rslt_testtest = oval_result_system_get_test(sys, id);
	if (rslt_testtest == NULL) {
		//test = oval_result_test_new(sys, id);
		rslt_testtest = make_result_test_from_oval_test(sys, oval_test, variable_instance);
		oval_result_system_add_test(sys, rslt_testtest);
	}
	else if (variable_instance != 0 && oval_result_test_get_instance(rslt_testtest) != variable_instance) {
		dI("Creating another result-test for id=%s based on variable_instance: %d", id, variable_instance);
		rslt_testtest = make_result_test_from_oval_test(sys, oval_test, variable_instance);
		oval_result_system_add_test(sys, rslt_testtest);
	}
	return rslt_testtest;
}

struct oval_results_model *oval_result_system_get_results_model(struct oval_result_system *sys) {
	__attribute__nonnull__(sys);

	return sys->model;
}

struct oval_syschar_model *oval_result_system_get_syschar_model(struct oval_result_system *sys) {
	__attribute__nonnull__(sys);

	return sys->syschar_model;
}

struct oval_sysinfo *oval_result_system_get_sysinfo(struct oval_result_system *sys) {
	struct oval_syschar_model *syschar_model = oval_result_system_get_syschar_model(sys);
	return (syschar_model)
	    ? oval_syschar_model_get_sysinfo(syschar_model) : NULL;
}

void oval_result_system_add_definition(struct oval_result_system *sys, struct oval_result_definition *definition) 
{
	__attribute__nonnull__(sys);
	if (definition) {
		const char *id = oval_result_definition_get_id(definition);
		oval_smc_put_last(sys->definitions, id, definition);
	}
}

void oval_result_system_add_test(struct oval_result_system *sys, struct oval_result_test *test) 
{
	__attribute__nonnull__(sys);
	if (test) {
		const char *id = oval_result_test_get_id(test);
		oval_smc_put_last(sys->tests, id, test);
	}
}

static int oval_result_system_parse(xmlTextReaderPtr reader, struct oval_parser_context *context, void *usr) {
	__attribute__nonnull__(usr);

	struct oval_result_system *sys = (struct oval_result_system *) usr;
	xmlChar *localName = xmlTextReaderLocalName(reader);

	int return_code = 0;
	if (strcmp((const char *)localName, "definitions") == 0) {
                return_code = oval_parser_parse_tag(reader, context, oval_result_definition_parse_tag, sys);
	} else if (strcmp((const char *)localName, "tests") == 0) {
		return_code = oval_parser_parse_tag(reader, context, oval_result_test_parse_tag, sys);
	} else if (strcmp((const char *)localName, OVAL_ROOT_ELM_SYSCHARS) == 0) {
		return_code = oval_syschar_model_parse(reader, context);
	} else {
                dW("Skipping tag: %s", localName);
                oval_parser_skip_tag(reader, context);
	}

        if (return_code != 0) {
                dW("Parsing of <%s> terminated by an error at line %d.", localName, xmlTextReaderGetParserLineNumber(reader));
        }

	free(localName);
	return return_code;
}

int oval_result_system_parse_tag(xmlTextReaderPtr reader, struct oval_parser_context *context, void *usr) {
	__attribute__nonnull__(context);

        char *tagname = (char *)xmlTextReaderLocalName(reader);
        char *namespace = (char *)xmlTextReaderNamespaceUri(reader);
	int return_code = 0;

	int is_ovalres = strcmp((const char *)OVAL_RESULTS_NAMESPACE, namespace) == 0;
	if (is_ovalres && (strcmp(tagname, "system") == 0)) {
		/* create new empty syschar for this model */
		struct oval_syschar_model *syschar_model = oval_syschar_model_new(context->definition_model);
		context->syschar_model = syschar_model;
		/* create new results system instance */
		struct oval_result_system *sys = oval_result_system_new(context->results_model, syschar_model);
		/* populate results system  */
		return_code = oval_parser_parse_tag(reader, context, oval_result_system_parse, sys);
        } else {
                dW("Skipping tag: %s", tagname);
                oval_parser_skip_tag(reader, context);
        }

        if (return_code != 0) {
                dW("Parsing of <%s> terminated by an error at line %d.", tagname, xmlTextReaderGetParserLineNumber(reader));
        }

        free(tagname);
        free(namespace);

	return return_code;
}

int oval_result_system_eval(struct oval_result_system *sys)
{
	struct oval_results_model *res_model;
	struct oval_definition_model *definition_model;
	struct oval_definition_iterator *definitions_itr;

	res_model = oval_result_system_get_results_model(sys);
	definition_model = oval_results_model_get_definition_model(res_model);
	definitions_itr = oval_definition_model_get_definitions(definition_model);

	while (oval_definition_iterator_has_more(definitions_itr)) {
		struct oval_definition *definition;
		struct oval_result_definition *rslt_definition;

		definition = oval_definition_iterator_next(definitions_itr);
		rslt_definition = oval_result_system_get_new_definition(sys, definition, 0);
		oval_result_definition_eval(rslt_definition);
	}

	oval_definition_iterator_free(definitions_itr);
	return 0;
}

int oval_result_system_eval_definition(struct oval_result_system *sys, const char *id)
{
	struct oval_result_definition *rslt_definition = oval_result_system_prepare_definition(sys, id);
	if (rslt_definition == NULL) {
		return -1;
	}
	oval_result_definition_eval(rslt_definition);
	return 0;
}

struct oval_result_definition *oval_result_system_prepare_definition(struct oval_result_system *sys, const char *id)
{
        struct oval_results_model *res_model;
        struct oval_definition_model *definition_model;
        struct oval_definition *oval_definition;
	struct oval_result_definition *rslt_definition;

	res_model = oval_result_system_get_results_model(sys);
	definition_model = oval_results_model_get_definition_model(res_model);
	oval_definition = oval_definition_model_get_definition(definition_model, id);
	if (oval_definition == NULL) {
		oscap_seterr(OSCAP_EFAMILY_OSCAP, "No definition with ID: %s in definition model.", id);
		return NULL;
	}

	struct oscap_list *visited_definitions = oscap_list_new();
        rslt_definition = oval_result_system_get_definition(sys, id);
        if (rslt_definition == NULL) {
		rslt_definition = make_result_definition_from_oval_definition(sys, oval_definition, visited_definitions, 1);
		if (rslt_definition == NULL)
			goto cleanup;
                oval_result_system_add_definition(sys, rslt_definition);
        }
	else if (oval_result_definition_get_variable_instance_hint(rslt_definition) != oval_result_definition_get_instance(rslt_definition)) {
		int hint = oval_result_definition_get_variable_instance_hint(rslt_definition);
		dI("Creating another result-definition for id=%s based on variable_instance: %d", id, hint);
		rslt_definition = make_result_definition_from_oval_definition(sys, oval_definition, visited_definitions, hint);
		if (rslt_definition == NULL)
			goto cleanup;
		oval_result_system_add_definition(sys, rslt_definition);
	}
cleanup:
	oscap_list_free(visited_definitions, free);
	return rslt_definition;
}

static void _oval_result_definition_to_dom_based_on_directives(struct oval_result_definition *rslt_definition,
						   struct oval_result_directives * directives,
						   xmlDocPtr doc,
						   xmlNode *definitions_node,
						   struct oval_smc *tstmap)
{
	oval_result_t result = oval_result_definition_get_result(rslt_definition);
	if (oval_result_directives_get_reported(directives, result)) {
		oval_result_directive_content_t content = oval_result_directives_get_content(directives, result);
		/* report definition according to directives settings */
		oval_result_definition_to_dom(rslt_definition, content, doc, definitions_node);
		if (content == OVAL_DIRECTIVE_CONTENT_FULL) {
			struct oval_result_criteria_node *criteria = oval_result_definition_get_criteria(rslt_definition);
			/* collect the tests that are referenced from reported definitions */
			if (criteria)
				_oval_result_system_scan_criteria_for_references(criteria, tstmap);
		} else if (content == OVAL_DIRECTIVE_CONTENT_THIN) {
			// NOOP
		}
	}
}

xmlNode *oval_result_system_to_dom(struct oval_result_system * sys,
				   struct oval_results_model * results_model,
				   struct oval_directives_model * directives_model, 
				   xmlDocPtr doc, xmlNode * parent) {

	struct oval_result_directives * directives;
	struct oval_result_directives * class_dirs;
	struct oval_result_directives * def_dirs = oval_directives_model_get_defdirs(directives_model);

	xmlNs *ns_results = xmlSearchNsByHref(doc, parent, OVAL_RESULTS_NAMESPACE);
	xmlNode *system_node = xmlNewTextChild(parent, ns_results, BAD_CAST "system", NULL);

	struct oval_smc *tstmap = oval_smc_new();

	struct oval_definition_model *definition_model = oval_results_model_get_definition_model(results_model);
	struct oval_definition_iterator *oval_definitions = oval_definition_model_get_definitions(definition_model);
	if(oval_definition_iterator_has_more(oval_definitions)) {
		xmlNode *definitions_node = xmlNewTextChild(system_node, ns_results, BAD_CAST "definitions", NULL);
		while(oval_definition_iterator_has_more(oval_definitions)) {
			struct oval_definition *oval_definition = oval_definition_iterator_next(oval_definitions);

			oval_definition_class_t def_class = oval_definition_get_class(oval_definition);
			class_dirs = oval_directives_model_get_classdir(directives_model, def_class);
			directives = class_dirs ? class_dirs : def_dirs;

			bool exported = false;
			struct oval_iterator *rslt_definitions_it = oval_smc_get_all_it(sys->definitions, oval_definition_get_id(oval_definition));
			if (rslt_definitions_it != NULL) {
				while (oval_collection_iterator_has_more(rslt_definitions_it)) {
					struct oval_result_definition *rslt_definition = oval_collection_iterator_next(rslt_definitions_it);
					_oval_result_definition_to_dom_based_on_directives(rslt_definition, directives, doc, definitions_node, tstmap);
					exported = true;
				}
				oval_collection_iterator_free(rslt_definitions_it);
			}
			if (!exported) {
				struct oval_result_definition *rslt_definition = oval_result_system_get_new_definition(sys, oval_definition, 1);
				if (rslt_definition) {
					_oval_result_definition_to_dom_based_on_directives(rslt_definition, directives, doc, definitions_node, tstmap);
				}
			}
		}
	}
	oval_definition_iterator_free(oval_definitions);

	struct oval_syschar_model *syschar_model = oval_result_system_get_syschar_model(sys);
	struct oval_string_map *sysmap = oval_string_map_new();
	struct oval_string_map *objmap = oval_string_map_new();
	struct oval_string_map *sttmap = oval_string_map_new();
	struct oval_string_map *varmap = oval_string_map_new();

	struct oval_smc_iterator *result_tests = oval_smc_iterator_new(tstmap);
	if (oval_smc_iterator_has_more(result_tests)) {
		xmlNode *tests_node = xmlNewTextChild(system_node, ns_results, BAD_CAST "tests", NULL);
		while (oval_smc_iterator_has_more(result_tests)) {
			struct oval_state_iterator *ste_itr;
			struct oval_result_test *result_test = oval_smc_iterator_next(result_tests);
			/* report the test */
			oval_result_test_to_dom(result_test, doc, tests_node);
			struct oval_test *oval_test = oval_result_test_get_test(result_test);
			/* collect the objects that are referenced from reported test */
			/* look for objects in path: test->object ...  */
			struct oval_object *object = oval_test_get_object(oval_test);
			if (object) {
				char *objid = oval_object_get_id(object);
				/* is object already "collected" */
				void *value = oval_string_map_get_value(objmap, objid);
				if (value == NULL) {
					/* is there a system characteristic for the object */
					struct oval_syschar *syschar =
					    oval_syschar_model_get_syschar(syschar_model, objid);
					if (syschar) {
						/* put object into map */
						oval_string_map_put(objmap, objid, object);
						_oval_result_system_scan_object_for_references
						    (syschar_model, object, objmap, sttmap, varmap, sysmap);
					}
				}
			}
			/* look for objects in test->state->... */
			ste_itr = oval_test_get_states(oval_test);
			while (oval_state_iterator_has_more(ste_itr)) {
				struct oval_state *state = oval_state_iterator_next(ste_itr);
				char *sttid = oval_state_get_id(state);
				void *value = oval_string_map_get_value(sttmap, sttid);
				if (value == NULL) {
					oval_string_map_put(sttmap, sttid, state);
					_oval_result_system_scan_state_for_references(syschar_model, state, objmap, sttmap,
										      varmap, sysmap);
				}
			}
			oval_state_iterator_free(ste_itr);
		}
	}
	oval_smc_iterator_free(result_tests);

	bool export_sys_char = oval_results_model_get_export_system_characteristics(results_model);
	oval_syschar_model_to_dom(syschar_model, doc, system_node, 
				  (oval_syschar_resolver *) _oval_result_system_resolve_syschar, sysmap, export_sys_char);

	oval_string_map_free(sysmap, NULL);
	oval_string_map_free(objmap, NULL);
	oval_string_map_free(sttmap, NULL);
	oval_string_map_free(varmap, NULL);
	oval_smc_free0(tstmap);

	return system_node;
}





static void _oval_result_system_scan_criteria_for_references
    (struct oval_result_criteria_node *node, struct oval_smc *testmap) {
	struct oval_result_criteria_node_iterator *subnodes = oval_result_criteria_node_get_subnodes(node);
	while (subnodes && oval_result_criteria_node_iterator_has_more(subnodes)) {
		struct oval_result_criteria_node *subnode = oval_result_criteria_node_iterator_next(subnodes);
		_oval_result_system_scan_criteria_for_references(subnode, testmap);
	}
	oval_result_criteria_node_iterator_free(subnodes);
	struct oval_result_test *result_test = oval_result_criteria_node_get_test(node);
	if (result_test) {
		const char *testid = oval_result_test_get_id(result_test);
		oval_smc_put_last_if_not_exists(testmap, testid, result_test);
	}
}

static void _oval_result_system_scan_object_for_references
    (struct oval_syschar_model *syschar_model, struct oval_object *object,
     struct oval_string_map *objmap,
     struct oval_string_map *sttmap, 
     struct oval_string_map *varmap, 
     struct oval_string_map *sysmap) {
	char *objid = oval_object_get_id(object);
	struct oval_syschar *syschar = oval_syschar_model_get_syschar(syschar_model, objid);
	if (syschar) /* put syschar of the object into map */
		oval_string_map_put(sysmap, objid, syschar);
	struct oval_object_content_iterator *contents = oval_object_get_object_contents(object);
	/* see if there are more objects referenced from this object's content */ 
	while (oval_object_content_iterator_has_more(contents)) {
		struct oval_object_content *content = oval_object_content_iterator_next(contents);
		struct oval_entity *entity = oval_object_content_get_entity(content);
		if (entity)
			_oval_result_system_scan_entity_for_references(syschar_model, entity, objmap, sttmap, varmap,
								       sysmap);
		struct oval_setobject *set = oval_object_content_get_setobject(content);
		if (set)
			_oval_result_system_scan_set_for_references(syschar_model, set, objmap, sttmap, varmap, sysmap);
	}
	oval_object_content_iterator_free(contents);
}

static void _oval_result_system_scan_state_for_references
    (struct oval_syschar_model *syschar_model, struct oval_state *state,
     struct oval_string_map *objmap,
     struct oval_string_map *sttmap, struct oval_string_map *varmap, struct oval_string_map *sysmap) {
	struct oval_state_content_iterator *contents = oval_state_get_contents(state);
	while (oval_state_content_iterator_has_more(contents)) {
		struct oval_state_content *content = oval_state_content_iterator_next(contents);
		struct oval_entity *entity = oval_state_content_get_entity(content);
		if (entity)
			_oval_result_system_scan_entity_for_references(syschar_model, entity, objmap, sttmap, varmap,
								       sysmap);
	}
	oval_state_content_iterator_free(contents);
}

static void _oval_result_system_scan_component_for_references
    (struct oval_syschar_model *syschar_model, struct oval_component *component,
     struct oval_string_map *objmap,
     struct oval_string_map *sttmap, struct oval_string_map *varmap, struct oval_string_map *sysmap) {
	struct oval_variable *variable = oval_component_get_variable(component);
	if (variable) {
		char *varid = oval_variable_get_id(variable);
		void *value = oval_string_map_get_value(varmap, varid);
		if (value == NULL) {
			oval_string_map_put(varmap, varid, variable);
			struct oval_component *component2 = oval_variable_get_component(variable);
			if (component2) {
				_oval_result_system_scan_component_for_references(syschar_model, component2, objmap,
										  sttmap, varmap, sysmap);
			}
		}
	} else {
		struct oval_component_iterator *fcomponents = oval_component_get_function_components(component);
		if (fcomponents)
			while (oval_component_iterator_has_more(fcomponents)) {
				struct oval_component *fcomponent = oval_component_iterator_next(fcomponents);
				_oval_result_system_scan_component_for_references(syschar_model, fcomponent, objmap,
										  sttmap, varmap, sysmap);
			}
		oval_component_iterator_free(fcomponents);

		struct oval_object *object = oval_component_get_object(component);
		if (object) {
			char *objid = oval_object_get_id(object);
			void *value = oval_string_map_get_value(objmap, objid);
			if (value == NULL) {
				oval_string_map_put(objmap, objid, object);
				_oval_result_system_scan_object_for_references(syschar_model, object, objmap, sttmap,
									       varmap, sysmap);
			}
		}
	}
}

static void _oval_result_system_scan_entity_for_references
    (struct oval_syschar_model *syschar_model, struct oval_entity *entity,
     struct oval_string_map *objmap,
     struct oval_string_map *sttmap, struct oval_string_map *varmap, struct oval_string_map *sysmap) {
	struct oval_variable *variable = oval_entity_get_variable(entity);
	if (variable) {
		char *varid = oval_variable_get_id(variable);
		void *value = oval_string_map_get_value(varmap, varid);
		if (value == NULL) {
			oval_string_map_put(varmap, varid, variable);
			struct oval_component *component = oval_variable_get_component(variable);
			if (component) {
				_oval_result_system_scan_component_for_references(syschar_model, component, objmap,
										  sttmap, varmap, sysmap);
			}
		}
	}
}

static void _oval_result_system_scan_set_for_references
    (struct oval_syschar_model *syschar_model, struct oval_setobject *set,
     struct oval_string_map *objmap,
     struct oval_string_map *sttmap, struct oval_string_map *varmap, struct oval_string_map *sysmap) {
	struct oval_object_iterator *objects = oval_setobject_get_objects(set);
	if (objects)
		while (oval_object_iterator_has_more(objects)) {
			struct oval_object *object = oval_object_iterator_next(objects);
			char *objid = oval_object_get_id(object);
			void *value = oval_string_map_get_value(objmap, objid);
			if (value == NULL) {
				oval_string_map_put(objmap, objid, object);
				_oval_result_system_scan_object_for_references(syschar_model, object, objmap, sttmap,
									       varmap, sysmap);
			}
		}
	oval_object_iterator_free(objects);
	struct oval_filter_iterator *filters = oval_setobject_get_filters(set);
	if (filters)
		while (oval_filter_iterator_has_more(filters)) {
			struct oval_filter *filter;
			struct oval_state *state;

			filter = oval_filter_iterator_next(filters);
			state = oval_filter_get_state(filter);
			char *sttid = oval_state_get_id(state);
			void *value = oval_string_map_get_value(sttmap, sttid);
			if (value == NULL) {
				oval_string_map_put(sttmap, sttid, state);
				_oval_result_system_scan_state_for_references(syschar_model, state, objmap, sttmap,
									      varmap, sysmap);
			}
		}
	oval_filter_iterator_free(filters);
	struct oval_setobject_iterator *subsets = oval_setobject_get_subsets(set);
	if (subsets)
		while (oval_setobject_iterator_has_more(subsets)) {
			struct oval_setobject *subset = oval_setobject_iterator_next(subsets);
			_oval_result_system_scan_set_for_references(syschar_model, subset, objmap, sttmap, varmap,
								    sysmap);
		}
	oval_setobject_iterator_free(subsets);
}

static bool _oval_result_system_resolve_syschar(struct oval_syschar *syschar, struct oval_string_map *sysmap) {
	const char *objid = oval_syschar_get_id(syschar);
	return oval_string_map_get_value(sysmap, objid) != NULL;
}

