# -*- coding: utf-8 -*-
#
#   Albow - File Dialogs
#

import os
from pygame import draw, Rect
from pygame.locals import *
from albow.widget import Widget
from albow.dialogs import Dialog, ask, alert
from albow.controls import Label, Button
from albow.fields import TextField
from albow.layout import Row, Column
from albow.palette_view import PaletteView
from albow.theme import ThemeProperty


class DirPathView(Widget):

    def __init__(self, width, client, **kwds):
        Widget.__init__(self, **kwds)
        self.set_size_for_text(width)
        self.client = client

    def draw(self, surf):
        frame = self.get_margin_rect()
        image = self.font.render(self.client.directory, True, self.fg_color)
        tw = image.get_width()
        mw = frame.width
        if tw <= mw:
            x = 0
        else:
            x = mw - tw
        surf.blit(image, (frame.left + x, frame.top))


class FileListView(PaletteView):

    #scroll_button_color = (255, 255, 0)

    def __init__(self, width, client, **kwds):
        font = self.predict_font(kwds)
        h = font.get_linesize()
        d = 2 * self.predict(kwds, 'margin')
        PaletteView.__init__(self, (width - d, h), 10, 1, scrolling=True, **kwds)
        self.client = client
        self.selection = None
        self.names = []

    def update(self):
        client = self.client
        dir = client.directory
        suffixes = client.suffixes

        def filter(name):
            path = os.path.join(dir, name)
            return os.path.isdir(path) or self.client.filter(path)

        try:
            names = [name for name in os.listdir(dir) if filter(name)]
                #if not name.startswith(".") and filter(name)]
        except EnvironmentError, e:
            alert(u"%s: %s" % (dir, e))
            names = []
        self.names = sorted(names)
        self.selection = None

    def num_items(self):
        return len(self.names)

    #def draw_prehighlight(self, surf, item_no, rect):
    #    draw.rect(surf, self.sel_color, rect)

    def draw_item(self, surf, item_no, rect):
        font = self.font
        color = self.fg_color
        buf = self.font.render(self.names[item_no], True, color)
        surf.blit(buf, rect)

    def click_item(self, item_no, e):
        self.selection = item_no
        self.client.dir_box_click(e.num_clicks == 2)

    def item_is_selected(self, item_no):
        return item_no == self.selection

    def get_selected_name(self):
        sel = self.selection
        if sel is not None:
            return self.names[sel]
        else:
            return ""


class FileDialog(Dialog):

    box_width = 250
    default_prompt = None
    up_button_text = ThemeProperty("up_button_text")

    def __init__(self, prompt=None, suffixes=None, **kwds):
        Dialog.__init__(self, **kwds)
        label = None
        d = self.margin
        self.suffixes = suffixes or ("",)
        up_button = Button(self.up_button_text, action=self.go_up)
        dir_box = DirPathView(self.box_width - up_button.width - 10, self)
        self.dir_box = dir_box
        top_row = Row([dir_box, up_button])
        list_box = FileListView(self.box_width - 16, self)
        self.list_box = list_box
        ctrls = [top_row, list_box]
        prompt = prompt or self.default_prompt
        if prompt:
            label = Label(prompt)
        if self.saving:
            filename_box = TextField(self.box_width)
            filename_box.change_action = self.update
            filename_box._enter_action = filename_box.enter_action
            filename_box.enter_action = self.enter_action
            self.filename_box = filename_box
            ctrls.append(Column([label, filename_box], align='l', spacing=0))
        else:
            if label:
                ctrls.insert(0, label)
        ok_button = Button(self.ok_label, action=self.ok, enable=self.ok_enable)
        self.ok_button = ok_button
        cancel_button = Button("Cancel", action=self.cancel)
        vbox = Column(ctrls, align='l', spacing=d)
        vbox.topleft = (d, d)
        y = vbox.bottom + d
        ok_button.topleft = (vbox.left, y)
        cancel_button.topright = (vbox.right, y)
        self.add(vbox)
        self.add(ok_button)
        self.add(cancel_button)
        self.shrink_wrap()
        self._directory = None
        self.directory = os.getcwdu()
        #print "FileDialog: cwd =", repr(self.directory) ###
        if self.saving:
            filename_box.focus()

    def get_directory(self):
        return self._directory

    def set_directory(self, x):
        x = os.path.abspath(x)
        while not os.path.exists(x):
            y = os.path.dirname(x)
            if y == x:
                x = os.getcwdu()
                break
            x = y
        if self._directory != x:
            self._directory = x
            self.list_box.update()
            self.update()

    directory = property(get_directory, set_directory)

    def filter(self, path):
        suffixes = self.suffixes
        if not suffixes or os.path.isdir(path):
            #return os.path.isfile(path)
            return True
        for suffix in suffixes:
            if path.endswith(suffix.lower()):
                return True

    def update(self):
        pass

    def go_up(self):
        self.directory = os.path.dirname(self.directory)
        self.list_box.scroll_to_item(0)

    def dir_box_click(self, double):
        if double:
            name = self.list_box.get_selected_name()
            path = os.path.join(self.directory, name)
            suffix = os.path.splitext(name)[1]
            if suffix not in self.suffixes and os.path.isdir(path):
                self.directory = path
            else:
                self.double_click_file(name)
        self.update()

    def enter_action(self):
        self.filename_box._enter_action()
        self.ok()

    def ok(self):
        self.dir_box_click(True)
        #self.dismiss(True)

    def cancel(self):
        self.dismiss(False)

    def key_down(self, evt):
        k = evt.key
        if k == K_RETURN or k == K_KP_ENTER:
            self.dir_box_click(True)
        if k == K_ESCAPE:
            self.cancel()


