class Host(object):
    def __init__(self, id, neighbors = None):
        self.id = id
        self.context_aggregator = ContextAggregator(id)
        self.state = "INIT"
        if neighbors is None:
            self.neighbors = []
        else:
            self.neighbors = neighbors

        self.send_history = {}
        self.receive_history = {}
        self.reset_history()

    def is_output_empty(self):
        return self.context_aggregator.output.is_empty()

    def sent_already(self, neighbor):
        return self.send_history[neighbor]

    def reset_history(self):
        for n in self.neighbors:
            self.send_history[n] = False
        for n in self.neighbors:
            self.receive_history[n] = False

    def send_all(self):
        for i in self.send_history.values():
            if i == False: return False
        return True

    def receive_all(self):
        for i in self.receive_history.values():
            if i == False: return False
        return True

    def set_state(self, state):
        self.state = state

    def get_state(self):
        return self.state

    def sample(self):
        self.context_aggregator.sample()

    def send(self, neighbor):
        # set the flag that this node sends context to neighbor
        self.send_history[neighbor] = True
        if self.send_all(): print "Node %s - send all!" % self.id
        return self.context_aggregator.send(neighbor)

    # node.receive(from_node=from_node,contexts=value,timestamp=0)
    def receive(self, from_node, contexts, timestamp=0):
        self.receive_history[from_node] = True
        if self.receive_all(): print "Node %s - receive all!" % self.id
        self.context_aggregator.receive(from_node, contexts)

    # def get_neighbors(self):
    #     return self.neighbors
    def __init__(self, id, neighbors = None):
        self.id = id
        self.context_aggregator = ContextAggregator(id)
        self.state = "INIT"
        if neighbors is None:
            self.neighbors = []
        else:
            self.neighbors = neighbors

        self.send_history = {}
        self.receive_history = {}
        self.reset_history()
    def test_send(self):
        """
        Three nodes are connected in serial

        0 <-> 1 <-> 2

        The test_for_real_world is to check if each one samples data and send correctly.
        The sent data is stored in r0,r1,r2
        """
        c0 = ContextAggregator(0)
        r = c0.process_to_set_output(neighbors=[1], timestamp = 0)
        self.assertTrue(same(r, {1: [[0], []]}))

        c1 = ContextAggregator(1)
        r = c1.process_to_set_output(neighbors=[0,2], timestamp = 0)
        self.assertTrue(same(r, {0: [[1], []], 2:[[1],[]]}))

        c2 = ContextAggregator(2)
        r = c2.process_to_set_output(neighbors=[1], timestamp = 0)
        self.assertTrue(same(r, {1: [[2], []]}))

        # First round
        ## c0 sends contexts to neighbors, s0 contains the contexts in standard form
        r0 = c0.send(timestamp=0)
        s0 = contexts_to_standard(r0[1])
        self.assertTrue(same(s0, [[0], []]))

        r1 = c1.send(neighbor=0, timestamp=0)
        s1 = contexts_to_standard(r1[0])
        self.assertTrue(same(s1, [[1], []]))

        r1 = c1.send(neighbor=2, timestamp=0)
        s1 = contexts_to_standard(r1[2])
        self.assertTrue(same(s1, [[1], []]))

        r2 = c2.send(timestamp=0)
        s2 = contexts_to_standard(r2[1])
        self.assertTrue(same(s2, [[2], []]))
 def test_run3(self):
     """Doctest case with propage recovered singles"""
     d = ContextAggregator(
         config={
             "propagation_mode": ContextAggregator.AGGREGATION_MODE,
             "max_tau": 1,
             "propagate_recovered_singles": True,
         }
     )
     # d.initialize() # Always execute initialize before newly receive data
     # Emulating receive data from neighbors
     d.receive(1, set([Context(value=1.0, cohorts=[0, 1, 2])]))
     d.receive(2, set([Context(value=2.0, cohorts=[0])]))
     d.receive(3, set([Context(value=3.0, cohorts=[1])]))
     d.receive(4, set([Context(value=7.0, cohorts=[9], hopcount=Context.SPECIAL_CONTEXT)]))
     # Emulating accumulated contexts
     context_db = set(
         [
             Context(value=1.0, cohorts=[2, 4, 5, 3]),
             Context(value=1.0, cohorts=[5, 6]),
             Context(value=7.0, cohorts=[7, 8]),
         ]
     )
     d.set_database(singles=set([]), aggregates=context_db, timestamp=10)
     d.run_dataflow(timestamp=10)
     # Emulating newly found singles and aggregates from database
     self.assertTrue(same(d.get_database_singles(timestamp=10), [[0, 1, 2, 9], []]))
     self.assertTrue(same(d.get_database_aggregates(timestamp=10), [[7, 8], [3, 4, 5], [6, 5]]))
     # Emulating the disaggregation process
     self.assertTrue(same(d.get_singles(timestamp=10), [[0, 1, 2, 9], []]))
     self.assertTrue(same(d.get_primes(timestamp=10), [[7, 8]]))
     self.assertTrue(same(d.get_non_primes(timestamp=10), [[3, 4, 5], [5, 6]]))
     self.assertTrue(same(d.get_selected_non_primes(timestamp=10), [[3, 4, 5]]))
     self.assertTrue(d.get_new_aggregate().get_cohorts_as_set() == set([0, 1, 2, 3, 4, 5, 7, 8, 9]))
     self.assertTrue(same(d.get_filtered_singles(), [[0, 1, 2, 9], []]))
 def test_run1(self):
     """Only [4,5] is prime
     All the others are singles
     """
     d = ContextAggregator()
     d.receive(1, set([Context(value=1.0, cohorts=[0, 1, 2])]))
     d.receive(2, set([Context(value=2.0, cohorts=[0])]))
     d.set_database(
         set([Context(value=1.0, cohorts=[0, 1, 2, 3, 4, 5]), Context(value=2.0, cohorts=[1])]),
         set([Context(value=1.0, cohorts=[2, 3])]),
     )
     d.run_dataflow()
     self.assertTrue(same(d.get_singles(), [[0, 1, 2, 3], []]))
     self.assertTrue(same(d.get_primes(), [[], [4, 5]]))
    def test_receive(self):
        c0 = ContextAggregator(0)
        c0.process_to_set_output(neighbors=[1], timestamp = 0)
        c1 = ContextAggregator(1)
        c1.process_to_set_output(neighbors=[0,2], timestamp = 0)
        c2 = ContextAggregator(2)
        c2.process_to_set_output(neighbors=[1], timestamp = 0)

        # First round
        ## c0 sends contexts to neighbors, s0 contains the contexts in standard form
        r0_1 = c0.send(neighbor=1, timestamp=0)
        r1_0 = c1.send(neighbor=0, timestamp=0)
        r1_2 = c1.send(neighbor=2, timestamp=0)
        r2_1 = c2.send(neighbor=1, timestamp=0)

        c1.receive(from_node=0, contexts=r0_1[1], timestamp=0)
        c0.receive(from_node=1, contexts=r1_0[0], timestamp=0)
        c2.receive(from_node=1, contexts=r1_2[2], timestamp=0)
        c1.receive(from_node=2, contexts=r2_1[1], timestamp=0)

        r1 = c1.get_received_data(from_node=0)
        self.assertEqual(contexts_to_standard(r1), [[0],[]])
        r0 = c0.get_received_data(from_node=1)
        self.assertEqual(contexts_to_standard(r0), [[1],[]])
        r1 = c1.get_received_data(from_node=2)
        self.assertEqual(contexts_to_standard(r1), [[2],[]])
        r2 = c2.get_received_data(from_node=1)
        self.assertEqual(contexts_to_standard(r2), [[1],[]])
    def test_run_dataflow_single_only(self):
        # at timestamp = 0
        config = {ContextAggregator.PM:ContextAggregator.SINGLE_ONLY_MODE}
        c0 = ContextAggregator(id=0, config=config)
        c1 = ContextAggregator(id=1, config=config)
        c2 = ContextAggregator(id=2, config=config)

        # First round
        ## compute
        c0.process_to_set_output(neighbors=[1], timestamp = 0)
        c1.process_to_set_output(neighbors=[0,2], timestamp = 0)
        c2.process_to_set_output(neighbors=[1], timestamp = 0)

        ## communication
        r0_1 = c0.send(neighbor=1, timestamp=0)
        r1_0 = c1.send(neighbor=0, timestamp=0)
        r1_2 = c1.send(neighbor=2, timestamp=0)
        r2_1 = c2.send(neighbor=1, timestamp=0)

        c1.receive(from_node=0, contexts=r0_1[1], timestamp=0)
        c0.receive(from_node=1, contexts=r1_0[0], timestamp=0)
        c2.receive(from_node=1, contexts=r1_2[2], timestamp=0)
        c1.receive(from_node=2, contexts=r2_1[1], timestamp=0)

        r1_0 = c1.get_received_data(from_node=0)
        r0_1 = c0.get_received_data(from_node=1)
        r1_2 = c1.get_received_data(from_node=2)
        r2_1 = c2.get_received_data(from_node=1)

        self.assertTrue(contexts_to_standard(r1_0), [[0],[]])
        self.assertTrue(contexts_to_standard(r0_1), [[1],[]])
        self.assertTrue(contexts_to_standard(r1_2), [[2],[]])
        self.assertTrue(contexts_to_standard(r2_1), [[1],[]])

        # Second round
        ## compute
        o0 = c0.process_to_set_output(neighbors=[1], timestamp = 0)
        o1 = c1.process_to_set_output(neighbors=[0,2], timestamp = 0)
        o2 = c2.process_to_set_output(neighbors=[1], timestamp = 0)

        self.assertTrue(contexts_to_standard(c0.get_singles(timestamp=0)) == [[0,1],[]])
        self.assertTrue(contexts_to_standard(c1.get_singles(timestamp=0)) == [[0,1,2],[]])
        self.assertTrue(contexts_to_standard(c2.get_singles(timestamp=0)) == [[1,2],[]])

        self.assertTrue(o0 == {1: [[], []]})
        self.assertTrue(o1 == {0: [[2], []], 2:[[0], []]})
        self.assertTrue(o2 == {1: [[], []]})

        ## communication
        self.assertTrue(c0.is_nothing_to_send())
        self.assertTrue(c2.is_nothing_to_send())

        r1_0 = c1.send(neighbor=0, timestamp=0)
        r1_2 = c1.send(neighbor=2, timestamp=0)
        self.assertTrue(contexts_to_standard(r1_0[0]) == [[2],[]])
        self.assertTrue(contexts_to_standard(r1_2[2]) == [[0],[]])

        c0.receive(from_node=1, contexts=r1_0[0], timestamp=0)
        c2.receive(from_node=1, contexts=r1_2[2], timestamp=0)

        r0_1 = c0.get_received_data(from_node=1)
        r2_1 = c2.get_received_data(from_node=1)

        self.assertTrue(contexts_to_standard(r0_1) == [[2],[]])
        self.assertTrue(contexts_to_standard(r2_1) == [[0],[]])

        # Third iteration
        o0 = c0.process_to_set_output(neighbors=[1], timestamp = 0)
        o1 = c1.process_to_set_output(neighbors=[0,2], timestamp = 0)
        o2 = c2.process_to_set_output(neighbors=[1], timestamp = 0)

        self.assertTrue(contexts_to_standard(c0.get_singles(timestamp=0)) == [[0,1,2],[]])
        self.assertTrue(contexts_to_standard(c1.get_singles(timestamp=0)) == [[0,1,2],[]])
        self.assertTrue(contexts_to_standard(c2.get_singles(timestamp=0)) == [[0,1,2],[]])

        self.assertTrue(o0 == {1: [[], []]})
        #self.assertTrue(o1 == {0: [[], []], 2:[[], []]})
        self.assertTrue(o1 == {}) # {0: [[], []], 2:[[], []]})
        self.assertTrue(o2 == {1: [[], []]})

        self.assertTrue(c0.is_nothing_to_send())
        self.assertTrue(c1.is_nothing_to_send())
        self.assertTrue(c2.is_nothing_to_send())