'''
Note: this version of FileBrowser was edited to suit my needs.
github.com/EdvardasDlugauskas


FileBrowser
===========

The :class:`FileBrowser` widget is an advanced file browser. You use it
similarly to FileChooser usage.

It provides a shortcut bar with links to special and system directories.
When touching next to a shortcut in the links bar, it'll expand and show
all the directories within that directory. It also facilitates specifying
custom paths to be added to the shortcuts list.

It provides a icon and list view to choose files from. And it also accepts
filter and filename inputs.

To create a FileBrowser which prints the currently selected file as well as
the current text in the filename field when 'Select' is pressed, with
a shortcut to the Documents directory added to the favorites bar::

    import os
    from kivy.app import App

    class TestApp(App):

        def build(self):
            user_path = os.path.join(get_home_directory(), 'Documents')
            browser = FileBrowser(select_string='Select',
                                  favorites=[(user_path, 'Documents')])
            browser.bind(on_success=self._fbrowser_success,
                         on_canceled=self._fbrowser_canceled,
                         on_submit=self._fbrowser_submit)
            return browser

        def _fbrowser_canceled(self, instance):
            print('cancelled, Close self.')

        def _fbrowser_success(self, instance):
            print(instance.selection)

        def _fbrowser_submit(self, instance):
            print(instance.selection)

    TestApp().run()

:Events:
    `on_canceled`:
        Fired when the `Cancel` buttons `on_release` event is called.

    `on_success`:
        Fired when the `Select` buttons `on_release` event is called.

    `on_success`:
        Fired when a file has been selected with a double-tap.

.. image:: _static/filebrowser.png
    :align: right
'''

__all__ = ('FileBrowser',)
__version__ = '1.1-dev'

import string
from functools import partial
from os import walk
from os.path import sep, dirname, expanduser, isdir, join, abspath
from sys import getfilesystemencoding

from kivy.clock import Clock
from kivy.compat import PY2
from kivy.lang import Builder
from kivy.properties import (ObjectProperty, StringProperty, OptionProperty,
                             ListProperty, BooleanProperty)
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.filechooser import FileChooserIconView as IconView
from kivy.uix.treeview import TreeViewLabel, TreeView
from kivy.utils import platform

if platform == 'win':
    from ctypes import windll, create_unicode_buffer


def get_home_directory():
    if platform == 'win':
        user_path = expanduser('~')

        if not isdir(join(user_path, 'Desktop')):
            user_path = dirname(user_path)

    else:
        user_path = expanduser('~')

    if PY2:
        user_path = user_path.decode(getfilesystemencoding())

    return user_path


def get_drives():
    drives = []
    if platform == 'win':
        bitmask = windll.kernel32.GetLogicalDrives()
        GetVolumeInformationW = windll.kernel32.GetVolumeInformationW
        for letter in string.ascii_uppercase:
            if bitmask & 1:
                name = create_unicode_buffer(64)
                # get name of the drive
                drive = letter + u':'
                res = GetVolumeInformationW(drive + sep, name, 64, None,
                                            None, None, None, 0)
                drives.append((drive, name.value))
            bitmask >>= 1
    elif platform == 'linux':
        drives.append((sep, sep))
        drives.append((expanduser(u'~'), '~/'))
        places = (sep + u'mnt', sep + u'media')
        for place in places:
            if isdir(place):
                for directory in next(walk(place))[1]:
                    drives.append((place + sep + directory, directory))
    elif platform == 'macosx' or platform == 'ios':
        drives.append((expanduser(u'~'), '~/'))
        vol = sep + u'Volume'
        if isdir(vol):
            for drive in next(walk(vol))[1]:
                drives.append((vol + sep + drive, drive))
    return drives


class FileBrowserIconView(IconView):
    pass


Builder.load_string('''
#:kivy 1.2.0
#:import metrics kivy.metrics
#:import abspath os.path.abspath

<TreeLabel>:
    on_touch_down:
        self.parent.browser.path = self.path if\
        self.collide_point(*args[1].pos) and self.path else\
        self.parent.browser.path
    on_is_open: self.is_open and self.parent.trigger_populate(self)

<FileBrowser>:
    orientation: 'vertical'
    spacing: 5
    padding: [6, 6, 6, 6]
    select_state: select_button.state
    cancel_state: cancel_button.state
    filename: file_text.text
    on_favorites: link_tree.reload_favs(self.favorites)
    BoxLayout:
        orientation: 'horizontal'
        spacing: 5

        ScrollView:
            size_hint_x: None
            width: '153sp'
            LinkTree:
                id: link_tree
                browser: icon_view
                size_hint_y: None
                height: self.minimum_height
                on_parent: self.fill_tree(root.favorites)
                root_options: {'text': 'Locations', 'no_selection':True}
        BoxLayout:
            size_hint_x: .8
            orientation: 'vertical'
            Label:
                size_hint_y: None
                height: '22dp'
                text_size: self.size
                padding_x: '10dp'
                text: abspath(root.path)
                valign: 'middle'
            FileBrowserIconView:
                id: icon_view
                path: root.path
                filters: root.filters
                filter_dirs: root.filter_dirs
                show_hidden: root.show_hidden
                multiselect: root.multiselect
                dirselect: root.dirselect
                rootpath: root.rootpath
                on_submit: root.dispatch('on_submit')
    GridLayout:
        size_hint: (1, None)
        height: file_text.line_height * 2
        cols: 3
        rows: 1
        spacing: [5]
        TextInput:
			readonly: True
            id: file_text
            text: (root.selection[0] if root.selection else root.path)
            hint_text: 'Filename'
            multiline: False
			is_focusable: False
        Button:
            id: cancel_button
            font_size: 20
            size_hint_x: None
            width: metrics.dp(100)
            text: root.cancel_string
            on_release: root.dispatch('on_canceled')
            background_normal: ''
            background_color: .25, .14, .14, 1

        Button:
            id: select_button
            font_size: 20
            size_hint_x: None
            width: metrics.dp(100)
            text: root.select_string
            on_release: root.dispatch('on_success')
            background_normal: ''
            background_color: .14, .25, .14, 1

''')


