import os.path

from pyelectro import analysis
from pyelectro import io

import os
import pprint

pp = pprint.PrettyPrinter(indent=4)

try:
    import unittest2 as unittest
except ImportError:
    import unittest

class TestAnalysis(unittest.TestCase):


    def get_data(self, tmax, dt, vmin, vmax, spikes):

        times = []
        data = []
        t = 0
        while (t<=tmax):
            if len(spikes)>0 and t>=spikes[0]:
                v = vmax
                spikes = spikes[1:]
            else:
                v = vmin
            data.append(v)
            times.append(t)
            t+=dt

        return times, data

    def get_real_data(self):

        data_file = 'Gran_0.dat'
        delimiter = '\t'
        if os.path.isfile(data_file):
            times, data = analysis.load_csv_data(data_file, delimiter=delimiter)
        elif os.path.isfile('test/'+data_file):
            times, data = analysis.load_csv_data('test/'+data_file, delimiter=delimiter)

        print("Loaded data with %i times & %i datapoints from %s"%(len(times),len(data),data_file))
        return times, data



    def test_spike_frequencies(self):

        print("- test_spike_frequencies()")

        data = [10,20,40,140]

        times, freqs = analysis.spike_frequencies(data)

        print("Times: %s"%times)
        print("Freqs: %s"%freqs)


        self.assertEqual(freqs[0],100)
        self.assertEqual(freqs[1],50)
        self.assertEqual(freqs[2],10)


    def add_horizontal_line(self, y, times):

        import matplotlib.pyplot as pylab
        ys = [y,y]
        xs = [times[0], times[-1]]
        pylab.plot(xs, ys, 'k--') 


    def test_iclamp_analysis_data(self, show=False):

        print("- test_iclamp_analysis_data()")

        analysis_var={'peak_delta':0,'baseline':0,'dvdt_threshold':0, 'peak_threshold':0}

        times, volts = self.get_real_data()

        max_min_methods = [analysis.max_min, analysis.max_min_simple]

        for max_min_method in max_min_methods:

            print('--------------  Analysing with: %s'%max_min_method)
            analysis_data=analysis.IClampAnalysis(volts,
                                               times,
                                               analysis_var,
                                               start_analysis=0,
                                               end_analysis=1000,
                                               smooth_data=False,
                                               show_smoothed_data=False,
                                               max_min_method=max_min_method)

            analysed = analysis_data.analyse()

            pp.pprint(analysed)

            test_data = \
                {'average_maximum': 20.332122777777784,
                'average_minimum': -78.491198000000011,
                'first_spike_time': 108.44,
                'interspike_time_covar': 0.019741062134352557,
                'max_peak_no': 18,
                'mean_spike_frequency': 34.545824019508231,
                'min_peak_no': 17,
                'peak_decay_exponent': -0.064912249086890028,
                'peak_linear_gradient': -0.0020092762353974025,
                'spike_broadening': 1.0495985656104889,
                'spike_frequency_adaptation': 0.015301587514290844,
                'spike_width_adaptation': 0.0078514736435321177,
                'trough_decay_exponent': 0.0043242589967645087,
                'trough_phase_adaptation': 0.01048418950808087,
                'max_interspike_time': 31.080000000000013,
                'min_interspike_time': 28.70999999999998}

            for key in analysed.keys():
                self.assertAlmostEqual(analysed[key],test_data[key])


            if show:
                import matplotlib.pyplot as pylab
                fig = pylab.figure()
                fig.canvas.set_window_title("Data loaded (%i traces at %i time points)"%(len(volts),len(times)))

                pylab.xlabel('Time (ms)')
                pylab.ylabel('Voltage (mV)')
                pylab.grid('on')


                maxmin = analysis_data.max_min_dictionary
                pp.pprint(maxmin)

                self.add_horizontal_line(analysis_data.analysis_results['average_maximum'], times)
                self.add_horizontal_line(analysis_data.analysis_results['average_minimum'], times)

                for i in range(len(maxmin['maxima_times'])):
                    pylab.plot(maxmin['maxima_times'][i],maxmin['maxima_values'][i],'go')

                for i in range(len(maxmin['minima_times'])):
                    pylab.plot(maxmin['minima_times'][i],maxmin['minima_values'][i],'ro')

                pylab.plot(times, volts)


        if show:
            pylab.show()

    def test_net_analysis_data(self):

        print("- test_net_analysis_data()")

        analysis_var={'peak_delta':0,'baseline':0,'dvdt_threshold':0, 'peak_threshold':0}

        times, volts0 = self.get_real_data()
        volts = {'v': volts0}

        max_min_methods = [analysis.max_min_simple]

        for max_min_method in max_min_methods:

            print('--------------  Analysing with: %s in NetworkAnalysis'%max_min_method)
            analysis_data=analysis.NetworkAnalysis(volts,
                                               times,
                                               analysis_var,
                                               start_analysis=0,
                                               end_analysis=1000,
                                               smooth_data=False,
                                               show_smoothed_data=False)

            analysed = analysis_data.analyse(extra_targets=['v:value_50','v:value_200','v:average_200_201','v:average_100_200'])

            pp.pprint(analysed)

            test_data = \
                {'v:average_100_200': -55.34134969170771,
                'v:average_200_201': -73.48867227722772,
                'v:average_last_1percent': -63.559740088571395,
                'v:average_maximum': 20.332122777777784,
                'v:average_minimum': -78.491198000000011,
                'v:first_spike_time': 108.44,
                'v:interspike_time_covar': 0.019741062134352557,
                'v:max_peak_no': 18,
                'v:maximum': 23.789272,
                'v:mean_spike_frequency': 34.545824019508231,
                'v:min_peak_no': 17,
                'v:minimum': -79.47941999999999,
                'v:peak_decay_exponent': -0.064912249086890028,
                'v:peak_linear_gradient': -0.0020092762353973994,
                'v:spike_broadening': 1.0495985656104889,
                'v:spike_frequency_adaptation': 0.015301587514290829,
                'v:spike_width_adaptation': 0.0078514736435321194,
                'v:trough_decay_exponent': 0.0043242589967644922,
                'v:trough_phase_adaptation': 0.010484189508080874,
                'v:value_200': -75.04318,
                'v:value_50': -62.48935,
                'v:max_interspike_time': 31.080000000000013,
                'v:min_interspike_time': 28.70999999999998}

            for key in analysed.keys():
                self.assertAlmostEqual(analysed[key],test_data[key])



    def test_max_min(self):

        print("- test_max_min()")

        times, data = self.get_data(10,1,-80,30,[2,6])

        res = analysis.max_min(data, times)

        assert(res['minima_values'] == [-80])
        assert(res['maxima_values'][0] == 30)

        times, data = self.get_data(600,0.1,-80,40,[23,55.5,120,333.88,555.999])

        res = analysis.max_min(data, times)


        times, data = self.get_real_data()
        print(io.summary(data, "Real data set"))

        res = analysis.max_min(data, times)

        print('Found %i maxima: %s'%(len(res['maxima_times']),res['maxima_times']))

        assert(res['maxima_times'] == [108.44, 139.52, 169.08, 198.15, 227.02, 255.80000000000004, 284.55, 313.26, 341.98, 370.7, 399.40999999999997, 428.13, 456.84999999999997, 485.58, 514.3100000000001, 543.04, 571.77, 600.54])



    def runTest(self):
        print("Running tests in TestAnalysis")

if __name__ == '__main__':

    import logging
    logging.basicConfig(level=logging.WARNING)
    ta = TestAnalysis()
    #ta.test_iclamp_analysis_data(True)
    ta.test_net_analysis_data()
