## ------------------------------------------------------------------------
## iSiLK - A python-based graphical user interface for SiLK
## ------------------------------------------------------------------------
## Copyright (c) 2007-2008 Carnegie Mellon University. All Rights Reserved.
## ------------------------------------------------------------------------
## Authors: Andrew Kompanek (ajk@cert.org)
## ------------------------------------------------------------------------
## GNU General Public License (GPL) Rights pursuant to Version 2, June 1991
## Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013
## ------------------------------------------------------------------------
## See the LICENSE file included in this distribution
## ------------------------------------------------------------------------

import wx
import ws
import matplotlib
if matplotlib.compare_versions(matplotlib.__version__, '0.98.3'):
    matplotlib.use("WXAgg", warn = False)
else:
    matplotlib.use("WXAgg")
import matplotlib.backends.backend_wxagg as backend_wxagg
from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx
import matplotlib.figure as figure
from matplotlib.dates import num2date, date2num
from timeutils import datetime_obj, silk_datetime_range, silk_date, silk_datetime
import datetime, time
from wx.lib.scrolledpanel import ScrolledPanel
# Playing with pickers
from matplotlib.patches import Patch, Rectangle 

class SelectionInfoFrame(wx.MiniFrame):
    def __init__(self, key_fields, *args, **kargs):
        wx.MiniFrame.__init__(self, *args, **kargs)
        self.SetTransparent(200)
        self.controls = {}
        def _lbl(f):
            txt = ws.SmStaticText(self, -1, f, style=wx.ALIGN_RIGHT)
            txt.SetFont(ws.SmFont(wx.SWISS, wx.NORMAL, wx.BOLD))
            return txt
        def _val(f, v):
            self.controls[f] = ws.SmStaticText(self, -1, v)
            return self.controls[f]
        sz = wx.GridBagSizer()
        for (r, k) in enumerate(key_fields):
            sz.Add(_lbl(k),     (r,0), (1,1), flag=wx.LEFT|wx.RIGHT|wx.TOP|wx.ALIGN_RIGHT, border=16)
            sz.Add(_val(k, ""), (r,1), (1,1), flag=wx.RIGHT|wx.TOP, border=16)
        sz.Add((0,0), (r+1,0), (1,2), flag=wx.ALL,border=16)
        self.SetSizerAndFit(sz)

        self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
        
    def OnMouseMotion(self, evt):
        print "Moving in selection frame"
        
    def SetValue(self, keys):
        if keys == None:
            for c in self.controls.values():
                c.SetLabel("")
            return
        for k in keys:
            if k == 'date':
                date = num2date(keys[k])
                val = silk_datetime(date)
            else:
                val = str(keys[k])
            self.controls[k].SetLabel(val)
        self.Fit()

from datacache import formatFieldAsString


class MyToolbar(NavigationToolbar2Wx):
    def __init(self, canvas):
        NavigationToolbar2Wx.__init__(self, canvas)
    
    def release_zoom(self, evt):
        print "Release zoom"
        NavigationToolbar2Wx.release_zoom(self, evt)
        self.GetParent().GetParent().GetParent().Refresh()

