
#############################################################################
#
# Author: Ruth Huey, Michel F. SANNER
#
# Copyright: M. Sanner TSRI 2000
#
#############################################################################

#
# $Header: /mnt/raid/services/cvs/python/packages/share1.5/Pmv/deleteCommands.py,v 1.81.2.1 2015/08/31 21:42:07 annao Exp $
#
# $Id: deleteCommands.py,v 1.81.2.1 2015/08/31 21:42:07 annao Exp $
#

"""
This Module implements commands to delete items from the MoleculeViewer:
for examples:
    Delete Molecule
"""

import types, string

from ViewerFramework.VFCommand import CommandGUI
from Pmv.moleculeViewer import DeleteAtomsEvent

class AfterDeleteAtomsEvent(DeleteAtomsEvent):
    pass

from Pmv.mvCommand import MVCommand
from Pmv.guiTools import MoleculeChooser
##  from ViewerFramework.gui import InputFormDescr
from mglutil.gui.InputForm.Tk.gui import InputFormDescr
from mglutil.util.callback import CallBackFunction

from MolKit.protein import Coil, Helix, Strand, Turn
from MolKit.tree import TreeNode, TreeNodeSet
from MolKit.molecule import MoleculeSet, AtomSet, Atom
from MolKit.protein import SecondaryStructure

import Tkinter

from ViewerFramework.VF import VFEvent

class BeforeDeleteMoleculesEvent(VFEvent):
    pass


