import numpy as np
from pathlib import Path
import warnings

from pynwb import NWBHDF5IO, validate, TimeSeries
from pynwb.image import ImageSeries
from pynwb.testing import TestCase


class TestReadOldVersions(TestCase):

    expected_errors = {
        '1.0.2_str_experimenter.nwb': [("root/general/experimenter (general/experimenter): incorrect shape - expected "
                                        "an array of shape '[None]', got non-array data 'one experimenter'")],
        '1.0.3_str_experimenter.nwb': [("root/general/experimenter (general/experimenter): incorrect shape - expected "
                                        "an array of shape '[None]', got non-array data 'one experimenter'")],
        '1.0.2_str_pub.nwb': [("root/general/related_publications (general/related_publications): incorrect shape "
                               "- expected an array of shape '[None]', got non-array data 'one publication'")],
        '1.0.3_str_pub.nwb': [("root/general/related_publications (general/related_publications): incorrect shape "
                               "- expected an array of shape '[None]', got non-array data 'one publication'")],
    }

    def test_read(self):
        """Test reading and validating all NWB files in the same folder as this file.

        This folder contains NWB files generated by previous versions of NWB using the script
        src/pynwb/testing/make_test_files.py
        """
        dir_path = Path(__file__).parent
        nwb_files = dir_path.glob('*.nwb')
        for f in nwb_files:
            with self.subTest(file=f.name):
                with NWBHDF5IO(str(f), 'r') as io:
                    errors = validate(io)
                    io.read()
                    if errors:
                        for e in errors:
                            if f.name in self.expected_errors and str(e) not in self.expected_errors[f.name]:
                                warnings.warn('%s: %s' % (f.name, e))
                        # TODO uncomment below when validation errors have been fixed
                        # raise Exception('%d validation error(s). See warnings.' % len(errors))

    def test_read_timeseries_no_data(self):
        """Test that a TimeSeries written without data is read with data set to the default value."""
        f = Path(__file__).parent / '1.5.1_timeseries_no_data.nwb'
        with NWBHDF5IO(str(f), 'r') as io:
            read_nwbfile = io.read()
            np.testing.assert_array_equal(read_nwbfile.acquisition['test_timeseries'].data, TimeSeries.DEFAULT_DATA)

    def test_read_timeseries_no_unit(self):
        """Test that an ImageSeries written without unit is read with unit set to the default value."""
        f = Path(__file__).parent / '1.5.1_timeseries_no_unit.nwb'
        with NWBHDF5IO(str(f), 'r') as io:
            read_nwbfile = io.read()
            self.assertEqual(read_nwbfile.acquisition['test_timeseries'].unit, TimeSeries.DEFAULT_UNIT)

    def test_read_imageseries_no_data(self):
        """Test that an ImageSeries written without data is read with data set to the default value."""
        f = Path(__file__).parent / '1.5.1_imageseries_no_data.nwb'
        with NWBHDF5IO(str(f), 'r') as io:
            read_nwbfile = io.read()
            np.testing.assert_array_equal(read_nwbfile.acquisition['test_imageseries'].data, ImageSeries.DEFAULT_DATA)

    def test_read_imageseries_no_unit(self):
        """Test that an ImageSeries written without unit is read with unit set to the default value."""
        f = Path(__file__).parent / '1.5.1_imageseries_no_unit.nwb'
        with NWBHDF5IO(str(f), 'r') as io:
            read_nwbfile = io.read()
            self.assertEqual(read_nwbfile.acquisition['test_imageseries'].unit, ImageSeries.DEFAULT_UNIT)
