include "primitives.alh"
include "constructors.alh"
include "object_operations.alh"
include "library.alh"
include "conformance_scd.alh"
include "io.alh"
include "metamodels.alh"
include "modelling.alh"
include "compilation_manager.alh"

Element function modify(model : Element, write : Boolean):
	String cmd

	Element attr_list_pn
	Element attr_keys_pn
	String attr_key_pn
	Element metamodel_element_pn
	String typename

	output("Model loaded, ready for commands!")
	output("Use 'help' command for a list of possible commands")

	while (True):
		output("Please give your command.")
		cmd = input()
		if (cmd == "help"):
			output("Allowed operations:")
			if (write):
				output(" == READ/WRITE ==")
				output("  instantiate -- Create a new model element")
				output("  delete      -- Delete an existing element")
				output("  attr_add    -- Add an attribute to an element")
				output("  attr_del    -- Delete an attribute of an element")
				output("  attr_modify -- Modify an attribute of an element")
				output("  constrain   -- Add a constraint function to the model")
				output("  rename      -- Rename an existing element")
				output("  modify      -- Modify the attributes of an element")
				output("  retype      -- Change the type of an element")
			else:
				output(" == READ-ONLY ==")
			output("  list        -- Prints the list of elements in the model")
			output("  list_full   -- Prints the list of all elements in the model")
			output("  types       -- Prints the list of elements that can be instantiated")
			output("  read        -- Prints the current state of a model element")
			output("  verify      -- Check whether the model conforms to the metamodel")
			output("  exit        -- Leave the modification interface")
		elif (cmd == "exit"):
			return model!
		elif (cmd == "instantiate"):
			if (write):
				String mm_type_name
				output("Type to instantiate?")
				mm_type_name = input()
				if (dict_in(model["metamodel"]["model"], mm_type_name)):
					String element_name
					output("Name of new element?")
					element_name = input()
					if (dict_in(model["model"], element_name)):
						output("Element already exists; aborting")
					else:
						if (is_edge(model["metamodel"]["model"][mm_type_name])):
							output("Source name?")
							String src_name
							src_name = input()
							if (dict_in(model["model"], src_name)):
								output("Destination name?")
								String dst_name
								dst_name = input()
								if (dict_in(model["model"], dst_name)):
									instantiate_link(model, mm_type_name, element_name, src_name, dst_name)
									output("Instantiation successful!")
								else:
									output("Unknown destination; aborting")
							else:
								output("Unknown source; aborting")
						else:
							instantiate_node(model, mm_type_name, element_name)
							output("Instantiation successful!")
				else:
					output("Unknown type specified; aborting")
			else:
				output("Permission denied")

		elif (cmd == "constrain"):
			if (write):
				output("Element to constrain (empty for global)?")
				String model_name
				model_name = input()

				if (model_name == ""):
					// Global constraint
					output("Give input to function constructors for GLOBAL constraint!")
					set_model_constraints(model, construct_function())
				elif (dict_in(model["model"], model_name)):
					// Local constraint for this model
					output("Give input to function constructors for LOCAL constraint!")
					add_constraint(model, model_name, construct_function())
					output("Added constraint to model!")
				else:
					// Local constraint, but model not found
					output("Unknown model; aborting")
			else:
				output("Permission denied")

		elif (cmd == "attr_modify"):
			if (write):
				String model_name
				output("Element to modify?")
				model_name = input()
				if (dict_in(model["model"], model_name)):
					Element attrs
					attrs = getAttributeList(model, model_name)
					String attr_name
					output("Attribute to modify?")
					attr_name = input()
					if (set_in(dict_keys(attrs), attr_name)):
						output("New value?")
						unset_attribute(model, model_name, attr_name)
						instantiate_attribute(model, model_name, attr_name, input())
						output("Modified!")
					else:
						output("No such attribute!")
				else:
					output("No such model!")
			else:
				output("Permission denied")

		elif (cmd == "attr_add"):
			if (write):
				String model_name
				output("Which model do you want to assign an attribute to?")
				model_name = input()
				if (dict_in(model["model"], model_name)):
					Element attrs
					attrs = getAttributeList(model, model_name)
					String attr_name
					output("Which attribute do you wish to assign?")
					attr_name = input()
					if (set_in(dict_keys(attrs), attr_name)):
						output("Value of attribute?")
						instantiate_attribute(model, model_name, attr_name, input())
						output("Added attribute!")
					else:
						output("No such attribute!")
				else:
					output("No such model!")
			else:
				output("Permission denied")

		elif (cmd == "attr_del"):
			if (write):
				String model_name
				output("Which model do you want to remove an attribute of?")
				model_name = input()
				if (dict_in(model["model"], model_name)):
					Element attrs
					attrs = getAttributeList(model, model_name)
					String attr_name
					output("Which attribute do you want to delete?")
					attr_name = input()
					if (set_in(dict_keys(attrs), attr_name)):
						unset_attribute(model, model_name, attr_name)
						output("Attribute deleted!")
					else:
						output("No such attribute!")
				else:
					output("No such model!")
			else:
				output("Permission denied")

		elif (cmd == "delete"):
			if (write):
				output("What is the name of the element you want to delete?")
				cmd = input()
				if (dict_in(model["model"], cmd)):
					model_delete_element(model, cmd)
					output("Deleted!")
				else:
					output("No such element; aborting")
			else:
				output("Permission denied")

		elif (cmd == "rename"):
			if (write):
				output("Old name?")
				String old_name_e
				old_name_e = input()
				if (dict_in(model["model"], old_name_e)):
					output("New name?")
					String new_name_e
					new_name_e = input()
					if (dict_in(model["model"], new_name_e)):
						output("New name already used; aborting")
					else:
						dict_add(model["model"], new_name_e, model["model"][old_name_e])
						dict_delete(model["model"], old_name_e)
						output("Rename complete!")
				else:
					output("Unknown element; aborting")
			else:
				output("Permission denied")

		elif (cmd == "list"):
			Element keys_m
			keys_m = dict_keys(model["model"])
			output("List of all elements:")
			String v_m
			while (read_nr_out(keys_m) > 0):
				v_m = set_pop(keys_m)
				// Filter out anonymous objects
				if (bool_not(string_startswith(v_m, "__"))):
					typename = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][v_m]))
					output((("  " + v_m) + " : ") + typename)

		elif (cmd == "list_full"):
			Element keys_m
			keys_m = dict_keys(model["model"])
			output("List of all elements:")
			String v_m
			while (read_nr_out(keys_m) > 0):
				v_m = set_pop(keys_m)
				// Filter out anonymous objects
				typename = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][v_m]))
				output((("  " + v_m) + " : ") + typename)

		elif (cmd == "read"):
			output("Element to read?")
			cmd = input()
			if (dict_in(model["model"], cmd)):
				Element read_elem
				read_elem = model["model"][cmd]
				metamodel_element_pn = dict_read_node(model["type_mapping"], read_elem)

				output("Name: " + cmd)
				output("Type: " + reverseKeyLookup(model["metamodel"]["model"], metamodel_element_pn))
				if (is_edge(read_elem)):
					output("Source: " + reverseKeyLookup(model["model"], read_edge_src(read_elem)))
					output("Destination: " + reverseKeyLookup(model["model"], read_edge_dst(read_elem)))
				if (cast_v2s(read_elem) != "None"):
					output("Value: " + cast_v2s(read_elem))
				output("Defines attributes:")
				attr_list_pn = getInstantiatableAttributes(model, read_elem)
				attr_keys_pn = dict_keys(attr_list_pn)
				while (0 < read_nr_out(attr_keys_pn)):
					attr_key_pn = set_pop(attr_keys_pn)
					output(((("  " + attr_key_pn) + " : ") + cast_v2s(attr_list_pn[attr_key_pn])))
				output("Attributes:")
				attr_list_pn = getAttributeList(model, cmd)
				attr_keys_pn = dict_keys(attr_list_pn)
				while (0 < read_nr_out(attr_keys_pn)):
					attr_key_pn = set_pop(attr_keys_pn)
					output((((("  " + cast_v2s(attr_key_pn)) + " : ") + cast_v2s(attr_list_pn[attr_key_pn])) + " = ") + cast_v2s(read_attribute(model, reverseKeyLookup(model["model"], read_elem), attr_key_pn)))
			else:
				output("Unknown element; aborting")

		elif (cmd == "verify"):
			output(conformance_scd(model))

		elif (cmd == "types"):
			Element keys_t
			keys_t = dict_keys(model["metamodel"]["model"])
			output("List of types:")
			String v_t
			while (read_nr_out(keys_t) > 0):
				v_t = set_pop(keys_t)
				if (bool_not(string_startswith(v_t, "__"))):
					output(string_join(("  " + v_t) + " : ", reverseKeyLookup(model["metamodel"]["metamodel"]["model"], dict_read_node(model["metamodel"]["type_mapping"], model["metamodel"]["model"][v_t]))))

		elif (cmd == "retype"):
			if (write):
				output("Element to retype?")
				String elementname
				elementname = input()
				if (dict_in(model["model"], elementname)):
					output("New type")
					typename = input()
					if (dict_in(model["metamodel"]["model"], typename)):
						// OK, do the retyping
						// First try removing the previous type if it exists
						dict_delete_node(model["type_mapping"], model["model"][elementname])
						// Now add the new type
						dict_add(model["type_mapping"], model["model"][elementname], model["metamodel"]["model"][typename])
						output("Retyped!")
					else:
						output("Unknown type; aborting")
				else:
					output("Unknown element; aborting")
			else:
				output("Permission denied")

		else:
			output("Unknown command: " + cast_v2s(cmd))
			output("Use command 'help' to get a list of available commands")

	return model!
