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

Boolean function main(model : Element):
	Element elements
	String class
	Element attrs
	Element attr_keys
	String attr_key
	String group
	String elem
	Integer loc
	Integer text_loc
	Element related_groups
	loc = 10

	Element groups
	groups = dict_create()

	elements = allInstances(model, "rendered/Group")
	while (set_len(elements) > 0):
		group = set_pop(elements)
		if (set_len(allIncomingAssociationInstances(model, group, "TracabilityClass")) == 0):
			Element to_remove
			String elem_to_remove
			to_remove = allAssociationDestinations(model, group, "rendered/contains")
			while (set_len(to_remove) > 0):
				elem_to_remove = set_pop(to_remove)
				if (read_type(model, elem_to_remove) == "rendered/Group"):
					set_add(to_remove, elem_to_remove)
				else:
					model_delete_element(model, elem_to_remove)
			model_delete_element(model, group)

	elements = allInstances(model, "abstract/Block")
	while (set_len(elements) > 0):
		class = set_pop(elements)
		
		Integer x
		Integer y
		x = loc
		y = 10

		// Check if there is already an associated element
		if (set_len(allOutgoingAssociationInstances(model, class, "TracabilityClass")) > 0):
			// Yes, but is it still clean?
			Boolean dirty
			dirty = False

			related_groups = allAssociationDestinations(model, class, "TracabilityClass")
			while (set_len(related_groups) > 0):
				group = set_pop(related_groups)
				if (value_eq(read_attribute(model, group, "dirty"), True)):
					// No, so mark all as dirty
					dirty = True
					break!
				else:
					// Yes, so just ignore this!
					continue!

			if (bool_not(dirty)):
				dict_add(groups, class, group)
				continue!
			else:
				related_groups = allAssociationDestinations(model, class, "TracabilityClass")
				Element to_remove
				String elem_to_remove
				while (set_len(related_groups) > 0):
					group = set_pop(related_groups)
					to_remove = allAssociationDestinations(model, group, "rendered/contains")
					x = create_value(read_attribute(model, group, "x"))
					y = create_value(read_attribute(model, group, "y"))
					while (set_len(to_remove) > 0):
						elem_to_remove = set_pop(to_remove)
						if (read_type(model, elem_to_remove) == "rendered/Group"):
							set_add(to_remove, elem_to_remove)
						else:
							model_delete_element(model, elem_to_remove)
					model_delete_element(model, group)

		attr_keys = dict_keys(getAttributeList(model, class))
		text_loc = 5

		group = instantiate_node(model, "rendered/Group", "")
		instantiate_attribute(model, group, "x", x)
		instantiate_attribute(model, group, "y", y)
		instantiate_attribute(model, group, "__asid", list_read(string_split_nr(class, "/", 1), 1))
		instantiate_attribute(model, group, "layer", 0)
		dict_add(groups, class, group)
		loc = loc + 100

		elem = instantiate_node(model, "rendered/Rectangle", "")
		instantiate_attribute(model, elem, "x", 0)
		instantiate_attribute(model, elem, "y", 0)
		instantiate_attribute(model, elem, "height", 50)
		instantiate_attribute(model, elem, "width", 50)
		instantiate_attribute(model, elem, "lineWidth", 4) 
		instantiate_attribute(model, elem, "lineColour", "black")
		instantiate_attribute(model, elem, "fillColour", "white")
		instantiate_attribute(model, elem, "layer", 1)
		instantiate_link(model, "rendered/contains", "", group, elem)

		elem = instantiate_node(model, "rendered/Text", "")
		instantiate_attribute(model, elem, "x", 20)
		instantiate_attribute(model, elem, "y", 20)
		instantiate_attribute(model, elem, "lineWidth", 1)
		instantiate_attribute(model, elem, "lineColour", "black")
		
		String type
		type = read_type(model, class)
		if (type == "abstract/ConstantBlock"):
			if (element_neq(read_attribute(model, class, "value"), read_root())):
				instantiate_attribute(model, elem, "text", cast_string(read_attribute(model, class, "value")))
			else:
				instantiate_attribute(model, elem, "text", "?")
		elif (type == "abstract/AdditionBlock"):
			instantiate_attribute(model, elem, "text", "+")
		elif (type == "abstract/NegatorBlock"):
			instantiate_attribute(model, elem, "text", "-")
		elif (type == "abstract/MultiplyBlock"):
			instantiate_attribute(model, elem, "text", "X")
		elif (type == "abstract/InverseBlock"):
			instantiate_attribute(model, elem, "text", "1/x")
		elif (type == "abstract/DelayBlock"):
			instantiate_attribute(model, elem, "text", "DELAY")
		elif (type == "abstract/IntegratorBlock"):
			instantiate_attribute(model, elem, "text", "1/s")
		elif (type == "abstract/DerivatorBlock"):
			instantiate_attribute(model, elem, "text", "dx")
		elif (type == "abstract/ProbeBlock"):
			instantiate_attribute(model, elem, "text", "PROBE")

		instantiate_attribute(model, elem, "layer", 2)
		instantiate_link(model, "rendered/contains", "", group, elem)

		instantiate_link(model, "TracabilityClass", "", class, group)

	// Flush all associations
	elements = allInstances(model, "rendered/ConnectingLine")
	while (set_len(elements) > 0):
		class = set_pop(elements)
		model_delete_element(model, class)

	// Rerender associations
	elements = allInstances(model, "abstract/Link")
	while (set_len(elements) > 0):
		class = set_pop(elements)

		elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
		instantiate_attribute(model, elem, "offsetSourceX", 25)
		instantiate_attribute(model, elem, "offsetSourceY", 25)
		instantiate_attribute(model, elem, "offsetTargetX", 25)
		instantiate_attribute(model, elem, "offsetTargetY", 25)
		instantiate_attribute(model, elem, "lineWidth", 1)
		instantiate_attribute(model, elem, "lineColour", "black")
		instantiate_attribute(model, elem, "arrow", True)
		instantiate_attribute(model, elem, "__asid", list_read(string_split_nr(class, "/", 1), 1))
		instantiate_attribute(model, elem, "layer", 0)
		instantiate_link(model, "rendered/contains", "", group, elem)

	// Rerender initial conditions
	elements = allInstances(model, "abstract/InitialCondition")
	while (set_len(elements) > 0):
		class = set_pop(elements)

		elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
		instantiate_attribute(model, elem, "offsetSourceX", 25)
		instantiate_attribute(model, elem, "offsetSourceY", 25)
		instantiate_attribute(model, elem, "offsetTargetX", 25)
		instantiate_attribute(model, elem, "offsetTargetY", 25)
		instantiate_attribute(model, elem, "lineWidth", 1)
		instantiate_attribute(model, elem, "lineColour", "red")
		instantiate_attribute(model, elem, "arrow", True)
		instantiate_attribute(model, elem, "__asid", list_read(string_split_nr(class, "/", 1), 1))
		instantiate_attribute(model, elem, "layer", 0)
		instantiate_link(model, "rendered/contains", "", group, elem)

	return True!