class DeleteMolecule(MVCommand):
    """Command to delete a molecule from the MoleculeViewer
    \nPackage : Pmv
    \nModule  :
    deleteCommands
    \nClass   : DeleteMolecule
    \nCommand : deleteMolecule
    \nSynopsis:\n
        None<---deleteMol(nodes, **kw)
    \nRequired Arguments:\n
        nodes --- TreeNodeSet holding the current selection
           It resets the undo stack automatically.\n
    """
    
    def onAddCmdToViewer(self):
        self.vf._deletedLevels = []
        if  not self.vf.commands.has_key('select'):
            self.vf.loadCommand("selectionCommands", "select", "Pmv",
                                topCommand=0)
        if  not self.vf.commands.has_key('clearSelection'):
            self.vf.loadCommand("selectionCommands", "clearSelection", "Pmv",
                                topCommand=0)
        if  not self.vf.commands.has_key('restoreMol'):
            self.vf.loadCommand("deleteCommands", "restoreMol", "Pmv",
                                topCommand=0)
            

    def onAddObjectToViewer(self, obj):
        if hasattr(self, 'chooser')\
               and self.chooser is not None \
               and self.form.root.winfo_exists():        
            w = self.chooser.form.descr.entryByName['Molecule']['widget']
            molParser = obj.parser
            molStr = molParser.getMoleculeInformation()
            w.add((obj.name, molStr))
 
           
    def deleteMolecule_cb(self):
        """called each time the 'Delete Molecule' button is pressed"""
        mols = self.chooser.getMolSet()
        if mols is not None and len(mols):
            #if self.vf.undoCmdStack == []:
            if self.vf.NEWundo.cmdStack == []:
                undoable = self.undoableVar.get()
                for mol in mols:
                    self.doitWrapper(mol, redraw=0, undoable=undoable)
            else:
                self.continue_cb()
                

    def hide_cb(self):
        if hasattr(self, 'chooser'):
            if self.chooser.ipf.form is not None:
                mols = self.chooser.getMolSet()
                self.vf.showMolecules(mols.name, negate=1, topCommand=0)
                self.chooser.done_cb()
            self.idf.form.destroy()
            

    def continue_cb(self):
        if hasattr(self, 'chooser'):
            if self.chooser.ipf.form is not None:
                mols = self.chooser.getMolSet()
                undoable = self.undoableVar.get()
                #if not undoable:
                    #self.vf.resetUndo(topCommand=0)
                for mol in mols:
                    self.doitWrapper(mol, redraw=0, undoable=undoable)
            #self.idf.form.destroy()


    def cancel_cb(self):
        self.idf.form.destroy()
        
    def guiCallback(self):
        if len(self.vf.Mols) == 0: return
        self.chooser = MoleculeChooser(self.vf,mode = 'extended',
                                       title='Choose Molecules to delete' )

        self.undoableVar =Tkinter.IntVar()
        self.undoableVar.set(1)
        self.chooser.ipf.append({'name':'Undo',
                                 'widgetType':Tkinter.Checkbutton,
                                 'wcfg':{ 'text':' Undoable Delete', 'variable':self.undoableVar},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W}}
                                 )
        
        self.chooser.ipf.append({'name':'Delete Button',
                                 'widgetType':Tkinter.Button,
                                 'text':'Delete Molecule',
                                 'wcfg':{'bd':6},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W},
                                 'command': self.deleteMolecule_cb})
        self.form = self.chooser.go(modal=0, blocking=0)


    def deleteMol(self, mol, undoable=False):
        """ Function to delete all the references to each elements of a
        molecule and then these elements and the molecule to free the
        memory space."""

        #  Call the removeObject function for all the command having an
        # onRemoveMol function
        self.vf.removeObject(mol, undoable=undoable)
        # Maybe do that in moleculeViewer ???
        # also need to clean up selector.selection:
        nodes = self.vf.getSelection()
        mol.__class__._numberOfDeletedNodes = 0
        node = mol
        while len(node.children):
            node = node.children

        # Initialize the variable _numberOfDeletedNodes at 0
        node[0].__class__._numberOfDeletedNodes = 0
        sslevels = [Coil, Helix, Strand, Turn]
        # Initialize the variable _numberOfDeletedNodes for each secondary
        # structure to 0.
        for sl in sslevels:
            # Initialize the variable _numberOfDeletedNodes at 0
            sl._numberOfDeletedNodes = 0

        # but only change selection if there is any
        if nodes is not None and len(nodes)>0:
            setClass = nodes.__class__
            thisMolNodes = setClass(nodes.get(lambda x, mol=mol: x.top==mol))
            #only change selection if this molecule has any nodes in it
            if len(thisMolNodes)>0:
                nodes = nodes-thisMolNodes
                self.vf.clearSelection(topCommand=0)
                if nodes is not None:
                    self.vf.select(nodes)
                    #self.vf.selector.select(nodes)

        if hasattr(self, 'chooser') and self.form.root.winfo_exists():
            # update the listChooser
            lc = self.chooser.ipf.entryByName['Molecule']['widget']
            lc.remove(mol.name)
            #lc.clearComments()

        #check for any possible reference in self.vf.GUI.VIEWER.lastPick
        if self.vf.hasGui and self.vf.GUI.VIEWER.lastPick:
            for key in self.vf.GUI.VIEWER.lastPick.hits.keys():
                if hasattr(key,'mol'):
                    if mol==key.mol:
                        del self.vf.GUI.VIEWER.lastPick.hits[key]

        # Remove the atoms of the molecule you are deleting from the
        # the AtomSet self.vf.allAtoms
        self.vf.allAtoms = self.vf.allAtoms - mol.allAtoms
        seqViewer = self.vf.commands.get("sequenceViewer", None)
        if seqViewer: seqViewer.deleteObject(mol)
        if not undoable:
            # Delete all the reference to the atoms you want to delete
            if hasattr(mol.allAtoms, 'bonds'):
                bnds = mol.allAtoms.bonds[0]
                for b in bnds:
                    b.__dict__.clear()
                    del(b)
            
            mol.allAtoms.__dict__.clear()
            del mol.allAtoms
    
            if self.vf.hasGui and hasattr(mol, 'geomContainer'):
                for g in mol.geomContainer.geoms.values():
                    if hasattr(g, 'mol'):
                        delattr(g, 'mol')
    
                mol.geomContainer.geoms.clear()
                mol.geomContainer.atoms.clear()
                delattr(mol.geomContainer, 'mol')
                del mol.geomContainer
    
            if hasattr(mol, 'atmNum'):
                mol.atmNum.clear()
                del mol.atmNum
    
            if hasattr(mol, 'childByName'):
                mol.childByName.clear()
                del mol.childByName
    
            if hasattr(mol, 'parser') and hasattr(mol.parser, 'mol'):
                delattr(mol.parser,'mol')
                del mol.parser

        # delete molecule from Vision, if Vision is running
        if self.vf.visionAPI:
            self.vf.visionAPI.remove(mol)

        if not undoable:
            if len(mol.children):
                deletedLevels = mol.deleteSubTree()
            else:
                deletedLevels = []
            # then delete all the refences to the molecule
            del mol.top
            # Then delete the molecule
            deletedLevels.insert(0, mol.__class__)
    
            mol.__dict__.clear()
            del mol
        
            self.vf._deletedLevels = deletedLevels

        if len(self.vf.Mols) == 0 and hasattr(self, 'chooser') \
                and self.form.root.winfo_exists():
            self.chooser.done_cb()


    def getFreeMemoryInformation(self):
        """Store how many TreeNodes have been actually free'ed during the
        last delete operation in a dictionary"""

        memoryInformation = {}
        #print 'self.vf._deletedLevels=', self.vf._deletedLevels
        for d in self.vf._deletedLevels:
            #print 'checking ', d, ' for deletedNodes'
            memoryInformation[d.__name__] = d._numberOfDeletedNodes
        sslevels = [Coil, Helix, Strand, Turn]
