## vim:ts=4:et:nowrap
##
##---------------------------------------------------------------------------##
##
## PySol -- a Python Solitaire game
##
## Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
## All Rights Reserved.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; see the file COPYING.
## If not, write to the Free Software Foundation, Inc.,
## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
##
## Markus F.X.J. Oberhumer
## <markus@oberhumer.com>
## http://www.oberhumer.com/pysol
##
##---------------------------------------------------------------------------##


# imports
import os, re, sys, types, Tkinter

# PySol imports
from mfxutil import destruct, Struct, KwStruct
from util import PACKAGE, CARDSET
from resource import CSI

# Toolkit imports
from tkutil import loadImage
from tkwidget import _ToplevelDialog, MfxDialog
from tkcanvas import MfxCanvasImage
from edittextdialog import DisplayTextDialog
from selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
from selecttree import SelectDialogTreeData, SelectDialogTreeCanvas
from selecttree import SelectDialogPreviewCanvas


# /***********************************************************************
# // Nodes
# ************************************************************************/

class SelectCardsetLeaf(SelectDialogTreeLeaf):
    pass


class SelectCardsetNode(SelectDialogTreeNode):
    def _getContents(self):
        contents = []
        for obj in self.tree.data.all_objects:
            if self.select_func(obj):
                node = SelectCardsetLeaf(self.tree, self, text=obj.name, key=obj.index)
                contents.append(node)
        return contents or self.tree.data.no_contents


# /***********************************************************************
# // Tree database
# ************************************************************************/

class SelectCardsetData(SelectDialogTreeData):
    def __init__(self, manager, key):
        SelectDialogTreeData.__init__(self)
        self.all_objects = manager.getAllSortedByName()
        self.all_objects = filter(lambda obj: not obj.error, self.all_objects)
        self.no_contents = [ SelectCardsetLeaf(None, None, "(no cardsets)", key=None), ]
        #
        select_by_type = None
        items = CSI.TYPE.items()
        items.sort(lambda a, b: cmp(a[1], b[1]))
        nodes = []
        for key, name in items:
            if manager.registered_types.get(key):
                nodes.append(SelectCardsetNode(None, name, lambda cs, key=key: key == cs.si.type))
        if nodes:
            select_by_type = SelectCardsetNode(None, "by Type", tuple(nodes), expanded=1)
        #
        select_by_style = None
        items = CSI.STYLE.items()
        items.sort(lambda a, b: cmp(a[1], b[1]))
        nodes = []
        for key, name in items:
            if manager.registered_styles.get(key):
                nodes.append(SelectCardsetNode(None, name, lambda cs, key=key: key in cs.si.styles))
        if nodes:
            nodes.append(SelectCardsetNode(None, "Uncategorized", lambda cs: not cs.si.styles))
            select_by_style = SelectCardsetNode(None, "by Style", tuple(nodes))
        #
        select_by_nationality = None
        items = CSI.NATIONALITY.items()
        items.sort(lambda a, b: cmp(a[1], b[1]))
        nodes = []
        for key, name in items:
            if manager.registered_nationalities.get(key):
                nodes.append(SelectCardsetNode(None, name, lambda cs, key=key: key in cs.si.nationalities))
        if nodes:
            nodes.append(SelectCardsetNode(None, "Uncategorized", lambda cs: not cs.si.nationalities))
            select_by_nationality = SelectCardsetNode(None, "by Nationality", tuple(nodes))
        #
        select_by_date = None
        items = CSI.DATE.items()
        items.sort(lambda a, b: cmp(a[1], b[1]))
        nodes = []
        for key, name in items:
            if manager.registered_dates.get(key):
                nodes.append(SelectCardsetNode(None, name, lambda cs, key=key: key in cs.si.dates))
        if nodes:
            nodes.append(SelectCardsetNode(None, "Uncategorized", lambda cs: not cs.si.dates))
            select_by_date = SelectCardsetNode(None, "by Date", tuple(nodes))
        #
        self.rootnodes = filter(None, (
            SelectCardsetNode(None, "All Cardsets", lambda cs: 1, expanded=len(self.all_objects)<=12),
            SelectCardsetNode(None, "by Size", (
                SelectCardsetNode(None, "Tiny cardsets",   lambda cs: cs.si.size == CSI.SIZE_TINY),
                SelectCardsetNode(None, "Small cardsets",  lambda cs: cs.si.size == CSI.SIZE_SMALL),
                SelectCardsetNode(None, "Medium cardsets", lambda cs: cs.si.size == CSI.SIZE_MEDIUM),
                SelectCardsetNode(None, "Large cardsets",  lambda cs: cs.si.size == CSI.SIZE_LARGE),
                SelectCardsetNode(None, "XLarge cardsets", lambda cs: cs.si.size == CSI.SIZE_XLARGE),
            ), expanded=1),
            select_by_type,
            select_by_style,
            select_by_date,
            select_by_nationality,
        ))


