## ------------------------------------------------------------------------
## 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 string
import silk
import tools
import resultset
import config.silk
import pdb
import wx, ws
import copy
from controls.previewcmdpanel import PreviewCommandPanel
from controls.filteroptionspanel import BasicFilterOptionsPanel
from controls.filteroptionspanel import MoreFilterOptionsPanel
from controls.filteroptionspanel import SizeFilterOptionsPanel
from controls.filteroptionspanel import PrefixMapFilterPanel
from controls.filteroptionspanel import ValidationError

class FilterTool(tools.AnalysisTool):
    def __init__(self, **kargs):
        tools.AnalysisTool.__init__(self, **kargs)
        
    def CreateDialog(parentResult, parent, title):
        return RefineDialog(parentResult, parent, title=title)
    CreateDialog = staticmethod(CreateDialog)
    
    def GetCategory():
        return "Filter"
    GetCategory = staticmethod(GetCategory)
    
    def _GetToolName():
        return "rwfilter drilldown"
    _GetToolName = staticmethod(_GetToolName)
    
    def CanRun(parentResult):
        if not parentResult:
            return False
        return parentResult.IsFilterResult()
    CanRun = staticmethod(CanRun)       
    
    def _GetResultClass(self):
        return resultset.FilterResult

    def _GetResultName(self):
        return "Untitled Drilldown"

    # FIXME: note that a better design would delay converting to
    # ascii until the user downloads the file
    def _RunAnalysis(self, context, inputFileName, outputFileName):
        silk.filter(context, inputFileName, outputFileName, **self.opts)
        silk.cut(context, outputFileName, outputFileName+".asc")
        
    def _GetCommandLines(inputFileName, outputFileName, **kargs):
        return silk.build_filter_command(False, "$output", kargs, inputFileName, commandsOnly=True)
    _GetCommandLines = staticmethod(_GetCommandLines)    

class EditNameDialog(wx.Dialog):
    def __init__(self, name, *args, **kargs):
        wx.Dialog.__init__(self, *args, **kargs)
        self.label = wx.StaticText(self, -1, name)
        self.edit = wx.TextCtrl(self, -1, "", validator=ws.NameValidator())
        szDlg = wx.BoxSizer(wx.VERTICAL)
        szBtns = self.CreateButtonSizer(wx.OK | wx.CANCEL)
        self.SetEscapeId(wx.ID_CANCEL)
        self.FindWindowById(wx.ID_OK).SetDefault()
        self.FindWindowById(wx.ID_OK).SetLabel("Save")
        szDlg.Add(self.label, flag=wx.EXPAND|wx.ALL, border=8)        
        szDlg.Add(self.edit, flag=wx.EXPAND|wx.ALL, border=8)
        szDlg.Add(szBtns, flag=wx.EXPAND|wx.ALL, border=8)
        self.SetSizerAndFit(szDlg)
        self.edit.SetFocus()
        
    def GetValue(self):
        return self.edit.GetValue()


class SaveOptionsPanel(wx.Panel):
    def __init__(self, name, *args, **kargs):
        wx.Panel.__init__(self, *args, **kargs)
        self.name = name
        self.lbl = ws.SmStaticLabel(self, -1, "Load a filter:")
        self.cb  = ws.SmChoiceCtrl(self, -1, choices=["(Choose a saved filter)", "test1","test2"], size=(200,-1))
        self.btn = ws.SmButton(self, -1, "Save %s Options..." % name)
        sz = wx.BoxSizer(wx.HORIZONTAL)
        sz.Add(self.lbl, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.ALIGN_RIGHT, border=4)
        sz.Add(self.cb, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND|wx.ALIGN_RIGHT, border=4)
        sz.Add(self.btn, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=4)
        self.SetSizerAndFit(sz)
        self.Bind(wx.EVT_BUTTON, self.OnSave, self.btn)
        
    def OnSave(self, evt):
        dlg = EditNameDialog("Filter Name", self.GetParent())
        dlg.SetSize((320,-1))
        dlg.CenterOnParent()
        if dlg.ShowModal() == wx.ID_OK:
            print "Named filter %s" % dlg.GetValue()
        

