include "primitives.alh"

AtomicDEVSBlock Generator {
    name = "Generator"
    
    initialState = """
        return {'name': 'generating'}
    """
    
    intTransition = """
        if self.state['name'] == 'generating':
            new_state = {}
            new_state['name'] = 'generating'
            return new_state
    """
    
    timeAdvance = """
        if self.state['name'] == 'generating':
            return 1
    """
    
    outputFnc = """
        if self.state['name'] == 'generating':
            return {self.my_ports['g_out']: [{'type': 'Job', 'repr': {'duration': 0.3}}]}
    """
    
    extTransition = """
        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
        return AtomicDEVS.extTransition(self, my_inputs)
    """
    
    confTransition = """
        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
        return AtomicDEVS.confTransition(self, my_inputs)
    """
}

AtomicDEVSBlock Processor {
    name = "Processor"
    
    initialState = """
        return {'name': 'idle'}
    """
    
    intTransition = """
        if self.state['name'] == 'processing':
            new_state = {}
            new_state['name'] = 'idle'
            return new_state
    """
    
    timeAdvance = """
        if self.state['name'] == 'processing':
            return self.state['job']['duration']
        if self.state['name'] == 'idle':
            return INFINITY
    """
    
    outputFnc = """
        if self.state['name'] == 'processing':
            return {self.my_ports['p_out']: [{'type': 'Job', 'repr': self.state['job']}]}
        if self.state['name'] == 'idle':
            return {}
    """
    
    extTransition = """
        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
        if self.state['name'] == 'idle':
            new_state = {}
            new_state['name'] = 'processing'
            new_state['job'] = inputs['p_in'][0]['repr']
            return new_state 
        else:
            return AtomicDEVS.extTransition(self, my_inputs)
    """
    
    confTransition = """
        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
        return AtomicDEVS.confTransition(self, my_inputs)
    """
}

AtomicDEVSBlock Collector {
    name = "Collector"
    
    initialState = """
        return {'name': 'waiting', 'nr_of_jobs': 0}
    """
    
    intTransition = """
        return AtomicDEVS.intTransition(self)
    """
    
    timeAdvance = """
        if self.state['name'] == 'waiting':
            return INFINITY
    """
    
    outputFnc = """
        if self.state['name'] == 'waiting':
            return {}
    """
    
    extTransition = """
        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
        if self.state['name'] == 'waiting':
            new_state = {}
            new_state['name'] = 'waiting'
            new_state['nr_of_jobs'] = self.state['nr_of_jobs'] + 1
            return new_state
        else:
            return AtomicDEVS.extTransition(self, my_inputs)
    """
    
    confTransition = """
        inputs = {k.getPortName(): v for k, v in my_inputs.iteritems()}
        return AtomicDEVS.confTransition(self, my_inputs)
    """
}

OutputPort g_out {name = "g_out"}
InputPort p_in {name = "p_in"}
OutputPort p_out {name = "p_out"}
InputPort c_in {name = "c_in"}

DEVSBlockToPort(Generator, g_out) {}
DEVSBlockToPort(Processor, p_in) {}
DEVSBlockToPort(Processor, p_out) {}
DEVSBlockToPort(Collector, c_in) {}

CoupledDEVSBlock CoupledProcessor {
    name = "CoupledProcessor"
}

InputPort cp_in {name = "cp_in"}
OutputPort cp_out {name = "cp_out"}

DEVSBlockToPort (CoupledProcessor, cp_in) {}
DEVSBlockToPort (CoupledProcessor, cp_out) {}

DEVSInstance p1 {
    name = "p1"
    type = "Processor"
}

DEVSInstance p2 {
    name = "p2"
    type = "Processor"
}

SubModel (CoupledProcessor, p1) {}
SubModel (CoupledProcessor, p2) {}

InputPort p1_in {name = "p_in"}
OutputPort p1_out {name = "p_out"}
InputPort p2_in {name = "p_in"}
OutputPort p2_out {name = "p_out"}

DEVSInstanceToPort (p1, p1_in) {}
DEVSInstanceToPort (p1, p1_out) {}
DEVSInstanceToPort (p2, p2_in) {}
DEVSInstanceToPort (p2, p2_out) {}

Channel (cp_in, p1_in) {}
Channel (p1_out, p2_in) {}
Channel (p2_out, cp_out) {}

CoupledDEVSBlock Root {
    name = "Root"
}

DEVSInstance generator {
    name = "generator"
    type = "Generator"
}

DEVSInstance coupledprocessor {
    name = "coupledprocessor"
    type = "CoupledProcessor"
}

DEVSInstance processor {
    name = "processor"
    type = "Processor"
}

DEVSInstance collector {
    name = "collector"
    type = "Collector"
}

SubModel (Root, generator) {}
SubModel (Root, coupledprocessor) {}
SubModel (Root, processor) {}
SubModel (Root, collector) {}

OutputPort generator_out {name = "g_out"}
InputPort coupledprocessor_in {name = "cp_in"}
OutputPort coupledprocessor_out {name = "cp_out"}
InputPort processor_in {name = "p_in"}
OutputPort processor_out {name = "p_out"}
InputPort collector_in {name = "c_in"}

DEVSInstanceToPort (generator, generator_out) {}
DEVSInstanceToPort (coupledprocessor, coupledprocessor_in) {}
DEVSInstanceToPort (coupledprocessor, coupledprocessor_out) {}
DEVSInstanceToPort (processor, processor_in) {}
DEVSInstanceToPort (processor, processor_out) {}
DEVSInstanceToPort (collector, collector_in) {}

Channel (generator_out, coupledprocessor_in) {}
Channel (coupledprocessor_out, processor_in) {}
Channel (processor_out, collector_in) {}