# FileChooser code is from
# https://github.com/crahan/ipyfilechooser

from __future__ import print_function, division
from ipywidgets import Dropdown, Text, Select, Button, HTML
from ipywidgets import Layout, GridBox, HBox, VBox
#from .utils import update_path, get_subpaths, get_dir_contents
import os

__version__ = '0.1.2'

class FileChooser(VBox):

    _LBL_TEMPLATE = '<span style="margin-left:10px; color:{1};">{0}</span>'
    _LBL_NOFILE = 'No file selected'

    def __init__(
            self,
            path=os.getcwd(),
            filename='',
            show_hidden=False,
            **kwargs):

        self._default_path = path.rstrip(os.path.sep)
        self._default_filename = filename
        self._selected_path = ''
        self._selected_filename = ''
        self._show_hidden = show_hidden

        # Widgets
        self._pathlist = Dropdown(
            description="",
            layout=Layout(
                width='auto',
                grid_area='pathlist'
            )
        )
        self._filename = Text(
            placeholder='output filename',
            layout=Layout(
                width='auto',
                grid_area='filename'
            )
        )
        self._dircontent = Select(
            rows=8,
            layout=Layout(
                width='auto',
                grid_area='dircontent'
            )
        )
        self._cancel = Button(
            description='Cancel',
            button_style='warning', # 'success', 'info', 'warning', 'danger' or ''
            layout=Layout(
                width='auto',
                display='none'
            )
        )
        self._select = Button(
            description='Select',
            button_style='success', # 'success', 'info', 'warning', 'danger' or ''
            layout=Layout(width='auto')
        )

        # Widget observe handlers
        self._pathlist.observe(
            self._on_pathlist_select,
            names='value'
        )
        self._dircontent.observe(
            self._on_dircontent_select,
            names='value'
        )
        self._filename.observe(
            self._on_filename_change,
            names='value'
        )
        self._select.on_click(self._on_select_click)
        self._cancel.on_click(self._on_cancel_click)

        # Selected file label
        self._label = HTML(
            value=self._LBL_TEMPLATE.format(
                self._LBL_NOFILE,
                'black'
            ),
            placeholder='',
            description=''
        )

        # Layout
        self._gb = GridBox(
            children=[
                self._pathlist,
                self._filename,
                self._dircontent
            ],
            layout=Layout(
                display='none',
                width='500px',
                grid_gap='0px 0px',
                grid_template_rows='auto auto',
                grid_template_columns='60% 40%',
                grid_template_areas='''
                    'pathlist filename'
                    'dircontent dircontent'
                    '''
            )
        )
        buttonbar = HBox(
            children=[
                self._select,
                self._cancel,
                self._label
            ],
            layout=Layout(width='auto')
        )

        # Call setter to set initial form values
        self._set_form_values(
            self._default_path,
            self._default_filename
        )

        # Call VBox super class __init__
        super().__init__(
            children=[
                self._gb,
                buttonbar,
            ],
            layout=Layout(width='auto'),
            **kwargs
        )

    def _set_form_values(self, path, filename):
        '''Set the form values'''

        # Disable triggers to prevent selecting an entry in the Select
        # box from automatically triggering a new event.
        self._pathlist.unobserve(
            self._on_pathlist_select,
            names='value'
        )
        self._dircontent.unobserve(
            self._on_dircontent_select,
            names='value'
        )
        self._filename.unobserve(
            self._on_filename_change,
            names='value'
        )

        # Set form values
        self._pathlist.options = get_subpaths(path)
        self._pathlist.value = path
        self._filename.value = filename
        self._dircontent.options = get_dir_contents(
            path,
            hidden=self._show_hidden
        )

        # If the value in the filename Text box equals a value in the
        # Select box and the entry is a file then select the entry.
        if ((filename in self._dircontent.options) and
                os.path.isfile(os.path.join(path, filename))):
            self._dircontent.value = filename
        else:
            self._dircontent.value = None

        # Reenable triggers again
        self._pathlist.observe(
            self._on_pathlist_select,
            names='value'
        )
        self._dircontent.observe(
            self._on_dircontent_select,
            names='value'
        )
        self._filename.observe(
            self._on_filename_change,
            names='value'
        )

        # Set the state of the select Button
        if self._gb.layout.display is None:
            selected = os.path.join(
                self._selected_path,
                self._selected_filename
            )

            # filename value is empty or equals the selected value
            if (filename == '') or (os.path.join(path, filename) == selected):
                self._select.disabled = True
            else:
                self._select.disabled = False

    def _on_pathlist_select(self, change):
        '''Handler for when a new path is selected'''
        self._set_form_values(
            change['new'],
            self._filename.value
        )

    def _on_dircontent_select(self, change):
        '''Handler for when a folder entry is selected'''
        new_path = update_path(
            self._pathlist.value,
            change['new']
        )

        # Check if folder or file
        if os.path.isdir(new_path):
            path = new_path
            filename = self._filename.value
        elif os.path.isfile(new_path):
            path = self._pathlist.value
            filename = change['new']

        self._set_form_values(
            path,
            filename
        )

    def _on_filename_change(self, change):
        '''Handler for when the filename field changes'''
        self._set_form_values(
            self._pathlist.value,
            change['new']
        )

    def _on_select_click(self, b):
        '''Handler for when the select button is clicked'''
        if self._gb.layout.display == 'none':
            self._gb.layout.display = None
            self._cancel.layout.display = None

            # Show the form with the correct path and filename
            if self._selected_path and self._selected_filename:
                path = self._selected_path
                filename = self._selected_filename
            else:
                path = self._default_path
                filename = self._default_filename

            self._set_form_values(path, filename)

        else:
            self._gb.layout.display = 'none'
            self._cancel.layout.display = 'none'
            self._select.description = 'Change'
            self._selected_path = self._pathlist.value
            self._selected_filename = self._filename.value
            # self._default_path = self._selected_path
            # self._default_filename = self._selected_filename

            selected = os.path.join(
                self._selected_path,
                self._selected_filename
            )

            if os.path.isfile(selected):
                self._label.value = self._LBL_TEMPLATE.format(
                    selected,
                    'orange'
                )
            else:
                self._label.value = self._LBL_TEMPLATE.format(
                    selected,
                    'green'
                )

    def _on_cancel_click(self, b):
        '''Handler for when the cancel button is clicked'''
        self._gb.layout.display = 'none'
        self._cancel.layout.display = 'none'
        self._select.disabled = False

    def reset(self, path=None, filename=None):
        '''Reset the form to the default path and filename'''
        self._selected_path = ''
        self._selected_filename = ''

        self._label.value = self._LBL_TEMPLATE.format(
            self._LBL_NOFILE,
            'black'
        )

        if path is not None:
            self._default_path = path.rstrip(os.path.sep)

        if filename is not None:
            self._default_filename = filename

        self._set_form_values(
            self._default_path,
            self._default_filename
        )

    def refresh(self):
        '''Re-render the form'''
        self._set_form_values(
            self._pathlist.value,
            self._filename.value
        )

    @property
    def show_hidden(self):
        '''Get current number of rows'''
        return self._show_hidden

    @show_hidden.setter
    def show_hidden(self, hidden):
        '''Set number of rows'''
        self._show_hidden = hidden
        self.refresh()

    @property
    def rows(self):
        '''Get current number of rows'''
        return self._dircontent.rows

    @rows.setter
    def rows(self, rows):
        '''Set number of rows'''
        self._dircontent.rows = rows

    @property
    def default(self):
        '''Get the default value'''
        return os.path.join(
            self._default_path,
            self._default_filename
        )

    @property
    def default_path(self):
        '''Get the default_path value'''
        return self._default_path

    @default_path.setter
    def default_path(self, path):
        '''Set the default_path'''
        self._default_path = path.rstrip(os.path.sep)
        self._default = os.path.join(
            self._default_path,
            self._filename.value
        )
        self._set_form_values(
            self._default_path,
            self._filename.value
        )

    @property
    def default_filename(self):
        '''Get the default_filename value'''
        return self._default_filename

    @default_filename.setter
    def default_filename(self, filename):
        '''Set the default_filename'''
        self._default_filename = filename
        self._default = os.path.join(
            self._pathlist.value,
            self._default_filename
        )
        self._set_form_values(
            self._pathlist.value,
            self._default_filename
        )

    @property
    def selected(self):
        '''Get selected value'''
        return os.path.join(
            self._selected_path,
            self._selected_filename
        )

    @property
    def selected_path(self):
        '''Get selected_path value'''
        return self._selected_path

    @property
    def selected_filename(self):
        '''Get the selected_filename'''
        return self._selected_filename

    @property
    def nmrname(self):      # added by MAD
        return os.path.join(os.path.basename(os.path.dirname(self._selected_path)),
                            os.path.basename(self._selected_path))
    
    def __repr__(self):
        str_ = ("FileChooser("
                "path='{0}', "
                "filename='{1}', "
                "show_hidden='{2}')").format(
            self._default_path,
            self._default_filename,
            self._show_hidden
        )
        return str_


def get_subpaths(path):
    '''Walk a path and return a list of subpaths'''
    if os.path.isfile(path):
        path = os.path.dirname(path)

    paths = [path]
    path, tail = os.path.split(path)

    while tail:
        paths.append(path)
        path, tail = os.path.split(path)

    return paths


def update_path(path, item):
    '''Update path with new item'''
    if item == '..':
        path = os.path.dirname(path)
    else:
        path = os.path.join(path, item)

    return path


def has_parent(path):
    '''Check if a path has a parent folder'''
    return os.path.basename(path) != ''


def get_dir_contents(path, hidden=False):
    '''Get directory contents'''
    files = list()
    dirs = list()

    if os.path.isdir(path):
        for item in os.listdir(path):
            append = True
            if item.startswith('.') and not hidden:
                append = False
            full_item = os.path.join(path, item)
            if os.path.isdir(full_item) and append:
                dirs.append(item)
            elif append:
                files.append(item)
        if has_parent(path):
            dirs.insert(0, '..')
    return sorted(dirs) + sorted(files)