##          geomslevels = [IndexedPolylines, IndexedPolygons]
        # Have to loop on the known secondarystructure because our
        # Data structure doesn't support multiple children and parents.
        for sl in sslevels:
            if sl._numberOfDeletedNodes!=0:
                memoryInformation[sl.__name__] = sl._numberOfDeletedNodes

##          for sg in geomslevels:
##              if sl._numberOfDeletedNodes!=0:
##                  memoryInformation[sl.__name__] = sl._numberOfDeletedNodes
                
        return memoryInformation




    def doit(self, nodes,  undoable=False, cleanRedo=True):
        #if called with no selection, just return
        molecules, nodeSets = self.vf.getNodesByMolecule(nodes)
        event = BeforeDeleteMoleculesEvent(molecules)
        self.vf.dispatchEvent(event)
        for mol in molecules:
            if not undoable:
                #print "cleaning the undo CmdStack"
                self.vf.cleanCmdStack(self.vf.NEWundo, mol)
                self.vf.cleanCmdStack(self.vf.redo, mol)
            else:
                if cleanRedo:
                    self.vf.cleanCmdStack(self.vf.redo, mol)
            self.deleteMol(mol, undoable)

        if self.vf.hasGui:
            self.vf.GUI.VIEWER.SetCurrentObject(self.vf.GUI.VIEWER.rootObject)
        #if not undoable:
        #    self.vf.resetUndo(topCommand=0)

            
    def __call__(self, nodes, undoable=False, **kw):
        """None <- deleteMol(nodes, **kw)
        \nnodes: TreeNodeSet holding the current selection.
        """
        if type(nodes) is types.StringType:
            self.nodeLogString = "'"+nodes+"'"
        kw['undoable'] = undoable
        self.doitWrapper( *(nodes,), **kw )


    def negateCmdBefore(self, molecule, undoable=False, **kw):
        #print "deleteMol, negateCmdBefore(), undoable", undoable
        if undoable:
            if type(molecule) is types.StringType:
                molecules, nodeSets = self.vf.getNodesByMolecule(molecule)
                if not len(molecules):return
                molecule = molecules[0]
            
            code = self.vf.getStateCodeForMolecule(molecule, mode="commands")
            return ([(self.vf.restoreMol, (molecule,), {'cmds':code, 'log':0})], self.name+" %s"%molecule.name)
            
            
##     def undo(self):
##         """Undo for DeleteMolecule:
##         We use self.vf.getStateCodeForMolecule from setupUndoBefore to restore the state of the molecule.
##         """
##         mol = self.undoStack.pop()
##         mol = mol[0][0]
##         self.vf.addMolecule(mol)
##         exec(mol.code, {'self':self.vf})