class SelectCardsetByTypeData(SelectDialogTreeData):
    def __init__(self, manager, key):
        SelectDialogTreeData.__init__(self)
        self.all_objects = manager.getAllSortedByName()
        self.no_contents = [ SelectCardsetLeaf(None, None, "(no cardsets)", key=None), ]
        #
        items = CSI.TYPE.items()
        items.sort(lambda a, b: cmp(a[1], b[1]))
        nodes = []
        for key, name in items:
            if manager.registered_types.get(key):
                nodes.append(SelectCardsetNode(None, name, lambda cs, key=key: key == cs.si.type))
        select_by_type = SelectCardsetNode(None, "by Type", tuple(nodes), expanded=1)
        #
        self.rootnodes = filter(None, (
            select_by_type,
        ))


# /***********************************************************************
# // Canvas that shows the tree
# ************************************************************************/

class SelectCardsetTree(SelectDialogTreeCanvas):
    data = None


class SelectCardsetByTypeTree(SelectDialogTreeCanvas):
    data = None


# /***********************************************************************
# // Dialog
# ************************************************************************/

class SelectCardsetDialogWithPreview(MfxDialog):
    Tree_Class = SelectCardsetTree
    TreeDataHolder_Class = SelectCardsetTree
    TreeData_Class = SelectCardsetData

    def __init__(self, parent, title, app, manager, key=None, **kw):
        kw = self.initKw(kw)
        _ToplevelDialog.__init__(self, parent, title, kw.resizable, kw.default)
        top_frame, bottom_frame = self.createFrames(kw)
        self.createBitmaps(top_frame, kw)
        #
        if key is None:
            key = manager.getSelected()
        self.manager = manager
        self.key = key
        if self.TreeDataHolder_Class.data is None:
            self.TreeDataHolder_Class.data = self.TreeData_Class(manager, key)
        #
        self.top.wm_minsize(400, 200)
        if self.top.winfo_screenwidth() >= 800:
            w1, w2 = 216, 400
        else:
            w1, w2 = 200, 300
        self.tree = self.Tree_Class(self, top_frame, key=key, default=kw.default,
                                   font=kw.font, width=w1)
        self.tree.frame.pack(side="left", fill=Tkinter.BOTH, expand=0, padx=kw.padx, pady=kw.pady)
        self.preview = SelectDialogPreviewCanvas(top_frame, width=w2)
        self.preview.setup(app, kw)
        # create a preview of the current state
        self.preview_key = -1
        self.preview_images = []
        self.updatePreview(key)
        #
        focus = self.createButtons(bottom_frame, kw)
        focus = self.tree.frame
        self.mainloop(focus, kw.timeout)

    def destroy(self):
        self.tree.updateNodesWithTree(self.tree.rootnodes, None)
        self.tree.destroy()
        self.preview.unbind_all()
        self.preview_images = []
        MfxDialog.destroy(self)

    def initKw(self, kw):
        kw = KwStruct(kw,
            strings=("OK", "Load", "Cancel",), default=0,
            separatorwidth=2, resizable=1,
            font=None,
            padx=10, pady=10,
            buttonpadx=10, buttonpady=5,
        )
        return MfxDialog.initKw(self, kw)

    def mDone(self, button):
        if button in (0, 1):               # Ok/Load
            self.key = self.tree.selection_key
            self.tree.n_expansions = 1  # save xyview in any case
        if button in (3, 4):
            cs = self.manager.get(self.tree.selection_key)
            if not cs:
                return
            f = os.path.join(cs.dir, "COPYRIGHT")
            if button == 4:
                f = os.path.join(cs.dir, "config.txt")
            try:
                file = open(f)
                text = file.read()
                file.close()
            except:
                return
            d = DisplayTextDialog(self.top, title=CARDSET+" "+cs.name,
                    text=text)
            return
        MfxDialog.mDone(self, button)

    def updatePreview(self, key):
        if key == self.preview_key:
            return
        canvas = self.preview.canvas
        canvas.deleteAllItems()
        self.preview_images = []
        cs = self.manager.get(key)
        if not cs:
            self.preview_key = -1
            return
        names, columns = cs.getPreviewCardNames()
        try:
            names, columns = cs.getPreviewCardNames()
            for n in names:
                f = os.path.join(cs.dir, n + cs.ext)
                self.preview_images.append(loadImage(file=f))
        except:
            self.preview_key = -1
            self.preview_images = []
            return
        i, x, y, sx, sy, dx, dy = 0, 10, 10, 0, 0, cs.CARDW + 10, cs.CARDH + 10
        for image in self.preview_images:
            MfxCanvasImage(canvas, x, y, anchor="nw", image=image)
            sx, sy = max(x, sx), max(y, sy)
            i = i + 1
            if i % columns == 0:
                x, y = 10, y + dy
            else:
                x = x + dx
        canvas.config(scrollregion=(0, 0, sx+dx, sy+dy))
        canvas.config(xscrollincrement=dx, yscrollincrement=dy)
##        self.preview.showHbar()
##        self.preview.showVbar()
        self.preview_key = key


class SelectCardsetByTypeDialogWithPreview(SelectCardsetDialogWithPreview):
    Tree_Class = SelectCardsetByTypeTree
    TreeDataHolder_Class = SelectCardsetByTypeTree
    TreeData_Class = SelectCardsetByTypeData

