<class name="Server">
    <relationships>
        <association name="sockets" class="Socket"/>
    </relationships>
    <constructor>
        <parameter name="bootfile"/>
        <body>
            <![CDATA[
            self.socket = None

            self.processing_association_name = None
            self.processing_data = None
            self.queue = []
            self.mvs = ModelverseState(bootfile)
            self.mvs_operations = {
                   "CN": self.mvs.create_node,
                   "CE": self.mvs.create_edge,
                   "CNV": self.mvs.create_nodevalue,
                   "CD": self.mvs.create_dict,

                   "RV": self.mvs.read_value,
                   "RO": self.mvs.read_outgoing,
                   "RI": self.mvs.read_incoming,
                   "RE": self.mvs.read_edge,
                   "RD": self.mvs.read_dict,
                   "RDN": self.mvs.read_dict_node,
                   "RDE": self.mvs.read_dict_edge,
                   "RRD": self.mvs.read_reverse_dict,
                   "RR": self.mvs.read_root,
                   "RDK": self.mvs.read_dict_keys,

                   "DE": self.mvs.delete_edge,
                   "DN": self.mvs.delete_node,

                   "DG": self.mvs.dump,
                }
            ]]>
        </body>
    </constructor>
    <method name="process_message">
        <parameter name="operation_name"/>
        <parameter name="parameters"/>
        <body>
            <![CDATA[
            op = self.mvs_operations[operation_name]
            return op(*parameters)
            ]]>
        </body>

    </method>
    <scxml initial="main">
        <parallel id="main">
            <state id="queue">
                <state id="queue">
                    <transition event="HTTP_output" target=".">
                        <parameter name="association_name"/>
                        <parameter name="data"/>
                        <script>
                            self.queue.append((association_name, data))
                        </script>
                    </transition>
                </state>
            </state>

            <state id="processor" initial="wait_for_input">
                <state id="wait_for_input">
                    <transition cond="len(self.queue) > 0" target="../process_input">
                        <script>
                            self.processing_association_name, self.processing_data = self.queue.pop(0)
                            try:
                                self.processing_data = json.loads(self.processing_data["requests"])
                            except:
                                print("Error in deserialization: " + str(self.processing_data))
                        </script>
                    </transition>
                </state>
                <state id="process_input">
                    <!-- A message from the client, containing data. -->
                    <transition target="../wait_for_input">
                        <script>
                            reply = []
                            print(self.processing_data)
                            for op, params in self.processing_data:
                                try:
                                    result = self.process_message(op, params)
                                    try:
                                        reply.append(result)
                                    except:
                                        traceback.print_exc()
                                        reply.append([None, 496])
                                except:
                                    traceback.print_exc()
                                    reply.append([None, 497])
                        </script>
                        <raise scope="narrow" target="self.processing_association_name" event="HTTP_input">
                            <parameter expr="{'data': json.dumps(reply)}"/>
                        </raise>
                    </transition>
                </state>
            </state>

            <state id="server" initial="init">
                <state id="init">
                    <onentry>
                        <raise scope="output" event="create_socket" port="socket_out"/>
                    </onentry>
                    <transition port="socket_in" event="created_socket" target="../binding">
                        <parameter name="socket"/>
                        <script>
                            self.socket = socket
                        </script>
                    </transition>
                </state>
                <!-- TODO fix hardcoded port number -->
                <state id="binding">
                    <onentry>
                        <raise scope="output" event="bind_socket" port="socket_out">
                            <parameter expr="self.socket"/>
                            <parameter expr="('', 8000)"/>
                        </raise>
                    </onentry>
                    <transition port="socket_in" event="bound_socket" cond="self.socket == socket" target="../listening">
                        <parameter name="socket"/>
                    </transition>
                </state>
                <state id="listening">
                    <onentry>
                        <raise scope="output" event="listen_socket" port="socket_out">
                            <parameter expr="self.socket"/>
                        </raise>
                    </onentry>
                    <transition port="socket_in" event="listened_socket" cond="self.socket == socket" target="../accepting">
                        <parameter name="socket"/>
                    </transition>
                </state>
                <state id="accepting">
                    <onentry>
                        <raise scope="output" port="socket_out" event="accept_socket">
                            <parameter expr="self.socket"/>
                        </raise>
                    </onentry>
                    <transition port="socket_in" event="accepted_socket" cond="self.socket == socket" target=".">
                        <parameter name="socket"/>
                        <parameter name="connected_socket"/>
                        <script>
                        </script>
                        <raise scope="cd" event="create_instance">
                            <parameter expr="'sockets'" />
                            <parameter expr="'Socket'" />
                            <parameter expr="connected_socket" />
                        </raise>
                    </transition>
                    <transition event="instance_created" target=".">
                        <parameter name="instancename"/>
                        <raise scope="cd" event="start_instance">
                            <parameter expr="instancename" />
                        </raise>
                        <raise scope="narrow" event="set_association_name" target="instancename">
                            <parameter expr="instancename"/>
                        </raise>
                    </transition>
                </state>
            </state>

            <state id="close_socket">
                <state id="close">
                    <transition event="close" target=".">
                        <parameter name="association_name"/>
                        <raise scope="cd" event="delete_instance">
                            <parameter expr="association_name"/>
                        </raise>
                    </transition>
                </state>
            </state>
        </parallel>
    </scxml>
</class>
