from __future__ import print_function
import matplotlib.pyplot as plt
%matplotlib inline
import SimpleITK as sitk
print(sitk.Version())

import sys
import os
import threading

from myshow import myshow
from myshow import myshow3d

size=256 # if this is too fast increase the size
img = sitk.GaborSource(sitk.sitkFloat32, size=[size]*3, sigma=[size*.2]*3, mean=[size*0.5]*3, frequency=.1)
myshow3d(img,zslices=[size/2],dpi=40);

myshow(img);

"""
Explanation: Progress Reporting and Command Observers
SimpleITK Filters and other classes derived from ProcessObjects have the ability for user code to be executed when certain events occour. This is known as the Command and Observer design patters to implement user callbacks. This allows for the monitoring and abortion of processes as they are being executed.
Consider the following image source which takes a few seconds to execute. It would be nice to quickly know how long your going to need to wait, to know if you can go get a cup of coffee.
End of explanation
"""


help(sitk.Command)

class MyCommand(sitk.Command):
    def __init__(self):
        # required
        super(MyCommand,self).__init__()

    def Execute(self):
        print("MyCommand::Execute Called")
        
cmd = MyCommand()
cmd.Execute()

help(sitk.PyCommand)

cmd = sitk.PyCommand()
cmd.SetCallbackPyCallable( lambda: print("PyCommand Called") )
cmd.Execute()

"""
Explanation: We need to add a command to display the progress reported by the ProcessObject::GetProgress method during the sitkProgressEvent. This involves three commponents:

Events
ProcessObject's methods
Commands

We'll look at some examples after a brief explanation of these components.
Events
The avaiable events to observed are defined in a namespace enumeration.
<table>
 <tr><td>sitkAnyEvent</td><td>Occurs for all event types.</td></tr>
 <tr><td>sitkAbortEvent</td><td>Occurs after the process has been aborted, but before exiting the Execute method.</td></tr>
 <tr><td>sitkDeleteEvent</td><td>Occurs when the underlying itk::ProcessObject is deleted.</td></tr>
 <tr><td>sitkEndEvent</td><td>Occurs at then end of normal processing.</td></tr>
 <tr><td>sitkIterationEvent</td><td>Occurs with some algorithms that run for a fixed or undetermined number of iterations.</td></tr>
 <tr><td>sitkProgressEvent</td><td>Occurs when the progress changes in most process objects.</td></tr>
 <tr><td>sitkStartEvent</td><td>Occurs when then itk::ProcessObject is starting.</td></tr>
 <tr><td>sitkUserEvent</td><td>Other events may fall into this enumeration.</td></tr>
</table>

The convention of pre-fixing enums with "sitk" is continued, although it's getting a little crowded. 
C++ is more stongly typed than Python it allows for implicit conversion from an enum type to an int, but not from an int to an enum type. Care needs to be made to ensure the correct enum value is passed in Python.
ProcessObject's methods
To be able to interface with the ProcessObject during execution, the object-oriented interface must be used to access the method of the ProcessObject. While any constant member function can be called during a command call-back there are two common methods:

ProcessObject::GetProgress()
ProcessObject::Abort()

The methods are only valid during the Command while a process is being executed, or when the process is not in the Execute method.
Additionally it should be noted that follow methods can not be called during a command or from another thread durring execution Execute and RemoveAllCommands. In general the ProcessObject should not be modified during execution.
Commands
The command design pattern is used to allow user code to be executed when an event occurs. It is implemented in the Command class. The Command class provides an Execute method to be overridden in derived classes. 
There are three ways to define a command with SimpleITK in Python.

Derive from the Command class.
Use the PyCommand class' SetCallbackPyCallable method.
Use an inline lambda function in ProcessOject::AddCommand.
End of explanation
"""


size=256
filter = sitk.GaborImageSource()
filter.SetOutputPixelType(sitk.sitkFloat32)
filter.SetSize([size]*3)
filter.SetSigma([size*.2]*3)
filter.SetMean([size*0.5]*3)
filter.SetFrequency(.1)
img = filter.Execute()
myshow3d(img,zslices=[size/2],dpi=40);

