import os
import shutil
import tempfile
import unittest

import param

from .utils import check_defaults


class TestFileSelectorParameters(unittest.TestCase):

    def setUp(self):
        super().setUp()

        tmpdir1 = tempfile.mkdtemp()
        fa = os.path.join(tmpdir1, 'a.txt')
        fb = os.path.join(tmpdir1, 'b.txt')
        glob1 = os.path.join(tmpdir1, '*')
        open(fa, 'w').close()
        open(fb, 'w').close()
        tmpdir2 = tempfile.mkdtemp()
        fc = os.path.join(tmpdir2, 'c.txt')
        fd = os.path.join(tmpdir2, 'd.txt')
        glob2 = os.path.join(tmpdir2, '*')
        open(fc, 'w').close()
        open(fd, 'w').close()

        self.tmpdir1 = tmpdir1
        self.tmpdir2 = tmpdir2
        self.fa = fa
        self.fb = fb
        self.fc = fc
        self.fd = fd
        self.glob1 = glob1
        self.glob2 = glob2

        class P(param.Parameterized):
            a = param.FileSelector(path=glob1)
            b = param.FileSelector(default=fa, path=glob1)

        self.P = P

    def tearDown(self):
        shutil.rmtree(self.tmpdir1)
        shutil.rmtree(self.tmpdir2)

    def _check_defaults(self, p):
        assert p.default is None
        assert p.allow_None is None
        assert p.objects == []
        assert p.compute_default_fn is None
        assert p.check_on_set is False
        assert p.names == {}
        assert p.path == ""

    def test_defaults_class(self):
        class P(param.Parameterized):
            s = param.FileSelector()

        check_defaults(P.param.s, label='S')
        self._check_defaults(P.param.s)

    def test_defaults_inst(self):
        class P(param.Parameterized):
            s = param.FileSelector()

        p = P()

        check_defaults(p.param.s, label='S')
        self._check_defaults(p.param.s)

    def test_defaults_unbound(self):
        s = param.FileSelector()

        check_defaults(s, label=None)
        self._check_defaults(s)

    def test_default_to_first(self):
        p = self.P()
        assert p.a == p.param.a.objects[0]

    def test_default_is_honored(self):
        p = self.P()
        assert p.b == self.fa
        assert p.param.b.default in [self.fa, self.fb]

    def test_allow_default_None(self):
        class P(param.Parameterized):
            a = param.FileSelector(default=None)

    def test_default_not_in_glob(self):
        with self.assertRaises(ValueError):
            class P(param.Parameterized):
                a = param.FileSelector(default='not/in/glob', path=self.glob1)

    def test_objects_auto_set(self):
        p = self.P()
        assert p.param.a.objects == [self.fa, self.fb]

    def test_set_object_constructor(self):
        p = self.P(a=self.fb)
        assert p.a == self.fb

    def test_set_object_outside_bounds(self):
        p = self.P()
        with self.assertRaises(ValueError):
            p.a = '/not/in/glob'

    def test_set_path_and_update(self):
        p = self.P()
        p.param.b.path = self.glob2
        p.param.b.update()
        assert p.param.b.objects == [self.fc, self.fd]
        assert p.param.b.default in [self.fc, self.fd]
        # Default updated but not the value itself
        assert p.b == self.fa

    def test_path_autoupdate(self):
        p = self.P()
        p.param.b.path = self.glob2
        assert p.param.b.objects == [self.fc, self.fd]
        assert p.param.b.default in [self.fc, self.fd]
        # Default updated but not the value itself
        assert p.b == self.fa

    def test_get_range(self):
        p = self.P()
        r = p.param.a.get_range()
        assert r['a.txt'] == self.fa
        assert r['b.txt'] == self.fb
        p.param.a.path = self.glob2
        p.param.a.update()
        r = p.param.a.get_range()
        assert r['c.txt'] == self.fc
        assert r['d.txt'] == self.fd

    def test_update_file_removed(self):
        p = self.P()
        assert p.param.b.objects == [self.fa, self.fb]
        assert p.param.b.default in [self.fa, self.fb]
        os.remove(self.fa)
        p.param.b.update()
        assert p.param.b.objects == [self.fb]
        assert p.param.b.default == self.fb


def test_fileselector_glob_parent(tmpdir):
    # https://github.com/holoviz/param/issues/139

    ncwd = tmpdir / 'folder'
    data = tmpdir / 'data'
    data.mkdir()
    (data / 'foo.txt').write_text('foo', encoding='utf-8')
    ncwd.mkdir()
    cwd = os.getcwd()
    os.chdir(ncwd)
    try:
        if os.name == 'nt':
            default = r'..\data\foo.txt'
        else:
            default = '../data/foo.txt'
        class P(param.Parameterized):
            fs = param.FileSelector(default, path='../data/*.txt')

        assert len(P.param.fs.objects) == 1
        assert P.fs == default
    finally:
        os.chdir(cwd)
