#
#   Python GUI - Windows - PyObjC version
#

from Foundation import NSRect, NSPoint, NSSize, NSObject
import AppKit
from AppKit import NSWindow, NSScreen, NSTextView
from Utils import NSMultiClass
import Components
from Components import PyGUI_NS_EventHandler
from Containers import PyGUI_Flipped_NSView
import Applications
from Applications import application
from Events import Event
from GWindows import Window as GWindow

_default_options_for_style = {
    'standard':
        {'movable': 1, 'closable': 1, 'hidable': 1, 'resizable': 1},
    'nonmodal_dialog':
        {'movable': 1, 'closable': 0, 'hidable': 1, 'resizable': 0},
    'modal_dialog':
        {'movable': 1, 'closable': 0, 'hidable': 0, 'resizable': 0},
    'alert':
        {'movable': 1, 'closable': 0, 'hidable': 0, 'resizable': 0},
}

class Window(GWindow):
    #  _ns_window        _PyGUI_NSWindow
    #  _ns_style_mask    int

    def __init__(self, style = 'standard', zoomable = None, **kwds):
        # We ignore zoomable, since it's the same as resizable.
        self._style = style
        options = dict(_default_options_for_style[style])
        for option in ['movable', 'closable', 'hidable', 'resizable']:
            if option in kwds:
                options[option] = kwds.pop(option)
        self._ns_style_mask = self._ns_window_style_mask(**options)
        ns_rect = NSRect(NSPoint(0, 0), NSSize(self._default_width, self._default_height))
        ns_window = _PyGUI_NSWindow.alloc()
        ns_window.initWithContentRect_styleMask_backing_defer_(
            ns_rect, self._ns_style_mask, AppKit.NSBackingStoreBuffered, True)
        ns_content = PyGUI_Flipped_NSView.alloc()
        ns_content.initWithFrame_(NSRect(NSPoint(0, 0), NSSize(0, 0)))
        ns_window.setContentView_(ns_content)
        ns_window.setAcceptsMouseMovedEvents_(True)
        ns_window.setDelegate_(ns_window)
        ns_window.pygui_component = self
        self._ns_window = ns_window
        GWindow.__init__(self, style = style, closable = options['closable'],
            _ns_view = ns_window.contentView(), _ns_set_autoresizing_mask = False,
            **kwds)
    
    def _ns_window_style_mask(self, movable, closable, hidable, resizable):
        if movable or closable or hidable or resizable:
            mask = AppKit.NSTitledWindowMask
            if closable:
                mask |= AppKit.NSClosableWindowMask
            if hidable:
                mask |= AppKit.NSMiniaturizableWindowMask
            if resizable:
                mask |= AppKit.NSResizableWindowMask
        else:
            mask = AppKit.NSBorderlessWindowMask
        return mask

    def destroy(self):
        #print "Window.destroy:", self ###
        self.hide()
        app = application()
        if app._ns_key_window is self:
            app._ns_key_window = None
        GWindow.destroy(self)
        #  We can't drop all references to the NSWindow yet, because this method
        #  can be called from its windowShouldClose: method, and allowing an
        #  NSWindow to be released while executing one of its own methods seems
        #  to be a very bad idea (Cocoa hangs). So we hide the NSWindow and store
        #  a reference to it in a global. It will be released the next time a
        #  window is closed and the global is re-used.
        global _ns_zombie_window
        _ns_zombie_window = self._ns_window
        self._ns_window.pygui_component = None
        #self._ns_window = None

    def get_bounds(self):
        ns_window = self._ns_window
        ns_frame = ns_window.frame()
        (l, y), (w, h) = ns_window.contentRectForFrameRect_styleMask_(
            ns_frame, self._ns_style_mask)
        b = Applications.ns_screen_height - y
        result = (l, b - h, l + w, b)
        return result
    
    def set_bounds(self, (l, t, r, b)):
        y = Applications.ns_screen_height - b
        ns_rect = NSRect(NSPoint(l, y), NSSize(r - l, b - t))
        ns_window = self._ns_window
        ns_frame = ns_window.frameRectForContentRect_styleMask_(
            ns_rect, self._ns_style_mask)
        ns_window.setFrame_display_(ns_frame, False)

    def get_title(self):
        return self._ns_window.title()
    
    def set_title(self, v):
        self._ns_window.setTitle_(v)

    def get_visible(self):
        return self._ns_window.isVisible()
    
    def set_visible(self, v):
        if v:
            self._ns_window.orderFront_(None)
        else:
            self._ns_window.orderOut_(None)
    
    def _show(self):
        self._ns_window.makeKeyAndOrderFront_(None)
    
    def get_target(self):
        ns_window = self._ns_window
        ns_view = ns_window.firstResponder()
        while ns_view and ns_view is not ns_window:
            component = Components._ns_view_to_component.get(ns_view)
            if component:
                return component
            ns_view = ns_view.superview()
        return self
    
    def center(self):
        self._ns_window.center()
    
    def key_down(self, e):
        pass
    
    def _stagger(self):
        key_win = application()._ns_key_window
        if key_win:
            (x, y), (w, h) = key_win._ns_window.frame()
            p = self._ns_window.cascadeTopLeftFromPoint_(NSPoint(x, y + h))
            self._ns_window.setFrameTopLeftPoint_(p)
        else:
            (x, y), (w, h) = NSScreen.mainScreen().visibleFrame()
            ns_vis_topleft = NSPoint(x, y + h)
            self._ns_window.setFrameTopLeftPoint_(ns_vis_topleft)
    