class RefineDialog(wx.Dialog):
    def __init__(self, parentResult, parent, *args, **kargs):
        wx.Dialog.__init__(self, parent, -1, *args, **kargs)
        self.parentResult = parentResult
        
        # Create two notebook pages
        self.nb = wx.Notebook(self)
        self.nb.AddPage(self._create_main_panel(self.nb), "Basic Filter Options")
        self.nb.AddPage(self._create_other_panel(self.nb), "Other Filter Options")
        
        # Name editor and preview panel
        self.previewPanel = PreviewCommandPanel(self,  "Not yet initialized")
        self._createNameEditor()
        
        # Create buttons
        sz = wx.BoxSizer(wx.HORIZONTAL)
        btnValidate = wx.Button(self, -1, "Validate Options")
        sz.Add(btnValidate, flag=wx.ALL, border=10)
        sz.Add((5,5), flag=wx.ALL, border=10)
        sz.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), flag=wx.ALL, border=10)
        btnCreate = wx.Button(self, wx.ID_OK, "Run Analysis") #, (110,-1), (100,-1))
        sz.Add(btnCreate, flag=wx.ALL, border=10)
        # Create is default button
        btnCreate.SetDefault()
        # Escape key or close causes cancel
        self.SetEscapeId(wx.ID_CANCEL)
        # Lay everything out
        self.gbs = gbs = wx.GridBagSizer(0,0)
        self.gbs.Add(self.nb, (0,0), (1,2), wx.ALL|wx.EXPAND, border=16)
        self.gbs.Add(ws.SmStaticLabel(self, -1, "Command line"), (1,0), (1,1),
            wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND, border=6)
        self.gbs.Add(self.previewPanel,(2,0), (1,2), wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.EXPAND, border=6)
        self.gbs.Add(self.szName, (3,0), (1,2), wx.ALIGN_RIGHT|wx.ALL, border=10)
        self.gbs.Add(sz, (4,0), (1,2), wx.ALIGN_RIGHT|wx.ALL, border=10)
        self.SetSizerAndFit(self.gbs)
        self.RefreshCommandLine()
        self.Bind(wx.EVT_BUTTON, self.OnOK, btnCreate)
        self.Bind(ws.EVT_OPTION_CHANGE, self.OnOptionChange)
        self.Bind(wx.EVT_BUTTON, self.OnValidate, btnValidate)
        
    def _create_main_panel(self, parent):
        panel = wx.Panel(parent)
        gbs = wx.GridBagSizer(5,5)
        # Build controls - dialog simply encapsulates a FilterOptionsPanel
        self.optionsPanel = BasicFilterOptionsPanel(panel, True)
        self.pmapPanel = PrefixMapFilterPanel(panel)
        gbs.Add(self.optionsPanel,    (0,0), (1,1), wx.ALL|wx.EXPAND, border=16)
        gbs.Add(self.pmapPanel,       (0,1), (1,1),wx.ALL|wx.EXPAND, border=16)
        panel.SetSizerAndFit(gbs)
        return panel
        
    def _create_other_panel(self, parent):
        panel = wx.Panel(parent)
        self.moreOptionsPanel = MoreFilterOptionsPanel(panel, True)
        self.sizeOptionsPanel = SizeFilterOptionsPanel(panel)
        gbs = wx.GridBagSizer(0,0)
        gbs.Add(self.moreOptionsPanel,(0,1), (1,1),wx.ALL|wx.EXPAND,border=16)
        gbs.Add(self.sizeOptionsPanel,(1,1), (1,1),wx.ALL|wx.EXPAND, border=16)
        panel.SetSizerAndFit(gbs)        
        return panel
        
    def _createNameEditor(self):
        self.name = wx.TextCtrl(self, -1, "Untitled Refinement", 
            validator=ws.NameValidator(), size=(200,-1))
        self.szName = szName = wx.BoxSizer(wx.HORIZONTAL)
        szName.Add(ws.SmStaticText(self, -1, "Name"),
            flag=wx.RIGHT|wx.ALIGN_CENTER, border=6)
        szName.Add(self.name, flag=wx.ALIGN_CENTER|wx.RIGHT, border=10)
    
    def OnOptionChange(self, evt):
        print "===== OnOptionChange"
        #self.ValidateOptions(False)
        self.RefreshCommandLine()
        
    def OnOK(self, evt):
        try:
           self.optionsPanel.ValidateOptions()
           evt.Skip(True)
        except ValidationError, e:
           d = wx.MessageDialog(self, e.details, "%s" % e.summary,
                  wx.ICON_EXCLAMATION)
           d.ShowModal()
           
    def ValidateOptions(self, displayValidDialog=False):
        try:
            self.optionsPanel.ValidateOptions()
            if displayValidDialog:
                d = wx.MessageDialog(self,
                    "Refinement filter options appear to valid.",
                    "Validation successful",
                    wx.ICON_INFORMATION)
                d.ShowModal()
        except ValidationError, e:
            d = wx.MessageDialog(self, e.details, "%s" % e.summary,
                    wx.ICON_EXCLAMATION)
            d.ShowModal()
            return
           
    def OnValidate(self, evt):
        ''' User wants to run validate. '''
        self.ValidateOptions(True)
    
    def GetCommandLine(self):
        opts = copy.copy(self.GetOptions())
        if config.silk.opts["WORK_REMOTE"]:
            return silk.build_filter_command(True, "$output", opts, self.parentResult.GetFileName(),
                cmdDir=self.parentResult.GetRemoteDir())
        else:
            return silk.build_filter_command(False, "$output", opts, self.parentResult.GetFileName(),
                cmdDir=self.parentResult.GetRemoteDir())
    
    def RefreshCommandLine(self):
        cmd = self.GetCommandLine()
        self.previewPanel.SetContent(cmd)
        
    def SetOptions(self, opts):
        #pdb.set_trace()
        self.optionsPanel.SetOptions(opts)
        self.moreOptionsPanel.SetOptions(opts)
        self.sizeOptionsPanel.SetOptions(opts)
        self.pmapPanel.SetOptions(opts)
        
    def GetResultName(self):
        return self.name.GetValue()
    
    def GetOptions(self):
        opts = self.optionsPanel.GetOptions()
        opts.update(self.moreOptionsPanel.GetOptions())
        opts.update(self.sizeOptionsPanel.GetOptions())
        opts.update(self.pmapPanel.GetOptions())
        return opts