"""
Explanation: Back to watching the progress of out Gabor image source. First lets create the filter as an object
End of explanation
"""


help(sitk.ProcessObject)

"""
Explanation: The ProcessObject interface for the Invoker or Subject
SimpleITK doesn't have a large heirachy of inheritance. It has been kept to a minimal, so there is no common Object or LightObject base class as ITK has. As most of the goals for the events have to do with observing processes, the "Subject" interface of the Observer patter or the "Invoker" part of the Command design pattern, has been added to a ProcessObject base class for filters.
The ProcessObject base class has the following methods of handling commands: AddCommand, RemoveAllCommands, and HasCommand.
Adding these functionalities are not available in the procedural interface available for SimpleITK. They are only available through the Object Oriented interface, and break the method chaining interface.
End of explanation
"""


class MyCommand(sitk.Command):
    def __init__(self, msg):
        # required
        super(MyCommand,self).__init__()
        self.msg = msg
    
    def __del__(self):
        print("MyCommand begin deleted: \"{0}\"".format(self.msg))

    def Execute(self):
        print(self.msg)

cmd1 = MyCommand("Start")
cmd2 = MyCommand("End")
filter.RemoveAllCommands() # this line is here so we can easily re-execute this code block
filter.AddCommand(sitk.sitkStartEvent, cmd1)
filter.AddCommand(sitk.sitkEndEvent, cmd2)
filter.Execute()

"""
Explanation: Deriving from the Command class
The traditional way of using Commands in ITK involves deriving from the Command class and adding to the ProcessObject.
End of explanation
"""


filter.AddCommand(sitk.sitkStartEvent, MyCommand("stack scope"))
print("Before Execution")
filter.Execute()

"""
Explanation: A reference to the Command object must be maintained, or else it will be removed from the ProcessObject.
End of explanation
"""


filter.RemoveAllCommands() # this line is here so we can easily re-execute this code block
filter.AddCommand(sitk.sitkStartEvent, lambda: print("Starting...",end=''))
filter.AddCommand(sitk.sitkStartEvent, lambda: sys.stdout.flush())
filter.AddCommand(sitk.sitkEndEvent, lambda: print("Done"))
filter.Execute()

"""
Explanation: Using a labmda function as the Command
In Python the AddCommand has been extended to accept PyCommand objects and implicitly creates a PyCommand from a callable python argument. This is really useful.
End of explanation
"""


filter.RemoveAllCommands()
filter.AddCommand(sitk.sitkProgressEvent, lambda: print("\rProgress: {0:03.1f}%...".format(100*filter.GetProgress()),end=''))
filter.AddCommand(sitk.sitkProgressEvent, lambda: sys.stdout.flush())
filter.AddCommand(sitk.sitkEndEvent, lambda: print("Done"))
filter.Execute()

"""
Explanation: Access to ITK data during command execution
The commands are not too useful unless you can query the filter through the SimpleITK interface. A couple status variables and methods are exposed in the SimpleITK ProcessObject through the polymorphic interface of the same ITK class.
End of explanation
"""


import uuid
from IPython.display import HTML, Javascript, display

divid = str(uuid.uuid4())

html_progress="""
<p style="margin:5px">FilterName:</p>
<div style="border: 1px solid black;padding:1px;margin:5px">
  <div id="{0}" style="background-color:blue; width:0%%">&nbsp;</div>
</div>
""".format(divid)

def command_js_progress(processObject):
    p = processObject.GetProgress()
    display(Javascript("$('div#%s').width('%i%%')" % (divid, int(p*100))))

filter.RemoveAllCommands()
filter.AddCommand(sitk.sitkStartEvent, lambda:  display(HTML(html_progress)))
filter.AddCommand(sitk.sitkProgressEvent, lambda: command_js_progress(filter))

filter.Execute()

"""
Explanation: Utilizing IPython Notebooks and Commands
Utilization of commands and event frequently occours with advanced integration into graphical user iterfaces. Let us now export this advanced integration into IPython Notebooks.
IPython notebooks support displaying output as HTML, and execution of javascript on demand. Together this can produce animation.
End of explanation
"""