class RestoreMolecule(MVCommand):
    """Command to restore a molecule that had been deleted with deleteMol command
    (when 'undoable' of the deleteMol command is set to True)
    \nPackage : Pmv
    \nModule  : deleteCommands
    \nClass   : RestoreMolecule
    \nCommand : restoreMol
    \nSynopsis:\n
        None<---restoreMolecules(molecule, cmds=None)
        \ncmds - a list of commands to execute to restore the molecule's state
        """
    
    def doit(self, molecule, cmds=None, **kw):
        
        self.vf.addMolecule(molecule)
        if not cmds: return
        if not len(self.vf.Mols): return "ERROR"
        mol = self.vf.Mols[-1]
        if not mol.name == molecule.name:
            return "ERROR"
        currentAtoms = mol.allAtoms
        currentAtoms.sort()
        from ViewerFramework.VFCommand import Command
        for entry in cmds:
            if isinstance(entry[0], Command):
                cmd, args, kw = entry
                kw['topCommand'] = 0
                kw['setupNegate'] = 0
                cmd(*args, **kw)
            elif callable(entry[0]):
                cmd, args, kw = entry
                cmd(*args, **kw)
            elif entry[0] == "atomcolors":
                for ind, colors in entry[1].items():
                    for att, col in colors.items():
                        currentAtoms[ind].colors[att] = col
            elif entry[0] == "atomdata":
                for ind, data in entry[1].items():
                    for att, val in data.items():
                        setattr(currentAtoms[ind], att, val)

                         
    def __call__(self, molecule, cmds=None, **kw):
        """None <- restoreMol(molecule, **kw)
        \nmolecule: molecule that had beed deleted with deleteMol command.
        """
        if cmds:
            kw['cmds'] = cmds
        self.doitWrapper(*(molecule,), **kw )
             

    def negateCmdAfter(self, molecule, cmds=None, **kw):
        #print "negateCmdAfter", self.name
        return ([(self.vf.deleteMol, (molecule,), {'undoable':1, 'cleanRedo':False})],
                self.name+ " %s"%molecule.name)


    def handleForgetUndo(self, mol, cmds=None, **kw):
        if mol in self.vf.Mols: return
        print self.name, "handleForgetUndo"
        # Delete all the reference to the atoms you want to delete
        if hasattr(mol.allAtoms, 'bonds'):
            bnds = mol.allAtoms.bonds[0]
            for b in bnds:
                b.__dict__.clear()
                del(b)

        mol.allAtoms.__dict__.clear()
        del mol.allAtoms

        if self.vf.hasGui and hasattr(mol, 'geomContainer'):
            for g in mol.geomContainer.geoms.values():
                if hasattr(g, 'mol'):
                    delattr(g, 'mol')

            mol.geomContainer.geoms.clear()
            mol.geomContainer.atoms.clear()
            delattr(mol.geomContainer, 'mol')
            del mol.geomContainer

        if hasattr(mol, 'atmNum'):
            mol.atmNum.clear()
            del mol.atmNum

        if hasattr(mol, 'childByName'):
            mol.childByName.clear()
            del mol.childByName

        if hasattr(mol, 'parser') and hasattr(mol.parser, 'mol'):
            delattr(mol.parser,'mol')
            del mol.parser



        if len(mol.children):
            deletedLevels = mol.deleteSubTree()
        else:
            deletedLevels = []
        # then delete all the refences to the molecule
        del mol.top
        # Then delete the molecule
        deletedLevels.insert(0, mol.__class__)

        mol.__dict__.clear()
        del mol

        self.vf._deletedLevels = deletedLevels
        

    
        
            
from Pmv.deleteCommandsGUI  import DeleteMoleculeGUI  