class TreeLabel(TreeViewLabel):
    path = StringProperty('')
    '''Full path to the location this node points to.

    :class:`~kivy.properties.StringProperty`, defaults to ''
    '''


class LinkTree(TreeView):
    # link to the favorites section of link bar
    _favs = ObjectProperty(None)
    _computer_node = None

    def fill_tree(self, fav_list):
        user_path = get_home_directory()
        self._favs = self.add_node(TreeLabel(text='Favorites', is_open=True,
                                             no_selection=True))
        self.reload_favs(fav_list)

        libs = self.add_node(TreeLabel(text='Libraries', is_open=True,
                                       no_selection=True))
        places = ('Documents', 'Music', 'Pictures', 'Videos')
        for place in places:
            if isdir(join(user_path, place)):
                self.add_node(TreeLabel(text=place, path=join(user_path,
                                                              place)), libs)
        self._computer_node = self.add_node(TreeLabel(text='Computer',
                                                      is_open=True, no_selection=True))
        self._computer_node.bind(on_touch_down=self._drives_touch)
        self.reload_drives()

    def _drives_touch(self, obj, touch):
        if obj.collide_point(*touch.pos):
            self.reload_drives()

    def reload_drives(self):
        nodes = [(node, node.text + node.path) for node in \
                 self._computer_node.nodes if isinstance(node, TreeLabel)]
        sigs = [s[1] for s in nodes]
        nodes_new = []
        sig_new = []
        for path, name in get_drives():
            if platform == 'win':
                text = u'{}({})'.format((name + ' ') if name else '', path)
            else:
                text = name
            nodes_new.append((text, path))
            sig_new.append(text + path + sep)
        for node, sig in nodes:
            if sig not in sig_new:
                self.remove_node(node)
        for text, path in nodes_new:
            if text + path + sep not in sigs:
                self.add_node(TreeLabel(text=text, path=path + sep),
                              self._computer_node)

    def reload_favs(self, fav_list):
        user_path = get_home_directory()
        favs = self._favs
        remove = []
        for node in self.iterate_all_nodes(favs):
            if node != favs:
                remove.append(node)
        for node in remove:
            self.remove_node(node)
        places = ('Desktop', 'Downloads')
        for place in places:
            if isdir(join(user_path, place)):
                self.add_node(TreeLabel(text=place, path=join(user_path,
                                                              place)), favs)
        for path, name in fav_list:
            if isdir(path):
                self.add_node(TreeLabel(text=name, path=path), favs)

    def trigger_populate(self, node):
        if not node.path or node.nodes:
            return
        parent = node.path
        _next = next(walk(parent))
        if _next:
            for path in _next[1]:
                self.add_node(TreeLabel(text=path, path=parent + sep + path),
                              node)


class FileBrowser(BoxLayout):
    '''FileBrowser class, see module documentation for more information.
    '''

    __events__ = ('on_canceled', 'on_success', 'on_submit')

    select_state = OptionProperty('normal', options=('normal', 'down'))
    '''State of the 'select' button, must be one of 'normal' or 'down'.
    The state is 'down' only when the button is currently touched/clicked,
    otherwise 'normal'. This button functions as the typical Ok/Select/Save
    button.

    :data:`select_state` is an :class:`~kivy.properties.OptionProperty`.
    '''
    cancel_state = OptionProperty('normal', options=('normal', 'down'))
    '''State of the 'cancel' button, must be one of 'normal' or 'down'.
    The state is 'down' only when the button is currently touched/clicked,
    otherwise 'normal'. This button functions as the typical cancel button.

    :data:`cancel_state` is an :class:`~kivy.properties.OptionProperty`.
    '''

    select_string = StringProperty('Ok')
    '''Label of the 'select' button.

    :data:`select_string` is an :class:`~kivy.properties.StringProperty`,
    defaults to 'Ok'.
    '''

    cancel_string = StringProperty('Cancel')
    '''Label of the 'cancel' button.

    :data:`cancel_string` is an :class:`~kivy.properties.StringProperty`,
    defaults to 'Cancel'.
    '''

    filename = StringProperty('')
    '''The current text in the filename field. Read only. When multiselect is
    True, the list of selected filenames is shortened. If shortened, filename
    will contain an ellipsis.

    :data:`filename` is an :class:`~kivy.properties.StringProperty`,
    defaults to ''.

    .. versionchanged:: 1.1
    '''

    selection = ListProperty([])
    '''Read-only :class:`~kivy.properties.ListProperty`.
    Contains the list of files that are currently selected in the current tab.
    See :kivy_fchooser:`kivy.uix.filechooser.FileChooserController.selection`.

    .. versionchanged:: 1.1
    '''

    path = StringProperty(u'/')
    '''