<?xml version="1.0" ?>
<diagram name="DebuggingEnvironment" author="Simon Van Mierlo">
	<description>
		Debugging environment for Dynamic Structure DEVS in HTML + JS (d3/w2ui).
	</description>
	<inport name="ui_input"/>
	<inport name="simulation_input"/>
	<outport name="output"/>
	<class name="MainApp" default="True">
		<relationships>
			<association name="toolbar" class="DebuggingToolbar" min="1" max="1" />
			<association name="visualizer" class="Visualizer" min="1" max="1" />
		</relationships>
		<method name="MainApp">
			<body>
			<![CDATA[
			]]>
			</body>
		</method>
		<scxml initial="creating_toolbar">
			<state id="creating_toolbar">
                <onentry>
                    <raise event="create_instance" scope="cd">
                        <parameter expr="'toolbar'" />
                        <parameter expr="'DebuggingToolbar'" />
                    </raise>
                </onentry>
                <transition target="../creating_visualizer" event="instance_created">
                    <parameter name="association_name" type="string"/>
                    <raise event="start_instance" scope="cd">
                        <parameter expr="association_name"/>
                    </raise>
                </transition>
            </state>
			<state id="creating_visualizer">
                <onentry>
                    <raise event="create_instance" scope="cd">
                        <parameter expr="'visualizer'" />
                        <parameter expr="'Visualizer'" />
                    </raise>
                </onentry>
                <transition target="../running" event="instance_created">
                    <parameter name="association_name" type="string"/>
                    <raise event="start_instance" scope="cd">
                        <parameter expr="association_name"/>
                    </raise>
                </transition>
            </state>
            <state id="running" />
		</scxml>
	</class>
    <class name="DebuggingToolbar">
		<relationships>
			<association name="parent" class="MainApp" min="1" max="1" />
			<association name="buttons" class="Button" />
		</relationships>
		<method name="DebuggingToolbar">
			<body>
			<![CDATA[
                this.visualized_simulator = "NETLOGO"
                this.parameters = {};
                this.buttons = {};
                this.curr_parameter = null;
                this.button_counter = 0;
                if (this.visualized_simulator == "NETLOGO") {
                    this.buttons_to_create = [{parent: this, description: 'Simulate', icon: 'simulate', command: 'simulate'},
                                              {parent: this, description: 'Realtime Simulate', icon: 'simulatert', command: 'realtime', parameter_needed: 'realtime_scale'},
                                              {parent: this, description: 'Realtime Scale', html: 'input size="1" value="1.0" style="border: 1px solid silver"', default: 1.0, parameter: 'realtime_scale'},
                                              {parent: this, description: 'Pause', icon: 'pause', command: 'pause'},
                                              {parent: this, description: 'Big Step', icon: 'bigstep', command: 'big_step'},
                                              {parent: this, description: 'Reset', icon: 'reset', command: 'reset'},
                                              {parent: this, description: 'Add Breakpoint', icon: 'breakpoint', action: function() {breakpoint_dialog.dialog( "open" );}}];
                } else {
                    this.buttons_to_create = [{parent: this, description: 'Simulate', icon: 'simulate', command: 'simulate'},
                                              {parent: this, description: 'Realtime Simulate', icon: 'simulatert', command: 'realtime', parameter_needed: 'realtime_scale'},
                                              {parent: this, description: 'Realtime Scale', html: 'input size="1" value="1.0" style="border: 1px solid silver"', default: 1.0, parameter: 'realtime_scale'},
                                              {parent: this, description: 'Pause', icon: 'pause', command: 'pause'},
                                              {parent: this, description: 'Big Step', icon: 'bigstep', command: 'big_step'},
                                              {parent: this, description: 'Small Step', icon: 'smallstep', command: 'small_step'},
                                              {parent: this, description: 'Reset', icon: 'reset', command: 'reset'},
                                              {parent: this, description: 'Add Breakpoint', icon: 'breakpoint', action: function() {breakpoint_dialog.dialog( "open" );}}];
                }
                this.tb = ui.create_toolbar('DebuggingToolbar');
			]]>
			</body>
		</method>
		<scxml initial="initializing">
            <state id="initializing" initial="check">
                <state id="check">
                    <transition target="../creating_button" cond="this.buttons_to_create.length &gt; 0">
                        <script>
                            if ('parameter' in this.buttons_to_create[0]) {
                                this.curr_parameter = this.buttons_to_create[0]['parameter']
                            }
                        </script>
                        <raise event="create_instance" scope="cd">
                            <parameter expr="'buttons'" />
                            <parameter expr="'Button'" />
                            <parameter expr="'button' + this.button_counter" />
                            <parameter expr="this.tb" />
                            <parameter expr="this.buttons_to_create.shift()" />
                        </raise>
                    </transition>
                    <transition target="../running" cond="this.buttons_to_create.length == 0" />
                </state>
                <state id="creating_button">
                    <transition target="../check" event="instance_created">
                        <parameter name="association_name" type="string"/>
                        <raise event="start_instance" scope="cd">
                            <parameter expr="association_name"/>
                        </raise>
                        <script>
                            if (this.curr_parameter) {
                                this.parameters[this.curr_parameter] = association_name;
                                this.curr_parameter = null;
                            }
                            this.buttons['button' + this.button_counter] = association_name;
                            this.button_counter += 1;
                        </script>
                    </transition>
                </state>
                <state id="running">
                    <transition target="../getting_parameter" event="get_parameter">
                        <parameter name="the_parameter" />
                        <parameter name="respond_id" />
                        <raise event="get_parameter" target="this.parameters[the_parameter]" />
                        <script>
                            this.respond_id = respond_id;
                        </script>
                    </transition>
                </state>
                <state id="getting_parameter">
                    <transition target="../running" event="parameter_reply">
                        <parameter name="parameter_value" />
                        <raise event="parameter_reply" target="this.buttons[this.respond_id]">
                            <parameter expr="parameter_value" />
                        </raise>
                    </transition>
                </state>
            </state>
        </scxml>
    </class>
    <class name="Button">
        <inport name="button_ui_input" />
		<relationships>
			<association name="parent" class="DebuggingToolbar" min="1" max="1" />
		</relationships>
		<method name="Button">
            <parameter name="button_id" />
            <parameter name="toolbar" />
            <parameter name="parameters" />
			<body>
			<![CDATA[
                this.button_id = button_id;
                this.toolbar = toolbar;
                this.action = null;
                this.command = null;
                if ('parameter_needed' in parameters) {
                    this.parameter_needed = parameters['parameter_needed'];
                } else {
                    this.parameter_needed = null;
                }
                if ('html' in parameters) {
                    var the_html = parameters['html']
                    the_html += ' id="' + this.button_id + '_input" onchange="ui.parameter_changed(\'' + button_id + '\');"'
                    this.btn = ui.create_tb_element(this.button_id, '<' + the_html + ' />', parameters['default'], this.toolbar, this.controller, this.inports['button_ui_input']);
                } else if ('action' in parameters) {
                    this.action = parameters['action'];
                    this.btn = ui.create_button(this.button_id, parameters['description'], parameters['icon'], this.toolbar, this.controller, this.inports['button_ui_input']);
                } else {
                    this.command = parameters['command'];
                    this.btn = ui.create_button(this.button_id, parameters['description'], parameters['icon'], this.toolbar, this.controller, this.inports['button_ui_input']);
                }
			]]>
			</body>
		</method>
		<scxml initial="listening">
            <state id="listening">
                <transition target="." event="mouse_press" port="button_ui_input" cond="this.action">
                    <script>
                        this.action();
                    </script>
                </transition>
                <transition target="." event="mouse_press" port="button_ui_input" cond="this.parameter_needed == null &amp;&amp; this.command">
                    <raise event="debugging_command" port="output">
                        <parameter expr="this.command" />
                    </raise>
                </transition>
                <transition target="../getting_parameter" event="mouse_press" port="button_ui_input" cond="this.parameter_needed != null &amp;&amp; this.command">
                    <raise event="get_parameter" target="'parent'">
                        <parameter expr="this.parameter_needed" />
                        <parameter expr="this.button_id" />
                    </raise>
                </transition>
                <transition target="." event="get_parameter">
                    <raise event="parameter_reply" target="'parent'">
                        <parameter expr="this.btn.value" />
                    </raise>
                </transition>
            </state>
            <state id="getting_parameter">
                <transition target="../listening" event="parameter_reply">
                    <parameter name="the_parameter" />
                    <script>
                        var the_parameters = {};
                        the_parameters[this.parameter_needed] = the_parameter;
                    </script>
                    <raise event="debugging_command" port="output">
                        <parameter expr="this.command" />
                        <parameter expr="the_parameters" />
                    </raise>
                </transition>
            </state>
        </scxml>
    </class>
    <class name="Visualizer">
		<relationships>
			<association name="parent" class="MainApp" min="1" max="1" />
		</relationships>
		<method name="Visualizer">
			<body>
                this.visualized_simulator = "NETLOGO"

                the_controller = this.controller;
                this.simulation_info = d3.select("body").append("div")
                                                        .attr("class", "simulationInfo")
                                                        .style("margin", "5px")
                                                        .style("display", "block");
                this.simulation_time = this.simulation_info.append("span")
                                                           .append("text")
                                                           .text("SIMULATION TIME: (not started)")
                                                           .style("float", "left");
                this.simulation_steps = this.simulation_info.append("span")
                                                            .style("margin", "5px")
                                                            .style("float", "left")
                                                            .attr("class", "invisibleInfo")
                                                            .attr("id", "smallStepInfo");
                this.simulation_steps.selectAll("div").data([0,1,2,3,4,5,6,7])
                                                      .enter()
                                                        .append("div")
                                                        .attr("id", function(d) {return "smallStepInfo_" + d})
                                                        .attr("class", "smallStepInfo inactive")
                                                        .style("transform", function(d) {return "translate(" + d * 5 + "px, -4px) rotate(45deg)"});
                d3.select("body").append("br");
                this.breakpoint_info = d3.select("body").append("div")
                                                        .attr("class", "breakpointInfo")
                                                        .style("margin", "5px")
                                                        .style("display", "block");
                this.breakpoint_text = this.breakpoint_info.append("span")
                                                           .append("text")
                                                           .text("BREAKPOINTS: ")
                                                           .style("float", "left");
                this.breakpoint_infos = this.breakpoint_info.append("span")
                                                            .style("margin", "5px")
                                                            .style("float", "left")
                                                            .attr("id", "breakpointInfos");
                this.breakpoints = [];
                this.port_connections = [];
                this.loc_to_item = {};
                event_to_inject = undefined;
                god_event_to_process = undefined;
                
                // TODO: this is domain-specific!
                this.particle_id_to_item = {};
                
                var margin = {top: 50, right: 0, bottom: 0, left: 0},
                    width = 960 - margin.right - margin.left,
                    height = 1024 - margin.top - margin.bottom;
                
                this.node_id = 0;
                if (this.visualized_simulator == "NETLOGO") {
                    this.data = [{'name': '&lt;root&gt;', 'children': [], 'loc': '', 'id': this.node_id}];
                    this.node_id++;
                } else {
                    this.data = [];
                }
                this.tree = d3.layout.tree()
                    .size([width, height]);
                this.diagonal = d3.svg.diagonal();
                this.port_connection_diagonal = d3.svg.diagonal().projection(function(d) {return [d.x, d.y]});
                this.parent_svg = d3.select("body").append("svg")
                    .attr("width", width + margin.right + margin.left)
                    .attr("height", height + margin.top + margin.bottom);
                
                var defs = this.parent_svg.append('svg:defs')

                var markers = [{name: 'arrow', path: 'M2,2 L2,11 L10,6 L2,2', fill: "red"},
                               {name: 'arrow_green', path: 'M2,2 L2,11 L10,6 L2,2', fill: "green"}];
                var marker = defs.selectAll('marker')
                                 .data(markers)
                                 .enter()
                                 .append('svg:marker')
                                   .attr('id', function(d){ return 'marker_' + d.name})
                                   .attr('markerHeight', 13)
                                   .attr('markerWidth', 13)
                                   .attr('markerUnits', 'strokeWidth')
                                   .attr('orient', 'auto')
                                   .attr('refX', 2)
                                   .attr('refY', 6)
                                   .append('svg:path')
                                     .attr('d', function(d){ return d.path })
                                     .attr('fill', function(d){ return d.fill });
                                     
                this.svg = this.parent_svg.append("g")
                                          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

                this_object = this;
                
                function godEvent() {
                    if (this_object.visualized_simulator == "NETLOGO") {
                        god_event_to_process = {'turtle': $('#currLoc').text(), 'attribute': $('#godEventName').val(), 'value': eval($('#godEventValue').val())};
                        the_controller.addInput(new Event("process_god_event", "ui_input", [god_event_to_process]), 0.0);
                        dialog.dialog("close");
                    } else {
                        god_event_to_process = {'model': $('#currLoc').text(), 'attribute': $('#godEventName').val(), 'value': eval($('#godEventValue').val())};
                        the_controller.addInput(new Event("process_god_event", "ui_input", [god_event_to_process]), 0.0);
                        dialog.dialog("close");
                    }
                }
                
                dialog = $( "#godEventPopup" ).dialog({
                  autoOpen: false,
                  height: 200,
                  width: 325,
                  modal: true,
                  buttons: {
                    "Submit": godEvent,
                    Cancel: function() {
                      dialog.dialog( "close" );
                    }
                  },
                  close: function() {
                    form[ 0 ].reset();
                  }
                }).css("font-size", "14px");;
             
                form = dialog.find( "form" ).on( "submit", function( event ) {
                  event.preventDefault();
                  godEvent();
                });
                
                function injectEvent() {
                    event_to_inject = {'port': $('#currLoc').text(), 'event': eval($('#injectEvent').val()), 'time': eval($('#injectTime').val())};
                    the_controller.addInput(new Event("inject_event", "ui_input", [event_to_inject]), 0.0);
                    inject_dialog.dialog("close");
                }
                
                inject_dialog = $( "#injectEventPopup" ).dialog({
                  autoOpen: false,
                  height: 200,
                  width: 325,
                  modal: true,
                  buttons: {
                    "Submit": injectEvent,
                    Cancel: function() {
                      inject_dialog.dialog( "close" );
                    }
                  },
                  close: function() {
                    inject_form[ 0 ].reset();
                  }
                }).css("font-size", "14px");
             
                inject_form = inject_dialog.find( "form" ).on( "submit", function( event ) {
                  event.preventDefault();
                  injectEvent();
                });

                if (this.visualized_simulator == "NETLOGO") {
                    $('#breakpointFunction').text("def breakpoint(time, turtles):\n")
                }
                
                function addBreakpoint() {
                    breakpoint_to_add = [$('#breakpointName').val(), $('#breakpointFunction').val(), $('#breakpointEnabled').is(":checked"), $('#breakpointDisableOnTrigger').is(":checked")];
                    the_controller.addInput(new Event("add_breakpoint", "ui_input", [breakpoint_to_add]), 0.0);
                    breakpoint_dialog.dialog("close");
                }
                
                breakpoint_dialog = $( "#breakpointPopup" ).dialog({
                  autoOpen: false,
                  height: 400,
                  width: 600,
                  modal: true,
                  buttons: {
                    "Submit": addBreakpoint,
                    Cancel: function() {
                      breakpoint_dialog.dialog( "close" );
                    }
                  },
                  close: function() {
                    breakpoint_form[ 0 ].reset();
                  }
                }).css("font-size", "14px");
             
                breakpoint_form = breakpoint_dialog.find( "form" ).on( "submit", function( event ) {
                  event.preventDefault();
                  addBreakpoint();
                });
			</body>
		</method>
        <method name="update_vis">
            <parameter name="structural_changes" />
            <body>
                if (this.visualized_simulator == "NETLOGO") {
                    var created_turtles = [],
                        deleted_turtles = [];
                    if ('CREATED_TURTLES' in structural_changes) {
                        created_turtles = structural_changes['CREATED_TURTLES'];
                    }
                    if ('DELETED_TURTLES' in structural_changes) {
                        deleted_turtles = structural_changes['DELETED_TURTLES'];
                    }

                    var node_id = this.node_id;
                    var loc_to_item = this.loc_to_item;
                    var data = this.data;
                    created_turtles.forEach(function(item) {
                        var node = {'name': 'turtle[' + item + ']', 'children': [], 'id': node_id++, 'turtle_id': item}
                        if (!data[0].hasOwnProperty('children')) {
                            data[0]['children'] = [];
                        }
                        data[0].children.push(node);
                        loc_to_item[item] = node;
                    });
                    deleted_turtles.forEach(function(item) {
                        curr_array = data;
                        data[0]['children'] = data[0]['children'].filter(function(el) {return el['name'] != ('turtle[' + item + ']')});
                    });

                    this.node_id = node_id;
                    this.data = data;

                    var nodes = this.tree.nodes(this.data[0]),
                        links = this.tree.links(nodes);
                    nodes.forEach(function(d, i) {
                                    d.y = d.depth * 100 + i * 40;
                                  });
                    
                    // Declare the nodes...
                    var node = this.svg.selectAll("g.node")
                                       .data(nodes, function(d) { return d.id; });
                                  
                    // Enter the nodes.
                    var nodeEnter = node.enter().append("g")
                                                .attr("class", "node")
                                                .attr("id", function(d) {return 'instance_' + d.id;})
                                                .attr("transform", function(d) { 
                                                                        return "translate(" + d.x + "," + d.y + ")";
                                                                   });
                    nodeEnter.append("rect")
                             .attr("width", 120)
                             .attr("height", 25)
                             .attr("transform", "translate(-60, 0)")
                             .on("click", function(d) {
                                console.log(JSON.stringify(d.state, null, 2));
                             })
                             .on("mouseover", function(d) {
                                                var node = d3.select("#instance_" + d.id)
                                                var stateInfo = node.selectAll(".stateInfo")
                                                                    .data(function(n) {if (n.state) {return [n.state]} else {return []}}, function(d) {return d.id});
                                                var stateInfoEnter = stateInfo.enter().append("text")
                                                                                      .attr("transform", "translate(-60, 60)")
                                                                                      .attr("id", this.node_id++)
                                                                                      .attr("class", "stateInfo");
                                                var stateInfoText = stateInfo.selectAll("tspan")
                                                                             .data(function(d) {return JSON.stringify(d, null, 2).split("\n")});
                                                var stateInfoTextEnter = stateInfoText.enter().append("tspan")
                                                                                              .attr("x", "0.0")
                                                                                              .attr("dy", "1.4em")
                                                                                              .attr("xml:space", "preserve")
                                                                                              .text(function(d) {return d});
                                             })
                             .on("mouseout", function(d) {
                                                var node = d3.select("#instance_" + d.id)
                                                var stateInfo = node.selectAll(".stateInfo");
                                                stateInfo.selectAll("tspan").data([]).exit().remove();
                                             })
                             .on("contextmenu", function (d, i) {
                                $( "#currLoc" ).html(d.turtle_id);
                                d3.event.preventDefault();
                                if (!d.children) {
                                    dialog.dialog( "open" );
                                }
                             });
                    nodeEnter.append("text")
                             .attr("y", 12)
                             .attr("dy", ".35em")
                             .attr("text-anchor", "middle")
                             .text(function(d) { return d.name; })
                             .style("fill-opacity", 1);

                     // Declare the links...
                    var link = this.svg.selectAll("path.link")
                                       .data(links);
                      
                    // Enter the links.
                    link.enter().insert("path", "g")
                        .attr("class", "link")
                        .attr("d", this.diagonal);

                    // Update the nodes.
                    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
                    node.classed("coupled", function(d) {return d.name == '&lt;root&gt;'});

                    // Transition links to their new position.
                    link.attr("d", this.diagonal);

                    // Remove nodes and links.
                    node.exit().remove();
                    link.exit().remove();
                } else {                
                    d3.select("#smallStepInfo_7").classed("inactive", false);
                    var created_models = [],
                        created_ports = [],
                        connected_ports = [],
                        deleted_models = [],
                        deleted_ports = [],
                        disconnected_ports = [];
                        
                    if ('CREATED_MODELS' in structural_changes) {
                        created_models = structural_changes['CREATED_MODELS'];
                    }
                    if ('CREATED_PORTS' in structural_changes) {
                        created_ports = structural_changes['CREATED_PORTS'];
                    }
                    if ('CONNECTED_PORTS' in structural_changes) {
                        connected_ports = structural_changes['CONNECTED_PORTS'];
                    }
                    if ('DELETED_MODELS' in structural_changes) {
                        deleted_models = structural_changes['DELETED_MODELS'];
                    }
                    if ('DELETED_PORTS' in structural_changes) {
                        deleted_ports = structural_changes['DELETED_PORTS'];
                    }
                    if ('DISCONNECTED_PORTS' in structural_changes) {
                        disconnected_ports = structural_changes['DISCONNECTED_PORTS'];
                    }
                    
                    // sort according to their depth (amounts of dots in their name)
                    created_models.sort(function(a, b) {
                        return (a.match(/./g) || []).length - (b.match(/./g) || []).length
                    })
                                    
                    data = this.data;
                                    
                    var node_id = this.node_id;
                    var loc_to_item = this.loc_to_item;
                    created_models.forEach(function(item) {
                        splitted_path = item.split('.');
                        element_to_insert = data;
                        while (splitted_path.length > 1) {
                            curr_name = splitted_path.shift();
                            element_to_insert = element_to_insert.find(function(el) {return el['name'] == curr_name}).children;
                        }
                        var node = {'name': splitted_path[0], 'children': [], 'ports': [], 'loc': item, 'id': node_id++}
                        element_to_insert.push(node);
                        loc_to_item[item] = node;
                    });
                    
                    created_ports.forEach(function(item) {
                        splitted_path = item[0].split('.');
                        curr_array = data;
                        while (splitted_path.length > 2) {
                            curr_name = splitted_path.shift();
                            curr_array = curr_array.find(function(el) {return el['name'] == curr_name}).children;
                        }
                        ports = curr_array.find(function(el) {return el['name'] == splitted_path[0]})['ports'];
                        var node = {'name': splitted_path[1], 'is_input': item[1], 'loc': item[0], 'id': node_id++};
                        ports.push(node);
                        loc_to_item[item[0]] = node;
                    });
                    this.node_id = node_id;

                    port_connections = this.port_connections
                    connected_ports.forEach(function(item) {
                        splitted_path_src = item[0].split('.');
                        curr_array = data;
                        while (splitted_path_src.length > 2) {
                            curr_name = splitted_path_src.shift();
                            curr_array = curr_array.find(function(el) {return el['name'] == curr_name}).children;
                        }
                        src_parent = curr_array.find(function(el) {return el['name'] == splitted_path_src[0]});
                        src = src_parent['ports'].find(function(el) {return el['name'] == splitted_path_src[1]});
                        splitted_path_dst = item[1].split('.');
                        curr_array = data;
                        while (splitted_path_dst.length > 2) {
                            curr_name = splitted_path_dst.shift();
                            curr_array = curr_array.find(function(el) {return el['name'] == curr_name}).children;
                        }
                        dst_parent = curr_array.find(function(el) {return el['name'] == splitted_path_dst[0]});
                        dst = dst_parent['ports'].find(function(el) {return el['name'] == splitted_path_dst[1]});
                        port_connections.push({'source': src, 'target': dst});
                    });
                    
                    disconnected_ports.forEach(function(item) {
                        port_connections = port_connections.filter(function(el) {return el.source.loc != item[0] || el.target.loc != item[1];});
                    });
                    this.port_connections = port_connections
                    
                    deleted_ports.forEach(function(item) {
                        splitted_path = item.split('.');
                        curr_array = data;
                        while (splitted_path.length > 2) {
                            curr_name = splitted_path.shift();
                            curr_array = curr_array.find(function(el) {return el['name'] == curr_name}).children;
                        }
                        parent = curr_array.find(function(el) {return el['name'] == splitted_path[0]});
                        parent['ports'] = parent['ports'].filter(function(el) {return el['name'] != splitted_path[1]});
                    });
                    
                    deleted_models.forEach(function(item) {
                        splitted_path = item.split('.');
                        curr_array = data;
                        while (splitted_path.length > 2) {
                            curr_name = splitted_path.shift();
                            curr_array = element_to_insert.find(function(el) {return el['name'] == curr_name}).children;
                        }
                        parent = curr_array.find(function(el) {return el['name'] == splitted_path[0]});
                        parent['children'] = parent['children'].filter(function(el) {return el['name'] != splitted_path[1]});
                    });
                    
                    this.data = data;
                    
                    var nodes = this.tree.nodes(this.data[0]),
                        links = this.tree.links(nodes);
                    nodes.forEach(function(d, i) {
                                    d.y = d.depth * 100 + i * 40
                                    d.ports.forEach(function(p, i) {p.dx = 13, p.dy = 18; p.x = (d.x - 40) + i * p.dx; p.y = d.y + p.dy;});
                                  });
                    
                    // Declare the nodes...
                    var node = this.svg.selectAll("g.node")
                                       .data(nodes, function(d) { return d.id; });
                                  
                    // Enter the nodes.
                    var nodeEnter = node.enter().append("g")
                                                .attr("class", "node")
                                                .attr("id", function(d) {return 'instance_' + d.id;})
                                                .attr("transform", function(d) { 
                                                                        return "translate(" + d.x + "," + d.y + ")";
                                                                   });
                    nodeEnter.append("rect")
                             .attr("width", 120)
                             .attr("height", 25)
                             .attr("transform", "translate(-60, 0)")
                             .on("click", function(d) {
                                console.log(JSON.stringify(d.state, null, 2));
                             })
                             .on("mouseover", function(d) {
                                                var node = d3.select("#instance_" + d.id)
                                                var stateInfo = node.selectAll(".stateInfo")
                                                                    .data(function(n) {if (n.state) {return [n.state]} else {return []}}, function(d) {return d.id});
                                                var stateInfoEnter = stateInfo.enter().append("text")
                                                                                      .attr("transform", "translate(-60, 60)")
                                                                                      .attr("id", this.node_id++)
                                                                                      .attr("class", "stateInfo");
                                                var stateInfoText = stateInfo.selectAll("tspan")
                                                                             .data(function(d) {return JSON.stringify(d, null, 2).split("\n")});
                                                var stateInfoTextEnter = stateInfoText.enter().append("tspan")
                                                                                              .attr("x", "0.0")
                                                                                              .attr("dy", "1.4em")
                                                                                              .attr("xml:space", "preserve")
                                                                                              .text(function(d) {return d});
                                             })
                             .on("mouseout", function(d) {
                                                var node = d3.select("#instance_" + d.id)
                                                var stateInfo = node.selectAll(".stateInfo");
                                                stateInfo.selectAll("tspan").data([]).exit().remove();
                                             })
                             .on("contextmenu", function (d, i) {
                                $( "#currLoc" ).html(d.loc);
                                d3.event.preventDefault();
                                if (!d.children) {
                                    dialog.dialog( "open" );
                                }
                             });
                    nodeEnter.append("text")
                             .attr("y", 12)
                             .attr("dy", ".35em")
                             .attr("text-anchor", "middle")
                             .text(function(d) { return d.name; })
                             .style("fill-opacity", 1);
                    nodeEnter.append("text")
                             .attr("class", "timeNext")
                             .attr("y", -10)
                             .attr("x", 30)
                             .attr("dy", ".35em")
                             .attr("text-anchor", "middle")
                             .text("TN: --")
                             .style("fill-opacity", 1);
                             
                    port = node.selectAll("g.port")
                               .data(function(n) {return n.ports}, function(d) { return d.id; })
                    
                    portEnter = port.enter().append("g")
                                            .attr("class", "port invisible")
                                            .attr("id", function(d) {return 'port_' + d.id;})
                                            .on("mouseover", function(d) {
                                                                d3.selectAll(".source_" + d.id).classed("invisibleLink", false)
                                                                                               .classed("input", false);
                                                                d3.selectAll(".target_" + d.id).classed("invisibleLink", false)
                                                                                               .classed("input", true);
                                                                port_connections.forEach(function(port_connection) {
                                                                    if (port_connection.source.id == d.id) {
                                                                        d3.select('#port_' + port_connection.target.id).attr("class", "port visible");
                                                                    } else if (port_connection.target.id == d.id) {
                                                                        d3.select('#port_' + port_connection.source.id).attr("class", "port visible");
                                                                    }
                                                                });
                                                                d3.select(this).attr("class", "port visible");
                                                             })
                                            .on("mouseout", function(d) {
                                                                d3.selectAll(".source_" + d.id).classed("invisibleLink", true);
                                                                d3.selectAll(".target_" + d.id).classed("invisibleLink", true);
                                                                d3.selectAll(".port").attr("class", "port invisible");
                                                            })
                                            .on("click", function (d, i) {
                                                $('#currLoc').html(d.loc);
                                                d3.event.preventDefault();
                                                if (d.is_input) {
                                                    inject_dialog.dialog( "open" );
                                                }
                                            });
                    portEnter.append("rect")
                             .attr("width", 10)
                             .attr("height", 10)
                             .style("fill", function(d) {return d.is_input ? "green" : "purple";})
                             .attr("transform", "rotate(45)");
                    portEnter.append("text")
                             .attr("dy", ".35em")
                             .attr("text-anchor", "left")
                             .text(function(d) {return d.name;})
                             .attr("transform", "translate(0, 20) rotate(30)");
                    
                    port.attr("transform", function(d, i) {return "translate(" + (-40 + i * d.dx) + ", " + d.dy + ")"});
                                      
                    // Declare the links...
                    var link = this.svg.selectAll("path.link")
                                       .data(links);
                      
                    // Enter the links.
                    link.enter().insert("path", "g")
                        .attr("class", "link")
                        .attr("d", this.diagonal);
                    
                    // Declare port connections...
                    var port_connection = this.svg.selectAll("path.portConnection")
                                       .data(port_connections);
                    
                    // Enter port connections.
                    port_connection.enter().insert("path", "g")
                        .attr("class", "invisibleLink portConnection");
                    
                    // Update the nodes.
                    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
                    node.classed("coupled", function(d) {return d.children});

                    // Transition links to their new position.
                    link.attr("d", this.diagonal);

                    // Transition links to their new position.
                    port_connection.attr("d", function(d) {
                                                var dx = d.target.x - d.source.x,
                                                    dy = d.target.y - d.source.y,
                                                    dr = Math.sqrt(dx * dx + dy * dy)/4,
                                                    mx = d.source.x + dx/2,
                                                    my = d.source.y + dy/2 + 30;
                                                return [
                                                  "M",d.source.x,d.source.y+5,
                                                  "T",mx,my,
                                                  "T",d.target.x,d.target.y+5
                                                ].join(" ");
                                              })
                                   .attr("class", function(d) {return "invisibleLink portConnection source_" + d.source.id + " target_" + d.target.id});
                    
                    // Remove nodes and links.
                    node.exit().remove();
                    link.exit().remove();
                    port.exit().remove();
                    port_connection.exit().remove();
                }
            </body>
        </method>
        <method name="visualize_initial_state">
            <parameter name="initial_states" />
            <body>
                if (this.visualized_simulator == "NETLOGO") {
                    for (var loc in initial_states) {
                        var item = this.loc_to_item[loc];
                        item.state = initial_states[loc];
                    }
                } else {
                    d3.select("#smallStepInfo").classed("invisibleInfo", true);
                    d3.selectAll("g.node").attr("class", "node")
                                          .classed("coupled", function(d) {return d.children});
                    d3.selectAll("circle.inmessage").data([]).exit().remove();
                    d3.selectAll("circle.outmessage").data([]).exit().remove();
                    d3.selectAll(".portConnection").classed("invisibleLink", true);
                    d3.selectAll(".port").classed("visible", false);
                    d3.selectAll(".port").classed("invisible", true);
                    d3.selectAll(".stateInfo").data([]).exit().remove();
                    
                    for (var loc in initial_states) {
                        var item = this.loc_to_item[loc];
                        d3.select("#instance_" + item.id + " .timeNext").text("TN: " + initial_states[loc][0][0] + "/" + initial_states[loc][0][1])
                        item.state = initial_states[loc][1];
                        if (item.state.particle_id) {
                            this.particle_id_to_item[item.state.particle_id] = item; // TODO: this is somewhat ugly, we're making a lot of assumptions here and it's no longer domain-independent!
                        }
                    }
                }
            </body>
        </method>
        <method name="visualize_new_state">
            <parameter name="new_states" />
            <parameter name="new_tn" />
            <body>
                d3.select("#smallStepInfo").classed("invisibleInfo", true);
                d3.selectAll("g.node").attr("class", "node")
                                      .classed("coupled", function(d) {return d.children});
                d3.selectAll("circle.inmessage").data([]).exit().remove();
                d3.selectAll("circle.outmessage").data([]).exit().remove();
                d3.selectAll(".portConnection").classed("invisibleLink", true);
                d3.selectAll(".port").classed("visible", false);
                d3.selectAll(".port").classed("invisible", true);
                d3.selectAll(".stateInfo").data([]).exit().remove();
                
                for (var loc in new_tn) {
                    var item = this.loc_to_item[loc];
                    d3.select("#instance_" + item.id + " .timeNext").text("TN: " + new_tn[loc][0] + "/" + new_tn[loc][1])
                    item.state = new_states[loc];
                    if (item.state.particle_id != undefined) {
                        this.particle_id_to_item[item.state.particle_id] = item; // TODO: this is somewhat ugly, we're making a lot of assumptions here and it's no longer domain-independent!
                    }
                }
            </body>
        </method>
        <method name="visualize_imminents">
            <parameter name="imminents" />
            <body>
                d3.selectAll(".portConnection").classed("invisibleLink", true);
                d3.selectAll(".port").classed("visible", false);
                d3.selectAll(".port").classed("invisible", true);
                d3.selectAll("circle.inmessage").data([]).exit().remove();
                d3.selectAll("circle.outmessage").data([]).exit().remove();
                if (this.transitioning_nodes) {
                    this.transitioning_nodes.forEach(function(n) {n.attr("class", "node")
                                                                   .classed("coupled", function(d) {return d.children});});
                }
                
                d3.select("#smallStepInfo").classed("invisibleInfo", false);
                d3.selectAll(".smallStepInfo").classed("inactive", true);
                d3.select("#smallStepInfo_0").classed("inactive", false);
                var loc_to_item = this.loc_to_item;
                this.imminents = imminents;
                imminents.forEach(function(imminent) {
                                    d3.select("#instance_" + loc_to_item[imminent].id).classed("imminent", true);
                                 })
            </body>
        </method>
        <method name="visualize_selected_imminent">
            <parameter name="selected_imminent" />
            <body>
                d3.select("#smallStepInfo_1").classed("inactive", false);
                var loc_to_item = this.loc_to_item;
                this.imminents.forEach(function(imminent) {
                                         if (!(imminent == selected_imminent)) {
                                            d3.select("#instance_" + loc_to_item[imminent].id).classed("imminent", false);
                                         }
                                      })
            </body>
        </method>
        <method name="visualize_messages">
            <parameter name="bag" />
            <parameter name="msg_type" />
            <body>
                var total_msgs = [];
                for (var key in bag) {
                    var msgs = bag[key];
                    var port = this.loc_to_item[key];
                    if (port != undefined) {
                        msgs[0].port = port;
                        Array.prototype.push.apply(total_msgs, msgs);
                    }
                }
                var msgs_vis = this.svg.selectAll("circle." + msg_type)
                                       .data(total_msgs);
                var msg_enter = msgs_vis.enter().append("circle")
                                                .attr("class", msg_type)
                                                .attr("id", function(m) {return "msg_" + m.port.id;})
                                                .attr("r", 5)
                                                .attr("transform", function(m) {return "translate(" + m.port.x + "," + (m.port.y + 22) + ")"})
                                                .on("click", function(d) {console.log(d[0])});
            </body>
        </method>
        <method name="visualize_inbags">
            <parameter name="inbags" />
            <body>                        
                d3.select("#smallStepInfo_3").classed("inactive", false);
                function transition(circle, path, source_port_vis, target_port_vis) {
                    circle.transition()
                          .duration(3000)
                          .attrTween("transform", translateAlong(path.node()))
                          .each("end", function() {
                                            path.classed("invisibleLink", true);
                                            source_port_vis.classed("invisible", true);
                                            target_port_vis.classed("invisible", true);
                                            source_port_vis.classed("visible", false);
                                            target_port_vis.classed("visible", false);
                                            circle.attr("class", "inmessage");
                                        });
                }

                // Returns an attrTween for translating along the specified path element.
                function translateAlong(path) {
                  var l = path.getTotalLength();
                  return function(d, i, a) {
                    return function(t) {
                      var p = path.getPointAtLength(t * l);
                      return "translate(" + p.x + "," + (p.y + 17) + ")";
                    };
                  };
                }
                var outports_visited = []
                for (var key in inbags) {
                    if (inbags[key].length == 2) {
                        var msgs = inbags[key][1];
                        var inport = this.loc_to_item[key];
                        if (inport != undefined) {
                            var circle = undefined;
                            var outport_id = this.loc_to_item[inbags[key][0]].id;
                            if (outports_visited.indexOf(outport_id) > -1) {
                                circle = d3.select('#msg_' + outport_id);
                                var parent = d3.select(circle.node().parentNode);
                                circle = parent.append("circle")
                                               .attr("class", "outmessage")
                                               .attr("id", circle.id + outports_visited.indexOf(outport_id))
                                               .attr("r", 5)
                                               .attr("transform", circle.transform)
                                               .on("click", (function(msgs) {return function(d) {console.log(msgs[0])}})(msgs));
                            } else {
                                circle = d3.select('#msg_' + outport_id);
                                circle.on("click", (function(msgs) {return function(d) {console.log(msgs[0])}})(msgs));
                            }
                            var path = d3.select(".source_" + outport_id + ".target_" + inport.id);
                            var source_port_vis = d3.select("#port_" + outport_id)
                            var target_port_vis = d3.select("#port_" + inport.id)
                            source_port_vis.classed("invisible", false);
                            target_port_vis.classed("invisible", false);
                            source_port_vis.classed("visible", true);
                            target_port_vis.classed("visible", true);
                            path.classed("invisibleLink", false);
                            transition(circle, path, source_port_vis, target_port_vis);
                            outports_visited.push(outport_id);
                        }
                    } else {
                        var msgs = inbags[key][0];
                        var inport = this.loc_to_item[key];
                        this.svg.append("circle")                        
                                .attr("class", "inmessage")
                                .attr("id", "msg_" + inport.id)
                                .attr("r", 5)
                                .attr("transform", "translate(" + inport.x + "," + (inport.y + 22) + ")")
                                .on("click", (function(msgs) {return function(d) {console.log(msgs[0])}})(msgs));
                    }
                }
            </body>
        </method>
        <method name="visualize_transitioning">
            <parameter name="transitioning" />
            <body>
                var transitioning_nodes = [];
                var loc_to_item = this.loc_to_item;
                Object.keys(transitioning).forEach(function(key) {
                                                        transitioning_nodes.push(d3.select("#instance_" + loc_to_item[key].id).classed(transitioning[key], true));
                                                     });
                this.transitioning_nodes = transitioning_nodes;
            </body>
        </method>
        <method name="handle_internal_state_change">
            <parameter name="new_internal_states" />
            <body>
                d3.select("#smallStepInfo_5").classed("inactive", false);
                for (var loc in new_internal_states) {
                    var item = this.loc_to_item[loc];
                    item.state = new_internal_states[loc];
                }
                if (this.transitioning_nodes) {
                    this.transitioning_nodes.forEach(function(n) {n.attr("class", "node")
                                                                   .classed("coupled", function(d) {return d.children});});
                }
                         
                var node = this.svg.selectAll("g.node");
                var stateInfo = node.selectAll("g.state");
                stateInfo.text(function(d) {return JSON.stringify(d);});
            </body>
        </method>
        <method name="visualize_new_tn">
            <parameter name="new_tn" />
            <body>
                d3.select("#smallStepInfo_6").classed("inactive", false);
                for (var loc in new_tn) {
                    var item = this.loc_to_item[loc];
                    d3.select("#instance_" + item.id + " .timeNext").text("TN: " + new_tn[loc][0] + "/" + new_tn[loc][1])
                }
            </body>
        </method>
        <method name="select_instance">
            <parameter name="instance_id" />
            <body>
                d3.selectAll(".stateInfo").data([]).exit().remove();
                if (instance_id in this.particle_id_to_item) {
                    var d = this.particle_id_to_item[instance_id];
                    var node = d3.select("#instance_" + d.id)
                    var stateInfo = node.selectAll(".stateInfo")
                                        .data(function(n) {if (n.state) {return [n.state]} else {return []}}, function(d) {return d.id});
                    var stateInfoEnter = stateInfo.enter().append("text")
                                                          .attr("transform", "translate(-60, 60)")
                                                          .attr("id", this.node_id++)
                                                          .attr("class", "stateInfo");
                    var stateInfoText = stateInfo.selectAll("tspan")
                                                 .data(function(d) {return JSON.stringify(d, null, 2).split("\n")});
                    var stateInfoTextEnter = stateInfoText.enter().append("tspan")
                                                                  .attr("x", "0.0")
                                                                  .attr("dy", "1.4em")
                                                                  .attr("xml:space", "preserve")
                                                                  .text(function(d) {return d});
                }
            </body>
        </method>
        <method name="visualize_breakpoints">
            <body>
                if (this.visualized_simulator == "PYDEVS") {
                    for (idx in this.breakpoints) {
                        var curr_bp = this.breakpoints[idx];
                        if (curr_bp.triggered) {
                            this.visualize_messages(curr_bp.outbag, 'outmessage');
                            for (var key in curr_bp.inbags) {
                                if (curr_bp.inbags[key].length == 2) {
                                    curr_bp.inbags[key] = [curr_bp.inbags[key][1]];
                                }
                            }
                            this.visualize_messages(curr_bp.inbags, 'inmessage');
                            this.visualize_transitioning(curr_bp.transitioned);
                        }
                    }
                }
                
                var curr_bps = this.breakpoint_infos.selectAll("div").data(this.breakpoints)
                
                curr_bps_enter = curr_bps.enter().append("div")                
                                                 .attr("id", function(d) {return "breakpoint_" + d.name})
                                                 .attr("class", "breakpoint")
                                                 .style("transform", function(d, i) {return "translate(" + i * 5 + "px, -8px)"})
                                                 .style("float", "left");
                curr_bps_enter.append("text")
                              .text(function(d) {return d.name})
                              .on("click", function(d) {
                                d.enabled = !d.enabled;
                                the_controller.addInput(new Event("toggle_breakpoint", "ui_input", [d.name, d.enabled]), 0.0);
                              })
                              .on('mouseover', function() {
                                d3.event.preventDefault();
                              });
                curr_bps_enter.append("img")
                              .attr('src', 'img/delete-bp.png')
                              .style('transform', 'translate(1px, 2px)')
                              .on("click", function(d) {
                                the_controller.addInput(new Event("del_breakpoint", "ui_input", [d.name]), 0.0);
                              });
                curr_bps.exit().remove();
                curr_bps.style("background-color", function(d) {
                                                    if (d.triggered) {
                                                        d.triggered = false;
                                                        if (d.disable_on_trigger) {
                                                            d.enabled = false;
                                                        }
                                                        return "red";
                                                    } else {
                                                        return "transparent";
                                                    }});
                curr_bps.select("text").style("opacity", function(d) {if (d.enabled) return "1"; else return "0.5";});
            </body>
        </method>
        <scxml initial="initializing">
            <state id="initializing">            
                <transition target="../running">
                    <raise event="reset" port="output" />
                </transition>
            </state>
            <state id="running">
                <transition target="." event="all_states_reset" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.data = [];
                        this.port_connections = [];
                        this.update_vis(the_parameters[2]);
                        this.visualize_initial_state(the_parameters[1]);
                        this.breakpoints = the_parameters[3];
                        this.visualize_breakpoints();
                    </script>
                </transition>
                <transition target="." event="all_states" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        <![CDATA[
                        if (this.visualized_simulator == "NETLOGO") {
                            this.simulation_time.text("SIMULATION TIME: " + the_parameters[0]);
                            this.update_vis(the_parameters[2]);
                            this.visualize_initial_state(the_parameters[1]);
                            this.visualize_breakpoints();
                        } else {
                            this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                            this.update_vis(the_parameters[2]);
                            this.visualize_initial_state(the_parameters[1]);
                            this.visualize_breakpoints();
                        }
                        ]]>
                    </script>
                </transition>
                <transition target="." event="new_states" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.update_vis(the_parameters[3]);
                        this.visualize_new_state(the_parameters[1], the_parameters[2]);
                        this.visualize_breakpoints();
                    </script>
                </transition>
                <transition target="." event="imminents" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.visualize_breakpoints();
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.visualize_imminents(the_parameters[1]);
                    </script>
                </transition>
                <transition target="." event="selected_imminent" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.visualize_selected_imminent(the_parameters[1]);
                    </script>
                </transition>
                <transition target="." event="outbag" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        d3.select("#smallStepInfo_2").classed("inactive", false);
                        d3.selectAll("g.node").classed("imminent", false);
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.visualize_messages(the_parameters[1], 'outmessage');
                    </script>
                </transition>
                <transition target="." event="inbags" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.visualize_inbags(the_parameters[1]);
                    </script>
                </transition>
                <transition target="." event="transitioning" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        d3.select("#smallStepInfo_4").classed("inactive", false);
                        d3.selectAll(".portConnection").classed("invisibleLink", true);
                        d3.selectAll(".port").classed("visible", false);
                        d3.selectAll(".port").classed("invisible", true);
                        d3.selectAll("circle.inmessage").data([]).exit().remove();
                        d3.selectAll("circle.outmessage").data([]).exit().remove();
                        this.visualize_transitioning(the_parameters[1]);
                    </script>
                </transition>
                <transition target="." event="new_internal_states" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.handle_internal_state_change(the_parameters[1]);
                    </script>
                </transition>
                <transition target="." event="new_tn" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.visualize_new_tn(the_parameters[1]);
                    </script>
                </transition>
                <transition target="." event="structural_changes" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.simulation_time.text("SIMULATION TIME: " + the_parameters[0][0] + "/" + the_parameters[0][1]);
                        this.update_vis(the_parameters[1]);
                    </script>
                </transition>
                <transition target="." event="select_instance" port="ui_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.select_instance(the_parameters);
                    </script>
                </transition>
                <transition target="." event="process_god_event" port="ui_input">
                    <raise event="god_event" port="output">
                        <parameter expr="god_event_to_process" />
                    </raise>
                </transition>
                <transition target="." event="god_event_ok" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        this.handle_internal_state_change(the_parameters[0]);
                    </script>
                </transition>
                <transition target="." event="inject_event" port="ui_input">
                    <raise event="inject" port="output">
                        <parameter expr="event_to_inject" />
                    </raise>
                </transition>
                <transition target="." event="inject_ok" port="simulation_input" />
                <transition target="." event="add_breakpoint" port="ui_input">
                    <raise event="add_breakpoint" port="output">
                        <parameter expr="breakpoint_to_add" />
                    </raise>
                    <script>
                        this.breakpoints.push({'name': breakpoint_to_add[0], 'enabled': breakpoint_to_add[2], 'disable_on_trigger': breakpoint_to_add[3], 'triggered': false});
                        this.visualize_breakpoints();
                    </script>
                </transition>
                <transition target="." event="toggle_breakpoint" port="ui_input">
                    <parameter name="breakpoint_id" />
                    <parameter name="enabled" />
                    <raise event="toggle_breakpoint" port="output">
                        <parameter expr="breakpoint_id" />
                        <parameter expr="enabled" />
                    </raise>
                    <script>
                        this.visualize_breakpoints();
                    </script>
                </transition>
                <transition target="." event="del_breakpoint" port="ui_input">
                    <parameter name="breakpoint_id" />
                    <raise event="del_breakpoint" port="output">
                        <parameter expr="breakpoint_id" />
                    </raise>
                    <script>
                        this.breakpoints = this.breakpoints.filter(function(bp) {return bp.name != breakpoint_id});
                        this.visualize_breakpoints();
                    </script>
                </transition>
                <transition target="." event="breakpoint_triggered" port="simulation_input">
                    <parameter name="the_parameters" />
                    <script>
                        for (var idx in this.breakpoints) {
                            var curr_bp = this.breakpoints[idx];
                            if (curr_bp.name == the_parameters[0]) {
                                curr_bp.triggered = true;
                                curr_bp.transitioned = the_parameters[1];
                                curr_bp.outbag = the_parameters[2];
                                curr_bp.inbags = the_parameters[3];
                            }
                        }
                        this.visualize_breakpoints()
                    </script>
                </transition>
            </state>
        </scxml>
    </class>
</diagram>