#
# Copyright 2012 Tomasz Wiszkowski
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import gobject
import gtk
from elements.xfcon_object import XfConObject

class XfConBox(XfConObject):
  def __xfcon_signals(self):
    return {
      XfConObject.XFCON_SIGNAL_MENU_BUILD: self.__on_menu_build,
      XfConObject.XFCON_SIGNAL_MENU_SHOW: self.__on_menu_show,
      XfConObject.XFCON_SIGNAL_MENU_HIDE: self.__on_menu_hide,
      XfConObject.XFCON_SIGNAL_VIEW_TERMINATE: self.__on_child_exit,
      XfConObject.XFCON_SIGNAL_VIEW_SPLIT_HORIZONTAL: self.__on_split_horizontal,
      XfConObject.XFCON_SIGNAL_VIEW_SPLIT_VERTICAL: self.__on_split_vertical,
      XfConObject.XFCON_SIGNAL_VIEW_ACTIVATE_NEXT: self.__on_activate_next,
      XfConObject.XFCON_SIGNAL_VIEW_ACTIVATE_PREVIOUS: self.__on_activate_previous,
      "focus-in-event": self.__on_focus_in,
      "focus-out-event": self.__on_focus_out
    }

  def __init__(self):
    self.handlers = {}
    self.current_focus = None

  def __on_split_vertical(self, source, sibling):
    self.__split(gtk.ORIENTATION_VERTICAL, source, sibling)
    return True

  def __on_split_horizontal(self, source, sibling):
    self.__split(gtk.ORIENTATION_HORIZONTAL, source, sibling)
    return True

  def __on_focus_in(self, source, event):
    self.emit("focus-in-event", event)
    self.current_focus = source

  def __on_focus_out(self, source, event):
    self.emit("focus-out-event", event)

  def __split(self, orientation, child, sibling):
    child_position = self.child_get_property(child, 'position')

    # if current orientation is not what we need, then create new box
    if self.get_orientation() == orientation:
      if orientation == gtk.ORIENTATION_HORIZONTAL:
        new_box = XfConVBox()
      else:
        new_box = XfConHBox()

      # since we're about to remove child from self, we need to unbind signals on it
      self.remove(child)
      new_box.pack_start(child)
      new_box.pack_start(sibling)
      new_box.show()
      self.pack_start(new_box)
      self.reorder_child(new_box, child_position)
    else:
      self.pack_start(sibling)
      self.reorder_child(sibling, child_position + 1)

  def __activate_first(self):
    if len(self.get_children()) == 0:
      return False

    child = self.get_children()[0]
    if isinstance(child, XfConBox):
      return child.__activate_first()
    else:
      child.grab_focus()
    return True

  def __activate_last(self):
    if len(self.get_children()) == 0:
      return False

    child = self.get_children()[-1]
    if isinstance(child, XfConBox):
      return child.__activate_last()
    else:
      child.grab_focus()
    return True

  def __on_menu_build(self, source, menu):
    return self.emit_menu_build(menu)

  def __on_menu_show(self, *args):
    return self.emit_menu_show()

  def __on_menu_hide(self, *args):
    return self.emit_menu_hide()

  def _gtk_pack_start(self, target, *args):
    self.handlers[target] = target.register_callbacks(self.__xfcon_signals())
    return gtk.Box.pack_start(self, target)

  def _gtk_remove(self, target):
    target.unregister_callbacks(self.handlers.pop(target))
    self.__on_activate_previous(target)
    return gtk.Box.remove(self, target)

  def _gtk_grab_focus(self):
    if (self.current_focus):
      self.current_focus.grab_focus()
    elif self.get_children():
      self.get_children()[0].grab_focus()

  def __on_child_exit(self, target):
    self.remove(target)
    target.destroy()
    if len(self.get_children()) == 0:
      self.emit_view_terminate()

  def __on_activate_next(self, source):
    position = self.child_get_property(source, 'position')
    children = self.get_children()
    if position < (len(children) - 1):
      child = children[position + 1]
      if isinstance(child, XfConBox):
        return child.__activate_first()
      else:
        child.grab_focus()
        return True
    else:
      if not self.emit_view_activate_next():
        return self.__activate_first()

  def __on_activate_previous(self, source):
    position = self.child_get_property(source, 'position')
    children = self.get_children()
    if position > 0:
      child = children[position - 1]
      if isinstance(child, XfConBox):
        return child.__activate_last()
      else:
        child.grab_focus()
        return True
    else:
      if not self.emit_view_activate_previous():
        return self.__activate_last()


class XfConHBox(gtk.HBox, XfConBox):
  __gsignals__ = XfConObject.XfConSignals()

  def __init__(self):
    super(self.__class__, self).__init__(True, True)
    XfConBox.__init__(self)

  def pack_start(self, target, *args, **kwargs):
    return self._gtk_pack_start(target, args)

  def remove(self, target):
    return self._gtk_remove(target)

  def grab_focus(self):
    return self._gtk_grab_focus()


class XfConVBox(gtk.VBox, XfConBox):
  __gsignals__ = XfConObject.XfConSignals()

  def __init__(self):
    super(self.__class__, self).__init__(True, True)
    XfConBox.__init__(self)

  def pack_start(self, target, *args, **kwargs):
    return self._gtk_pack_start(target, args)

  def remove(self, target):
    return self._gtk_remove(target)

  def grab_focus(self):
    return self._gtk_grab_focus()
