"""
wxSplitterWindow objects

@copyright: 2002-2007 Alberto Griggio
@copyright: 2014 Carsten Grohmann
@license: MIT (see license.txt) - THIS PROGRAM COMES WITH NO WARRANTY
"""

import wx

import common
import wcodegen
from tree import Tree
from widget_properties import *
from edit_windows import ManagedBase, EditStylesMixin
from edit_sizers.edit_sizers import Sizer, SizerSlot

try:
    from panel import EditPanel
    _has_panel = True
except ImportError:
    _has_panel = False


class SplitterWindowSizer(Sizer):
    """\
    "Virtual sizer" responsible for the management of a SplitterWindow.
    """
    def set_item(self, pos, option=None, flag=None, border=None, size=None,
                 force_layout=True):
        """\
        Updates the layout of the item at the given pos.
        """
        #self._logger.debug('set_item()')
        if self.window.widget and \
                self.window.window_old and self.window.window_old.widget:
            self.window.widget.Unsplit(self.window.window_old.widget)
            self.window.window_old = None
        if self.window.window_1 and self.window.window_2:
            self.window.split()
    
    def add_item(self, item, pos=None, option=0, flag=0, border=0, size=None,
                 force_layout=True):
        """\
        Adds an item to self.window.
        """
        #self._logger.debug('add_item(): %s', item.name)
        if pos == 1:
            self.window.window_old = self.window.window_1
            self.window.window_1 = item
            self.window.properties['window_1'].set_value(item.name)
        else:
            self.window.window_old = self.window.window_2
            self.window.window_2 = item
            self.window.properties['window_2'].set_value(item.name)
    
    def free_slot(self, pos, force_layout=True):
        """\
        Replaces the element at pos with an empty slot
        """
        if pos == 1:
            if self.window.widget and \
                    self.window.window_1 and self.window.window_1.widget:
                self.window.widget.Unsplit(self.window.window_1.widget)
            self.window.window_1 = SizerSlot(self.window, self, pos)
            w = self.window.window_1
        else:
            if self.window.widget and \
                    self.window.window_2 and self.window.window_2.widget:
                self.window.widget.Unsplit()
            self.window.window_2 = SizerSlot(self.window, self, pos)
            w = self.window.window_2
        self.window.split()
        w.widget.SetFocus()
        
    def get_itempos(self, attrs):
        """\
        Get position of sizer item (used in xml_parse)
        """
        if hasattr(self.window.properties['window_1'], 'value') and \
                attrs['name'] == self.window.properties['window_1'].value:
            pos = 1
        else:
            pos = 2
        return pos
    
    def is_virtual(self):
        return True

# end of class SplitterWindowSizer


