import unittest
import pysal
from pysal.esda import moran
import numpy as np


class Moran_Tester(unittest.TestCase):
    def setUp(self):
        self.w = pysal.open(pysal.examples.get_path("stl.gal")).read()
        f = pysal.open(pysal.examples.get_path("stl_hom.txt"))
        self.y = np.array(f.by_col['HR8893'])

    def test_moran(self):
        mi = moran.Moran(self.y, self.w, two_tailed=False)
        self.assertAlmostEqual(mi.I, 0.24365582621771659, 7)
        self.assertAlmostEqual(mi.p_norm, 0.00013573931385468807)

    def test_sids(self):
        w = pysal.open(pysal.examples.get_path("sids2.gal")).read()
        f = pysal.open(pysal.examples.get_path("sids2.dbf"))
        SIDR = np.array(f.by_col("SIDR74"))
        mi = pysal.Moran(SIDR, w, two_tailed=False)
        self.assertAlmostEqual(mi.I, 0.24772519320480135)
        self.assertAlmostEqual(mi.p_norm,  5.7916539074498452e-05)


class Moran_Rate_Tester(unittest.TestCase):
    def setUp(self):
        self.w = pysal.open(pysal.examples.get_path("sids2.gal")).read()
        f = pysal.open(pysal.examples.get_path("sids2.dbf"))
        self.e = np.array(f.by_col['SID79'])
        self.b = np.array(f.by_col['BIR79'])

    def test_moran_rate(self):
        mi = moran.Moran_Rate(self.e, self.b, self.w, two_tailed=False)
        self.assertAlmostEqual(mi.I, 0.16622343552567395, 7)
        self.assertAlmostEqual(mi.p_norm, 0.004191499504892171)


class Moran_BV_matrix_Tester(unittest.TestCase):
    def setUp(self):
        f = pysal.open(pysal.examples.get_path("sids2.dbf"))
        varnames = ['SIDR74', 'SIDR79', 'NWR74', 'NWR79']
        self.names = varnames
        vars = [np.array(f.by_col[var]) for var in varnames]
        self.vars = vars
        self.w = pysal.open(pysal.examples.get_path("sids2.gal")).read()

    def test_Moran_BV_matrix(self):
        res = moran.Moran_BV_matrix(self.vars, self.w, varnames=self.names)
        self.assertAlmostEqual(res[(0, 1)].I, 0.19362610652874668)
        self.assertAlmostEqual(res[(3, 0)].I, 0.37701382542927858)


class Moran_Local_Tester(unittest.TestCase):
    def setUp(self):
        np.random.seed(10)
        self.w = pysal.open(pysal.examples.get_path("desmith.gal")).read()
        f = pysal.open(pysal.examples.get_path("desmith.txt"))
        self.y = np.array(f.by_col['z'])

    def test_Moran_Local(self):
        lm = moran.Moran_Local(
            self.y, self.w, transformation="r", permutations=99)
        self.assertAlmostEqual(lm.z_sim[0], -0.081383956359666748)
        self.assertAlmostEqual(lm.p_z_sim[0], 0.46756830387716064)
        self.assertAlmostEqual(lm.VI_sim, 0.2067126047680822)


class Moran_Local_BV_Tester(unittest.TestCase):
    def setUp(self):
        np.random.seed(10)
        self.w = pysal.open(pysal.examples.get_path("sids2.gal")).read()
        f = pysal.open(pysal.examples.get_path("sids2.dbf"))
        self.x = np.array(f.by_col['SIDR79'])
        self.y = np.array(f.by_col['SIDR74'])

    def test_Moran_Local_BV(self):
        lm = moran.Moran_Local_BV(self.x, self.y, self.w,
                                  transformation="r", permutations=99)
        self.assertAlmostEqual(lm.Is[0], 1.4649221250620736)
        self.assertAlmostEqual(lm.z_sim[0], 2.9246889997781773)
        self.assertAlmostEqual(lm.p_z_sim[0], 0.0017240031348827456)
        self.assertAlmostEqual(lm.VI_sim, 0.24983591065175745)


class Moran_Local_Rate_Tester(unittest.TestCase):
    def setUp(self):
        np.random.seed(10)
        self.w = pysal.open(pysal.examples.get_path("sids2.gal")).read()
        f = pysal.open(pysal.examples.get_path("sids2.dbf"))
        self.e = np.array(f.by_col['SID79'])
        self.b = np.array(f.by_col['BIR79'])

    def test_moran_rate(self):
        lm = moran.Moran_Local_Rate(self.e, self.b, self.w,
                                    transformation="r", permutations=99)
        self.assertAlmostEqual(lm.z_sim[0], -0.27099998923550017)
        self.assertAlmostEqual(lm.p_z_sim[0], 0.39319552026912641)
        self.assertAlmostEqual(lm.VI_sim, 0.21879403675396222)


suite = unittest.TestSuite()
test_classes = [Moran_Tester, Moran_Rate_Tester, 
                Moran_BV_matrix_Tester, Moran_Local_Tester,
                Moran_Local_BV_Tester, Moran_Local_Rate_Tester]
for i in test_classes:
    a = unittest.TestLoader().loadTestsFromTestCase(i)
    suite.addTest(a)

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite)