class DeleteAllMolecules(DeleteMolecule):
    """Command to delete all molecules from the MoleculeViewer
    \nPackage : Pmv
    \nModule  : deleteCommands
    \nClass   : DeleteAllMolecules
    \nCommand : deleteAllMolecules
    \nSynopsis:\n
        None<---deleteAllMolecules( **kw)
    \nRequired Arguments:\n
         It resets the undo stack automatically.\n
    """
            
    def onAddCmdToViewer(self):
        self.vf._deletedLevels = [] 
           
    def guiCallback(self):
        """called each time the 'Delete All Molecules' button is pressed"""
        if len(self.vf.Mols) == 0: 
            self.warningMsg("No molecules present in the Viewer")
            return
        mols = self.vf.Mols
        if mols is not None and len(mols):
            text = """WARNING: This command cannot be undone.
            if you choose to continue commands on the undo/redo command stack
            refering to this molecule will be deleted.
            Do you want to continue?""" 
            if not hasattr(self, 'idf'): 
                self.idf = InputFormDescr(title="WARNING")
                self.idf.append({'widgetType':Tkinter.Label,
                            'wcfg':{'text':text},
                            'gridcfg':{'columnspan':3,'sticky':'w'}})

                self.idf.append({'name': 'Continue Button',
                            'widgetType':Tkinter.Button,
                            'wcfg':{'text':'CONTINUE',
                                    'command':self.continue_cb},
                            'gridcfg':{'sticky':'we'}})

                self.idf.append({'name': 'Cancel Button',
                            'widgetType':Tkinter.Button,
                            'wcfg':{'text':'CANCEL',
                                    'command':self.cancel_cb},
                            'gridcfg':{'row':-1,'sticky':'we'}})
            self.vf.getUserInput(self.idf, okcancel=0)

                


    def continue_cb(self):
        #self.vf.resetUndo(topCommand=0)
        
        self.doitWrapper()
        if hasattr(self, 'idf') and hasattr(self.idf, 'form'):
            self.idf.form.destroy()


    def cancel_cb(self):
        if hasattr(self, 'idf') and hasattr(self.idf, 'form'):
            self.idf.form.destroy()
        

    def getFreeMemoryInformation(self):
        """Store how many TreeNodes have been actually free'ed during the
        last delete operation in a dictionary"""

        memoryInformation = {}
        #print 'self.vf._deletedLevels=', self.vf._deletedLevels
        for d in self.vf._deletedLevels:
            #print 'checking ', d, ' for deletedNodes'
            memoryInformation[d.__name__] = d._numberOfDeletedNodes
        sslevels = [Coil, Helix, Strand, Turn]
##          geomslevels = [IndexedPolylines, IndexedPolygons]
        # Have to loop on the known secondarystructure because our
        # Data structure doesn't support multiple children and parents.
        for sl in sslevels:
            if sl._numberOfDeletedNodes!=0:
                memoryInformation[sl.__name__] = sl._numberOfDeletedNodes

##          for sg in geomslevels:
##              if sl._numberOfDeletedNodes!=0:
##                  memoryInformation[sl.__name__] = sl._numberOfDeletedNodes
                
        return memoryInformation


    def doit(self):
        for i in range(len(self.vf.Mols)):
            self.deleteMol(self.vf.Mols[-1])
        self.vf.NEWundo.resetCmdStack()
        self.vf.redo.resetCmdStack()
        if self.vf.hasGui:
            self.vf.GUI.VIEWER.SetCurrentObject(self.vf.GUI.VIEWER.rootObject)
            self.vf.GUI.VIEWER.Redraw()


    def __call__(self, **kw):
        """ None<---deleteAllMolecules( **kw)
        \nRemove all molecules in the viewer
        \nIt resets the undo stack automatically.
        """
        
        apply ( self.doitWrapper, (), kw )
        #self.vf.resetUndo(topCommand=0)


    def negateCmdBefore(self):
        "DeleteALLMolecules is undoable"
        return

    
from Pmv.deleteCommandsGUI  import DeleteAllMoleculesGUI