class EditSplitterWindow(ManagedBase, EditStylesMixin):
    """\
    Class to handle wxSplitterWindow objects

    @ivar orientation: Orientation of the widget e.g. wxSPLIT_VERTICAL
    @type orientation: str | unicode
    """

    _custom_base_classes = True
    events = [
        'EVT_SPLITTER_SASH_POS_CHANGING',
        'EVT_SPLITTER_SASH_POS_CHANGED',
        'EVT_SPLITTER_UNSPLIT',
        'EVT_SPLITTER_DCLICK',
        ]

    def __init__(self, name, parent, id, style, win_1, win_2, orientation,
                 sizer, pos, property_window, show=True):

        # Initialise parent classes
        ManagedBase.__init__(self, name, 'wxSplitterWindow', parent, id,
                             sizer, pos, property_window, show=show)
        EditStylesMixin.__init__(self)

        # initialise instance variables
        self.set_style(style)
        self.virtual_sizer = SplitterWindowSizer(self)
        self.window_1 = win_1
        self.window_2 = win_2
        self.orientation = orientation
        self.sash_pos = 0
        self.min_pane_size = 20

        # initialise properties remaining staff
        self.access_functions['min_pane_size'] = (self.get_min_pane_size,
                                                  self.set_min_pane_size)
        self.access_functions['style'] = (self.get_style, self.set_style)
        self.access_functions['sash_pos'] = (self.get_sash_pos,
                                             self.set_sash_pos)
        prop = self.properties
        prop['style'] = CheckListProperty(self, 'style', self.widget_writer)
        self.access_functions['orientation'] = (self.get_orientation,
                                                self.set_orientation)
        prop['orientation'] = HiddenProperty(
            self, 'orientation', label=_("Orientation"))

        self.access_functions['window_1'] = (self.get_win_1, lambda v: None)
        self.access_functions['window_2'] = (self.get_win_2, lambda v: None)
        prop['window_1'] = HiddenProperty(self, 'window_1')
        prop['window_2'] = HiddenProperty(self, 'window_2')
        self.window_1 = SizerSlot(self, self.virtual_sizer, 1)
        self.window_2 = SizerSlot(self, self.virtual_sizer, 2)

        prop['min_pane_size'] = SpinProperty(self, 'min_pane_size',
                                             can_disable=True, r=(10, 2000),
                                             label=_('Minimum pane size'))

        prop['sash_pos'] = SpinProperty(self, 'sash_pos', r=(0, 400),
                                        can_disable=True,
                                        label=_("Sash position"))
        self.no_custom_class = False
        self.access_functions['no_custom_class'] = (self.get_no_custom_class,
                                                    self.set_no_custom_class)
        prop['no_custom_class'] = CheckBoxProperty(
            self, 'no_custom_class',
            label=_("Don't generate code for this custom class"))

    def create_widget(self):
        self.widget = wx.SplitterWindow(self.parent.widget, self.id,
                                        style=self.get_int_style())
        self.split()

    def finish_widget_creation(self):
        ManagedBase.finish_widget_creation(self,
                                           sel_marker_parent=self.widget)

        sp = self.properties['sash_pos']
        if sp.is_active():
            sp.set_value(self.sash_pos)
            self.widget.SetSashPosition(self.sash_pos)
        else:
            sp.set_value(self.widget.GetSashPosition())

        min_pane_size = self.properties['min_pane_size']
        if sp.is_active():
            min_pane_size.set_value(self.min_pane_size)
            self.widget.SetMinimumPaneSize(self.min_pane_size)
        else:
            min_pane_size.set_value(self.widget.GetMinimumPaneSize())
        
        wx.EVT_SPLITTER_SASH_POS_CHANGED(self.widget, self.widget.GetId(),
                                         self.on_sash_pos_changed)

    def on_set_focus(self, event):
        self.show_properties()
        # here we must call event.Skip() also on Win32 as this we should be
        # able to move the sash
        event.Skip()

    def create_properties(self):
        ManagedBase.create_properties(self)
        panel = wx.ScrolledWindow(self.notebook, -1, style=wx.TAB_TRAVERSAL)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.properties['no_custom_class'].display(panel)
        self.properties['style'].display(panel)
        self.properties['sash_pos'].display(panel)
        self.properties['min_pane_size'].display(panel)
        sizer.Add(self.properties['no_custom_class'].panel, 0,
                  wx.ALL | wx.EXPAND, 3)
        sizer.Add(self.properties['style'].panel, 0, wx.EXPAND)
        sizer.Add(self.properties['sash_pos'].panel, 0, wx.EXPAND)
        sizer.Add(self.properties['min_pane_size'].panel, 0, wx.EXPAND)
        panel.SetAutoLayout(True)
        panel.SetSizer(sizer)
        sizer.Fit(panel)
        self.notebook.AddPage(panel, 'Widget')
        
    def split(self):
        if not self.widget:
            return
        if self.window_1 and self.window_2:
            self.window_1.show_widget(True)
            self.window_2.show_widget(True)
            sp = self.properties['sash_pos'].get_value()
            if not self.properties['sash_pos'].is_active():
                if self.orientation == 'wxSPLIT_VERTICAL':
                    max_pos = self.widget.GetClientSize()[0]
                else:
                    max_pos = self.widget.GetClientSize()[1]
                sp = max_pos / 2
            if self.orientation == 'wxSPLIT_VERTICAL':
                self.widget.SplitVertically(self.window_1.widget,
                                            self.window_2.widget, sp)
            else:
                self.widget.SplitHorizontally(self.window_1.widget,
                                              self.window_2.widget, sp)
            for window in self.window_1, self.window_2:
                if hasattr(window, 'sel_marker'):
                    window.sel_marker.update()

    def get_sash_pos(self):
        return self.sash_pos

    def set_sash_pos(self, value):
        try:
            value = int(value)
        except ValueError:
            return
        self.sash_pos = value
        if self.widget:
            self.widget.SetSashPosition(value)

    def get_min_pane_size(self):
        return self.min_pane_size

    def set_min_pane_size(self, value):
        try:
            value = int(value)
        except ValueError:
            return
        self.min_pane_size = value
        if self.widget:
            self.widget.SetMinimumPaneSize(value)

    def on_size(self, event):
        if not self.widget:
            return
        try:
            if self.orientation == 'wxSPLIT_VERTICAL':
                max_pos = self.widget.GetClientSize()[0]
            else:
                max_pos = self.widget.GetClientSize()[1]
            self.properties['sash_pos'].set_range(-max_pos, max_pos)
            if not self.properties['sash_pos'].is_active():
                self.widget.SetSashPosition(max_pos / 2)
                self.sash_pos = self.widget.GetSashPosition()
                self.properties['sash_pos'].set_value(self.sash_pos)
        except (AttributeError, KeyError):
            pass
        ManagedBase.on_size(self, event)

    def on_sash_pos_changed(self, event):
        self.sash_pos = self.widget.GetSashPosition()
        self.properties['sash_pos'].set_value(self.sash_pos)
        event.Skip()

    def get_orientation(self):
        """\
        Return the attribute name of the selected orientation.

        @rtype: str | unicode
        """
        return self.orientation

    def set_orientation(self, value):
        """\
        Select a orientation

        @param value: Attribute name e.g. 'wxSPLIT_HORIZONTAL'
        @type value:  str | unicode
        """
        assert value in ['wxSPLIT_HORIZONTAL', 'wxSPLIT_VERTICAL']
        self.orientation = value

    def get_win_1(self):
        if not isinstance(self.window_1, SizerSlot):
            return self.window_1.name
        return ''

    def get_win_2(self):
        if not isinstance(self.window_2, SizerSlot):
            return self.window_2.name
        return ''

    def get_no_custom_class(self):
        return self.no_custom_class

    def set_no_custom_class(self, value):
        self.no_custom_class = bool(int(value))

