include "primitives.alh"
include "object_operations.alh"
include "modelling.alh"

Element function make_matching_schedule(LHS_model : Element):
	Element schedule
	Element workset
	Element all_elements
	Integer required_size
	String new_element
	Integer counter
	String next

	// Initialize
	schedule = create_node()
	workset = create_node()
	all_elements = allInstances(LHS_model, "Pre_Element")
	required_size = read_nr_out(all_elements)

	// Need to keep adding to the schedule
	while (read_nr_out(schedule) < required_size):

		// workset is empty, but we still need to add to the list
		// Therefore, we pick a random, unbound node, and add it to the workset
		new_element = set_pop(all_elements)
		while (bool_or(set_in(schedule, new_element), is_edge(LHS_model["model"][new_element]))):
			// Element is not usable, so pick another one
			new_element = set_pop(all_elements)
		set_add(workset, new_element)

		// Handle the workset
		while (read_nr_out(workset) > 0):
			// Still elements in the workset, so pop from these first
			next = set_pop(workset)

			// Check if element might not be already used somewhere
			if (bool_not(set_in(schedule, next))):
				list_append(schedule, next)

				// If it is an edge, we should also add the target and source
				if (is_edge(LHS_model["model"][next])):
					// Add the target/source to the schedule
					set_add(workset, read_edge_src(LHS_model["model"][next]))
					set_add(workset, read_edge_dst(LHS_model["model"][next]))

				// Also add all outgoing links
				counter = read_nr_out(LHS_model["model"][next])
				while (counter > 0):
					counter = counter - 1
					if (set_in_node(LHS_model["model"], read_out(LHS_model["model"][next], counter))):
						set_add(workset, reverseKeyLookup(LHS_model["model"], read_out(LHS_model["model"][next], counter)))

	return schedule!

Void function transform(host_model : Element, LHS_model : Element, RHS_model : Element):
	Element schedule

	schedule = make_matching_schedule(LHS_model)
	output("Got schedule")
	while (read_nr_out(schedule) > 0):
		output(list_pop(schedule, 0))

	return!
