## ------------------------------------------------------------------------
## 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 pdb
import silk, silkutils
import tools
import resultset
import wx, ws
from filemanager import FilePicker
from controls.previewcmdpanel import PreviewCommandPanel

class SetToolTool(tools.AnalysisTool):
    def __init__(self, **kargs):
        tools.AnalysisTool.__init__(self, **kargs)
        
    def CreateDialog(parentResult, parent, title):
        return SetToolDialog(parentResult, parent, title=title)
    CreateDialog = staticmethod(CreateDialog)
    
    def CanRun(parentResult):
        if not parentResult:
            return False
        return parentResult.IsSetResult()
    CanRun = staticmethod(CanRun)
    
    def _GetToolName():
        return "rwsettool"
    _GetToolName = staticmethod(_GetToolName)
            
    def _GetResultClass(self):
        return resultset.SetResult

    def _GetResultName(self):
        return "Set"
        
    def _RunAnalysis(self, context, inputFileName, outputFileName):
        silk.rwsettool(context, inputFileName, outputFileName, **self.opts)
        silk.rwsetcat(context, outputFileName, outputFileName+".asc", **self.opts)
        
    def _GetCommandLines(inputFile, outputFile, **kargs):
        cmd = silk.build_rwsettool_command(False, "", inputFile, outputFile,
            commandsOnly=True, **kargs)
        return cmd
    _GetCommandLines = staticmethod(_GetCommandLines)


def _createNameEditor(dlg):
    tcName = wx.TextCtrl(dlg, -1, "Untitled set result", 
        validator=ws.NameValidator(), size=(200,-1))
    szName = wx.BoxSizer(wx.HORIZONTAL)
    szName.Add(ws.SmStaticText(dlg, -1, "Name"),
        flag=wx.RIGHT|wx.ALIGN_CENTER, border=6)
    szName.Add(tcName, flag=wx.ALIGN_CENTER|wx.RIGHT, border=10)
    return tcName, szName

