include "primitives.alh"
include "utils.alh"

Element function get_type_mapping(model : Element):
	// Deserialize dictionary as model
	return model["type_mapping"]!

Void function set_type_mapping(model : Element, type_mapping_model : Element):
	// Serialize model to dictionary
	dict_overwrite(model, "type_mapping", type_mapping_model)
	return!

Element function elements_typed_by(model : Element, type_name : String):
	Element result
	Element temp_result
	String temp
	Element m_model

	m_model = model["model"]
	result = set_create()
	temp_result = reverseKeyLookupMultiValue(get_type_mapping_as_dict(model), type_name)
	while (set_len(temp_result) > 0):
		temp = set_pop(temp_result)
		if (dict_in(m_model, temp)):
			set_add(result, temp)
	return result!

Element function get_type_mapping_as_dict(model : Element):
	return model["type_mapping"]["root"]!

String function read_type(model : Element, name : String):
	String result
	Element tm
	if (dict_in(model["model"], name)):
		if (dict_in(model["type_mapping"]["root"], name)):
			result = model["type_mapping"]["root"][name]
			if (dict_in(model["metamodel"]["model"], result)):
				return result!
			else:
				return ""!
		else:
			return ""!
	else:
		return ""!

Void function retype(model : Element, element : String, type : String):
	// Retype a model, deleting any previous type the element had
	Element tm
	tm = model["type_mapping"]

	remove_type(model, element)

	// Create new elements
	Element type_link
	Element type_elem
	Element instance_link
	Element instance_elem
	type_elem = create_value(type)
	instance_elem = create_value(element)
	type_link = create_edge(tm["root"], type_elem)
	instance_link = create_edge(type_link, instance_elem)
	dict_add(tm, cast_id(type_elem), type_elem)
	dict_add(tm, cast_id(instance_elem), instance_elem)
	dict_add(tm, cast_id(type_link), type_link)
	dict_add(tm, cast_id(instance_link), instance_link)
	return!

Void function new_type_mapping(model : Element):
	dict_overwrite(model, "type_mapping", dict_create())
	dict_add(model["type_mapping"], "root", create_node())
	return !

Void function remove_type(model : Element, name : String):
	Element value
	value = dict_read_edge(model["type_mapping"]["root"], name)
	if (element_neq(value, read_root())):
		delete_element(value)
	return !