import uuid
from IPython.display import HTML, Javascript, display

g_Abort = False
divid = str(uuid.uuid4())

html_progress_abort="""
<div style="background-color:gainsboro; border:2px solid black;padding:15px">
<p style="margin:5px">FilterName:</p>
<div style="border: 1px solid black;padding:1px;margin:5px">
  <div id="{0}" style="background-color:blue; width:0%%">&nbsp;</div>
</div>
<button onclick="set_value()" style="margin:5px" >Abort</button>
</div>
""".format(divid)

javascript_abort = """
<script type="text/Javascript">
    function set_value(){
        var command = "g_Abort=True"
        console.log("Executing Command: " + command);
        
        var kernel = IPython.notebook.kernel;
        kernel.execute(command);
    }
</script>
"""

def command_js_progress_abort(processObject):
    p = processObject.GetProgress()
    display(Javascript("$('div#%s').width('%i%%')" % (divid, int(p*100))))
    if g_Abort:
        processObject.Abort()
        
def command_js_start_abort():        
    g_Abort=False

g_Abort=False
filter.RemoveAllCommands()
filter.AddCommand(sitk.sitkStartEvent, command_js_start_abort )
filter.AddCommand(sitk.sitkStartEvent, lambda:  display(HTML(html_progress_abort+javascript_abort)))
filter.AddCommand(sitk.sitkProgressEvent, lambda: command_js_progress_abort(filter))

"""
Explanation: Support for Bi-direction JavaScript
It's possible to get button in HTML to execute python code...
End of explanation
"""


import threading
threading.Thread( target=lambda:filter.Execute() ).start()

"""
Explanation: A caveat with this approach is that the is that the IPython kernel must continue to execute while the filter is running. So we must place the filter in a thread.
End of explanation
"""


#### The following shows a failure that you will want to avoid.
threading.Thread( target=lambda:filter.Execute() ).start()

"""
Explanation: While the lambda command are convenient, the lack for having an object to hold data can stil be problematic. For example in the above code the uuid, is used to uniquely identify the HTML element. So if the filter is executed multiple times then the JavaScript update will be confused on what to update.
End of explanation
"""


import uuid
from IPython.display import HTML, Javascript, display

class HTMLProgressWatcher:
    def __init__(self, po):
        self.processObject = po
        self.abort = False
        
        po.AddCommand(sitk.sitkStartEvent, lambda: self.cmdStartEvent() )
        po.AddCommand(sitk.sitkProgressEvent, lambda: self.cmdProgressEvent() )
        po.AddCommand(sitk.sitkEndEvent, lambda: self.cmdEndEvent() )
        
    def cmdStartEvent(self):
        global sitkIPythonProgress_UUID
        self.abort=False
        self.divid = str(uuid.uuid4())
        
        try:
            sitkIPythonProgress_UUID[self.divid] = self
        except NameError:
            sitkIPythonProgress_UUID = {self.divid: self}
        
        html_progress_abort="""
<p style="margin:5px">{0}:</p>
<div style="border: 1px solid black;padding:1px;margin:5px">
  <div id="{1}" style="background-color:blue; width:0%%">&nbsp;</div>
</div>
""".format(self.processObject.GetName(), self.divid)
        
        display(HTML(html_progress_abort+javascript_abort))
    
    def cmdProgressEvent(self):
        p = self.processObject.GetProgress()
        display(Javascript("$('div#%s').width('%i%%')" % (self.divid, int(p*100))))
        if self.abort:
            self.processObject.Abort()
    
    def cmdEndEvent(self):
        global sitkIPythonProgress_UUID
        del sitkIPythonProgress_UUID[self.divid]
        del self.divid


filter.RemoveAllCommands()
watcher  = HTMLProgressWatcher(filter)

filter.Execute()

threading.Thread.start?

"""
Explanation: A Reusable class for IPython Progress
There currently are too many caveates with out support for Abort. Let us create a reusable class which will automatically generate the UUID and just display the progress.
End of explanation
"""