class SetToolDialog(wx.Dialog):
    def __init__(self, parentResult, parent, *args, **kargs):
        wx.Dialog.__init__(self, parent, -1, *args, **kargs)
            
        self.setlbl = wx.StaticText(self, -1, "Combine this set with", size=(480,-1))
        self.txtSet = ws.SmTextCtrl(self, -1, "(choose a set)", style=wx.TE_READONLY)
        self.btnChoose = ws.SmButton(self, -1, "Choose a set...")
        self.previewPanel = PreviewCommandPanel(self,  "Not yet initialized")
        self.oplbl = wx.StaticText(self, -1, "Using the set operation:")
        self.rbunion = wx.RadioButton(self, -1, "Union", style = wx.RB_GROUP)
        self.rbdifference = wx.RadioButton(self, -1, "Difference")
        self.rbintersect = wx.RadioButton(self, -1, "Intersection")
        self.rbunion.SetValue(True)
        self.rbdifference.SetValue(False)
        self.rbintersect.SetValue(False)
        self.szrb = wx.BoxSizer(wx.HORIZONTAL)
        self.szrb.Add(self.rbunion, flag=wx.ALL, border=8)
        self.szrb.Add(self.rbintersect, flag=wx.ALL, border=8)
        self.szrb.Add(self.rbdifference, flag=wx.ALL, border=8)
        
        # Create name editor
        self.name, self.szName = _createNameEditor(self)
        # Create buttons
        sz = wx.BoxSizer(wx.HORIZONTAL)
        sz.Add(wx.Button(self, wx.ID_CANCEL, "Cancel"), flag=wx.ALL, border=10)
        self.btnCreate = wx.Button(self, wx.ID_OK, "Run Analysis") #, (110,-1), (100,-1))
        self.btnCreate.Enable(False)
        sz.Add(self.btnCreate, flag=wx.ALL, border=10)
        # Create is default button
        self.btnCreate.SetDefault()
        # Escape key or close causes cancel
        self.SetEscapeId(wx.ID_CANCEL)
        szDlg = wx.BoxSizer(wx.VERTICAL)
        szDlg.Add(self.setlbl, flag=wx.ALL, border=8)
        szDlg.Add(self.txtSet, flag=wx.ALL|wx.EXPAND, border=8)
        szDlg.Add(self.btnChoose, flag=wx.ALL|wx.ALIGN_RIGHT, border=8)
        szDlg.Add(self.oplbl, flag=wx.ALL, border=8)
        szDlg.Add(self.szrb, flag=wx.LEFT, border=16)
        szDlg.Add(self.previewPanel, flag=wx.ALL|wx.EXPAND, border=8)
        
        szDlg.Add(self.szName, flag=wx.ALL|wx.ALIGN_RIGHT, border=8)
        szDlg.Add(sz, flag=wx.ALL|wx.ALIGN_RIGHT, border=8)
        self.SetSizerAndFit(szDlg)
        self.Bind(wx.EVT_BUTTON, self.OnPickSet, self.btnChoose)
        self.Bind(wx.EVT_CHECKBOX, self.OnCheck)
        self.RefreshCommandLine()
        

    def GetResultName(self):
        return self.name.GetValue()
        
    def OnPickSet(self, evt):
        # Create a set picker
        dlg = FilePicker(self, title="Choose an IP set")
        dlg.CenterOnParent()
        if dlg.ShowModal() == wx.ID_OK:
            val = dlg.GetResult()
        else:
            val = "(Choose a set)"
        self.txtSet.SetValue(val)
        self.btnCreate.Enable(self.txtSet != "(Choose a set)")    
        
        #wx.PostEvent(self, ws.OptionChangeEvent(-1, "sip", val))
        self.RefreshCommandLine()
        
    def GetOptions(self):
        opts = {}
        if self.rbunion.GetValue():
            opts["union"] = True
        elif self.rbintersect.GetValue():
            opts["intersect"] = True
        else:
            opts["difference"] = True
        # FIXME: hack to handle multipe input files
        opts["inputs"] = self.txtSet.GetValue()
        return opts
        
    def SetOptions(self, opts):
        print "Setting options: %s" % opts
        if "intersect" in opts:
            self.rbintersect.SetValue(True)
        elif "difference" in opts:
            self.rbdifference.SetValue(True)
        else:
            self.rbunion.SetValue(True)

    def GetCommandLine(self):
        opts = self.GetOptions()
        cmd = silk.build_rwsettool_command(False, "", "$input", "$output",
            commandsOnly=True, **opts)
        return cmd

    def OnCheck(self):
        self.RefreshCommandLine()
        
            
    def RefreshCommandLine(self):
         cmd = self.GetCommandLine()
         self.previewPanel.SetContent(cmd)


#
# setbuild
#


class SetBuildTool(tools.AnalysisTool):
    def __init__(self, **kargs):
        tools.AnalysisTool.__init__(self, **kargs)
        
    def CreateDialog(parentResult, parent, title):
        return SetBuildDialog(parentResult, parent, title=title)
    CreateDialog = staticmethod(CreateDialog)
    
    def CanRun(parentResult):
        if not parentResult:
            return False
        return parentResult.IsSetResult()
    CanRun = staticmethod(CanRun)
    
    def _GetToolName():
        return "rwsetbuild"
    _GetToolName = staticmethod(_GetToolName)
            
    def _GetResultClass(self):
        return resultset.SetResult

    def _GetResultName(self):
        return "Set"
        
    def _RunAnalysis(self, context, inputFileName, outputFileName):
        asTextFileName = outputFileName + ".asc"
        silk.rwsetbuild_ips(context, None, asTextFileName, **self.opts)
        silk.rwsetbuild(context, asTextFileName, outputFileName, **self.opts)
        silk.rwsetcat_ranges(context, outputFileName, outputFileName+".asc", **self.opts)
        
    def _GetCommandLines(inputFile, outputFile, **kargs):
        return "rwsetbuild $input %s" % (outputFile)
    _GetCommandLines = staticmethod(_GetCommandLines)