class GraphPanel(ScrolledPanel):
    def __init__(self, parent, graph):
        ScrolledPanel.__init__(self, parent, size=(0,0), style=wx.SIMPLE_BORDER)   
        #wx.Panel.__init__(self, parent)
        self.toolTip = wx.ToolTip("")
        self.figureParent = self
        self.graph = graph
        self.resultset = graph.parentResult
        # Create canvas and figure
        self.graph.GetSize()
        GRAPH_DPI = 75
        (in_w, in_h) = self.graph.GetSize()
        self.fig    = figure.Figure(figsize=(in_w/GRAPH_DPI, in_h/GRAPH_DPI), dpi=GRAPH_DPI)
        self.canvas = backend_wxagg.FigureCanvasWxAgg(self.figureParent, -1, self.fig)
        self.toolTip.Enable(False)
        self.toolTip.SetDelay(0)
        self.canvas.SetToolTip(self.toolTip)
        #self.toolbar = MyToolbar(self.canvas)
        #self.toolbar.Realize()
        #self.toolbar.Hide()
        self.toolbar = None
       
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas,1,wx.EXPAND)
        if self.toolbar:
            sizer.Add(self.toolbar, 0 , wx.LEFT | wx.EXPAND)
        self.SetSizer(sizer)

        self.figmgr = backend_wxagg.FigureManager(self.canvas, 1, self)
        
        # Use a background more consistent with system colors
        self.SetBackgroundColour(wx.Color(255,255,255))
        rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
        rgbtuple=(255,255,255)
        col = [c/255.0 for c in rgbtuple]
        self.fig.set_facecolor(col)
        self.fig.set_edgecolor(col)
        # Generate the graph
        self.graph.Plot(self.fig)
        self.graph.Plot(None)
        # Layout the panel
        sz = wx.BoxSizer(wx.VERTICAL)
        sz.Add(self.canvas)
        self.SetSizer(sz)
        self.SetAutoLayout(1)
        self.SetupScrolling()        
        # Handle movement to update selection
        self.canvas.mpl_connect('motion_notify_event', self.OnMotion)
        # Double does drill down on current selection
        self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
        return
        style = wx.FRAME_FLOAT_ON_PARENT | wx.FRAME_NO_TASKBAR | wx.NO_BORDER
        self.selwin = SelectionInfoFrame(self.graph.GetFields(),
            self.GetParent(), -1,
            "Graph Selection", style=style)
        self.selwin.SetPosition(self.canvas.GetScreenPosition())
        self.selwin.Show(True)
        self.selwin.Layout()
        
    def OnActivated(self, activated):
       # print "Activate state changed %s" % activated
       # self.selwin.Show(activated)
        pass
       
    def OnDoubleClick(self, evt):
        self.graph.OnDoubleClick(evt)
        self.GetParent().Refresh()

    def GetSelectionString(self, multiline=False,
            exclude_keys=False, exclude_vals=False):
        val_fields = ["bytes", "records", "packets", "unique_dip", "unique_sip"]
        sel = self.graph.GetSelection()
        if not sel:
            return None
        if exclude_keys and exclude_vals:
            return None
        # Remove fields we don't care about
        fields = sel.keys()
        for field in fields:
            if exclude_vals and field in val_fields:
                del sel[field]
            if exclude_keys and not field in val_fields:
                del sel[field]
        sep = ", "
        if multiline:
            sep = "\n"
        tip = ""
        for (i,k) in enumerate(sel.keys()):
            if k == 'date':
                date = num2date(sel[k])
                val = silk_datetime(date)
            else:
                val = formatFieldAsString(k, sel[k])
            if i != 0: tip += sep
            tip += "%s" % (val)
        return tip
        
    def OnMotion(self, evt):
        # Let graph update the selection based on new position
        self.graph.OnMotion(evt)
        # Get information about the data that's under the mouse
        tip = self.GetSelectionString(multiline=False, exclude_keys=True)
        if tip == None:
            self.toolTip.Enable(False)
            return
        self.toolTip.SetTip(tip)
        self.toolTip.Enable(True)

    def RefreshContents(self):
        pass
      
    def GetData(self):
        return self.graph

    def GetStatus(self):
        if not self.resultset.IsLocalFileAvailable():
            return
        cmds = self.resultset.GetCommandLines()
        cmd = cmds[len(cmds)-1]
        status = self.resultset.GetPath()
        sel = self.GetSelectionString(exclude_vals=True)
        print "selection string = %s" % sel
        if sel:
            status += " - %s" % sel
        return [self.resultset.GetRecordCount(), status, cmd]

    # Not using a mpl toolbar
    def GetToolBar(self): 
        return self.toolbar
        #return None
