import unittest
from connectome.model import ER
from unittest.mock import MagicMock

from connectome.analysis import RelativeCycleAnalysis
from connectome.model.network import Network
from modelflow import DynamicGraph


class TestCycleAnalysis(unittest.TestCase):
    def test_zero_length_5(self):
        adjacency = [[0,0,0,0,0,0],
                     [0,0,0,0,0,0],
                     [0,0,0,0,0,0],
                     [0,0,0,0,0,0],
                     [0,0,0,0,0,0],
                     [0,0,0,0,0,0]]
        net = Network(adjacency, nr_exc=3, nr_inh=3)
        cycle_analysis = RelativeCycleAnalysis(length=5)
        cycle_analysis._verify_connectivity_range = MagicMock(return_value=True)
        self.assertEqual(0, cycle_analysis(network=net)['relative_cycles_5'])

    def test_zero_length_8(self):
        adjacency = [[0,0,0,0,0,0],
                     [0,0,0,0,0,0],
                     [0,0,0,0,0,0],
                     [0,0,0,0,0,0],
                     [0,0,0,0,0,0],
                     [0,0,0,0,0,0]]
        net = Network(adjacency, nr_exc=3, nr_inh=3)
        cycle_analysis = RelativeCycleAnalysis(length=8)
        cycle_analysis._verify_connectivity_range = MagicMock(return_value=True)
        self.assertEqual(0, cycle_analysis(network=net)['relative_cycles_8'])


class ERTest(unittest.TestCase):
    length = None

    def setUp(self):
        er = ER(inh_ratio=.05, p_inh=0)
        cycles_analysis = RelativeCycleAnalysis(length=self.length)
        cycles_analysis._verify_connectivity_range = MagicMock(return_value=True)
        computation = DynamicGraph()
        computation.add_inputs(["p", "n"])
        computation.add_path(({"n": "nr_neurons",
                               "p": "p_exc"}, er),
                             ({"%": "network"}, cycles_analysis))
        self.computation = computation


class TestERCyclesLength3(ERTest):
    length = 3

    def test_small_net_low_connectivity(self):
        self.assertLess(abs(self.computation(n=500, p=.07)['relative_cycles_3']-1), .02)

    def test_small_net_high_connectivity(self):
        self.assertLess(abs(self.computation(n=500, p=.4)['relative_cycles_3']-1), .01)

    def test_large_net_low_connectivity(self):
        self.assertLess(abs(self.computation(n=2000, p=.07)['relative_cycles_3']-1), .01)

    def test_large_net_high_connectivity(self):
        self.assertLess(abs(self.computation(n=2000, p=.4)['relative_cycles_3']-1), .01)


class TestERCyclesLength5(ERTest):
    length = 5

    def test_small_net_low_connectivity(self):
        self.assertLess(abs(self.computation(n=500, p=.07)['relative_cycles_5']-1), .025)

    def test_small_net_high_connectivity(self):
        self.assertLess(abs(self.computation(n=500, p=.4)['relative_cycles_5']-1), .01)

    def test_large_net_low_connectivity(self):
        self.assertLess(abs(self.computation(n=2000, p=.07)['relative_cycles_5']-1), .01)

    def test_large_net_high_connectivity(self):
        self.assertLess(abs(self.computation(n=2000, p=.4)['relative_cycles_5']-1), .01)


class TestERCyclesLength8ERTest(ERTest):
    length = 8

    def test_small_net_low_connectivity(self):
        self.assertLess(abs(self.computation(n=500, p=.07)['relative_cycles_8']-1), .02)

    def test_small_net_high_connectivity(self):
        self.assertLess(abs(self.computation(n=500, p=.4)['relative_cycles_8']-1), .01)

    def test_large_net_low_connectivity(self):
        self.assertLess(abs(self.computation(n=2000, p=.07)['relative_cycles_8']-1), .01)

    def test_large_net_high_connectivity(self):
        self.assertLess(abs(self.computation(n=2000, p=.4)['relative_cycles_8']-1), .01)


if __name__ == "__main__":
    unittest.main()