class DeleteAtomSet(MVCommand):
    """ Command to remove an AtomSet from the MoleculeViewer
    \nPackage : Pmv
    \nModule  : deleteCommands
    \nClass   : DeleteAtomSet
    \nCommand : deleteAtomSet
    \nSynopsis:\n
        None<---deleteAtomSet(atoms, **kw)\n
    \nRequired Arguments:\n
        atoms --- AtomSet to be deleted.\n
    """
    
    def __init__(self, func=None):
        MVCommand.__init__(self, func)
        self.flag = self.flag | self.objArgOnly

    def onAddCmdToViewer(self):
        self.vf._deletedLevels = []
        #if self.vf.hasGui and not self.vf.commands.has_key('deleteMol'):
        if not self.vf.commands.has_key('deleteMol'):
            self.vf.loadCommand("deleteCommands", "deleteMol", "Pmv",
                            topCommand=0)
        if  not self.vf.commands.has_key('select'):
            self.vf.loadCommand("selectionCommands", "select", "Pmv",
                                topCommand=0)
        if  not self.vf.commands.has_key('clearSelection'):
            self.vf.loadCommand("selectionCommands", "clearSelection", "Pmv",
                                topCommand=0)


    def __call__(self, atoms, **kw):
        """None <- deleteAtomSet(atoms, **kw)
        \natoms: AtomSet to be deleted."""
        if type(atoms) is types.StringType:
            self.nodeLogString = "'"+atoms+"'"
        ats = self.vf.expandNodes(atoms)
        if not len(ats):
            return 'ERROR'
        # MS here we create a copy of what findType returns
        ats = ats.findType(Atom)
        kw['redraw'] = True
        apply(self.doitWrapper, (ats,), kw)


    def doit(self, ats):
        """ Function to delete all the references to each atom  of a
        AtomSet."""

        # Remove the atoms of the molecule you are deleting from the
        # the AtomSet self.vf.allAtoms
        self.vf.allAtoms = self.vf.allAtoms - ats

        atmsInSel = self.vf.selection.findType(Atom)[:]
        atmsInSel.sort()
        event = DeleteAtomsEvent(objects=ats)
        self.vf.dispatchEvent(event)

        #  Call the updateGeoms function for all the command having an
        # updateGeom function
        molecules, atomSets = self.vf.getNodesByMolecule(ats)
        ats.sort()
        done = 0
        allAtoms = AtomSet([])
        for mol, atSet in map(None, molecules, atomSets):
            if len(atSet)==len(mol.allAtoms):
                #have to add atoms back to allAtoms for deleteMol to work
                self.vf.allAtoms = self.vf.allAtoms + atSet
                self.vf.cleanCmdStack(self.vf.NEWundo, mol)
                self.vf.cleanCmdStack(self.vf.redo, mol)
                self.vf.deleteMol.deleteMol(mol)
                #if this is the last atom, quit the loop
                if mol==molecules[-1]:
                    done=1
                    break
                continue

            mol.allAtoms = mol.allAtoms - atSet
            allAtoms = allAtoms + atSet
            #FIRST remove any possible hbonds
            hbondAts = atSet.get(lambda x: hasattr(x, 'hbonds'))
            if hbondAts is not None:
                #for each atom with hbonds
                for at in hbondAts:
                    if not hasattr(at, 'hbonds'):
                        continue
                    #remove each of its hbonds 
                    for b in at.hbonds:
                        self.removeHBond(b)
        
            atSetCopy = atSet.copy() #fixed bug#:       1143
            for at in atSetCopy:
                for b in at.bonds:
                    at2 = b.atom1
                    if at2 == at: at2 = b.atom2
                    at2.bonds.remove(b)
                if at.parent.children:
                    at.parent.remove(at, cleanup=1)
        if len(atmsInSel):
            if atmsInSel == ats:
                # the current selection was deleted 
                #self.vf.clearSelection(topCommand=0, createEvents=False)
                self.vf.clearSelection(topCommand=0)
            else:
                nodes = self.vf.selection
                lenSel = len(nodes)
                setClass = nodes.__class__
                elementClass = nodes.elementType
                if lenSel>0:
                    # this breaks if selectionlevel is Molecule, for instance
                    # setClass = nodes.__class__
                    # newSel = setClass(nodes.findType(Atom) - ats)
                    # newSel2 = setClass([])
                    newSel = atmsInSel-ats
                    newSel2 = AtomSet([])
                    # may have ats which have been deleted everywhere else
                    for at in newSel:
                        if at in at.top.allAtoms:
                            newSel2.append(at)
                    if len(newSel2)!=lenSel:
                        self.vf.clearSelection(topCommand=0)
                        if len(newSel2):
                            newSel2 = newSel2.findType(elementClass).uniq()
                            self.vf.select(newSel2, topCommand=0)

        # this fixes an exception that occured when the last chain was split
        # out of a ptrotein
        if not done:
            event = AfterDeleteAtomsEvent(objects=ats)
            self.vf.dispatchEvent(event)
        
        #this fixed a bug which occured when only 1 molecule present
        #and cmd invoked with mv.deleteAtomSet(mv.Mols[0].allAtoms)
        if not done:
            for at in ats: del at
        #self.vf.resetUndo(topCommand=0)
                    
    def removeHBond(self, b):
        atList = [b.donAt, b.accAt]
        if b.hAt is not None:
            atList.append(b.hAt)
        for at in atList:
            #hbonds might already be gone
            if not hasattr(at, 'hbonds'):
                continue
            okhbnds = []
            for hb in at.hbonds:
                if hb!=b:
                    okhbnds.append(hb)
            if len(okhbnds):
                at.hbonds = okhbnds
            else:
                delattr(at, 'hbonds')
        return 

