include "primitives.alh"
include "modelling.alh"
include "object_operations.alh"
include "library.alh"
include "conformance_scd.alh"
include "random.alh"

Void function main():
	Element model
	String verify_result

	while (True):
		output("Which model do you want to execute with RPGame semantics?")
		model = import_node(input())

		if (element_eq(model, read_root())):
			output("Could not find model; aborting")
		elif (element_neq(model["metamodel"], import_node("models/RPGame"))):
			log("Got metamodel: " + cast_e2s(model["metamodel"]))
			log("Expected metamodel: " + cast_e2s(import_node("models/RPGame")))
			output("Not a RPGame model; aborting")
		else:
			verify_result = conformance_scd(model)
			if (verify_result == "OK"):
				output("Model OK!")
				execute_rpgame(model)
			else:
				output("Non-conforming model: " + verify_result)

String function getHeroTile(model : Element, hero : String):
	return set_pop(followAssociation(model, hero, "Character_on_tile"))

String function getGoalTile(model : Element, goal : String):
	return set_pop(followAssociation(model, goal, "Item_on_tile"))

Void function setHeroTile(model : Element, hero : String, tile : String):
	Element assocs

	assocs = allOutgoingAssociationInstances(model, hero, "Character_on_tile")
	while (0 < list_len(assocs)):
		model_delete_element(model, set_pop(assocs))

	instantiate_link(model, "Character_on_tile", "", hero, tile)

	return

Element function getConnectedTiles(model : Element, tile : String):
	Element left
	Element right
	Element top
	Element bottom
	Element result

	result = create_node()
	left = followAssociation(model, tile, "tile_left")
	right = followAssociation(model, tile, "tile_right")
	top = followAssociation(model, tile, "tile_top")
	bottom = followAssociation(model, tile, "tile_bottom")

	while (dict_len(left) > 0):
		set_add(result, set_pop(left))
	while (dict_len(right) > 0):
		set_add(result, set_pop(right))
	while (dict_len(top) > 0):
		set_add(result, set_pop(top))
	while (dict_len(bottom) > 0):
		set_add(result, set_pop(bottom))

	return result

Void function execute_rpgame(model : Element):
	String hero
	String goal
	String hero_tile
	String goal_tile

	log("Executing model!")

	// Make the assumption that only a single hero and goal exist
	hero = set_pop(allInstances(model, "Hero"))
	goal = set_pop(allInstances(model, "Goal"))

	log("Got all tiles")
	goal_tile = getGoalTile(model, goal)
	log("Got goal tile: " + goal_tile)
	hero_tile = getHeroTile(model, hero)
	log("Got hero tile: " + hero_tile)

	log("Keep executing")
	while (hero_tile != goal_tile):
		output((("Hero: " + hero_tile) + " -- Goal: ") + goal_tile)
		hero_tile = random_choice(getConnectedTiles(model, hero_tile))
		setHeroTile(model, hero, hero_tile)
	output("Hero reached goal!")
	return
