# Copyright 2012 James McCauley
#
# This file is part of POX.
#
# POX 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 3 of the License, or
# (at your option) any later version.
#
# POX 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 POX.  If not, see <http://www.gnu.org/licenses/>.

"""
Lets you use Tk with POX.

Highly experimental.
"""

from collections import deque
from pox.core import core

log = core.getLogger()

#TODO: Bind revent events across thread

class MessageBoxer (object):
  def __init__ (self, tk):
    import tkMessageBox, tkColorChooser, tkSimpleDialog, tkFileDialog
    fields = "ERROR INFO QUESTION WARNING ABORTRETRYIGNORE OKCANCEL "
    fields += "RETRYCANCEL YESNO YESNOCANCEL ABORT RETRY IGNORE OK "
    fields += "CANCEL YES NO"
    for f in fields.split():
      setattr(self, f, getattr(tkMessageBox, f))

    methods = "showinfo showwarning showerror askquestion "
    methods += "askokcancel askyesno askretrycancel"
    self._addmethods(tkMessageBox, methods, tk)

    methods = "askinteger askfloat askstring"
    self._addmethods(tkSimpleDialog, methods, tk)

    methods = "askcolor"
    self._addmethods(tkColorChooser, methods, tk)

    methods = "askopenfilename asksaveasfilename"
    self._addmethods(tkFileDialog, methods, tk)

  def _addmethods (self, module, methods, tk):
    for m in methods.split():
      def f (m):
        def f2 (*args, **kw):
          return getattr(module, m)(*args,**kw)
        def f4 (*args, **kw):
          _ = kw.pop('_', None)
          tk.do_ex(getattr(module, m), rv = _, args=args, kw=kw)
        def f5 (_, *args, **kw):
          tk.do_ex(f2, rv = _, args=args, kw=kw)
        return f4,f5
      a,b = f(m)
      setattr(self, m, a)
      setattr(self, m+"_cb", b)

 
class Tk (object):
  _core_name = "tk"

  def __init__ (self):
    self._q = deque()
    self.dialog = MessageBoxer(self)

  def do_ex (self, code, rv=None, args=[], kw={}):
    self._q.append((code, rv, args, kw))
    self.root.event_generate('<<Ping>>', when='tail')

  def do (__self, __code, __rv=None, *args, **kw):
    __self._q.append((__code, __rv, args, kw))
    __self.root.event_generate('<<Ping>>', when='tail')
    
  def _dispatch (self, event):
    while len(self._q):
      self._dispatch_one(*self._q.popleft())

  def _dispatch_one (self, code, rv, args, kw):
    if callable(code):
      r = code(*args, **kw)
    else:
      def f ():
        l = {'self':self}
        l.update(kw)
        exec code in globals(), l
      r = f()
    if rv: core.callLater(rv, r)

  def run (self):
    import Tkinter
    root = Tkinter.Tk()
    root.bind('<<Ping>>', self._dispatch)

    self.root = root

    # Become live once in a while so that signals get handled
    def timer ():
      root.after(500, timer)
    timer()

    self.root.withdraw()
    try:
      root.mainloop()
    except KeyboardInterrupt:
      pass
    log.debug("Quitting")


def launch ():
  import boot
  core.registerNew(Tk)
  boot.set_main_function(core.tk.run)

  """
  def pr (msg):
    print "From Tk:", msg
  core.callDelayed(5,lambda: core.tk.msgbox.showinfo_cb(pr,
      "Hello", "Hello, World!"))
  """

@@ -2253,16 +2253,37 @@
 er(self)
+%0A    self.root = None
 %0A%0A  def 
@@ -2364,24 +2364,91 @@
  args, kw))%0A
+    self._ping()%0A%0A  def _ping (self):%0A    if not self.root: return%0A
     self.roo
@@ -2603,51 +2603,14 @@
 elf.
-root.event_generate('%3C%3CPing%3E%3E', when='tail'
+_ping(
 )%0A  
@@ -3240,16 +3240,43 @@
 hdraw()%0A
+%0A    self._dispatch(None)%0A%0A
     try:

Allow calls to do/do_ex early on