#------------------------------------------------------------------------------
#
#   Python GUI - Windows - PyObjC version
#
#------------------------------------------------------------------------------

from Foundation import NSRect, NSPoint, NSSize, NSObject
import AppKit
from AppKit import NSWindow, NSScreen, NSTextView, NSMenu
from GUI import export
from GUI import Globals
from GUI.Utils import NSMultiClass, PyGUI_NS_EventHandler, PyGUI_Flipped_NSView
from GUI import application
from GUI import Event
from GUI.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},
    'fullscreen':
        {'movable': 0, 'closable': 0, 'hidable': 0, 'resizable': 0},
        #{'movable': 1, 'closable': 1, 'hidable': 1, 'resizable': 1},
}

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

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)
        if style == 'fullscreen':
            ns_rect = NSScreen.mainScreen().frame()
        else:
            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_NS_ContentView.alloc()
        ns_content.initWithFrame_(NSRect(NSPoint(0, 0), NSSize(0, 0)))
        ns_content.pygui_component = self
        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_responder = ns_window,
            _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 = Globals.ns_screen_height - y
        result = (l, b - h, l + w, b)
        return result
    
    def set_bounds(self, (l, t, r, b)):
        y = Globals.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):
        #  At some mysterious time between creating a window and showing
        #  it for the first time, Cocoa adjusts its position so that it
        #  doesn't extend above the menu bar. This is a nuisance for
        #  our fullscreen windows, so we need to readjust the position
        #  before showing.
        if v:
            if self._style == 'fullscreen':
                self._ns_window.setFrameOrigin_(NSPoint(0, 0))
            self._ns_window.orderFront_(None)
        else:
            self._ns_window.orderOut_(None)
    
    def _show(self):
        self.visible = True
        self._ns_window.makeKeyWindow()
    
    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 = Globals._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 _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)

    def _document_needs_saving(self, state):
        self._ns_window.setDocumentEdited_(state)
    
#------------------------------------------------------------------------------

class PyGUI_NSWindow(NSWindow, PyGUI_NS_EventHandler):
    #  pygui_component   Window
    #  resize_delta      point or None
    
    __metaclass__ = NSMultiClass
    __slots__ = ['pygui_component', 'resize_delta', 'pygui_field_editor']
    
#	pygui_component = 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 = getattr(self, 'resize_delta', None)
        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.
        #print "Window: Field editor requested for", object.__repr__(ns_obj) ###
        #editor = self.pygui_field_editor
        #if not editor:
        try:
            editor = self.pygui_field_editor
        except AttributeError:
            #print "...creating new field editor" ###
            editor = PyGUI_FieldEditor.alloc().initWithFrame_(
                NSRect(NSPoint(0, 0), NSSize(0, 0)))
            editor.setFieldEditor_(True)
            editor.setDrawsBackground_(False)
            self.pygui_field_editor = editor
        return editor
    
    #  Need the following two methods so that a fullscreen window can become
    #  the main window. Otherwise it can't, because it has no title bar.

    def canBecomeKeyWindow(self):
        return self.isVisible()
    
    def canBecomeMainWindow(self):
        #print "PyGUI_NSWindow.canBecomeMainWindow"
        return self.isVisible()
    
    def windowDidBecomeMain_(self, notification):
        #print "PyGUI_NSWindow.windowDidBecomeMain_:",  self.pygui_component.title ###
        comp = self.pygui_component
        if comp and comp._style == 'fullscreen':
            #print "...hiding menu bar" ###
            NSMenu.setMenuBarVisible_(False)
            #self.setFrameOrigin_(NSPoint(0, 0))

    def windowDidResignMain_(self, notification):
        #print "PyGUI_NSWindow.windowDidResignMain_:",  self.pygui_component.title ###
        comp = self.pygui_component
        if comp and comp._style == 'fullscreen':
            #print "...showing menu bar" ###
            NSMenu.setMenuBarVisible_(True)

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

class PyGUI_NS_ContentView(PyGUI_Flipped_NSView, PyGUI_NS_EventHandler):
    #  pygui_component   Window

    __metaclass__ = NSMultiClass
    __slots__ = ['pygui_component']

    def acceptsFirstResponder(self):
        return False

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

class PyGUI_FieldEditorBase(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_FieldEditorBase.keyDown_ for", self.pygui_component ###
        if ns_event.characters() == "\r":
            if self.pygui_component._multiline:
                self.insertText_("\n")
                return
        NSTextView.keyDown_(self, ns_event)

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

class PyGUI_FieldEditor(PyGUI_FieldEditorBase, PyGUI_NS_EventHandler):
    
    __metaclass__ = NSMultiClass
    
    def get_pygui_component(self):
        pygui_nstextfield = self.superview().superview()
        component = pygui_nstextfield.pygui_component
        component._ns_responder = self
        return component
    
    pygui_component = property(get_pygui_component)

export(Window)