# end of class EditSplitterWindow


editor_class = EditSplitterWindow
editor_icon = 'icons/splitter_window.xpm'
editor_name = 'EditSplitterWindow'
editor_style = 'wxSPLIT_VERTICAL'

dlg_title = _('wxSplitterWindow')
box_title = _('Orientation')
choices = 'wxSPLIT_VERTICAL|wxSPLIT_HORIZONTAL'
tmpl_label = 'window'


def builder(parent, sizer, pos, number=[1]):
    """\
    Factory function for EditSplitterWindow objects.
    """
    dialog = wcodegen.WidgetStyleSelectionDialog(
        dlg_title, box_title, choices)

    if not dialog.ShowModal() == wx.ID_OK:
        return

    label = '%s_%d' % (tmpl_label, number[0])
    while common.app_tree.has_name(label):
        number[0] += 1
        label = tmpl_label % number[0]
    widget = editor_class(label, parent, wx.NewId(), None, None, None,
                          dialog.get_selection(),
                          sizer, pos, common.property_panel, show=False)
    if _has_panel:
        pane1 = EditPanel(label + '_pane_1', widget, wx.NewId(),
                          widget.virtual_sizer, 1, common.property_panel)
        pane2 = EditPanel(label + '_pane_2', widget, wx.NewId(),
                          widget.virtual_sizer, 2, common.property_panel)
        widget.window_1 = pane1
        widget.window_2 = pane2
    
    node = Tree.Node(widget)
    widget.node = node
    widget.virtual_sizer.node = node

    widget.set_option(1)
    widget.set_style("wxEXPAND")
    widget.show_widget(True)

    common.app_tree.insert(node, sizer.node, pos - 1)

    if _has_panel:
        node2 = Tree.Node(widget.window_1)
        widget.window_1.node = node2
        common.app_tree.add(node2, widget.node)

        node3 = Tree.Node(widget.window_2)
        widget.window_2.node = node3
        common.app_tree.add(node3, widget.node)

    sizer.set_item(widget.pos, 1, wx.EXPAND)


def xml_builder(attrs, parent, sizer, sizeritem, pos=None):
    """\
    Factory to build editor objects from a XML file.
    """
    from xml_parse import XmlParsingError
    try:
        name = attrs['name']
    except KeyError:
        raise XmlParsingError(_("'name' attribute missing"))
    if sizer is None or sizeritem is None:
        raise XmlParsingError(_("sizer or sizeritem object cannot be None"))
    widget = editor_class(name, parent, wx.NewId(), None, None, None,
                          editor_style, sizer, pos, common.property_panel)
    sizer.set_item(widget.pos, option=sizeritem.option,
                   flag=sizeritem.flag, border=sizeritem.border)
    node = Tree.Node(widget)
    widget.node = node
    if pos is None:
        common.app_tree.add(node, sizer.node)
    else:
        common.app_tree.insert(node, sizer.node, pos - 1)
    return widget


def initialize():
    """\
    initialization function for the module: returns a wxBitmapButton to be
    added to the main palette.
    """
    common.widgets[editor_name] = builder
    common.widgets_from_xml[editor_name] = xml_builder
    return common.make_object_button(editor_name, editor_icon)