class SetBuildDialog(wx.Dialog):
    def __init__(self, parentResult, parent, *args, **kargs):
        wx.Dialog.__init__(self, parent, -1, *args, **kargs)

        # Manual specification
        self.lblManual = wx.StaticText(self, -1, "Enter IPs, one per line:")
        self.txtcIps = wx.TextCtrl(self, -1, "",
            style=(wx.TE_MULTILINE | wx.TE_PROCESS_TAB), size=(125,300))

        #self.fpImport = wx.FilePickerCtrl(self, -1, message="Import File")
        
        self.btnCreate = ws.SmButton(self, wx.ID_OK, "Build Set")
        self.btnCancel = ws.SmButton(self, wx.ID_CANCEL, "Cancel")

        # Events (let ID_OK and ID_CANCEL field affirm/cancel)
        self.SetEscapeId(wx.ID_CANCEL)
#        self.Bind(wx.EVT_FILEPICKER_CHANGED, self.OnImport, self.fpImport)
        
        self.btnCreate.SetDefault()

        # Add name editor
        self.setName, szName = _createNameEditor(self)

        # The main dialog
        szDlg = wx.BoxSizer(wx.VERTICAL)

        szDlg.Add(self.lblManual, flag=wx.TOP|wx.LEFT|wx.RIGHT, border=8)
        szDlg.Add(self.txtcIps, flag=wx.ALL|wx.EXPAND, border=16)
        szDlg.Add(szName, flag=wx.ALL, border=8)

        #szImporter = wx.BoxSizer(wx.HORIZONTAL)

        #szImporter.Add(wx.StaticText(self, -1, "Import file:"),
        #    flag=(wx.ALL | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL), border=8)
        #szImporter.Add(self.fpImport, flag=(wx.ALL | wx.ALIGN_RIGHT), border=8)
        #szDlg.Add(szImporter, flag=(wx.ALL | wx.ALIGN_RIGHT), border=8)

        szButtons = wx.BoxSizer(wx.HORIZONTAL)
        szButtons.Add(self.btnCreate, flag=wx.RIGHT, border=8)
        szButtons.Add(self.btnCancel, flag=wx.ALL)
        szDlg.Add(szButtons,
            flag=(wx.ALL | wx.ALIGN_RIGHT), border=8)

        self.SetSizerAndFit(szDlg)
        self.RefreshCommandLine()
        self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnCreate)
        
    def _validateIps(self, showDialog=False):
        val = self.txtcIps.GetValue().replace(" ", "")
        val = self.txtcIps.GetValue().replace("\t", "")
        ip_list = set(val.split("\n"))
        ip_list.remove("")
        pdb.set_trace()
        if len(ip_list) == 0:
            d = wx.MessageDialog(self, "You must specify at least one address.", "Can't parse IP list",
                          wx.ICON_EXCLAMATION)
            d.ShowModal()
            return False
        for ip in ip_list:
            try:
                silkutils.validate_ip_arg(ip)
            except Exception, e:
                if showDialog:
                     d = wx.MessageDialog(self, str(e), "Can't parse IP list",
                            wx.ICON_EXCLAMATION)
                     d.ShowModal()
                return False
        return True
        
    def OnOK(self, evt):
        if not self._validateIps(showDialog=True):
           return
        evt.Skip(True)

    def OnImport(self, evt):
        f = open(evt.GetPath())
        try:
            ips = f.read()
            # FIXME: validate file contents
        finally:
            f.close()
        self.txtcIps.AppendText(ips)
        
    def GetResultName(self):
        return self.setName.GetValue()
        
    def GetOptions(self):
        opts = {}
        if self.txtcIps.GetValue():
            opts["ips"] = self.txtcIps.GetValue()
        if self.setName.GetValue():
            opts["setName"] = self.setName.GetValue()
        return opts
        
    def SetOptions(self, opts):
        print "Setting options: %s" % opts
        if "ips" in opts:
            self.txtcIps.SetValue(opts['ips'])
        elif "setName" in opts:
            self.setName.SetValue(opts['setName'])

    def GetCommandLine(self):
        opts = self.GetOptions()
        if "ips" in opts:
            return "echo '%s' | rwsetbuild stdin $output" % opts['ips']
        else:
            return "echo $ips | rwsetbuild stdin $output"

    def RefreshCommandLine(self):
         cmd = self.GetCommandLine()
         #self.previewPanel.SetContent(cmd)