class FileSaveDialog(FileDialog):

    saving = True
    default_prompt = "Save as:"
    ok_label = "Save"

    def get_filename(self):
        return self.filename_box.value

    def set_filename(self, x):
        dsuf = self.suffixes[0]
        if x.endswith(dsuf):
            x = x[:-len(dsuf)]
        self.filename_box.value = x

    filename = property(get_filename, set_filename)

    def get_pathname(self):
        path = os.path.join(self.directory, self.filename_box.value)
        suffixes = self.suffixes
        if suffixes and not path.endswith(suffixes[0]):
            path = path + suffixes[0]
        return path

    pathname = property(get_pathname)

    def double_click_file(self, name):
        self.filename_box.value = name

    def ok(self):
        path = self.pathname
        if os.path.exists(path):
            answer = ask("Replace existing '%s'?" % os.path.basename(path))
            if answer != "OK":
                return
        #FileDialog.ok(self)
        self.dismiss(True)

    def update(self):
        FileDialog.update(self)

    def ok_enable(self):
        return self.filename_box.text != ""


class FileOpenDialog(FileDialog):

    saving = False
    ok_label = "Open"

    def get_pathname(self):
        name = self.list_box.get_selected_name()
        if name:
            return os.path.join(self.directory, name)
        else:
            return None

    pathname = property(get_pathname)

    #def update(self):
    #    FileDialog.update(self)

    def ok_enable(self):
        path = self.pathname
        enabled = self.item_is_choosable(path)
        return enabled

    def item_is_choosable(self, path):
        return bool(path) and self.filter(path)

    def double_click_file(self, name):
        self.dismiss(True)


class LookForFileDialog(FileOpenDialog):

    target = None

    def __init__(self, target, **kwds):
        FileOpenDialog.__init__(self, **kwds)
        self.target = target

    def item_is_choosable(self, path):
        return path and os.path.basename(path) == self.target

    def filter(self, name):
        return name and os.path.basename(name) == self.target


def request_new_filename(prompt=None, suffix=None, extra_suffixes=None,
        directory=None, filename=None, pathname=None):
    if pathname:
        directory, filename = os.path.split(pathname)
    if extra_suffixes:
        suffixes = extra_suffixes
    else:
        suffixes = []
    if suffix:
        suffixes = [suffix] + suffixes
    dlog = FileSaveDialog(prompt=prompt, suffixes=suffixes)
    if directory:
        dlog.directory = directory
    if filename:
        dlog.filename = filename
    if dlog.present():
        return dlog.pathname
    else:
        return None


def request_old_filename(suffixes=None, directory=None):
    dlog = FileOpenDialog(suffixes=suffixes)
    if directory:
        dlog.directory = directory
    if dlog.present():
        return dlog.pathname
    else:
        return None


def look_for_file_or_directory(target, prompt=None, directory=None):
    dlog = LookForFileDialog(target=target, prompt=prompt)
    if directory:
        dlog.directory = directory
    if dlog.present():
        return dlog.pathname
    else:
        return None
