include "primitives.alh"
include "modelling.alh"
include "random.alh"
include "model_management.alh"
include "object_operations.alh"
include "modelling.alh"

Boolean function main(model : Element):
	// Do a single simulation step

	// Find enabled transitions
	Element all_transitions
	Element enabled_transitions
	String under_study
	Boolean enabled
	Element in_arcs
	String arc_under_study

	all_transitions = allInstances(model, "PetriNet_Runtime/Transition")
	enabled_transitions = create_node()

	while (0 < read_nr_out(all_transitions)):
		under_study = set_pop(all_transitions)
		enabled = True

		// Find all incoming transitions
		in_arcs = allIncomingAssociationInstances(model, under_study, "PetriNet_Runtime/P2T")

		while (0 < read_nr_out(in_arcs)):
			arc_under_study = set_pop(in_arcs)

			Integer present_tokens
			Integer required_tokens
			required_tokens = read_attribute(model, arc_under_study, "weight")
			present_tokens = read_attribute(model, reverseKeyLookup(model["model"], read_edge_src(model["model"][arc_under_study])), "tokens")
			if (present_tokens < required_tokens):
				// Less tokens than required, so disable the transition completely
				enabled = False

		if (enabled):
			set_add(enabled_transitions, under_study)

	// Pick random enabled transition
	String transition

	transition = random_choice(set_to_list(enabled_transitions))

	// Consume tokens
	Element workset
	String working_arc
	String working_place
	Integer new_value

	workset = allIncomingAssociationInstances(model, transition, "PetriNet_Runtime/P2T")
	while (0 < read_nr_out(workset)):
		working_arc = set_pop(workset)
		working_place = reverseKeyLookup(model["model"], read_edge_src(model["model"][working_arc]))
		new_value = integer_subtraction(read_attribute(model, working_place, "tokens"), read_attribute(model, working_arc, "weight"))
		instantiate_attribute(model, working_place, "tokens", new_value)

	// Add tokens
	workset = allOutgoingAssociationInstances(model, transition, "PetriNet_Runtime/T2P")
	while (0 < read_nr_out(workset)):
		working_arc = set_pop(workset)
		working_place = reverseKeyLookup(model["model"], read_edge_dst(model["model"][working_arc]))
		new_value = integer_addition(read_attribute(model, working_place, "tokens"), read_attribute(model, working_arc, "weight"))
		instantiate_attribute(model, working_place, "tokens", new_value)

	// Finish up
	return True!