from Pmv.deleteCommandsGUI  import DeleteCurrentSelectionGUI


class DeleteCurrentSelection(DeleteAtomSet):
    """ Command to remove an AtomSet from the MoleculeViewer
    \nPackage : Pmv
    \nModule  : deleteCommands
    \nClass   : DeleteCurrentSelection
    \nCommand : deleteCurrentSelection
    \nSynopsis:\n
        None<---deleteCurrentSelection(**kw)\n
    \nRequired Arguments:\n
        None
    """
    
    def __call__(self, *args, **kw):
        """None <- deleteCurrentSelection(atoms, **kw)
        \natoms: AtomSet to be deleted."""
        self.doitWrapper(**kw)


    def guiCallback(self, event=None):
        """called each time the 'Delete Selected Atoms' button is pressed"""
        z = self.vf.getSelection()
        if z:
            ats = z.findType(Atom)
##             if self.vf.userpref['Expand Node Log String']['value'] == 0:
##                 self.vf.deleteAtomSet.nodeLogString = "self.getSelection()"
        else:
            self.vf.warningMsg('no atoms selected')
            return 'ERROR'
        if ats:
            #if self.vf.undoCmdStack == []:
            if self.vf.NEWundo.cmdStack == []:
                self.doitWrapper(ats, redraw=0)
            else:
                text = """WARNING: This command cannot be undone.
                if you choose to continue the undo list will be reset.
                Do you want to continue?""" 

                idf = self.idf = InputFormDescr(title="WARNING")
                idf.append({'widgetType':Tkinter.Label,
                            'wcfg':{'text':text},
                            'gridcfg':{'columnspan':2,'sticky':'w'}})

                idf.append({'name': 'continueBut',
                            'widgetType':Tkinter.Button,
                            'wcfg':{'text':'CONTINUE',
                                    'command':self.continue_cb},
                            'gridcfg':{'sticky':'we'}})

                idf.append({'name': 'cancelBut',
                            'widgetType':Tkinter.Button,
                            'wcfg':{'text':'CANCEL', 'command':self.cancel_cb},
                            'gridcfg':{'row':-1,'sticky':'we'}})

                self.form = self.vf.getUserInput(idf, modal = 0, blocking = 0)
                self.form.root.protocol('WM_DELETE_WINDOW',self.cancel_cb)



    def continue_cb(self):
        #self.vf.resetUndo(topCommand=0)
        self.doitWrapper()
        #self.doitWrapper(ats, log=0)
        self.form.destroy()


    def cancel_cb(self):
        self.idf.form.destroy()
        

    def doit(self):
        """ Function to delete all the references to each atom of a
        the currentSelection."""

        atoms = old = self.vf.getSelection()[:] # make copy of selection
        ats = self.vf.expandNodes(atoms)
        if not len(ats):
            return
        ats = ats.findType(Atom)

        self.vf.clearSelection(log=0)
        self.vf.deleteAtomSet(ats, redraw=True, log=0)


