# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
"""Test for resource files management."""

__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/01/2018"


import os
import unittest
import shutil
import tempfile

from silx.third_party import six
import silx.resources
from .utils import utilstest
import socket


class TestResources(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        super(TestResources, cls).setUpClass()

        cls.tmpDirectory = tempfile.mkdtemp(prefix="resource_")
        os.mkdir(os.path.join(cls.tmpDirectory, "gui"))
        destination_dir = os.path.join(cls.tmpDirectory, "gui", "icons")
        os.mkdir(destination_dir)
        source = silx.resources.resource_filename("gui/icons/zoom-in.png")
        destination = os.path.join(destination_dir, "foo.png")
        shutil.copy(source, destination)
        source = silx.resources.resource_filename("gui/icons/zoom-out.svg")
        destination = os.path.join(destination_dir, "close.png")
        shutil.copy(source, destination)

    @classmethod
    def tearDownClass(cls):
        super(TestResources, cls).tearDownClass()
        shutil.rmtree(cls.tmpDirectory)

    def setUp(self):
        # Store the original configuration
        self._oldResources = dict(silx.resources._RESOURCE_DIRECTORIES)
        unittest.TestCase.setUp(self)

    def tearDown(self):
        unittest.TestCase.tearDown(self)
        # Restiture the original configuration
        silx.resources._RESOURCE_DIRECTORIES = self._oldResources

    def test_resource_dir(self):
        """Get a resource directory"""
        icons_dirname = silx.resources.resource_filename('gui/icons/')
        self.assertTrue(os.path.isdir(icons_dirname))

    def test_resource_file(self):
        """Get a resource file name"""
        filename = silx.resources.resource_filename('gui/icons/colormap.png')
        self.assertTrue(os.path.isfile(filename))

    def test_resource_nonexistent(self):
        """Get a non existent resource"""
        filename = silx.resources.resource_filename('non_existent_file.txt')
        self.assertFalse(os.path.exists(filename))

    def test_isdir(self):
        self.assertTrue(silx.resources.is_dir('gui/icons'))

    def test_not_isdir(self):
        self.assertFalse(silx.resources.is_dir('gui/icons/colormap.png'))

    def test_list_dir(self):
        result = silx.resources.list_dir('gui/icons')
        self.assertTrue(len(result) > 10)

    # With prefixed resources

    def test_resource_dir_with_prefix(self):
        """Get a resource directory"""
        icons_dirname = silx.resources.resource_filename('silx:gui/icons/')
        self.assertTrue(os.path.isdir(icons_dirname))

    def test_resource_file_with_prefix(self):
        """Get a resource file name"""
        filename = silx.resources.resource_filename('silx:gui/icons/colormap.png')
        self.assertTrue(os.path.isfile(filename))

    def test_resource_nonexistent_with_prefix(self):
        """Get a non existent resource"""
        filename = silx.resources.resource_filename('silx:non_existent_file.txt')
        self.assertFalse(os.path.exists(filename))

    def test_isdir_with_prefix(self):
        self.assertTrue(silx.resources.is_dir('silx:gui/icons'))

    def test_not_isdir_with_prefix(self):
        self.assertFalse(silx.resources.is_dir('silx:gui/icons/colormap.png'))

    def test_list_dir_with_prefix(self):
        result = silx.resources.list_dir('silx:gui/icons')
        self.assertTrue(len(result) > 10)

    # Test new repository

    def test_repository_not_exists(self):
        """The resource from 'test' is available"""
        self.assertRaises(ValueError, silx.resources.resource_filename, 'test:foo.png')

    def test_adding_test_directory(self):
        """The resource from 'test' is available"""
        silx.resources.register_resource_directory("test", "silx.test.resources", forced_path=self.tmpDirectory)
        path = silx.resources.resource_filename('test:gui/icons/foo.png')
        self.assertTrue(os.path.exists(path))

    def test_adding_test_directory_no_override(self):
        """The resource from 'silx' is still available"""
        silx.resources.register_resource_directory("test", "silx.test.resources", forced_path=self.tmpDirectory)
        filename1 = silx.resources.resource_filename('gui/icons/close.png')
        filename2 = silx.resources.resource_filename('silx:gui/icons/close.png')
        filename3 = silx.resources.resource_filename('test:gui/icons/close.png')
        self.assertTrue(os.path.isfile(filename1))
        self.assertTrue(os.path.isfile(filename2))
        self.assertTrue(os.path.isfile(filename3))
        self.assertEqual(filename1, filename2)
        self.assertNotEqual(filename1, filename3)

    def test_adding_test_directory_non_existing(self):
        """A resource while not exists in test is not available anyway it exists
        in silx"""
        silx.resources.register_resource_directory("test", "silx.test.resources", forced_path=self.tmpDirectory)
        resource_name = "gui/icons/colormap.png"
        path = silx.resources.resource_filename('test:' + resource_name)
        path2 = silx.resources.resource_filename('silx:' + resource_name)
        self.assertFalse(os.path.exists(path))
        self.assertTrue(os.path.exists(path2))


class TestResourcesWithoutPkgResources(TestResources):

    @classmethod
    def setUpClass(cls):
        super(TestResourcesWithoutPkgResources, cls).setUpClass()
        cls._old = silx.resources.pkg_resources
        silx.resources.pkg_resources = None

    @classmethod
    def tearDownClass(cls):
        silx.resources.pkg_resources = cls._old
        del cls._old
        super(TestResourcesWithoutPkgResources, cls).tearDownClass()


class TestResourcesWithCustomDirectory(TestResources):

    @classmethod
    def setUpClass(cls):
        super(TestResourcesWithCustomDirectory, cls).setUpClass()
        cls._old = silx.resources._RESOURCES_DIR
        base = os.path.dirname(silx.resources.__file__)
        silx.resources._RESOURCES_DIR = base

    @classmethod
    def tearDownClass(cls):
        silx.resources._RESOURCES_DIR = cls._old
        del cls._old
        super(TestResourcesWithCustomDirectory, cls).tearDownClass()


def isSilxWebsiteAvailable():
    try:
        six.moves.urllib.request.urlopen('http://www.silx.org', timeout=1)
        return True
    except six.moves.urllib.error.URLError:
        return False
    except socket.timeout:
        # This exception is still received in Python 2.7
        return False


class TestExternalResources(unittest.TestCase):
    """This is a test for the ExternalResources"""

    @classmethod
    def setUpClass(cls):
        if not isSilxWebsiteAvailable():
            raise unittest.SkipTest("Network or silx website not available")

    def setUp(self):
        self.utilstest = silx.resources.ExternalResources("toto", "http://www.silx.org/pub/silx/")

    def tearDown(self):
        if self.utilstest.data_home:
            shutil.rmtree(self.utilstest.data_home)
        self.utilstest = None

    def test_download(self):
        "test the download from silx.org"
        f = self.utilstest.getfile("lena.png")
        self.assertTrue(os.path.exists(f))
        di = utilstest.getdir("source.tar.gz")
        for fi in di:
            self.assertTrue(os.path.exists(fi))

    def test_download_all(self):
        "test the download of all files from silx.org"
        filename = self.utilstest.getfile("lena.png")
        directory = "source.tar.gz"
        _filelist = self.utilstest.getdir(directory)
        # download file and remove it to create a json mapping file
        os.remove(filename)
        directory_path = os.path.join(self.utilstest.data_home, "source")
        shutil.rmtree(directory_path)
        directory_path = os.path.join(self.utilstest.data_home, directory)
        os.remove(directory_path)
        filelist = self.utilstest.download_all()
        self.assertGreater(len(filelist), 1, "At least 2 items were downloaded")


def suite():
    loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
    test_suite = unittest.TestSuite()
    test_suite.addTest(loadTests(TestResources))
    test_suite.addTest(loadTests(TestResourcesWithoutPkgResources))
    test_suite.addTest(loadTests(TestResourcesWithCustomDirectory))
    test_suite.addTest(loadTests(TestExternalResources))
    return test_suite


if __name__ == '__main__':
    unittest.main(defaultTest='suite')