#------------------------------------------------------------------------------

class _PyGUI_NSWindow(NSWindow, PyGUI_NS_EventHandler):
    __metaclass__ = NSMultiClass
    #  pygui_component   Window
    #  resize_delta      point or None
    
    resize_delta = None
    pygui_field_editor = None
    
    def _ns_event_position(self, ns_event):
        return ns_event.locationInWindow()

    def windowShouldClose_(self, sender):
        #  We use this to detect when the Aqua window closing button
        #  is pressed, and do the closing ourselves.
        self.pygui_component.close_cmd()
        return False
    
    #  The NSWindow is made its own delegate.

    def windowWillResize_toSize_(self, ns_win, new_ns_size):
        w0, h0 = self.frame().size
        w1, h1 = new_ns_size
        self.resize_delta = (w1 - w0, h1 - h0)
        return new_ns_size
    
    def windowDidResize_(self, notification):
        delta = self.resize_delta
        if delta:
            self.pygui_component.resized(delta)
            self.resize_delta = None

    def windowDidBecomeKey_(self, notification):
        app = application()
        app._ns_key_window = self.pygui_component
        app._update_menubar()

    def windowDidResignKey_(self, notification):
        app = application()
        app._ns_key_window = None
        app._update_menubar()
    
    def windowWillReturnFieldEditor_toObject_(self, ns_window, ns_obj):
        #  Return special field editor for newline handling in text fields.
        if True: #getattr(ns_obj, 'pygui_multiline', False):
            editor = self.pygui_field_editor
            if not editor:
                editor = _PyGUI_Field_Editor.alloc().initWithFrame_(
                    NSRect(NSPoint(0, 0), NSSize(0, 0)))
                editor.setFieldEditor_(True)
                editor.setDrawsBackground_(False)
                self.pygui_field_editor = editor
        else:
            editor = None
        return editor

#------------------------------------------------------------------------------

class _PyGUI_Field_Editor(NSTextView):
    #  Special field editor for use by TextFields. Intercepts
    #  return key events and handles them our own way.

    def keyDown_(self, ns_event):
        #print "_PyGUI_Field_Editor.keyDown_: %r" % ns_event.characters() ###
        pygui_nstextfield = self.superview().superview()
        ns_chars = ns_event.characters()
        if ns_chars == "\r":
            if pygui_nstextfield.pygui_multiline:
                #print "...inserting CR" ###
                self.insertText_("\n")
            else:
                NSTextView.keyDown_(self, ns_event)
                #print "...passing to PyGUI_NSTextField" ###
                pygui_nstextfield.keyDown_(ns_event)
        else:
            #print "...passing to NSTextView" ###
            NSTextView.keyDown_(self, ns_event)
            if ns_chars == "\x03": # Enter
                pygui_nstextfield.keyDown_(ns_event)