include "primitives.alh"
include "services.alh"
include "modelling.alh"
include "object_operations.alh"
include "utils.alh"
include "io.alh"
include "typing.alh"

Boolean function main(model : Element):
    String model_rep
    Element all_atomics
    Element curr_atomic
    Element all_coupleds
    Element curr_coupled
    Element string_element
    Element all_ports
    Element all_submodels
    Element curr_port
    Element curr_submodel
    Element out_channels
    Element curr_channel
    Element possible_parent
    Element parent
    String curr_port_name
    String curr_port_type
    String curr_submodel_name
    String curr_submodel_type
	String curr_submodel_parameters

	model_rep = ""
    model_rep = model_rep + "from pypdevs.DEVS import AtomicDEVS, CoupledDEVS\n"
	model_rep = model_rep + "from pypdevs.infinity import INFINITY\n"

    all_atomics = allInstances(model, "DEVS/AtomicDEVSBlock")
    while (read_nr_out(all_atomics) > 0):
        curr_atomic = set_pop(all_atomics)
        model_rep = model_rep + "class " + cast_string(read_attribute(model, curr_atomic, "name")) + "(AtomicDEVS):\n"
        model_rep = model_rep + "\tdef __init__(self, name, parameters):\n"
		model_rep = model_rep + "\t\tself.parameters = parameters\n"
        model_rep = model_rep + "\t\tAtomicDEVS.__init__(self, name)\n"
		model_rep = model_rep + "\t\tself.initialState()\n"
        model_rep = model_rep + "\t\tself.my_ports = {"
        all_ports = allAssociationDestinations(model, curr_atomic, "DEVS/DEVSBlockToPort")
        while (read_nr_out(all_ports) > 0):
            curr_port = set_pop(all_ports)
            curr_port_name = cast_value(read_attribute(model, curr_port, "name"))
            curr_port_type = read_type(model, curr_port)
            if (curr_port_type == "DEVS/InputPort"):
                model_rep = model_rep + curr_port_name + ": self.addInPort(" + curr_port_name + ")"
            if (curr_port_type == "DEVS/OutputPort"):
                model_rep = model_rep + curr_port_name + ": self.addOutPort(" + curr_port_name + ")"
            if (read_nr_out(all_ports) > 0):
                model_rep = model_rep + ", "
        model_rep = model_rep + "}\n"
        model_rep = model_rep + "\tdef initialState(self):\n" + cast_string(read_attribute(model, curr_atomic, "initialState")) + "\n"
        model_rep = model_rep + "\tdef timeAdvance(self):\n" + cast_string(read_attribute(model, curr_atomic, "timeAdvance")) + "\n"
        model_rep = model_rep + "\tdef outputFnc(self):\n" + cast_string(read_attribute(model, curr_atomic, "outputFnc")) + "\n"
        model_rep = model_rep + "\tdef intTransition(self):\n" + cast_string(read_attribute(model, curr_atomic, "intTransition")) + "\n"
        model_rep = model_rep + "\tdef extTransition(self, inputs):\n" + cast_string(read_attribute(model, curr_atomic, "extTransition")) + "\n"

    all_coupleds = allInstances(model, "DEVS/CoupledDEVSBlock")
    while (read_nr_out(all_coupleds) > 0):
        curr_coupled = set_pop(all_coupleds)
        model_rep = model_rep + "class " + cast_string(read_attribute(model, curr_coupled, "name")) + "(CoupledDEVS):\n"
        model_rep = model_rep + "\tdef __init__(self, name, parameters):\n"
        model_rep = model_rep + "\t\tCoupledDEVS.__init__(self, name)\n"
		model_rep = model_rep + "\t\tself.parameters = parameters\n"
        model_rep = model_rep + "\t\tself.my_ports = {"
        all_ports = allAssociationDestinations(model, curr_coupled, "DEVS/DEVSBlockToPort")
        while (read_nr_out(all_ports) > 0):
            curr_port = set_pop(all_ports)
            curr_port_name = cast_value(read_attribute(model, curr_port, "name"))
            curr_port_type = read_type(model, curr_port)
            if (curr_port_type == "DEVS/InputPort"):
                model_rep = model_rep + curr_port_name + ": self.addInPort(" + curr_port_name + ")"
            if (curr_port_type == "DEVS/OutputPort"):
                model_rep = model_rep + curr_port_name + ": self.addOutPort(" + curr_port_name + ")"
            if (read_nr_out(all_ports) > 0):
                model_rep = model_rep + ", "
        model_rep = model_rep + "}\n"
        model_rep = model_rep + "\t\tself.submodels = {"
        all_submodels = allAssociationDestinations(model, curr_coupled, "DEVS/SubModel")
        while (read_nr_out(all_submodels) > 0):
            curr_submodel = set_pop(all_submodels)
            curr_submodel_name = cast_value(read_attribute(model, curr_submodel, "name"))
            curr_submodel_type = cast_string(read_attribute(model, curr_submodel, "type"))
			curr_submodel_parameters = cast_string(read_attribute(model, curr_submodel, "parameters"))
            model_rep = model_rep + curr_submodel_name + ": self.addSubModel(" + curr_submodel_type + "(" + curr_submodel_name + ", " + curr_submodel_parameters + ")" + ")"
            if (read_nr_out(all_submodels) > 0):
                model_rep = model_rep + ", "
        model_rep = model_rep + "}\n"
        all_ports = allAssociationDestinations(model, curr_coupled, "DEVS/DEVSBlockToPort")
        while (read_nr_out(all_ports) > 0):
            curr_port = set_pop(all_ports)
            out_channels = allAssociationDestinations(model, curr_port, "DEVS/Channel")
            while (read_nr_out(out_channels) > 0):
                curr_channel = set_pop(out_channels)
                parent = set_pop(allAssociationOrigins(model, curr_channel, "DEVS/DEVSInstanceToPort"))
                model_rep = model_rep + "\t\tself.connectPorts(self.my_ports[" + cast_value(read_attribute(model, curr_port, "name")) + "], self.submodels[" + cast_value(read_attribute(model, parent, "name")) + "].my_ports[" + cast_value(read_attribute(model, curr_channel, "name")) + "])\n"
        all_submodels = allAssociationDestinations(model, curr_coupled, "DEVS/SubModel")
        while (read_nr_out(all_submodels) > 0):
            curr_submodel = set_pop(all_submodels)
            curr_submodel_name = cast_value(read_attribute(model, curr_submodel, "name"))
            all_ports = allAssociationDestinations(model, curr_submodel, "DEVS/DEVSInstanceToPort")
            while (read_nr_out(all_ports) > 0):
                curr_port = set_pop(all_ports)
                out_channels = allAssociationDestinations(model, curr_port, "DEVS/Channel")
                while (read_nr_out(out_channels) > 0):
                    curr_channel = set_pop(out_channels)
                    possible_parent = allAssociationOrigins(model, curr_channel, "DEVS/DEVSInstanceToPort")
                    if (read_nr_out(possible_parent) == 0):
                        model_rep = model_rep + "\t\tself.connectPorts(self.submodels[" + curr_submodel_name + "].my_ports[" + cast_value(read_attribute(model, curr_port, "name")) + "], self.my_ports[" + cast_value(read_attribute(model, curr_channel, "name")) + "])\n"
                    else:
                        parent = set_pop(possible_parent)
                        model_rep = model_rep + "\t\tself.connectPorts(self.submodels[" + curr_submodel_name + "].my_ports[" + cast_value(read_attribute(model, curr_port, "name")) + "], self.submodels[" + cast_value(read_attribute(model, parent, "name")) + "].my_ports[" + cast_value(read_attribute(model, curr_channel, "name")) + "])\n"
        model_rep = model_rep + "\n"

	String port
    String the_input
    String devs_model
	port = comm_connect("pypdevs_batch_simulator")
        
    comm_set(port, model_rep)

	String experiment
	experiment = read_attribute(model, set_pop(allInstances(model, "Experiment/Experiment")), "code")
	comm_set(port, experiment)
    
	the_input = comm_get(port)

	String str
	str = instantiate_node(model, "result/String", "")
	instantiate_attribute(model, str, "value", the_input)

	return True!