class DeleteHydrogens(DeleteAtomSet):
    """ Command to remove hydrogen atoms from the MoleculeViewer
    \nPackage : Pmv
    \nModule  : deleteCommands
    \nClass   : DeleteHydrogens
    \nCommand : deleteHydrogens
    \nSynopsis:\n
        None<---deleteAtomSet(atoms, **kw)\n
    \nRequired Arguments:\n 
        atoms --- AtomSet to be deleted.\n
    """
    def guiCallback(self):
        """called each time the 'Delete Selected Atoms' button is pressed"""
        z = self.vf.getSelection()
        hats = None
        if z:
            ats = z.findType(Atom)
            if ats:
                hats = ats.get(lambda x: x.element=='H')
        else:
            self.vf.warningMsg('no atoms selected')
            return 'ERROR'
        if hats is None:
            self.vf.warningMsg('no hydrogens selected')
            return 'ERROR'

        #only get to this point if hats
        #if self.vf.undoCmdStack == []:
        if self.vf.NEWundo.cmdStack == []:
            self.doitWrapper(hats, redraw=0)
        else:
            text = """WARNING: This command cannot be undone.
            if you choose to continue the undo list will be reset.
            Do you want to continue?""" 

            idf = self.idf = InputFormDescr(title="WARNING")
            idf.append({'widgetType':Tkinter.Label,
                        'wcfg':{'text':text},
                        'gridcfg':{'columnspan':2,'sticky':'w'}})

            idf.append({'name': 'continueBut',
                        'widgetType':Tkinter.Button,
                        'wcfg':{'text':'CONTINUE',
                                'command':CallBackFunction(self.continue_cb,
                                                           hats)},
                        'gridcfg':{'sticky':'we'}})

            idf.append({'name': 'cancelBut',
                        'widgetType':Tkinter.Button,
                        'wcfg':{'text':'CANCEL', 'command':self.cancel_cb},
                        'gridcfg':{'row':-1,'sticky':'we'}})

            self.form = self.vf.getUserInput(idf, modal = 0, blocking = 0)
            self.form.root.protocol('WM_DELETE_WINDOW',self.cancel_cb)


    def continue_cb(self, hats):
        #self.vf.resetUndo(topCommand=0)
        self.vf.NEWundo.resetCmdStack()
        self.vf.redo.resetCmdStack()
        self.doitWrapper(hats, redraw=0)
        if hasattr(self, 'idf') and hasattr(self.idf, 'form'):
            self.idf.form.destroy()

    def cancel_cb(self):
        self.idf.form.destroy()
        


    def __call__(self, atoms, **kw):
        """None <- deleteAtomSet(atoms, **kw)
        \natoms: AtomSet to be deleted."""
        if type(atoms) is types.StringType:
            self.nodeLogString = "'"+atoms+"'"
        
        ats = self.vf.expandNodes(atoms)
        if not len(ats):
            return 'ERROR'
        hats = ats.get(lambda x: x.element=='H')
        if not len(hats):
            return 'ERROR'
        ats = hats
        #WHY???
        #kw['log'] = 0
        apply(self.doitWrapper, (ats,), kw)

from Pmv.deleteCommandsGUI  import DeleteHydrogensGUI

commandList = [
    {'name':'deleteMol','cmd': DeleteMolecule(),'gui': DeleteMoleculeGUI},
    {'name':'deleteAllMolecules','cmd': DeleteAllMolecules(),'gui': DeleteAllMoleculesGUI},
#    {'name':'deleteAtomSet','cmd': DeleteAtomSet(),'gui': DeleteAtomSetGUI},
        {'name':'deleteAtomSet','cmd': DeleteAtomSet(),'gui': None },
    {'name':'deleteCurrentSelection','cmd': DeleteCurrentSelection(),
     'gui': DeleteCurrentSelectionGUI },
    {'name':'deleteHydrogens','cmd': DeleteHydrogens(),'gui': DeleteHydrogensGUI},
    {'name':'restoreMol','cmd': RestoreMolecule(),'gui': None},
    ]

def initModule(viewer):
    for dict in commandList:
        viewer.addCommand(dict['cmd'], dict['name'], dict['gui'])
