## Automatically adapted for numpy.oldnumeric Jul 23, 2007 by 

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


# $Header: /opt/cvs/python/packages/share1.5/AutoDockTools/autogpfCommands.py,v 1.128.4.3 2012/03/08 21:35:06 rhuey Exp $
#
# $Id: autogpfCommands.py,v 1.128.4.3 2012/03/08 21:35:06 rhuey Exp $
#
#
#
#
#




"""
This Module facilitates producing a grid parameter file for AutoGrid. The steps in this process are:

    * 'Macromolecule': Selecting the macromolecule: 
        The user can select the macromolecule for autogpf in two ways: 
           - it can be chosen from molecules previously added to the moleculeViewer  
           - it can be read in from a file:

        o Choose Macromol...

        o Read Macromolecule 


    * 'Set Map Types': Setting the types of maps to generate: 

        o Set Map Types Directly

        o By Choosing Ligand

        o By Reading Formatted File

The user can change the types of maps to be calculated.
He decides which types of possible hydrogen bonding he wishes to model. 
For instance, IF hydrogens are present  AND nitrogens, oxygens and /or sulfurs, 
the user can decide to model N-H bonds, O-H bonds and/or S-H bonds.  
He sets which type of dielectric to use:
    -distance-dependent dielectric  
    -constant dielectric  
(Other ligand-related commands allow the user to set energy parameters for new 
atom types or to set up a specialized 'covalent' grid-map.)


    * 'Set Grid': The user positions the grid and sets its dimensions by:

        o Setting the center of the grid maps: 

            - by picking an atom or

            - by entering the full-name of an atom or 

            - by entering the desired coordinates in entries 'x center', 'y center', 
'z center' (NB: ALL entries must be 'activated' by a 'Return')

            - by choosing  the 'Center on Macromolecule' option which sets the 
center of the grid to the geometric center of the macromolecule (obtained by 
averaging all its coordinates)

            - by choosing  the 'Center on Ligand' option which sets the center of 
the grid to the geometric center of the ligand (obtained by averaging all its 
coordinates)

        o Setting the number of grid points in each direction (which has to be an 
even number) and the spacing between the points. This is done by using the 
corresponding scale widgets.

        o Adjusting the position of the grid using scales for x-offset, y-offset 
and z-offset.  These scales allow the user to move the grid box up to 10 angstroms 
in any direction along any of the three axes. 
(NOTE that the units of these scales are tenths of Angstroms and the new coordinates 
of the center are reflected in the x-center, y-center, z-center entries)

    * 'Set Other Options': The user adjusts these additional parameters: 
    
        o the smoothing factor can be changed from its default 0.5Angstrom value.  
This changes the radius of the area within which the minimum energy is stored.
        o  electrostatic potential map may or may not be generated by AutoGrid

        o floating point potential map may or may not be generated 

        o the user may decide whether or not to use the default distance dependent 
dielectric constant.  If not, he can enter his desired dielectric constant or use 
the default value, 40. It should be noted that this entered value is multiplied 
by 0.1146 by the program for input to AutoGrid.

    * 'Write GPF': The results of the previous steps are written to a file. 
The user selects a filename via a filebrowser.  By convention, the file should 
have a .gpf extension. If no macromolecule has been selected, it is not possible 
to write a grid parameter file and the user gets a warning message to that effect. 
Likewise, the types of the maps to be calculated must be set before the grid 
parameter file is written and a warning message to this effect appears if the 
types have not been set.

    * 'Edit GPF': Allows user to edit a grid parameter file.  If one has been
written, it is automatically loaded. Otherwise, the user can select any *.gpf
file to edit from a file browser.
    
"""
from ViewerFramework.VFCommand import CommandGUI
from Pmv.moleculeViewer import AddAtomsEvent
#from ViewerFramework.VF import ModificationEvent
##  from ViewerFramework.gui import InputFormDescr
from mglutil.gui.InputForm.Tk.gui import InputFormDescr

from mglutil.util.callback import CallBackFunction
from mglutil.util.misc import ensureFontCase

from MolKit.tree import TreeNode, TreeNodeSet
from MolKit.molecule import Atom, AtomSet
from MolKit.protein import Residue, ResidueSet
from MolKit import Read
from Pmv.mvCommand import MVCommand, MVAtomICOM
from Pmv.guiTools import MoleculeChooser
from Pmv.qkollua import q
from SimpleDialog import SimpleDialog
import types, Tkinter, math, os
import numpy.oldnumeric as Numeric


from energyConstants import Rij, epsij, SolVol, SolPar, SolCon
#from AutoDockTools.Objects.energyConstants import Rij, epsij, SolVol, SolPar, SolCon
from autotorsCommands import checkMolCharges
from autotorsCommands import  set_autoMergeNPHS
from GridParameters import GridParameters, \
                grid_parameter_list, grid_parameter_list4
#from AutoDockTools.Objects.GridParameters import GridParameters, grid_parameter_list
from mglutil.gui.BasicWidgets.Tk.thumbwheel import ThumbWheel
import tkSimpleDialog
from string import split, find, join, upper, rfind, replace
from MoleculePreparation import ReceptorPreparation, AD4ReceptorPreparation

from atomTypeTools import AutoDock4_AtomTyper

from DejaVu.Geom import Geom

#create a global geometry for this module

def check_autogpf_geoms(VFGUI):
    autogpf_geoms_list = VFGUI.VIEWER.findGeomsByName('autogpf_geoms')
    if autogpf_geoms_list==[]:
        autogpf_geoms = Geom("autogpf_geoms", shape=(0,0), protected=True)
        VFGUI.VIEWER.AddObject(autogpf_geoms, parent=VFGUI.miscGeom)
        autogpf_geoms_list = [autogpf_geoms]
    return autogpf_geoms_list[0]



from DejaVu.Spheres import Spheres
cenSph = Spheres(name='autogpf_cenSph', materials=((0.,1.,0),), shape = (0,3),
         radii = 0.3, vertices=((0.,0.,0.),), visible=0,
         pickable=0,  inheritMaterial=0)
cenSph.in_viewer = False

from DejaVu.Points import CrossSet
cenCross = CrossSet('autogpf_cenCross', materials=((1.,1.,0),),
                    inheritMaterial=0,
            offset=1.0,lineWidth=2, visible=0, pickable=0)
cenCross.in_viewer = False

from mglutil.gui.BasicWidgets.Tk.customizedWidgets import ExtendedSliderWidget
#from DejaVu.extendedSlider import ExtendedSlider
from DejaVu.IndexedPolygons import IndexedPolygons
from DejaVu.Box import Box
from DejaVu import viewerConst
from DejaVu.bitPatterns import patternList
from opengltk.OpenGL import GL
import numpy.oldnumeric as Numeric

face=((0,3,2,1),(3,7,6,2),(7,4,5,6),(0,1,5,4),(1,2,6,5),(0,4,7,3))
coords=((1,1,-1),(-1,1,-1),(-1,-1,-1),(1,-1,-1),(1,1,1),(-1,1,1),(-1,-1,1),(1,-1,1))
#new style RGB->
materials=((0,0,1),(0,1,0),(0,0,1),(0,1,0),(1,0,0),(1,0,0),)
#box=Box('box', materials=materials, vertices=coords, faces=face, 
#                    inheritMaterial=0)
box=IndexedPolygons('box', materials=materials, vertices=coords, faces=face,
                    inheritMaterial=0)
box.Set(frontPolyMode=GL.GL_FILL)
box.inheritShading=0
box.shading=GL.GL_FLAT
box.Set(matBind=viewerConst.PER_PART)
box.Set(visible=0, inheritStipplePolygons=0)
box.polygonstipple.Set(pattern=patternList[0])
box.Set(stipplePolygons=1)
box.transparent=0
box.oldFPM = None
box.in_viewer = False
#box.oldFPM = GL.GL_LINE

#these are the texts on menubuttons, menu entries etc:
menuText = {}
#menuText['AutoGpfMB'] = ' Set Grid Parameters '
menuText['AutoGpfMB'] = 'Grid'

menuText['ReadGpfMB'] = 'Open GPF...'  #CLARIFY THIS
menuText['MacromoleculeMB'] = 'Macromolecule'
menuText['ChooseMacro'] = 'Choose...(AG3)'
menuText['ReadMacro'] = 'Open...(AG3)'
menuText['ChooseMacro4'] = 'Choose...'
menuText['ReadMacro4'] = 'Open...'
menuText['MergeNPHS'] = 'Merge NonPolar Hydrogens'  #obsolete entry
menuText['AddSol'] = 'Add Solvent Parameters...(AG3)'

menuText['SetMapTypesMB'] = 'Set Map Types'
menuText['SetMapDirectly4'] = 'Directly...'
menuText['SetMapDirectly'] = 'Directly...(AG3)'
menuText['SetUpCovalentMap4'] = 'Set Up Covalent Map...'
menuText['SetUpCovalentMap'] = 'Set Up Covalent Map...(AG3)'
menuText['ByChoosingLigand'] = 'Choose Ligand...(AG3)'
menuText['ByReadingFile'] = 'Open Ligand...(AG3)'
menuText['ByChoosingLigand4'] = 'Choose Ligand...'
menuText['ByReadingFile4'] = 'Open Ligand...'
menuText['ByChoosingFlexRes4'] = 'Choose FlexRes...'
menuText['ByReadingFlexResFile4'] = 'Open FlexRes...'
menuText['SetNewTypeParms'] = 'Set New Atom Type Parameters...(AG3)'

menuText['SetGridMB'] = 'Grid Box...'

menuText['SetOtherOptionsMB'] = 'Other Options...'
menuText['SetOtherOptionsMB_AG3'] = 'Other Options...(AG3)'
menuText['SetParameterFilename'] = 'Parameter Library Filename...'
menuText['EditParameterFile'] = 'Edit Parameter Library...'

menuText['WriteMB'] = 'Output'
menuText['WriteGpfMB'] = 'Save GPF...(AG3)'
menuText['WriteGpf4MB'] = 'Save GPF...'

menuText['EditGpfMB'] = 'Edit GPF...'

#Set Grid text strings
gridOpts = {}
gridOpts['PickCenter'] = 'on picked Atom'
gridOpts['CenterLigand'] = "on Ligand"
gridOpts['CenterMacro'] = "on Macromolecule\n('auto' option)"
gridOpts['EnterCenter'] = "Enter Center Atom\nFull Name:"
gridOpts['TotalPtsLabel'] = "Current Total Grid Pts per map:"
gridOpts['XNumLabel'] = "number of xpts"
gridOpts['YNumLabel'] = "number of ypts"
gridOpts['ZNumLabel'] = "number of zpts"
gridOpts['gridSpacingLabel'] = "grid spacing:"
gridOpts['ShowGridBoxLabel'] = "Show Box"
gridOpts['ShowCenterCrossLabel'] = "Show Center Marker"
gridOpts['AsLinesLabel'] = "As Lines"
gridOpts['AsFacesLabel'] = "As Faces"
gridOpts['CenterGridBoxLabel'] = "Center Grid Box:                  <offset>       "
gridOpts['XCenterLabel'] = "x center:  "
gridOpts['YCenterLabel'] = "y center:  "
gridOpts['ZCenterLabel'] = "z center:  "
gridOpts['XOffsetLabel'] = "x offset(tenths of Angstrom):"
gridOpts['YOffsetLabel'] = "y offset(tenths of Angstrom):"
gridOpts['ZOffsetLabel'] = "z offset(tenths of Angstrom):"
gridOpts['AcceptBut'] = "Accept"
gridOpts['CloseBut'] = "Close"


#set warningMsg texts:
messages = {}
messages['unknownExt'] = 'unknown file extension: must be pdbqs or pdbq or pdb'
messages['requiredExt'] = "macromolecule type must be 'pdbqs', 'pdbq', 'pdb' or 'mol2'"
messages['multipleMols'] = 'more than one molecule in file'
messages['multipleLigs'] = 'more than one ligand in file'
messages['multipleFlexRes'] = 'more than one flexible residue molecules in file'
messages['unknownLigExt'] = "unknown ligand type"
messages['unknownFlexResExt'] = "unknown flexible residue filetype"
messages['mergeNPHSReqExt'] = "for GpfMergeNonPolarHs: macromolecule type\
must be 'pdbqs' or 'pdbq'"
messages['noNonPolarHs'] = 'No NonPolarHydrogens Found'
messages['nphsOutExt'] = 'must save to pdbqs or pdbq type file'
messages['addSolExt'] = "for addsol: macromolecule type must be 'pdbq'"
messages['addSolExt'] = "for addsol: macromolecule type must be 'pdbq'"


def checkHasGpo(vf):
    if not hasattr(vf, 'gpo'):
        vf.gpo = GridParameters()
        vf.gpo.vf = vf
    if vf.hasGui:
        autogpf_geoms = check_autogpf_geoms(vf.GUI)
        if not cenSph.in_viewer:
            vf.GUI.VIEWER.AddObject(cenSph, redo=0, parent=autogpf_geoms)
            cenSph.in_viewer = True
        if not cenCross.in_viewer:
            vf.GUI.VIEWER.AddObject(cenCross, redo=0, parent=autogpf_geoms)
            cenCross.in_viewer = True
        if not box.in_viewer:
            vf.GUI.VIEWER.AddObject(box, redo=0, parent=autogpf_geoms)
            box.in_viewer = True



class GpfSetGpo(MVCommand):
    """ Command to set values in gpo object using gui input results"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def doit(self, *args, **kw):
        if not len(kw.items()):
            return 'ERROR'

        for key, val in kw.items():
            self.vf.gpo[key]['value'] = val




class GpfLoadDefaults(MVCommand):
    """ allows user to select a file containing a set of defaults"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def __call__(self, gpffile, **kw):
        if not os.path.exists(gpffile):
            raise IOError
        apply(self.doitWrapper,(gpffile,),kw)
        

    def doit(self, gpffile):
        if not gpffile: return 'ERROR'
        self.vf.gpo.read(gpffile)


    def guiCallback(self):
        """called each time the 'select defaultList file' button is pressed"""
        gpfFile = self.vf.askFileOpen(types=[('grid parameter files:', '*.gpf')],
            title = 'Select GPF File:')
        #if gpfFile is not None:
        if gpfFile:
            self.doitWrapper(gpfFile, log=1, redraw=0)


GpfLoadDefaultsGUI = CommandGUI()
GpfLoadDefaultsGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], menuText['ReadGpfMB'])



class GpfMacroInit(MVCommand):
    """AD3 receptor is initialized as specified in parameters:
            autodock_element field added
            whether receptor is a protein is determined
            if molecule is lacking charges or if charges are all 0.
                Kollman charges are added to protein receptors
                and Gasteiger charges are computed for non-protein receptors.
            a check is made that total charge per residue is an integer.
            lone pairs merged
            non-polar hydrogens merged unless userpref set not to merge
            macro sidelengths set (???????????)
            types of atoms in receptor added as '.mset'
                possibility of adding new atom types to Rij/epsij dicts
            solvation parameter fields are added: AtVol + AtSolPar
                which is written to newfilename if specified 
                otherwise to mol.name+'.pdbqs'
            receptor is colored by Atom Type"""


    def onRemoveObjectFromViewer(self, obj):
        if hasattr(self.vf.gpo, 'receptor') and obj==self.vf.gpo.receptor:
            self.vf.gpo.receptor = None


    def onAddCmdToViewer(self):
        if self.vf.hasGui:
            for item in ['writePDB','writePDBQ','writePDBQS']:
                if not hasattr(self.vf, item):
                    self.vf.loadCommand('fileCommands', item, 'Pmv')
            self.vf.loadModule('colorCommands','Pmv')
        #if not hasattr(self.vf,'add_h'):
            #self.vf.loadModule('editCommands','Pmv')
        if not hasattr(self.vf, 'editHist_h'):
            self.vf.loadCommand('repairCommands', 'editHist_h', 'Pmv')
        self.vf.loadModule('editCommands','Pmv')

        checkHasGpo(self.vf)
        self.resKeys = q.keys()
        self.editHISprotonation = None
        if 'Automerge NPHS' not in self.vf.userpref.keys():
            doc = """Automatically merge non-polar hydrogens in formatting molecules for AutoDock. Valid values are 1 or 0"""
            if 'Automerge NPHS' in self.vf.userpref.settings.keys():
                value = self.vf.userpref.settings['Automerge NPHS']
            else:
                value = 1
            self.vf.userpref.add('Automerge NPHS', value, [0,1],
                callbackFunc = [set_autoMergeNPHS], doc=doc, category='AutoDockTools')
        if 'HIS Protonation' not in self.vf.userpref.keys():
            if 'HIS Protonation' in self.vf.userpref.settings.keys():
                value = self.vf.userpref.settings['HIS Protonation']
            else:
                value =  'No change'
            doc = """Automatically set protonation state of all histidine residues in macromolecule. Valid values are 'HD1', 'HE2', 'HD1HE2', 'No change'.  Default value is 'No change' which has no effect on macromolecule. Any other choice invokes editHist_h method of repairCommand module to edit hydrogens on histidine ring. For example, if userpref is set to 'HD1' each histidine ring will have hydrogen atom 'HD1' and not 'HE2' hydrogen atom."""
            self.vf.userpref.add('HIS Protonation', 'No change', 
                    ['No change', 'HD1', 'HE2', 'HD1HE2'],
                    callbackFunc = [self.set_editHISprotonation], doc=doc , category='AutoDockTools')
                

    def set_editHISprotonation(self, name, oldval, newval):
        self.editHISprotonation = newval
        try:
            self.vf.ADgpf4_initMacro.editHISprotonation = newval
        except:
            pass


    def checkIsPeptide(self, resSet):
        #check whether each restype is in std list
        #if so, mol is a peptide
        dict = {}
        for r in resSet:
            dict[r.type] = 0
        for t in dict.keys():
            if t not in self.resKeys:
                return 0
        #only get to this point if all
        #residue types were found
        return 1


    def __call__(self, mol, filename=None, **kw):
        """                             """
        mols = self.vf.expandNodes(mol)
        if not mols:
            return 'ERROR'
        #kw should be mol and possibly filename
        kw['filename'] = filename
        apply(self.doitWrapper,(mols[0],), kw)


    def doit(self, mol, **kw):
        #what is its already processed: eg from pdbqs file???
        #user might want to do this twice
        #if hasattr(mol, 'gpf_init'):
        #    print mol.name, ' already initialized'
        #    return
        msg = 'initializing ' + os.path.basename(mol.parser.filename) + ':\n'
        #make sure all atoms have autodock_element
        for at in mol.allAtoms:
            #FIX THIS: what about Zn
            if not hasattr(at, 'autodock_element'):
                at.autodock_element = at.element
        needToAddCharges = 0
        nphs = None
        lps = None
        needToAddSolPar = 0
        basename = os.path.basename(mol.parser.filename)
        if os.path.splitext(basename)[1]!='.pdbqs':
            #in this case check charges and solvation parameters
            #CHARGES: decide if its a peptide
            mol.isPeptide = self.checkIsPeptide(mol.chains.residues)
            if mol.isPeptide:
                msg = msg + '   it is a peptide\n'
            else:
                msg = msg + '   it is not a peptide\n'
            chargedAts = mol.allAtoms.get(lambda x: hasattr(x, 'charge'))
            if not chargedAts:
                needToAddCharges = 1
            elif len(chargedAts)!=len(mol.allAtoms):
                needToAddCharges = 1
            elif len(filter(lambda x:x.charge==0, chargedAts))==len(chargedAts):
                #this checks that each atom doesn't have charge=0
                needToAddCharges = 1
            if needToAddCharges:     
                if mol.isPeptide:
                    self.vf.addKollmanCharges(mol, topCommand=0, log=0)
                    msg = msg + '   -added Kollman charges\n'
                else:
                    self.vf.computeGasteiger(mol, topCommand=0, log=0)
                    msg = msg + '   -added gasteiger charges\n'

            #CHECK FOR NPHS and LPS and merge if found
            #redisplay = 0
            renumber = 0
            hs = mol.allAtoms.get(lambda x: x.element=='H')
            hs_with_no_bonds = hs.get(lambda x: len(x.bonds)==0)
            hs_with_bonds = hs.get(lambda x: len(x.bonds)>0)
            #nphs = mol.allAtoms.get(lambda x: x.element=='H' and \
            #        (x.bonds[0].atom1.element=='C' or x.bonds[0].atom2.element=='C'))
            nphs = hs_with_bonds.get(lambda x: x.bonds[0].atom1.element=='C' or x.bonds[0].atom2.element=='C')
            if not nphs:
                msg = msg + '   -found ' + str(len(nphs)) + ' non-polar hydrogens\n'
                if hs_with_no_bonds:
                    m3 = "'" + mol.name + "'" + " has one or more hydrogens with no bonds: "
                    for at in hs_with_no_bonds:
                        m3 += at.parent.parent.name + ':'+ at.parent.name +':'+ at.name + ','
                    self.vf.warningMsg(m3[:-1], title='AD3 Receptor Summary:')
            if len(nphs) and self.vf.userpref['Automerge NPHS']['value']:
                #userpref determines whether to automatically merge detected nphs
                #default is to always merge
                renumber = 1
                if self.vf.hasGui:
                    self.vf.mergeNPHSGC(mol, logBaseCmd=0)
                    #redisplay = 1
                else:
                    self.vf.mergeNPHS(mol)
                msg = msg + '   -merged nphs\n'

            #SHOULD THIS BE OPTIONAL???
            hs = self.vf.allAtoms.get(lambda x: x.element=='H')
            if hs: self.vf.fixHNames(hs, topCommand=0)

            #always merge lone pairs
            lps = filter(lambda x: x.element=='Xx' and \
                      (x.name[0]=='L' or x.name[1]=='L'),mol.allAtoms)
            if len(lps):
                renumber = 1
                if self.vf.hasGui:
                    self.vf.mergeLPSGC(mol)
                    #redisplay = 1
                else:
                    self.vf.mergeLPS(mol)
                msg = msg + '   -merged ' + str(len(lps)) + ' lone pairs\n'

            if renumber:
                atSet = mol.allAtoms
                atSet.sort()
                fst = atSet[0].number
                atSet.number = range(fst, len(atSet)+fst)
            #FIX THIS: CHECK THAT DISPLAY GETS UPDATED
            #if self.vf.hasGui and redisplay:
            #    self.vf.displayLines(mol, negate=1, topCommand=0, log=0)
            #    self.vf.displayLines(mol, topCommand=0, log=0)

            #add solvation parameters, also
            solParAts = mol.allAtoms.get(lambda x: hasattr(x, 'AtSolPar'))
            if not solParAts:
                needToAddSolPar = 1
            elif len(solParAts)!=len(mol.allAtoms):
                needToAddSolPar = 1
            if needToAddSolPar:
                #outfile=-1 parameter keeps from writing pdbqs in AddSol
                self.vf.ADgpf_addSolvationParameters(mol, outfile=-1, log=0)
                msg = msg + '   -added solvation parameters\n'

            errCharge, resList = checkMolCharges(mol, self.vf)
            mol.checked_charges = 1
        else:
            msg = msg + '   -pdbqs file so skip nphs, lps, adding solpar steps\n'
        # set the protonation state of all the histidines to userpref 
        # unless the preference is None
        histVal = self.editHISprotonation
        newHs = AtomSet([])
        if histVal!='No change':
            hisRES = mol.chains.residues.get(lambda x: x.type=='HIS')
            if hisRES:
                d = {}
                for res in hisRES:
                    d[res.full_name()] = histVal
                newHs = self.vf.editHist_h(d)
                if len(newHs): 
                    #fix the solvation parameters here
                    for h in newHs:
                        h.AtVol = 0.0
                        h.AtSolPar = 0.0
                    if self.vf.hasGui:
                        event = AddAtomsEvent(objects=newHs)
                        self.vf.dispatchEvent(event)
                        #modEvent = ModificationEvent('add', 'coords', newHs)
                        #mol.geomContainer.updateGeoms(modEvent)
                        #self.vf.GUI.VIEWER.Redraw()
                msg = msg + '   -edited histidine protonation to userpref:' + histVal + '\n'
        title = mol.name + " Summary"
        self.vf.warningMsg(msg, title=title)
            
        update = self.vf.ADgpf_checkMacroTypes(mol, topCommand=0)
        if update or needToAddSolPar or needToAddCharges or nphs is not None or \
                        lps is not None or len(newHs):
            filename = kw['filename']
            if filename is None:
                currentPath = os.getcwd()
                defaultFilename = os.path.join(currentPath, mol.name) + '.pdbqs'
                filename = self.vf.askFileSave(idir=currentPath, ifile=defaultFilename,
                    types=[('PDBQS files', '*.pdbqs')],
                    title = 'Modified AutoDock Macromolecule File:')
                #if filename is None:
                if not filename:
                    msg="AutoGrid requires written pdbqs molecule!"
                    self.vf.warningMsg(msg)
                else:
                    #self.vf.writePDBQS(filename, mol, recType='none')
                    self.vf.writePDBQS( mol, filename=filename, 
                            pdbRec=['ATOM','HETATM'],
                            bondOrigin=[])

            elif filename=='auto':
                fname = os.path.splitext(os.path.basename(mol.parser.filename))[0]
                filename = fname + '.pdbqs'
                self.vf.writePDBQS( mol, filename=filename, 
                            pdbRec=['ATOM','HETATM'],
                            bondOrigin=[])
                #self.vf.writePDBQS(filename, mol, recType='none')
            else:
                self.vf.writePDBQS( mol, filename=filename, 
                            pdbRec=['ATOM','HETATM'],
                            bondOrigin=[])
                #self.vf.writePDBQS(filename, mol, recType='none')
        else:
            filename = mol.parser.filename

        mol.gpf_init = 1
        mol.outputfilename = filename
        if filename is not None:
            self.vf.gpo.set_receptor(filename)
            self.vf.gpo.receptor = mol
            mol.outputfilename = os.path.basename(filename)
        if not hasattr(mol, 'center'):
            mol.getCenter()

        if self.vf.hasGui:
            self.vf.colorByAtomType(mol, ['lines'], topCommand=0, redraw=1)



class CheckMacroAtomTypes(MVCommand):
    """detect types of atoms in receptor; 
       for non-standard types (limited to 2:'X' and 'M'):
            define new energy parameters: 
                Rij and epsij
            write file substituting X or M for non-standard element """


    def onAddCmdToViewer(self):
        if self.vf.hasGui and not hasattr(self.vf, 'writePDBQS'):
            self.vf.loadCommand('fileCommands', 'writePDBQS', 'Pmv')
        checkHasGpo(self.vf)


    def __call__(self, mol, newfilename=None, **kw):
        """len(newtypes)<-mv.ADgpf_checkMacroTypes(mol, newfilename=None)
mol: macromolecule to check
newfilename:optional argument, outputfile needed if a new type is renamed M or X
len(newtypes):number of atom types which had to be changed: to M or X
        """
        mols = self.vf.expandNodes(mol)
        if not mols:
            return 'ERROR'
        kw['newfilename'] = newfilename
        return apply(self.doitWrapper, (mols[0],), kw)
        

    def doit(self, mol, **kw):
        newfilename = kw['newfilename']
        typeList = ['C','N','O','S','H']
        newAts = ['M','X']
        newNum = 2
        num = 0

        #make sure every atom has autodock_element field
        #IS THIS REDUNDANT... ie was it already done before this is called
        has_ad_element = filter(lambda x: hasattr(x, 'autodock_element'), \
                                            mol.allAtoms)
        if len(has_ad_element)!=len(mol.allAtoms):
            setAutoDockElements(mol)

        #setAutoDockElements(mol)

        # build a list of uniq autodock_elements in mol.allAtoms
        typeD = {}
        for a in mol.allAtoms:
            typeD[a.autodock_element[0]] = 0
        autodockTypes = typeD.keys()
        #NB: made autodockTypes 1 character only
        #THIS IS PROBABLY WRONG...what about Zn, Mg....

        updateList = []
        for ty in autodockTypes:
            if ty[0] not in typeList:
                if ty in newAts:
                    # X or M get added here
                    msg= 'adding ', ty,' to macromolecule types'
                    title = "NEW TYPE "+ ty + " for MACROMOLECULE"
                    self.vf.warningMsg(msg, title=title)
                    typeList.append(ty)
                    newNum = newNum -1
                    newAts.remove(ty)
                elif num < newNum:
                    if self.vf.hasGui:
                        msg = mol.name + " has unusual atom type:" + ty + "\nDo you want to add this type which means changing " + ty+ " to "  + newAts[num] + " and defining new energy parameters?\n(Currently you can define "+str(2-num)+ " types)"
                        d=SimpleDialog(self.vf.GUI.ROOT, text=msg, buttons=['Yes','No'], default=0, title='Define new type?')
                        ok=d.go()
                        if ok==0:
                            updateList.append((ty, newAts[num]))
                            #= self.DoNewType(mol, ty, newAts[num], newfilename)
                            typeList.append(newAts[num])
                            num=num+1
                    else:
                        msg = 'no energyConstants entries for '+ ty
                        self.vf.warningMsg(msg)
                        continue
                else:
                    msg= "Too many new types!: " + ty + " will be mapped to 'C' or first map type)"
                    self.vf.warningMsg(msg)
        #at this point if there are any entries in updateList:
        #do the update (once)
        if len(updateList):
            self.updateTypes(mol, updateList)
        delta = 7 - len(typeList)
        for i in range(delta):
            typeList.append('H')    
        mol.mset = join(typeList, '')
        #be sure that X preceeds M
        if 'X' in mol.mset:
            if 'M' in mol.mset:
                mol.mset = 'CNOSHXM'
            else:
                mol.mset = 'CNOSHXH'
        elif 'M' in mol.mset:
            mol.mset = 'CNOSHHM'
        else:         
            mol.mset = 'CNOSHHH'
        self.vf.gpo['mset']['value'] = mol.mset
        #return 0 if nothing has been changed
        #else return 1 to signify need to write new file
        return len(updateList)


    def updateTypes(self, mol, updateList, newfilename=None):
        #eg entry in updateList: ('P','M')
        for entry in updateList:
            self.DoNewType(mol, entry[0], entry[1])
        #FIX THIS: should be able to write pdbqs if have all info;
        #else pdbq if have charges else pdb
        return 1


    def DoNewType(self, mol, elemType, newType):
        #call vf.ADgpf_defineAtomParameters; edit file; save newfile
        defineCommand = self.vf.ADgpf_defineAtomParameters
        defineCommand.elem.set(newType)
        if hasattr(Rij,newType):
            defineCommand.Rij.set(Rij[newType])
        if hasattr(epsij,newType):
            defineCommand.epsij.set(epsij[newType])
        defineCommand.guiCallback()

        for at in mol.allAtoms:
            if at.autodock_element==elemType:
                at.autodock_element = newType
                ##at.element = newType
                if len(at.name)>1:
                    at.name = newType + at.name[1:]
                else:
                    at.name = newType


    def guiCallback(self):
        mols = self.vf.getSelection()
        if len(mols):
            mols = mols.top.uniq()
            mol = mols[0]
            kw = {}
            kw['newfilename'] = None
            return apply(self.doitWrapper, (mol,), kw)


#FIX THIS: it needs updating
autodockElementDict = {}
autodockElementDict['l'] = 'Xx'
#autodockElementDict['A'] = 'C'
#autodockElementDict['n'] = 'N'
autodockElementDict['f'] = 'Fe'
autodockElementDict['c'] = 'Cl'
autodockElementDict['b'] = 'Br'


#FIX THIS: it needs updating
def setAutoDockElements(mol):
    for item in mol.allAtoms:
        try:
            item.autodock_element
        except AttributeError:
            #check if element is in special list
            if item.name=='ZN' or item.name=='Zn':
                item.autodock_element='Zn'
            elif len(item.element)>2:  #Cu,Ca,
                item.autodock_element=item.element
            elif item.element[0] == 'Z':
                #this is for covalentmaps' attached atom
                item.autodock_element = 'Z'
                if len(item.element)>1:
                    item.element = item.element[1]
                else:
                    item.element = 'C'
            elif item.element not in autodockElementDict.keys():
                item.autodock_element=item.element
            else:
                item.autodock_element = autodockElementDict[item.element]



def getSideLengths(mol, spacing):
    c = mol.allAtoms.coords
    maxo = Numeric.maximum.reduce(c)
    mino = Numeric.minimum.reduce(c)
    sideLengths = maxo-mino
    mol.npts = sideLengths/(spacing*1.0)
    #FIX THIS:
    #should use center:
    #mino+(maxo-mino)/2.0
    #getCenter sets center to averaged coords
    mol.center = mino + (maxo - mino)/2.0



def checkFile(vf, filename):
    ftype= split(filename,'.')[-1]
    if ftype== 'pdbqs':
        return None, None, None, None, None
    typeCharges = None
    addSolPar = None
    mergeNPHS = None
    mergeLPS = None
    ifd = InputFormDescr(title = 'Options')
    mergenphs = Tkinter.IntVar(master=self.vf.GUI.ROOT)
    mergenphs.set(0)
    mergelps = Tkinter.IntVar(master=self.vf.GUI.ROOT)
    mergelps.set(0)
    chargeType = Tkinter.IntVar(master=self.vf.GUI.ROOT)
    chargeType.set(3)
    addSol = Tkinter.IntVar(master=self.vf.GUI.ROOT)
    addSol.set(3)
    newname = Tkinter.StringVar(master=self.vf.GUI.ROOT)
    #newname.set(os.path.basename(filename[:rfind(filename,'.')]+'.pdbqs'))
    # eg ('1crn', 'pdbqs')[0]+'.pdbqs'
    nameParts = os.path.splitext(os.path.basename(filename)) 
    newname.set(nameParts[0]+'.pdbqs')
    if ftype != 'pdbqs':
        mergenphs.set(1)
        mergelps.set(1)
        if ftype != 'pdbq':
            chargeType.set(0)
            ifd.append({'name': 'typeChargeLab',
                'widgetType':Tkinter.Label,
                'text':'charge type to use:',
                'gridcfg':{'sticky':Tkinter.W}}),
            ifd.append({'name':    'gastCharg',
                'widgetType':Tkinter.Radiobutton,
                'text':'gasteiger',
                'variable':chargeType,
                'value':1, 
                'gridcfg':{'sticky':Tkinter.W,
                        'row':-1,'column':1}}),
            ifd.append({'name':    'kollCharg',
                'widgetType':Tkinter.Radiobutton,
                'text':'Kollman united atom ',
                'variable':chargeType,
                'value':0, 
                'gridcfg':{'sticky':Tkinter.W,'row':-1,'column':2}}),
            if ftype == 'mol2' or ftype == 'pdbq':
                ifd.append({'name':    'keepCharg',
                    'widgetType':Tkinter.Radiobutton,
                    'text':'keep original charges',
                    'variable':chargeType,
                    'value':3, 
                    'gridcfg':{'sticky':Tkinter.W,'column':1}}),
        addSol.set(1)
        ifd.append({'name': 'addSolLab',
            'widgetType':Tkinter.Label,
            'text':'add solvation parameters?',
            'gridcfg':{'sticky':Tkinter.W}}),
        ifd.append({'name':    'yesAddSol',
            'widgetType':Tkinter.Radiobutton,
            'wcfg':{'text':'yes',
                    'variable':addSol,
                    'value':1},
            'gridcfg':{'sticky':Tkinter.W,'row':-1,'column':1}}),
        ifd.append({'name':    'noAddSol',
            'widgetType':Tkinter.Radiobutton,
            'wcfg':{'text':'no',
                    'variable':addSol,
                    'value':0}, 
            'gridcfg':{'sticky':Tkinter.W,'row':-1,'column':2}}),
    ifd.append({'name': 'mergeNPHSLab',
        'widgetType':Tkinter.Label,
        'text':'automatically merge non-polar Hs?',
        'gridcfg':{'sticky':Tkinter.W}}),
    ifd.append({'name':    'yesMergeNPHs',
        'widgetType':Tkinter.Radiobutton,
        'wcfg':{'text':'yes',
                'variable':mergenphs,
                'value':1},
        'gridcfg':{'sticky':Tkinter.W,'row':-1,'column':1}}),
    ifd.append({'name':    'noMergeNPHs',
        'widgetType':Tkinter.Radiobutton,
        'wcfg':{'text':'no',
                'variable':mergenphs,
                'value':0}, 
        'gridcfg':{'sticky':Tkinter.W,'row':-1,'column':2}}),
    ifd.append({'name': 'mergeLPSLab',
        'widgetType':Tkinter.Label,
        'text':'automatically merge lone pairs?',
        'gridcfg':{'sticky':Tkinter.W}}),
    ifd.append({'name':    'yesMergeLPS',
        'widgetType':Tkinter.Radiobutton,
        'wcfg':{'text':'yes',
                'variable':mergelps,
                'value':1},
        'gridcfg':{'sticky':Tkinter.W,'row':-1,'column':1}}),
    ifd.append({'name':    'noMergeLPS',
        'widgetType':Tkinter.Radiobutton,
        'wcfg':{'text':'no',
                'variable':mergelps,
                'value':0}, 
        'gridcfg':{'sticky':Tkinter.W,'row':-1,'column':2}}),
    ifd.append({'name':    'newfileEnt',
        'widgetType':Tkinter.Entry,
        'wcfg':{
            'label':'save result as:',
            'textvariable':newname},
        'gridcfg':{'sticky':Tkinter.E,'columnspan':2}}),
    vals = vf.getUserInput(ifd)

    if vals:
        typeCharges = chargeType.get()
        addSolPar = addSol.get()
        mergeLPS = mergelps.get()
        mergeNPHS = mergenphs.get()
        newfilename = vals['newfileEnt']
    else:
        return 0,0,0,0,0

    if chargeType.get()==3:
        typeCharges = None
    if addSol.get()==3:
        addSolPar = None

    return typeCharges, addSolPar, mergeNPHS, mergeLPS, newfilename
        


class GpfMacroReader(MVCommand):
    """ allows user to select the receptor via a file browser"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'read macromolecule' button is pressed"""
        macroFile = self.vf.askFileOpen(types=[('PDBQS files', '*.pdbqs'),
            ('PDBQ files','*.pdbq'),('PDB files','*.pdb'),('MOL2 files', '*.mol2'),('all files', '*.*')], 
            title = 'Macromolecule File:')
        #allow user to set typeCharges and addSolPar here
        #if macroFile is not None:
        if macroFile:
            kw = {}
            apply(self.doitWrapper, (macroFile,), kw)


    def __call__(self, macroFile, **kw):
        if not os.path.exists(macroFile):
            raise IOError
        apply(self.doitWrapper,(macroFile,),kw)


    def doit(self, macroFile, **kw):
        mols = Read(macroFile)
        if len(mols)>1:
            self.vf.warningMsg(messages['multipleMols'])

        mol = mols[0]
        self.vf.addMolecule(mol)
        if not mol.chains[0].hasBonds:
            mol.buildBondsByDistance()
            if self.vf.hasGui:
                self.vf.centerScene(topCommand=0)
                self.vf.displayLines(mol,topCommand=0,redraw=1)

        kw['topCommand'] = 0
        apply(self.vf.ADgpf_initMacro, (mol,), kw)


GpfMacroReaderGUI = CommandGUI()
GpfMacroReaderGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
    menuText['ReadMacro'], cascadeName = menuText['MacromoleculeMB'],
    separatorAbove=1)



class GpfMacroChooser(MVCommand):
    """ allows user to choose a molecule already present for the receptor"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def __init__(self, mode='single', title = 'Choose Macromolecule'):
        MVCommand.__init__(self)
        self.mode = mode
        self.title = title


    def chooseMolecule_cb(self, event = None):
        """called each time the 'choose Molecule' button is pressed"""
        try:
            self.chooser.form.withdraw()
        except:
            pass
        mol = self.chooser.getMolSet()
        if mol: 
            macroFile = os.path.basename(mol.parser.filename)
            kw = {}
            apply(self.doitWrapper, (mol,), kw)


    def guiCallback(self):
        self.chooser = MoleculeChooser(self.vf, self.mode, self.title)
        self.chooser.ipf.append({'name':'Select Button',
                                 'widgetType':Tkinter.Button,
                                 'text':'Select Molecule',
                                 'wcfg':{'bd':6},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W},
                                 'command': self.chooseMolecule_cb})
        self.form = self.chooser.go(modal=0, blocking=0)
        lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb
        lb.bind("<Double-Button-1>", self.chooseMolecule_cb)


    def __call__(self, nodes, **kw):
        apply(self.doitWrapper,(nodes,),kw)


    def doit(self, nodes, **kw):
        mols = self.vf.expandNodes(nodes)
        if not len(mols):
            return 'ERROR'
        kw['topCommand'] = 0
        apply(self.vf.ADgpf_initMacro, (mols[0],), kw)


GpfMacroChooserGUI = CommandGUI()
GpfMacroChooserGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], menuText['ChooseMacro'], cascadeName = menuText['MacromoleculeMB'])





class GpfAddSol(MVCommand):
    """ allows user to add solvation parameters to a receptor """


    def onAddCmdToViewer(self):
        from AutoDockTools.sol_par import solvs
        #from AutoDockTools.Objects.sol_par import *
        self.solvs = solvs
        if self.vf.hasGui:
            for item in ['readMolecule','writePDBQS']:
                if not hasattr(self.vf, item):
                    self.vf.loadCommand('fileCommands', item, 'Pmv')
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'Add Solvent Parameters' button is pressed"""
        t = 'Is Molecule already in the viewer?'
        d = SimpleDialog(self.vf.GUI.ROOT, text=t, buttons=['Yes','No'], default=0,title='Select Molecule')
        ok = d.go()
        if ok==0:
            self.chooser = MoleculeChooser(self.vf, 'single', 'Choose Macromolecule')
            self.chooser.ipf.append({'name':'Select Button',
                                 'widgetType':Tkinter.Button,
                                 'text':'Select Molecule',
                                 'wcfg':{'bd':6},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W},
                                 'command': self.chooseMolecule_cb})
            self.form = self.chooser.go(modal=0, blocking=0)
            lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb
            lb.bind("<Double-Button-1>", self.chooseMolecule_cb)
        else:
            macroFile = self.vf.askFileOpen(types=[('PDBQ files', '*.pdbq'), 
                    ('PDB files','*.pdb'),('MOL2 files', '*.mol2'), 
                    ('PDBQS files', '*.pdbqs')], title = 'Macromolecule File:')
            #if macroFile is None:
            if not macroFile:
                return 'ERROR'

            ftype = os.path.splitext(os.path.basename(macroFile))[-1]
            #FIX THIS could it be a pdbqs file ?
            #why would you add solvation parameters to a pdbqs file type?
            if ftype=='.pdbq' or ftype=='.mol2' or ftype=='.pdbqs'\
                    or ftype=='.pdb':
                mols = self.vf.readMolecule(macroFile, topCommand=0)
                #readMolecule returns None if it has a problem
                if mols is None: return 'ERROR'

                mol = mols[0]
                if not mol.chains[0].hasBonds:
                    mol.buildBondsByDistance()
                    self.vf.centerScene(topCommand=0)
                self.vf.displayLines(mol,topCommand=0)
                outfile = self.vf.askFileSave(types=[('PDBQS files', '*.pdbqs')],
                    title = 'Modified Macromolecule File:')
                if not outfile:
                    msg="AutoGrid requires written pdbqs molecule"
                    self.vf.warningMsg(msg)
                return self.doitWrapper(mol, log=0, redraw=0, outfile=outfile)


    def chooseMolecule_cb(self, event = None):
        """called each time the 'choose Molecule' button is pressed"""
        mols = self.chooser.getMolSet()
        if mols is None: return
        if issubclass(mols.__class__, TreeNode):
            mols = mols.setClass([mols])
        mol = mols[0]
        try:
            self.chooser.form.withdraw()
        except:
            pass
        kw = {}
        kw['log'] = 0
        kw['redraw'] = 0
        outfile = self.vf.askFileSave(types=[('PDBQS files', '*.pdbqs')],
            title = 'Modified Macromolecule File:')
        if not outfile:
            msg="AutoGrid requires written pdbqs molecule"
            self.vf.warningMsg(msg)
        kw['outfile'] = outfile
        return apply(self.doitWrapper,(mol,), kw)


    def __call__(self, mol, outfile=None , **kw):
        """newfileName <-ADgpf_addSolvationParameters(mol, outfile=None)
            mol is macromolecule 
            outfile is new  filename"""
        kw['outfile'] = outfile
        return apply(self.doitWrapper,(mol,),kw)


    def doit(self, mol, **kw):
        outfile = kw['outfile']
        mols = self.vf.expandNodes(mol)
        if not mols: return 'ERROR'
        else: mol = mols[0]

        chargeAts = mol.allAtoms.get(lambda x: hasattr(x, 'charge'))
        if not chargeAts or len(chargeAts)!=len(mol.allAtoms):
            t = "for addsol: macromolecule must have charges\ncalling Add Kollman Charges"
            self.vf.warningMsg(t)
            self.vf.addKollmanCharges(mol, topCommand=0, log=0)

        #check for zeroCharges
        zeroChargeAts = mol.allAtoms.get(lambda x: hasattr(x, 'charge') and x.charge==0)
        if zeroChargeAts  and len(zeroChargeAts)==len(mol.allAtoms):
            t = "all atoms have zero charge"
            self.vf.warningMsg(t)

        bblist=['C','O','N','CA']
        nuc_acid_list = ['  A','  C','  G']

        atSet = mol.allAtoms
        solvsKeys = self.solvs.keys()
        for at in atSet:
            if at.name in bblist:
                atKey = at.name + '---'
            elif (at.name=='C2*' or at.name=='C2\'') \
                    and at.parent.type in nuc_acid_list:
                childnames = at.parent.atoms.name
                if 'O2*' in childnames or 'O2\'' in childnames:
                    #build special 
                    atKey = at.name + ' R' + at.parent.type[2]
                    print 'special rna key', atKey
                else:
                    atKey = at.name + at.parent.type
            else:
                atKey = at.name + at.parent.type
            #try this:
            #5/15: these were backwards:
            #at.AtSolPar, atAtVol = self.solvs.get(atKey,(0.00,0.00))
            if atKey in solvsKeys:
                #FIXED 5/15:
                at.AtVol, at.AtSolPar = self.solvs[atKey]
                #at.AtSolPar,at.AtVol=self.solvs[atKey]
            else:
                #FIXED 5/15:
                at.AtVol, at.AtSolPar = (0.00, 0.00)
                #at.AtSolPar,at.AtVol=(0.00,0.00)

        #if not going to write to outfile, return here
        if outfile is None or outfile is -1 or outfile == ():
            return -1

        #Renumber HERE!??!
        atSet.sort()
        fst = atSet[0].number
        atSet.number = range(fst, len(atSet)+fst)

        #don't want to write any CONECT records
        #self.vf.writePDBQS(outfile, atSet, recType='none', topCommand=0)
        self.vf.writePDBQS( mol, filename=outfile, 
                            pdbRec=['ATOM','HETATM'], 
                            bondOrigin=[],
                            topCommand=0)
        outfile = os.path.basename(outfile)
        self.vf.gpo.set_receptor(outfile)
        self.vf.gpo.receptor = mol
        return outfile
        

GpfAddSolGUI= CommandGUI()
GpfAddSolGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], menuText['AddSol'], cascadeName = menuText['MacromoleculeMB'])



class GpfInitLigand(MVCommand):
    """initializes the ligand:
        checkCharges
        getTypes
        getSideLengths
        setAutoDockElements
        colorByAtom + color aromatic C's green
        
        GUI allows user to:
            decide which types of hydrogen bonds to model
            modify list of atom types detected in ligand
        
        """


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)
        if self.vf.hasGui:
            self.gtypes = Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.gtypes.set('')
            self.showLig = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showLig.set(0)
            self.NHBonds = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.OHBonds = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.SHBonds = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.vf.loadModule('colorCommands','Pmv')


    def __call__(self, mol,  **kw):
        apply(self.doitWrapper,(mol,),kw)


    def doit(self, mol):
        lig = self.vf.expandNodes(mol)[0]
        errCharge, resList = checkMolCharges(lig, self.vf)
        if hasattr(lig, 'outputfile'):
            filename = lig.outputfile
        else:
            filename = os.path.basename(lig.parser.filename)
        self.vf.gpo.set_ligand(filename)
        self.vf.gpo.ligand = lig
        spacing = self.vf.gpo['spacing']['value']
        getSideLengths(lig, spacing)
        #now getSideLengths also sets center
        #lig.getCenter()
        #this is bounding box center, not average center
        lig.center = (round(lig.center[0],3), round(lig.center[1],3), round(lig.center[2],3))

        self.getTypes(lig)
        setAutoDockElements(lig)

        changeVals = {}
        typs = lig.types
        if self.vf.gpo['types']['value'] != typs:
            changeVals['types'] = typs

        if self.vf.hasGui:
            self.vf.displayLines(lig, topCommand=0)
            self.vf.colorByAtomType(lig,['lines'], topCommand=0)
            aromCs = AtomSet(filter(lambda x:x.autodock_element=='A',\
                lig.allAtoms))
            if len(aromCs):
                self.vf.color(aromCs,((0.,1.,0.,),),['lines'],\
                    topCommand=0, redraw=1)
            if not hasattr(self, 'form'):
                self.buildForm()
                self.form = self.vf.getUserInput(self.ifd, modal=0, blocking=0)
                self.form.root.protocol('WM_DELETE_WINDOW',self.Close_cb)
            else:
                self.form.deiconify()
            self.showLig.set(1)
            self.showLigand(lig)
            NHB = 'N' in typs
            OHB = 'O' in typs
            SHB = 'S' in typs
            if 'H' in typs: 
                #override NHB,OHB and SHB because
                # N,O or S could be in receptor
                NHB = 1
                self.NHBonds.set(1)
                OHB = 1
                self.OHBonds.set(1)
                SHB = 1
                self.SHBonds.set(1)
            else: 
                #N could hbond to H in receptor
                self.NHBonds.set(NHB)
                #O could hbond to H in receptor
                self.OHBonds.set(OHB)
                #S could hbond to H in receptor
                self.SHBonds.set(SHB)
            for item in ['NHB','OHB','SHB']:
                if eval(item) != self.vf.gpo[item]['value']:
                    changeVals[item] = eval(item)
        else:
            #otherwise have to set NHB,OHB and SHB by hand (?)
            if 'H' not in typs:
                for item in ['NHB','OHB','SHB']:
                    if self.vf.gpo[item]['value']:
                        changeVals[item]['value'] = 0
        if len(changeVals.items()):
            apply(self.vf.ADgpf_setGpo, (), changeVals)


    def buildForm(self):
        lig = self.vf.gpo.ligand
        ifd = self.ifd = InputFormDescr(title = "AutoGpf Ligand")
        ifd.append( {'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'Ligand Atom Types:',
                'textvariable': self.gtypes,
                'command':self.updateTypes,
                'eventType':'<Key>'
            },
            'gridcfg':{'sticky':Tkinter.W,'columnspan':2}})
        ifd.append({'name': 'Show Ligand',
            'widgetType':Tkinter.Checkbutton,
            'text': 'Show Ligand',
            'variable': self.showLig,
            'gridcfg':{'sticky':Tkinter.W},
            'command': CallBackFunction(self.showLigand, lig)})
        ifd.append({'name': 'HBondsLabel',
            'widgetType':Tkinter.Label,
            'text': 'Model Hydrogen Bonding',
            'gridcfg':{'sticky':Tkinter.W}})
        ifd.append({'name': 'N-HBonds',
            'widgetType':Tkinter.Checkbutton,
            'text': 'Nitrogens ',
            'variable': self.NHBonds,
            'gridcfg':{'sticky':Tkinter.W}})
        ifd.append({'name': 'O-HBonds',
            'widgetType':Tkinter.Checkbutton,
            'text': 'Oxygens ',
            'variable': self.OHBonds,
            'gridcfg':{'sticky':Tkinter.W}})
        ifd.append({'name': 'S-HBonds',
            'widgetType':Tkinter.Checkbutton,
            'text': 'Sulphurs ',
            'variable': self.SHBonds,
            'gridcfg':{'sticky':Tkinter.W}})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Accept',
            'wcfg':{'bd':4},
            'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'columnspan':2},
            'command':self.Accept_cb})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Close',
            'wcfg':{'bd':4},
            'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'column':2, 'row':-1},
            'command':self.Close_cb})
    

    def Close_cb(self, event=None):
        self.form.withdraw()


    def Accept_cb(self, event=None):
        changeVals = {}
        gt = self.gtypes.get()
        if gt != self.vf.gpo['types']['value']:
            changeVals['types'] = gt
        nhb = self.NHBonds.get()
        if nhb != self.vf.gpo['NHB']['value']:
            changeVals['NHB'] = nhb
        ohb = self.OHBonds.get()
        if ohb != self.vf.gpo['OHB']['value']:
            changeVals['OHB'] = ohb
        shb = self.SHBonds.get()
        if shb != self.vf.gpo['SHB']['value']:
            changeVals['SHB'] = shb
        if len(changeVals.items()):
            changeVals['topCommand'] = 0
            apply(self.vf.ADgpf_setGpo, (), changeVals)
        self.form.withdraw()


    def showLigand(self, ligand, event=None):
        if self.showLig.get():
            self.vf.displayLines(ligand, topCommand=0, redraw=1)
        else:
            self.vf.displayLines(ligand, negate=1, topCommand=0, redraw=1)
        

    def getTypes(self, ligand):
        """ligand.types<-getTypes(ligand)"""
        ligstring = ''
        dict = {}
        for at in ligand.allAtoms:
            dict[at.autodock_element] = 0

        dictKeyList = dict.keys()
        for k in dictKeyList:
            if k not in ['C','A','N','O','S','P','H','n','f','F','c','b','I','M']:
                if self.vf.hasGui:
                    self.vf.ADgpf_defineAtomParameters.elem.set(at.autodock_element)
                    self.vf.ADgpf_defineAtomParameters.guiCallback()
        sortedList = []
        for kk in ['C','A','N','O','S','P','H','n','f','F','c','b','I','M']:
            if kk in dictKeyList:
                sortedList.append(kk)
        for k in dictKeyList:
            if k not in sortedList:
                print 'unknown autodock_type ', k
                sortedList.append(k)
        sortedstring = join(sortedList,'')
        ligand.types = sortedstring
        if self.vf.hasGui:
            self.gtypes.set(sortedstring)
            self.updateTypes()
        return ligand.types


    def updateTypes(self, event=None):
        if not hasattr(self, 'ifd'):
            return
        ll= ['N','S','O']
        ligstring = self.gtypes.get()
        for item in ll:
            w=eval("self.ifd.entryByName['%s-HBonds']"%item)
            if item in ligstring:
                w['widget'].config(state='normal')
            else:
                w['widget'].config(state='disabled')
            #if 'H' in ligstring:
            #    self.ifd.entryByName['HBondsLabel']['widget'].config(text ='Model Hydrogen Bonding:')
            #    if item in ligstring:
            #        w['widget'].config(state='normal')
            #    else:
            #        w['widget'].config(state='disabled')
            #        w['variable'].set(0)
            #else:
            #    self.ifd.entryByName['HBondsLabel']['widget'].config(text ='No Hydrogen Bonding')
            #    w['widget'].config(state='disabled')
            #    w['variable'].set(0)
            


class GpfLigandChooser(MVCommand):
    """ allows user to choose a molecule already present for the ligand"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def __init__(self, mode='single', title = 'Choose Ligand'):
        MVCommand.__init__(self)
        self.mode = mode
        self.title = title


    def chooseLigand_cb(self, event = None):
        """called each time the 'choose Ligand' button is pressed"""
        mol = self.chooser.getMolSet()
        if mol: 
            try:
                self.chooser.form.withdraw()
            except:
                pass
            dict = self.vf.atorsDict
            #check that the molecule has a torTree 
            #OR
            #it is current atorsDict['molecule'] and has outputfile
            ok = 0
            if hasattr(mol, 'torTree'):
                ok = 1
            elif dict.has_key('molecule') and mol==dict['molecule']:
                ok = hasattr(mol, 'outputfile')
            if not ok:
                self.vf.warningMsg('can only select molecule with written autotors output file')
                return 'ERROR'
            self.doitWrapper(mol,log=1,redraw=0)
            try:
                self.chooser.form.withdraw()
            except:
                pass


    def guiCallback(self):
        self.chooser = MoleculeChooser(self.vf, self.mode, self.title)
        self.chooser.ipf.append({'name':'Select Button',
                                 'widgetType':Tkinter.Button,
                                 'text':'Select Ligand',
                                 'wcfg':{'bd':6},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W},
                                 'command': self.chooseLigand_cb})
        self.form = self.chooser.go(modal=0, blocking=0)
        lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb
        lb.bind("<Double-Button-1>", self.chooseLigand_cb)


    def __call__(self, nodes, **kw):
        apply(self.doitWrapper,(nodes,),kw)


    def doit(self, nodes):
        ligand = self.vf.expandNodes(nodes)[0]
        self.vf.ADgpf_initLigand(ligand, topCommand=0)


GpfLigandChooserGUI= CommandGUI()
GpfLigandChooserGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
    menuText['ByChoosingLigand'], cascadeName = menuText['SetMapTypesMB'])



class GpfLigReader(MVCommand):
    """ allows user to choose a ligand file via a file browser"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'select ligand' button is pressed"""

        ligFile = self.vf.askFileOpen(types=[('PDBQ ligand files:',
                '*.pdbq'),('MOL2 ligand files','*.mol2')],
                title = 'Ligand File:')
        #if ligFile is not None:
        if ligFile:
            self.doitWrapper(ligFile, log=1, redraw=1)


    def __call__(self, ligFile, **kw):
        if not os.path.exists(ligFile):
            raise IOError
        apply(self.doitWrapper,(ligFile,),kw)


    def doit(self, ligFile):
        ftype=split(ligFile,'.')[-1]
        if ftype not in ['pdbq', 'mol2']:
            self.vf.warningMsg(messages['unknownLigExt'])
            return 'ERROR'

        ligs = Read(ligFile)
        if len(ligs)>1:
            self.vf.warningMsg(messages['multipleLigs'])

        lig = ligs[0]
        self.vf.addMolecule(lig)
        if not lig.chains[0].hasBonds:
            lig.buildBondsByDistance()
        self.vf.ADgpf_initLigand(lig, topCommand=0)


GpfLigReaderGUI= CommandGUI()
GpfLigReaderGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['ByReadingFile'], cascadeName = menuText['SetMapTypesMB'])


class GpfEditor(MVCommand):
    """ allows user to edit current output file and write it"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def __call__(self, filename=None, **kw):
        if not filename and len(self.vf.gpo.gpf_written_filename):
            filename=self.vf.gpo.gpf_written_filename
        else:
            filename = self.vf.askFileOpen(types=[('AutoGrid Parameter files:','*.gpf')],
                title = 'gpf File:')
        #if filename is not None:
        if filename:
            apply(self.doitWrapper,(filename,),kw)


    def doit(self, filename):
        fptr=open(filename,'r')
        allLines=fptr.readlines()
        ss=''
        for item in allLines:
            ss=ss+item
        titleStr = 'Edit  gpf'
        self.ifd = ifd  = InputFormDescr(title = titleStr)
        ifd.append({'name': 'gpfText',
            'size':[80,30],
            'label':filename,
            'defaultValue':ss,
            'widgetType':'ScrolledText',
            'writeFileType': [('Grid Parameter Files','*.gpf')],
            'readFileType': [('Grid Parameter Files','*.gpf')],
            'readButton':1,'writeButton':1})
        vals = self.vf.getUserInput(ifd)
        if len(vals)==0:
            return


    def guiCallback(self):
        if len(self.vf.gpo.gpf_written_filename):
            filename=self.vf.gpo.gpf_written_filename
        else:
            filename = self.vf.askFileOpen(types=[('AutoGrid Parameter files:', '*.gpf')],
                title = 'gpf File:')
        #if filename is not None:
        if filename:
            self.doitWrapper(filename, log=1, redraw=0)


GpfEditorGUI= CommandGUI()
GpfEditorGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
        menuText['EditGpfMB'])



class GpfWriter(MVCommand):
    """ allows user to choose an output filename and write it"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)

            
    def __call__(self, outfile, **kw):
        apply(self.doitWrapper,(outfile,),kw)


    def doit(self, outfile):
        if not len(self.vf.gpo.receptor_stem):
            self.vf.warningMsg("You must choose a macromolecule before writing gpf")
            return 'ERROR'
        #check whether a covalent map has been set up
        if len(self.vf.gpo['covalent_coords']['value']):
            parm_list = []
            for item in grid_parameter_list:
                parm_list.append(item)
            parm_list.append('covalentmap')
            self.vf.gpo.write(outfile, parm_list)
        else:
            self.vf.gpo.write(outfile, grid_parameter_list)
        

    def guiCallback(self):
        if not len(self.vf.gpo.receptor_stem):
            self.vf.warningMsg("You must choose a macromolecule before writing gpf")
            return 'ERROR'
        outfile = self.vf.askFileSave(types=[('gpf file', '*.gpf')],
                title = 'Grid Parameter Output File:')
        #if outfile is not None: 
        if outfile:
            self.doitWrapper(outfile, log=1)


GpfWriterGUI= CommandGUI()
GpfWriterGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['WriteGpfMB'], cascadeName=menuText['WriteMB'])




class SelectCenter(MVCommand, MVAtomICOM):
    """ allows user to pick an atom to be the center of the grid"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)
        for item in ['readMolecule','writePDBQS']:
            if not hasattr(self.vf, item):
                self.vf.loadCommand('fileCommands', item, 'Pmv')
        if self.vf.hasGui and not hasattr(self.vf, 'setICOM'):
            self.vf.loadCommand('interactiveCommands', 'setICOM', 'Pmv')


    def __init__(self, func=None):
        MVCommand.__init__(self, func)
        MVAtomICOM.__init__(self)
        self.save = None


    def dismiss_cb(self, event = None):
        if self.vf.ADgpf_setGrid.ifd.entryByName.has_key('Pick Center'):
            self.vf.ADgpf_setGrid.ifd.entryByName['Pick Center']['variable'].set(0)
        if hasattr(self.vf.ADgpf_setGrid, 'form') and self.vf.ADgpf_setGrid.form.root.winfo_ismapped():
            self.vf.ADgpf_setGrid.form.root.withdraw()

        
    def stopICOM(self):
        if not hasattr(self.vf.ADgpf_setGrid, 'ifd'):
            return
        d = self.vf.ADgpf_setGrid.ifd.entryByName
        if d.has_key('Pick Center'):
            d['Pick Center']['variable'].set(0)


    def setupUndoBefore(self, atom, ):
        #keep old center
        if hasattr(self.vf.gpo, 'atomcenter'):
            oldatom = self.vf.gpo.atomcenter
        elif len(self.vf.Mols):
            oldatom = self.vf.Mols.allAtoms[0]
        self.addUndoCall( (oldatom, ), {'redraw':1},
                  self.name )


    def __call__(self, atom, **kw):
        """None <- mv.ADgpf_selectCenter(atom, **kw) sets box geometry center 
to the picked atom's coordinates"""
        atoms = self.vf.expandNodes(atom).findType(Atom)
        if not len(atoms): return 'ERROR'
        atom = atoms[0]
        apply( self.doitWrapper, (atom,), kw)


    def doit(self,atom):
        self.vf.gpo.atomcenter=atom
        self.vf.ADgpf_setGrid.xCen.set(str(atom.coords[0]))
        self.vf.ADgpf_setGrid.yCen.set(str(atom.coords[1]))
        self.vf.ADgpf_setGrid.zCen.set(str(atom.coords[2]))
        cenSph.Set(vertices=(atom.coords,))
        cenSph.Set(visible=0)
        cenCross.Set(vertices=(atom.coords,))
        cenCross.Set(visible=1)
        self.vf.ADgpf_setGrid.updateCoords()
        box.Set(visible=1)
        self.vf.ADgpf_setGrid.showBox.set(1)
        if hasattr(self.vf.ADgpf_setGrid, 'ifd'):
            d = self.vf.ADgpf_setGrid.ifd.entryByName
            if d.has_key('Pick Center'):
                d['Pick Center']['variable'].set(-1)
        if self.save:
            self.vf.setICOM(self.save, modifier="Shift_L", topCommand=0)
            self.save=None
        try:
            self.vf.ADgpf_setGrid.cenVal.set(-1)
        except:
            pass


    def guiCallback(self):
        #check that there is a Macromolecule +/or Ligand
        self.save = self.vf.ICmdCaller.commands.value["Shift_L"]
        self.vf.setICOM(self, modifier="Shift_L", topCommand=0)
        self.vf.setIcomLevel( Atom )



class SetMapTypes(MVCommand):
    """ allows user to enter types of maps to be calculated, directly"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)
        if self.vf.hasGui:
            self.gtypes= Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.NHBonds= Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.OHBonds= Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.SHBonds= Tkinter.IntVar(master=self.vf.GUI.ROOT)


    def guiCallback(self):
        if not hasattr(self, 'form'):
            self.buildForm()
        else:
            self.form.deiconify()
        self.gtypes.set(self.vf.gpo['types']['value'])
        self.NHBonds.set(self.vf.gpo['NHB']['value'])
        self.OHBonds.set(self.vf.gpo['OHB']['value'])
        self.SHBonds.set(self.vf.gpo['SHB']['value'])


    def buildForm(self):
        ifd = self.ifd = InputFormDescr(title = "AutoGpf Ligand")
        ifd.append( {'name': 'MapTypesEntry',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'Map Atom Types:',
                'textvariable': self.gtypes,
                'command':self.updateHbonds,
                'eventType':'<Key>'
             },
            'gridcfg':{'sticky':Tkinter.W,'columnspan':2}})
        ifd.append({'name': 'HBondsLabel',
            'widgetType':Tkinter.Label,
            'text': 'Model Hydrogen Bonding',
            'gridcfg':{'sticky':Tkinter.W}})
        ifd.append({'name': 'N-HBonds',
            'widgetType':Tkinter.Checkbutton,
            'text': 'Nitrogens ',
            'variable': self.NHBonds,
            'gridcfg':{'sticky':Tkinter.W},
            'command': self.updateHbonds})
        ifd.append({'name': 'O-HBonds',
            'widgetType':Tkinter.Checkbutton,
            'text': 'Oxygens ',
            'variable': self.OHBonds,
            'gridcfg':{'sticky':Tkinter.W},
            'command': self.updateHbonds})
        ifd.append({'name': 'S-HBonds',
            'widgetType':Tkinter.Checkbutton,
            'text': 'Sulphurs ',
            'variable': self.SHBonds,
            'gridcfg':{'sticky':Tkinter.W},
            'command': self.updateHbonds})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Accept',
            'wcfg':{'bd':4},
            'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'columnspan':2},
            'command':self.Accept_cb})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Close',
            'wcfg':{'bd':4},
            'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'column':2, 'row':-1},
            'command':self.Close_cb})
        self.form = self.vf.getUserInput(self.ifd, modal=0, blocking=0)
        self.form.root.protocol('WM_DELETE_WINDOW',self.Close_cb)
    

    def Close_cb(self, event=None):
        self.form.withdraw()


    def Accept_cb(self, event=None):
        types = self.gtypes.get()
        NHB = self.NHBonds.get()
        OHB = self.OHBonds.get()
        SHB = self.SHBonds.get()
        kw={}
        kw['topCommand'] = 0
        apply(self.doitWrapper, (types, NHB, OHB, SHB), kw)
        self.form.withdraw()


    def updateHbonds(self, event=None):
        ll= ['N','S','O']
        ligstring = self.ifd[0]['widget'].get()
        for item in ll:
            w=eval("self.ifd.entryByName['%s-HBonds']"%item)
            if 'H' in ligstring:
                self.ifd.entryByName['HBondsLabel']['widget'].config(text ='Model Hydrogen Bonding:')
                if item in ligstring:
                    w['widget'].config(state='normal')
                else:
                    w['widget'].config(state='disabled')
                    w['variable'].set(0)
            else:
                self.ifd.entryByName['HBondsLabel']['widget'].config(text ='No Hydrogen Bonding')
                w['widget'].config(state='disabled')
                w['variable'].set(0)


    def __call__(self, typeList, nbh, ohb, shb,  **kw):
        """None<-mv.ADgpf_setMapTypes(typeList, nbh, ohb, shb)
typeList: types of maps to calculate, eg 'CNOSH'
nbh: flag to model nitrogen hydrogen bonding
obh: flag to model oxygen hydrogen bonding
sbh: flag to model sulfur hydrogen bonding
        """
        apply(self.doitWrapper,(typeList, nbh, ohb, shb,), kw)


    def doit(self, types, NHB, OHB, SHB):
        if self.vf.hasGui: 
            for item in types:
                if item not in ['A','C','N','O','S','P','H','n',\
                    'f','F','c','b','I','M']:
                    self.vf.ADgpf_defineAtomParameters.elem.set(item)
                    self.vf.ADgpf_defineAtomParameters.guiCallback()

        changeVals = {}
        for item in ['types','NHB','OHB','SHB']:
            if self.vf.gpo[item]['value']!= eval(item):
                changeVals[item]=eval(item)
        if len(changeVals.keys()):
            changeVals['topCommand'] = 1
            apply(self.vf.ADgpf_setGpo, (), changeVals)
        

SetMapTypesGUI= CommandGUI()
SetMapTypesGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
    menuText['SetMapDirectly'], cascadeName = menuText['SetMapTypesMB'],
    separatorAbove=1)


class SetUpCovalentMap(MVCommand):

    def onAddCmdToViewer(self):
        self.well_depth='10000.'
        self.well_width='5.0'
        self.constant=-1.780
        self.coords=None
        self.atomType=None
        checkHasGpo(self.vf)
        self.typeList=[('PDBQ files', '*.pdbq')]
        self.ifd_title = "Covalent Grid Parameters, AD3"
        self.version='AD3'
        self.z_string = "Z"
        if self.vf.hasGui:
            self.setPickAtom=Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.setSelAtom=Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.setSelectedAtom=Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.constantVar=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.coordStr=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.atomType=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.wellDepth=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.wellWidth=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.wellWidth.set("5.0")
            self.xVar=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.yVar=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.zVar=Tkinter.StringVar(master=self.vf.GUI.ROOT)


    def guiCallback(self):
        if not hasattr(self, 'ifd'):
            self.buildForm()
        else:
            self.form.deiconify()
        self.updateValues()


    def buildForm(self):
        ifd = self.ifd = InputFormDescr(title = self.ifd_title)
        ifd.append( {'name': 'energyWellDepth',
            'widgetType':ExtendedSliderWidget,
            'wcfg':{'label': "energy barrier height :", 'minval':0.0,
                'entrywcfg': {'width':8}, 'init':self.wellDepth.get(),
                'sliderType':'int',
                'right':20,'left':20, 'labelsCursorFormat':'%.0f',
                'maxval':10000.0,'entrypackcfg':{'side':'right','fill':'x'}, 'immediate':1,
                'command':self.set_energyWellDepth},
            'gridcfg':{'sticky':'w','columnspan':4}})
        ifd.append( {'name': 'energyWellWidth',
            'widgetType':ExtendedSliderWidget,
            'wcfg':{'label': "half-width (Angstrom):", 'minval':5.0,
                'init':self.wellWidth.get(),
                'right':20,'left':20, 'labelsCursorFormat':'%.2f',
                'maxval':50.0,'entrypackcfg':{'side':'right'}, 'immediate':1,
                'command':self.set_energyWellWidth},
            'gridcfg':{'sticky':'w','columnspan':4}})
        if self.version=='AD3':
            ifd.append( {'name': 'constantEnt',
                'widgetType':Tkinter.Entry,
                'wcfg': {
                    'label': 'Covalent Map constant',
                    'textvariable': self.constantVar,
                },
                'gridcfg':{'sticky':'w','columnspan':4}})
        #ifd.append({'name': 'PickAtom',
            #'widgetType':Tkinter.Checkbutton,
            #'text': 'Pick Atom',
            #'variable':self.setPickAtom,
            #'gridcfg':{'sticky':'w','columnspan':2},
            #'command': self.setAtomPick_cb})
        ifd.append({'name': 'UseSelection',
            'widgetType':Tkinter.Checkbutton,
            'text': 'Use selection for Attachment Atom:',
            'variable':self.setSelAtom,
            'command': self.setAtomSel_cb,
            'gridcfg':{'sticky':'w'}})
            #'gridcfg':{'sticky':'w', 'row':-1, 'column':1},
            #'gridcfg':{'sticky':'we','columnspan':2,'row':-1,'column':2},
        ifd.append({'name': 'SaveSelection',
            'widgetType':Tkinter.Button,
            'text': 'Save with Z atom',
            'gridcfg':{'sticky':'w', 'row':-1, 'column':1},
            #'gridcfg':{'sticky':'we','columnspan':2,'row':-1,'column':2},
            'command': self.saveAtomSel_cb})
        ifd.append( {'name': 'typeLabel',
            'widgetType':Tkinter.Label,
            'text': 'Atom Type:',
            'gridcfg':{'sticky':'w','row':-1,'column':2}})
        ifd.append( {'name': 'coordsLabel',
            'widgetType':Tkinter.Label,
            'text': ' Coords:',
            'gridcfg':{'sticky':'w', 'columnspan':4}})
        ifd.append( {'name': 'xEnt',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'x:',
                'textvariable': self.xVar,
                'command':self.updateCoordStr,
            },
            'gridcfg':{'sticky':'we'}})
        ifd.append( {'name': 'yEnt',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'y:',
                'textvariable': self.yVar,
                'command':self.updateCoordStr,
            },
            'gridcfg':{'sticky':'we', 'row':-1, 'column':1}})
        ifd.append( {'name': 'zEnt',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'z:',
                'textvariable': self.zVar,
                'command':self.updateCoordStr,
            },
            'gridcfg':{'sticky':'we', 'row':-1, 'column':2}})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Accept',
            'wcfg':{'bd':6},
            'gridcfg':{'sticky':'ew', 'columnspan':2},
            'command':self.Accept_cb})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Close',
            'wcfg':{'bd':6},
            'gridcfg':{'sticky':'ew', 
                    'columnspan':2,
                    'row':-1, 'column':2},
            'command':self.Close_cb})
        self.form = self.vf.getUserInput(self.ifd, modal=0, blocking=0)
        self.form.root.protocol('WM_DELETE_WINDOW',self.Close_cb)
        if self.version=='AD3':
            self.ifd.entryByName['constantEnt']['widget'].bind('<Key>',self.updateConstant)
        self.ifd.entryByName['xEnt']['widget'].bind('<Key>',self.updateCoordStr)
        self.ifd.entryByName['yEnt']['widget'].bind('<Key>',self.updateCoordStr)
        self.ifd.entryByName['zEnt']['widget'].bind('<Key>',self.updateCoordStr)


    def updateValues(self):
        if self.version=='AD3':
            self.constantVar.set(str(self.vf.gpo['covalent_constant']['value']))
        self.wellWidth.set(str(self.vf.gpo['covalent_half_width']['value']))
        self.wellDepth.set(str(self.vf.gpo['covalent_energy_barrier']['value']))
        #self.wellDepth.set('10000')


    def updateConstant(self,event=None):
        self.constant=float(self.constantVar.get())
        msg='self.vf.ADgpf_setUpCovalentMap.updateConstant()'
        self.vf.log(msg)


    def Accept_cb(self, event=None):
        if not hasattr(self,'atom_type'):
            msg="No atom picked as attachment"
            self.vf.warningMsg(msg)
            return
        if not self.coords:
            msg="No atom picked as attachment"
            self.vf.warningMsg(msg)
            return
        self.setUpConstants(self.atom_type)
        types = self.vf.gpo['types']['value']
        if self.z_string not in types:
            types = self.vf.gpo['types']['value'] + self.z_string
        self.doitWrapper(self.coords,types,self.constant,self.wellWidth.get(),self.wellDepth.get(),topCommand=0)
        self.form.withdraw()


    def __call__(self,  coords, types, constant, wellWidth, wellDepth, **kw):
        """None<-mv.ADgpf_setUpCovalentMap(coords,types,constant,wellWidth,wellDepth,**kw) 
coords: x,y,z for attachment point, center of gaussian map
types: ligand_types plus 'Z' 
constant: AD3 constant energy
wellWidth: covalent_half_width, for the Gaussian
wellDepth: covalent_energy_barrier, for the Gaussian
        """
        kw['topCommand'] = 0
        apply(self.doitWrapper,(coords,types,constant,wellWidth,wellDepth),kw)


    def doit(self, coords, types, constant, wellWidth, wellDepth):
        changeVals = {}
        if self.version=='AD3':
            if self.vf.gpo['types']['value']!=types:
                changeVals['types'] = types
            if self.vf.gpo['covalent_constant']['value']!=constant:
                changeVals['covalent_constant'] = constant
        else:
            if self.vf.gpo['ligand_types']['value']!=types:
                changeVals['ligand_types'] = types
        if self.vf.gpo['covalent_coords']['value']!=coords:
            changeVals['covalent_coords'] = coords
        if self.vf.gpo['covalent_energy_barrier']['value']!=wellDepth:
            changeVals['covalent_energy_barrier'] = wellDepth
        if self.vf.gpo['covalent_half_width']['value']!=wellWidth:
            changeVals['covalent_half_width'] = wellWidth
        if self.vf.gpo['covalentmap']['value']!=1:
            changeVals['covalentmap'] = 1
        if len(changeVals.keys()):
            apply(self.vf.ADgpf_setGpo,(), changeVals)


    def setUpConstants(self, atomType):
        for item in ['C','N','n','O','P','S','H','f','F','c','b','I','M']:
            itemStr = 'ljZ'+item
            atStr = 'lj'+atomType+item
            Rij[itemStr] = Rij[atStr]
            epsij[itemStr] = epsij[atStr]
        SolCon['Z'] = self.constant
        SolVol['Z'] = SolVol[atomType]
        SolPar['Z'] = SolPar[atomType]
        msg='self.vf.ADgpf_setUpCovalentMap.setUpConstants('+atomType+')'
        self.vf.log(msg)
        
        
    def Close_cb(self, event=None):
        self.form.withdraw()


    def updateCoordStr(self, event=None):
        oldStr = self.coordStr.get()
        x = self.xVar.get()
        y = self.yVar.get()
        z = self.zVar.get()
        try:
            x=float(x)
            y=float(y)
            z=float(z)
            coordsStr = "%6.4f %6.4f %6.4f" %(x,y,z)
            self.coordStr.set(coordsStr)
            self.coords = coordsStr
            w = self.ifd.entryByName['coordsLabel']['widget']
            newStr = "Coords: " + coordsStr
            w.config(text = newStr)
        except:
            pass



    def setUpAtom(self, atom):
        coordsStr = "%6.4f %6.4f %6.4f"%(atom.coords[0], atom.coords[1], atom.coords[2])
        #coordsStr = `atom.coords`[1:-1]
        #coordsStr = replace(coordsStr,',',' ')
        #DO CHANGES TO THIS ATOM and undo changes to last atom
        oldname=atom.name
        atom.autodock_element='Z'
        if len(atom.element)==1:
            newNameStr = ' Z'+ atom.element + ' '
        elif len(atom.element)==2:
            newNameStr = ' Z'+ atom.element
        else:
            newNameStr = ' Z'+ atom.element[:2]
        atom.name = newNameStr
        if hasattr(self,'oldatom') and self.oldatom!=atom:
            self.oldatom.name=self.oldatom.element    
        self.atomType.set(atom.element)
        self.atom_type = atom.element


    def saveAtom(self, atom, savefile):
        filename = atom.top.parser.filename
        fptr=open(filename)
        allLines=fptr.readlines()
        fptr.close()
        #srchstr = 'ATOM  %5i  %s' %(z.number,z.normalname)
        srchStr='ATOM  %5i' %(atom.number)
        if atom.hetatm:
            srchStr='HETATM%5i' %(atom.number)
        #srchStr='ATOM  %5i %4.4s' %(atom.number,oldname)
        #newStr= 'ATOM  %5i  %4.4s' %(atom.number,atom.name)
        found=0
        for i in range(len(allLines)):
            l=allLines[i]
            if find(l, srchStr)==0:
                #also check for coords
                xcoord = float(l[30:38])
                ycoord = float(l[38:46])
                zcoord = float(l[46:54])
                #possibly there are two atoms with the same number
                #but they can't have the same coordinates
                if atom.coords[0]!=xcoord or atom.coords[1]!=ycoord or \
                        atom.coords[2]!=zcoord:
                    continue
                allLines[i] = l[:12] + atom.name + l[16:]
                found=1
                break
        if not found:
            msg="incorrect ligand file format: unable to write with Z atom"
            self.vf.warningMsg(msg)
        else:
            sptr=open(savefile,'w')
            sptr.writelines(allLines)    
            sptr.close()


    def saveAtomSel_cb(self, event=None):
        z=self.vf.getSelection()
        if not len(z): 
            return
        atom = z[0]
        savefile = self.vf.askFileSave(types= self.typeList, title = 'Save ligand with Z type atom:')
        #if savefile is not None: 
        if savefile:
            self.saveAtom(atom, savefile)
        else:
            msg="no changes to ligand:" + atom.top.name
            self.vf.warningMsg(msg)

    def setAtomSel_cb(self, event=None):
        if self.setSelAtom.get():
            self.setPickAtom.set(0)
            self.setAtomPick_cb()
            self.setSelAtom.set(0)
            z=self.vf.getSelection()
            if not len(z) or z[0].__class__!=Atom:
                msg='for this option, selection must be a single atom'
                self.vf.warningMsg(msg)
                return
            atom = z[0]
            self.setUpAtom(atom)
            #update the GUI:
            self.xVar.set(str(atom.coords[0]))
            self.yVar.set(str(atom.coords[1]))
            self.zVar.set(str(atom.coords[2]))
            coordsStr = "%6.4f %6.4f %6.4f"%(atom.coords[0], atom.coords[1], atom.coords[2])
            self.coordStr.set(coordsStr)
            self.coords = coordsStr
            self.updateCoordStr()
            newstr = "Atom Type: " + atom.element
            self.ifd.entryByName['typeLabel']['widget'].config(text=newstr)


    def setAtomPick_cb(self, event=None):
        if self.setPickAtom.get():
            if not self.doAtomPick_cb in self.vf.GUI.VIEWER.pickingFunctions:
                self.saveFUNC=self.vf.GUI.VIEWER.SetPickingCallback(self.doAtomPick_cb)
                ##self.vf.GUI.ehm.AddCallback("<Button-1>", self.doAtomPick_cb)
        else:
            ##if self.vf.GUI.ehm.HasCallback("<Button-1>", self.doAtomPick_cb):
            if self.doAtomPick_cb in self.vf.GUI.VIEWER.pickingFunctions:
                self.vf.GUI.VIEWER.SetPickingCallback(self.saveFUNC)
                ##self.vf.GUI.VIEWER.RemoveCallback("<Button-1>", self.doAtomPick_cb)


    def doAtomPick_cb(self, pick, event=None):
        atoms = self.vf.findPickedAtoms(event)
        if len(atoms):
            if hasattr(self,'atom'):self.oldatom=self.atom
            self.atom=atoms[0]
            if not hasattr(self,'oldatom'):self.oldatom=atoms[0]
            #remove [ and ]
            self.setUpAtom(atoms[0])
            self.vf.GUI.VIEWER.SetPickingCallback(self.saveFUNC)
            ###???###
            self.saveFUNC=None
            #self.vf.GUI.ehm.RemoveCallback("<Button-1>", self.doAtomPick_cb)
            self.setPickAtom.set(0)


    def set_energyWellWidth(self, val):
        val=round(val,2)
        self.wellWidth.set(str(val))
        self.well_width=str(val)
        msg='self.vf.ADgpf_setUpCovalentMap.set_energyWellWidth('+str(val)+')'
        self.vf.log(msg)


    def set_energyWellDepth(self, val,log=0):
        val=round(val,0)
        self.wellDepth.set(str(val))
        self.well_depth=str(val)
        if log:
            msg='self.vf.ADgpf_setUpCovalentMap.set_energyWellDepth('+str(val)+'),log=' + str(0)
            self.vf.log(msg)


SetUpCovalentMapGUI = CommandGUI()
SetUpCovalentMapGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['SetUpCovalentMap'], cascadeName = menuText['SetMapTypesMB'])



class SetUpCovalentMap4(SetUpCovalentMap):


    def onAddCmdToViewer(self):
        self.well_depth='10000.'
        self.well_width='5.0'
        self.constant=-1.780
        self.coords=None
        self.atomType=None
        checkHasGpo(self.vf)
        self.version='AD4'
        self.ifd_title = "Covalent Grid Parameters, AD4"
        self.typeList=[('PDBQT files', '*.pdbqt')]
        self.z_string = " Z"
        if self.vf.hasGui:
            self.setPickAtom=Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.setSelAtom=Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.setSelectedAtom=Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.constantVar=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.coordStr=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.atomType=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.wellDepth=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.wellWidth=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.xVar=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.yVar=Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.zVar=Tkinter.StringVar(master=self.vf.GUI.ROOT)


#    def updateValues(self):
#        self.constantVar.set(str(self.vf.gpo['covalent_constant']['value']))
#        self.wellWidth.set(str(self.vf.gpo['covalent_half_width']['value']))
#        self.wellDepth.set(str(self.vf.gpo['covalent_energy_barrier']['value']))
#        #self.wellDepth.set('10000')


    def updateConstant(self,event=None):
        pass
        #self.constant=float(self.constantVar.get())
        #msg='self.vf.ADgpf_setUpCovalentMap4.updateConstant()'
        #self.vf.log(msg)


    def Accept_cb(self, event=None):
        if not hasattr(self,'atom_type'):
            msg="No atom picked as attachment"
            self.vf.warningMsg(msg)
            return
        if not self.coords:
            msg="No atom picked as attachment"
            self.vf.warningMsg(msg)
            return
        self.setUpConstants(self.atom_type)
        types = self.vf.gpo['ligand_types']['value']
        #try not to add 'Z' a second time
        #self.warningMsg('adding Z')
        if 'Z' not in types.split():
            types = self.vf.gpo['ligand_types']['value'] + self.z_string
        self.doitWrapper(self.coords,types,0,self.wellWidth.get(),self.wellDepth.get(),topCommand=0)
        #self.doitWrapper(self.coords,types, self.constant,self.wellWidth.get(),self.wellDepth.get(),topCommand=0)
        self.form.withdraw()


    def __call__(self,  coords, types, constant, wellWidth, wellDepth, **kw):
        """None<-mv.ADgpf_setUpCovalentMap4(coords,types,constant,wellWidth,wellDepth,**kw) 
coords: x,y,z for attachment point, center of gaussian map
types: ligand_types plus 'Z' 
constant: n/a for autodock4 
wellWidth: covalent_half_width, for the Gaussian
wellDepth: covalent_energy_barrier, for the Gaussian
        """
        kw['topCommand'] = 0
        apply(self.doitWrapper,(coords,types,constant,wellWidth,wellDepth),kw)


    def setUpConstants(self, atomType):
        pass


    def saveAtom(self, atom, savefile):
        filename = atom.top.parser.filename
        fptr=open(filename)
        allLines=fptr.readlines()
        fptr.close()
        #srchstr = 'ATOM  %5i  %s' %(z.number,z.normalname)
        srchStr='ATOM  %5i' %(atom.number)
        if atom.hetatm:
            srchStr='HETATM%5i' %(atom.number)
        #srchStr='ATOM  %5i %4.4s' %(atom.number,oldname)
        #newStr= 'ATOM  %5i  %4.4s' %(atom.number,atom.name)
        found=0
        for i in range(len(allLines)):
            l=allLines[i]
            if find(l, srchStr)==0:
                #also check for coords
                xcoord = float(l[30:38])
                ycoord = float(l[38:46])
                zcoord = float(l[46:54])
                #possibly there are two atoms with the same number
                #but they can't have the same coordinates
                if atom.coords[0]!=xcoord or atom.coords[1]!=ycoord or \
                        atom.coords[2]!=zcoord:
                    continue
                allLines[i] = l[:12] + atom.name + l[16:77] + 'Z\n'
                found=1
                break
        if not found:
            msg="incorrect ligand file format: unable to write with Z atom"
            self.vf.warningMsg(msg)
        else:
            sptr=open(savefile,'w')
            sptr.writelines(allLines)    
            sptr.close()

        
    #def setUpAtom(self, atom):
    #    #AD4:
    #    coordsStr = "%6.4f %6.4f %6.4f"%(atom.coords[0], atom.coords[1], atom.coords[2])
    #    #coordsStr = `atom.coords`[1:-1]
    #    #coordsStr = replace(coordsStr,',',' ')
    #    self.coordStr.set(coordsStr)
    #    #coordsStr = replace(coordsStr,',',' ')
    #    self.xVar.set(str(atom.coords[0]))
    #    self.yVar.set(str(atom.coords[1]))
    #    self.zVar.set(str(atom.coords[2]))
    #    self.coords = coordsStr
    #    self.atomType.set(atom.autodock_element)
    #    self.atom_type = atom.autodock_element
    #    self.updateCoordStr()
    #    #DO CHANGES TO THIS ATOM and undo changes to last atom
    #    self.oldname=atom.name
    #    atom.name='Z'+atom.element
    #    atom.autodock_element = 'Z'
    #    if len(atom.element)==1:
    #        newNameStr = ' Z'+ atom.element + ' '
    #    elif len(atom.element)==2:
    #        newNameStr = ' Z'+ atom.element
    #    else:
    #        newNameStr = ' Z'+ atom.element[:2]
    #    if hasattr(self,'oldatom') and self.oldatom!=atom:
    #        self.oldatom.name=self.oldatom.element    
    #    #this is done in setAtomSel_cb, which is inherited from AD3 version
    #    #newstr = "Atom Type: " + atom.element
    #    #self.ifd.entryByName['typeLabel']['widget'].config(text=newstr)
 

SetUpCovalentMap4GUI = CommandGUI()
SetUpCovalentMap4GUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['SetUpCovalentMap4'], cascadeName = menuText['SetMapTypesMB'])



class DefineNewAtomParms(MVCommand):


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)
        if self.vf.hasGui:
            self.elem= Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.elem.set('')
            self.Rij= Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.epsij= Tkinter.StringVar(master=self.vf.GUI.ROOT)
            ##Tkinter.Widget.bind(self.ifd.form, '<Key>',self.clearElem)


    def guiCallback(self):
        ifd = self.ifd = InputFormDescr(title = "Enter Atom Type Parameters")
        ifd.append( {'name': 'eName',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'Atom Type:\n(Only M or X is valid!)',
                #'label': 'Atom Type:\n(Only first character valid!)',
                'textvariable': self.elem
            },
            'gridcfg':{'sticky':Tkinter.E,'columnspan':2}})
        ifd.append( {'name': 'rij',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'Rii:\n(Equilibrium separation between\nnuclei of 2 like atoms)',
                'textvariable': self.Rij
            },
            'gridcfg':{'sticky':Tkinter.E,'columnspan':2}})
        ifd.append( {'name': 'eps',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'epsii:\n(Potential energy well-depth\n(.1485 * epsii)',
                'textvariable': self.epsij
            },
            'gridcfg':{'sticky':Tkinter.E,'columnspan':2}})
        vals = self.vf.getUserInput(self.ifd)
        if vals is not None and len(vals) and vals['eName'] in ['X','M']:
            self.doitWrapper(self.elem.get(), float(self.Rij.get()),
                    float(self.epsij.get()),log=1,redraw=0)
        elif vals is not None and vals['eName'] not in ['X','M']:
            self.vf.warningMsg("new atom type must be 'X' or 'M'")


    def __call__(self, elem, rij, Epsij, **kw):
        """None<-mv.ADgpf_defineAtomParameters(elem, Rij, epsij)
elem: name of new element, 'M' or 'X' currently
Rij: lennard jones 12-6 parameter for element-element equilibrium distance
epsij: lennard jones 12-6 parameter for element-element equilibrium
well-depth"""
        apply(self.doitWrapper,(elem, rij, Epsij,), kw)


    def doit(self, elem, rij, Epsij):
        if elem not in ['X','M']:
            raise IndexError
        if len(elem)>0: elem = elem[0]
        Rij['lj'+elem+elem] = rij
        epsij['lj'+elem+elem] = Epsij

        for item in ['C','A','N','O','S','H','f','F','c','b','I','M']:
            newStr = 'lj'+elem+item
            newStr2 = 'lj'+item+elem
            val2 = Rij['lj' + item + item]
            newval = 0.5*(rij + val2)
            Rij[newStr] = Rij[newStr2] = newval

            val2 = epsij['lj' + item+ item]
            newval = round(math.sqrt(Epsij * val2),4)
            epsij[newStr2] = epsij[newStr] = newval
        SolPar[elem]=0.0
        SolCon[elem]=0.0
        SolVol[elem]=0.0


    def clearElem(self, event=None):
        self.elem.set('')
            

DefineNewAtomParmsGUI= CommandGUI()
DefineNewAtomParmsGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
    menuText['SetNewTypeParms'], cascadeName = menuText['SetMapTypesMB'])



class SetBoxParameters(MVCommand):
    """ allows user to set center, spacing, and extent of 
        grids (number of pts in each dimension) to be calculated"""


    def __init__(self):
        self.gridcenter = (0.,0.,0.)
        apply(MVCommand.__init__, (self,), {})


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)
        self.gridCenterType = 'set'
        self.cenDict = {}
        self.cenOpts = ['Pick an atom', 'Center on ligand', \
            'Center on macromolecule', 'On a named atom']
        self.centerFuncs=[self.pickCenter, self.autoCenterLig,\
            self.autoCenter, self.updateCenFromName]
        for i in range(4):
            self.cenDict[self.cenOpts[i]] = self.centerFuncs[i]
        self.visiDict = {}
        self.visiOpts = ['Show box','Show box as lines', 'Show center marker',\
                    'Adjust marker size']

        self.visiFuncs = [self.showGridBox,self.updateGridBox,self.showCenterCross,\
            self.adjustMarker]
        for i in range(len(self.visiOpts)):
            self.visiDict[self.visiOpts[i]] = self.visiFuncs[i]

        if self.vf.hasGui:
            self.oldx = 0.0
            self.oldy = 0.0
            self.oldz = 0.0
            self.xCen = Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.yCen = Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.zCen = Tkinter.StringVar(master=self.vf.GUI.ROOT)
            #now for the rest of the Tkinter vars:
            self.cenVal = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.cenVal.set(-1)
            self.visiVal = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showFileMenu = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showFileMenu.set(0)
            self.showCenMenu = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showCenMenu.set(0)
            self.showVisiMenu = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showVisiMenu.set(0)
            self.pickCen = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.autoLigCen = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.autoCen = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.nameCen = Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.showBox = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showCross = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showCross.set(1)
            self.adjustCross = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.adjustCross.set(0)
            self.showBoxMode = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showBoxMode.set(0)
            self.showLig = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.showLig.set(1)
            self.totalPtsVar = Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.totalPtsVar.set('Current Total Grid Pts per map:    64000')


    def guiCallback(self):
        """called each time the menuText['SetGridMB'] button is pressed"""
        if not hasattr(self, 'form'):
            self.buildForm()
        else:
            self.form.deiconify()
        #make sure form entries reflect gpo data
        self.updateValues()
        

    def updateValues(self):
        #method to keep form entries synchronized with gpo
        #called each time guiCallback is invoked to open form for changes
        npts = self.vf.gpo['npts']['value'] 
        spacing = self.vf.gpo['spacing']['value']
        self.nxpts.set(npts[0])
        self.nypts.set(npts[1])
        self.nzpts.set(npts[2])
        self.gridcenter = self.vf.gpo['gridcenter']['value']
        if self.gridcenter == 'auto':
            if hasattr(self.vf.gpo, 'receptor'):
                v = self.vf.gpo.receptor.center
                centerList = []
                for item in v:
                    centerList.append(round(item,3))
                self.gridcenter = centerList
                #self.gridcenter = self.vf.gpo.receptor.center
            else:
                self.gridcenter = (0., 0., 0.)
        #xCen,yCen and zCen are entries so must have strings
        self.xCen.set(str(self.gridcenter[0]))
        self.yCen.set(str(self.gridcenter[1]))
        self.zCen.set(str(self.gridcenter[2]))
        self.spacewheel.set(spacing)
        self.showBox.set(1)
        self.showCross.set(1)
        self.showGridBox()
        self.ifd.entryByName['spacenumber']['widget'].val = spacing


    def buildForm(self):
        # called once to set up form
        spacing = self.vf.gpo['spacing']['value']
        ifd = self.ifd = InputFormDescr(title = "Grid Options")
        specfont = (ensureFontCase('helvetica'), 12, 'bold')
        ifd.append( {'name': 'FileMB',
            'widgetType':Tkinter.Menubutton,
            'wcfg':{'text': 'File',
                    #'font': specfont,
                    'relief': 'flat'},
            'gridcfg':{'sticky':'we'}})
        ifd.append({'name': 'CenMB',
            'widgetType': Tkinter.Menubutton,
            'wcfg':{'text': 'Center',
                    #'font': specfont,
                    'relief': 'flat'},
            'gridcfg': {'sticky':'we', 'row':-1, 'column':1}})
        ifd.append({'name': 'VisiMB',
            'widgetType': Tkinter.Menubutton,
            'wcfg':{'text': 'View',
                    #'font': specfont,
                    'relief': 'flat'},
            'gridcfg': {'sticky':'we', 'row':-1, 'column':2}})
        ifd.append({'name': 'HelpMB',
            'widgetType': Tkinter.Menubutton,
            'wcfg':{'text': '  Help  ',
                    #'font': specfont,
                    'relief': 'flat'},
            'gridcfg': {'sticky':'we', 'row':-1, 'column':3}})
        ifd.append( {'name': 'totalPts',
            'widgetType':Tkinter.Label,
            'textvariable': self.totalPtsVar,
            'wcfg':{'font':(ensureFontCase('helvetica'),12,'bold')},
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':4}})
        ifd.append( {'name': 'xScaleLab',
            'widgetType':Tkinter.Label,
            'wcfg':{'text':'number of points in x-dimension:', 
                'font':(ensureFontCase('helvetica'),12,'bold')},
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':4}})
        #ifd.append( {'name': 'xnumber',
        #    'widgetType':Tkinter.Scale,
        #    'wcfg':{'troughcolor':'red', 'from_':10,'to_':126,
        #            'orient':'horizontal', 'length': '3i',
        #            'resolution':2,
        #            'command':self.updateBoth},
        #    'gridcfg':{'sticky':Tkinter.W,'columnspan':4}})
        ifd.append({'name': 'xnumber',
            'wtype':ThumbWheel,
            'widgetType':ThumbWheel,
            #'wcfg':{'text':'number of points in x-dimension',
            #'wcfg':{'text':None,
            #'wcfg':{'text':'number of points in x',
            'wcfg':{'text':None,
                'showLabel':1, 'width':100,
                'min':0,
                'max':126,
                'lockBMin':1,
                'lockBMax':1,
                'lockBIncrement':1,
                'value':40,
                'oneTurn':1000,
                'type':'int',
                'increment':2,
                'canvasCfg':{'bg':'red'},
                #'canvascfg':{'bg':'red'},
                'wheelLabCfg':{'font':(ensureFontCase('times'),14,'bold')},
                'callback':self.updateBoth,
                'continuous':1, 'wheelPad':1, 'height':20},
            'gridcfg':{'sticky':'e','columnspan':4}})
        ifd.append( {'name': 'yScaleLab',
            'widgetType':Tkinter.Label,
            'wcfg':{'text':'number of points in y-dimension:', 
                'font':(ensureFontCase('helvetica'),12,'bold')},
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':4}})
        #ifd.append( {'name': 'ynumber',
            #'widgetType':Tkinter.Scale,
            #'wcfg':{'troughcolor':'green', 'from_':10,'to_':126,
                    #'orient':'horizontal', 'length': '3i',
                    #'resolution':2,
                    #'command':self.updateBoth},
            #'gridcfg':{'sticky':Tkinter.W,'columnspan':4}})
        ifd.append({'name': 'ynumber',
            'wtype':ThumbWheel,
            'widgetType':ThumbWheel,
            #'wcfg':{'text':'number of points in y-dimension',
            'wcfg':{'text':None,
                'showLabel':1, 'width':100,
                'min':0,
                'max':126,
                'lockBMin':1,
                'lockBMax':1,
                'lockBIncrement':1,
                'value':40,
                'oneTurn':1000,
                'type':'int',
                'increment':2,
                'canvasCfg':{'bg':'green'},
                #'canvascfg':{'bg':'green'},
                'wheelLabCfg':{'font':(ensureFontCase('times'),14,'bold')},
                'callback':self.updateBoth,
                'continuous':1, 'wheelPad':1, 'height':20},
            'gridcfg':{'sticky':'e','columnspan':4}})
        ifd.append( {'name': 'zScaleLab',
            'widgetType':Tkinter.Label,
            'wcfg':{'text':'number of points in z-dimension:', 
                'font':(ensureFontCase('helvetica'),12,'bold')},
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':4}})
        #ifd.append( {'name': 'znumber',
        #    'widgetType':Tkinter.Scale,
        #    'wcfg':{'troughcolor':'blue', 'from_':10,'to_':126,
        #            'orient':'horizontal', 'length': '3i',
        #            'resolution':2,
        #            'command':self.updateBoth},
        #    'gridcfg':{'sticky':Tkinter.W,'columnspan':4}})
        ifd.append({'name': 'znumber',
            'wtype':ThumbWheel,
            'widgetType':ThumbWheel,
            #'wcfg':{'text':'number of points in z',
            'wcfg':{'text':None,
                'showLabel':1, 'width':100,
                'min':0,
                'max':126,
                'lockBMin':1,
                'lockBMax':1,
                'lockBIncrement':1,
                'value':40,
                'type':'int',
                'oneTurn':1000,
                'increment':2,
                'canvasCfg':{'bg':'blue'},
                #'canvascfg':{'bg':'blue'},
                'wheelLabCfg':{'font':(ensureFontCase('times'),14,'bold')},
                'callback':self.updateBoth,
                'continuous':1, 'wheelPad':1, 'height':20},
            'gridcfg':{'sticky':'e','columnspan':4}})
        ifd.append({ 'widgetType':Tkinter.Label,
            'wcfg':{ 'text': '',},
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':4}})
        ifd.append({ 'widgetType':Tkinter.Label,
            'wcfg':{ 'text': 'Spacing (angstrom):',
                'font':(ensureFontCase('helvetica'),12,'bold')},
            'gridcfg':{'sticky':'w', 'columnspan':2}})
        ifd.append({'name': 'spacenumber',
            'wtype':ThumbWheel,
            'widgetType':ThumbWheel,
            'wcfg':{'text':None,
                'showLabel':2, 'width':100,
                'min':.01, 'max':1.0, 'type':float, 'precision':3,
                'value':0.375,
                'showLabel':1,
                'callback': self.updateBox,
                'continuous':1, 'oneTurn':2, 'wheelPad':2, 'height':20},
            'gridcfg':{'sticky':'e', 'row':-1, 'column':2,'columnspan':2}})
        ifd.append({ 'widgetType':Tkinter.Label,
            'wcfg':{ 'text': gridOpts['CenterGridBoxLabel'],
                'font':(ensureFontCase('helvetica'),12,'bold')},
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':4}})
        ifd.append( {'name': 'xcenter',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': gridOpts['XCenterLabel'],
                'width':7,
                'textvariable': self.xCen
            },
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':2}})
        ifd.append({'name': 'xoffset',
            'wtype':ThumbWheel,
            'widgetType':ThumbWheel,
            'wcfg':{'text':None,
                'showLabel':2, 'width':100,
                'precision':3,
                'canvasCfg':{'bg':'red'},
                #'canvascfg':{'bg':'red'},
                'wheelLabCfg':{'font':(ensureFontCase('times'),14,'bold')},
                'callback':self.set_xoffset,
                'continuous':1, 'oneTurn':10, 'wheelPad':2, 'height':20},
            'gridcfg':{'sticky':'e','row':-1, 'column':2,'columnspan':2}})
        ifd.append( {'name': 'ycenter',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': gridOpts['YCenterLabel'],
                'width':7,
                'textvariable': self.yCen
            },
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':2}})
        ifd.append({'name': 'yoffset',
            'wtype':ThumbWheel,
            'widgetType':ThumbWheel,
            'wcfg':{'text':None,
                'showLabel':2, 'width':100,
                'precision':3,
                'canvasCfg':{'bg':'green'},
                #'canvascfg':{'bg':'green'},
                'wheelLabCfg':{'font':(ensureFontCase('times'),14,'bold')},
                'callback':self.set_yoffset,
                'continuous':1, 'oneTurn':10, 'wheelPad':1, 'height':20},
            'gridcfg':{'sticky':'e', 'row':-1, 'column':2,'columnspan':2}})
        ifd.append( {'name': 'zcenter',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': gridOpts['ZCenterLabel'],
                'width':7,
                'textvariable': self.zCen
            },
            'gridcfg':{'sticky':Tkinter.W, 'columnspan':2}})
        ifd.append({'name': 'zoffset',
            'wtype':ThumbWheel,
            'widgetType':ThumbWheel,
            'wcfg':{'text':None,
                'showLabel':2,  'width':100,
                'precision':3,
                'canvasCfg':{'bg':'blue'},
                #'canvascfg':{'bg':'blue'},
                'wheelLabCfg':{'font':(ensureFontCase('times'),14,'bold')},
                #'wheelLabcfg1':{'font':(ensureFontCase('times'),14,'bold')},
                #'wheelLabcfg2':{'font':(ensureFontCase('times'),14,'bold')},
                'callback':self.set_zoffset,
                'continuous':1, 'oneTurn':10, 'wheelPad':1, 'height':20},
            'gridcfg':{'sticky':'e','row':-1,'column':2,'columnspan':2}})
        self.form = self.vf.getUserInput(self.ifd, scrolledFrame=1,
                width=330, height=400, modal=0, blocking=0)
        self.form.root.protocol('WM_DELETE_WINDOW',self.Close_cb)

        # bind callback to entries:
        for item in ['xcenter','ycenter','zcenter']:
            wid = self.ifd.entryByName[item]['widget']
            wid.bind('<Key>', self.updateCoords)

        # bind callbacks to menubuttons:
        mbs = ['FileMB','VisiMB','CenMB','HelpMB']
        funcs = [self.buildFileMenu, self.buildVisiMenu,\
            self.buildCenterMenu, self.buildHelpMenu]
        for i in range(4):
            wid = self.ifd.entryByName[mbs[i]]['widget']
            wid.bind( '<ButtonPress>', funcs[i], add='+')


        # setup handles to widgets
        self.nxpts = self.ifd.entryByName['xnumber']['widget']
        self.nypts = self.ifd.entryByName['ynumber']['widget']
        self.nzpts = self.ifd.entryByName['znumber']['widget']
        self.spacewheel = self.ifd.entryByName['spacenumber']['widget']
        self.xwheel = self.ifd.entryByName['xoffset']['widget']
        self.ywheel = self.ifd.entryByName['yoffset']['widget']
        self.zwheel = self.ifd.entryByName['zoffset']['widget']
    

            
    #------------------------------------------------------------------
    # METHODS TO BUILD MENUS AT TOP OF FORM:
    #       general method  
    #       file menu    
    #       center menu    
    #       visibility menu    
    #       help menu 
    #------------------------------------------------------------------

    def buildMenu(self, keyList, mB, vars, cmd, type='radio', cmdList=None):
        #called in building each of the following 4 menus
        mB.menu = Tkinter.Menu(mB)
        mB['menu'] = mB.menu
        for i in range(len(keyList)):
            if type=='radio':
                mB.menu.add_radiobutton(label=keyList[i],
                    var=vars[i],value=i,command=CallBackFunction(cmd,i))
            elif type=='check':
                mB.menu.add_checkbutton(label=keyList[i],
                    var=vars[i],command=CallBackFunction(cmd,i))
            elif type=='button':
                mB.menu.add_command(label=keyList[i],command=cmdList[i])


    def buildFileMenu(self, event=None):
        # called by File menubutton in form
        fileMb = self.ifd.entryByName['FileMB']['widget']
        cmdList = [self.Accept_cb, self.Close_cb, self.WriteGridDim_cb]
        fileOpts = ['Close saving current', 'Close w/out saving', 'Output grid dimensions file']
        if not self.showFileMenu.get():
            if not hasattr(fileMb, 'menu'):
                self.buildMenu(fileOpts, fileMb, None, None, 
                    type='button', cmdList=cmdList)
            self.showFileMenu.set(1)
        else:
            fileMb.menu.unpost()
            self.showFileMenu.set(0)


    def buildCenterMenu(self, event=None):
        # called by Center menubutton in form
        cenMb = self.ifd.entryByName['CenMB']['widget']
        if not self.showCenMenu.get():
            if not hasattr(cenMb, 'menu'):
                vars = [self.cenVal, self.cenVal, self.cenVal, self.cenVal]
                self.buildMenu(self.cenOpts, cenMb, vars, self.setCenVal)
            self.showCenMenu.set(1)
        else:
            cenMb.menu.unpost()
            self.showCenMenu.set(0)


    def buildVisiMenu(self, event=None):
        # called by Visibility menubutton in form
        visiMb = self.ifd.entryByName['VisiMB']['widget']
        if not self.showVisiMenu.get():
            #have to do 3 call to buildMenu for 3 choices
            if not hasattr(visiMb, 'menu'):
                vars = [self.showBox, self.showBoxMode, self.showCross,\
                     self.adjustCross]
                self.buildMenu(self.visiOpts, visiMb, vars, \
                        self.setVisiVal, type='check')
            self.showVisiMenu.set(1)
        else:
            visiMb.menu.unpost()
            self.showVisiMenu.set(0)


    def buildHelpMenu(self, event=None):
        # called by Help menubutton in form
        self.vf.warningMsg('File Menu:\nClose saving current stores\nbox location and dimensions\nand exits.\nClose w/out saving does not\nchange previous box parms.')


    #------------------------------------------------------------------
    # FILE METHODS CALLED FROM MENU:
    #------------------------------------------------------------------
    def WriteGridDim_cb(self, event=None):
        if not hasattr(self.vf.gpo, 'receptor'):
            self.warningMsg("Please specify a receptor before trying to write a grid dimensions file")
            return -1
        m = self.vf.gpo.receptor
        m.npts = nx,ny,nz = [self.nxpts.get(), self.nypts.get(), self.nzpts.get()]
        m.spacing = self.spacewheel.get()
        m.gridcenter = [round(float(self.xCen.get()),3), round(float(self.yCen.get()),3), round(float(self.zCen.get()),3)]
        cx,cy, cz = m.gridcenter
        dimStr = "%s\nspacing   %6.3f\nnpts       %d %d %d\ncenter    %6.3f %6.3f %6.3f\n" %(m.name, m.spacing, nx,ny,nz, cx,cy,cz)
        gridDimFile = self.vf.askFileSave( types=[('.txt', '*.txt')],
                    title = 'Grid Dimensions File:')
        if gridDimFile:
            fptr=open(gridDimFile,'w')
            fptr.write(dimStr)
            fptr.close()
        #?update self.vf.gpo?
        d = self.vf.gpo
        d['npts']['value'] = m.npts
        d['spacing']['value'] = m.spacing
        d['gridcenter']['value'] = m.gridcenter


    def Close_cb(self, event=None):
        # called from 'Close w/out saving' button in File menu
        # and from self.Accept_cb below
        self.showBox.set(0)
        self.showCross.set(0)
        self.showGridBox()
        #problem here is to link closing this panel with removing ICOM
        self.vf.ADgpf_selectCenter.dismiss_cb()
        #self.form.withdraw()


    def Accept_cb(self, event=None):
        # called from 'Close saving current' button in File menu
        self.updateCoords()
        changeVals = {}
        #check first that gridcenter !='auto' (???)
        if self.gridCenterType == 'set':
            changeVals['gridcenter'] = [round(float(self.xCen.get()),3), round(float(self.yCen.get()),3), round(float(self.zCen.get()),3)]
            changeVals['gridcenterAuto'] = 0
        else:
            changeVals['gridcenter'] = 'auto'
            changeVals['gridcenterAuto'] = 1
        changeVals['npts'] = [self.nxpts.get(), self.nypts.get(), self.nzpts.get()]
        #changeVals['npts'] = [self.nXpts.get(), self.nYpts.get(), self.nZpts.get()]
        changeVals['spacing'] = self.spacewheel.get()
        changeVals['topCommand'] = 0
        #NB this is what calls doit->
        apply(self.doitWrapper, (), changeVals)
        self.Close_cb()


            
    #------------------------------------------------------------------
    # GENERAL CENTER METHOD CALLED FROM MENU:
    #------------------------------------------------------------------


    # used to set method for determining center:
    # link from buttons in menu to various centering methods below
    # cenDict and cenOpts set up in onAddCmdToViewer
    #    self.cenOpts = ['Pick an atom', 'Center on ligand', \
    #        'Center on macromolecule', 'On a named atom']
    #    self.centerFuncs=[self.pickCenter, self.autoCenterLig,\
    #        self.autoCenter, self.updateCenFromName]
    def setCenVal(self, val, event=None):
        opt = self.cenOpts[val]
        f = self.cenDict[opt]
        apply(f, (),{})



    #------------------------------------------------------------------
    # SPECIFIC CENTER METHODS:
    #   METHODS INVOKED FROM MENU
    #       1. pick an atom for center
    #       2. center on molecule
    #           A. ligand
    #           B. macromolecule
    #       3. center on named atom
    #   METHOD INVOKED by '<RETURN>' in entry
    #       4. enter coords of center
    #
    #   NB: all changes in center force: 
    #       zeroing of offsets,
    #       updating x-center,y-center,z-center entries,
    #       AND repositioning box + marker
    #------------------------------------------------------------------


    # pick an atom in viewer for center of box
    def pickCenter(self, event=None):
        #called from 'Pick an atom' button in Center menu
        self.gridCenterType = 'set'
        # FIX THIS:
        # THIS CALLS A DIFFERENT COMMAND WHICH IS AN ICOM
        self.vf.ADgpf_selectCenter.guiCallback()
        # because xCen,yCen+zCen are set don't have to call updateCoords
        # also updateBox geometry via guiCallback
        # so just call zeroOffsets
        self.zeroOffsets()


    # center on autodock ligand
    def autoCenterLig(self, event=None):
        #called from 'Center on ligand' button in Center menu
        self.gridCenterType = 'set'
        self.findAutoLigandCenter()
        self.zeroOffsets()
        self.cenVal.set(-1)


    def findAutoLigandCenter(self):
        if not hasattr(self.vf.gpo, 'ligand'):
            self.vf.warningMsg(' no current ligand')
            if self.ifd.entryByName.has_key('Auto Lig Center'):
                self.ifd.entryByName['Auto Lig Center']['widget'].toggle()
            return
        ligand = self.vf.gpo.ligand
        #NB ligand.center gets set by call to getCenter in InitLigand
        #make sure values are rounded off
        autocenterlig=(round(ligand.center[0],3), round(ligand.center[1],3), round(ligand.center[2],3))
        ligand.center = autocenterlig
        self.adjustSideLengths(ligand)
        self.setCenter(ligand)
        if self.vf.hasGui:
            if hasattr(self, 'form') and not self.form.root.winfo_ismapped():
                self.spacing.set(self.vf.gpo['spacing']['value'])
                self.nxpts.set(ligand.npts[0])
                self.nypts.set(ligand.npts[1])
                self.nzpts.set(ligand.npts[2])
            if self.ifd.entryByName.has_key('Auto Lig Center'):
                self.ifd.entryByName['Auto Lig Center']['widget'].toggle()


    # enforces AutoDock grid number of points requirements:
    #   In each dimension x,y,z 
    #       0. Number of pts can be different (eg nptx!=npty etc)
    #       1. Number of pts must be even
    #       2. Number of pts must be 126 or fewer
    def adjustSideLengths(self, ligand):
        #attempts to resize box to fit ligand
        #NB npts gets set by call to getSideLengths in InitLigand
        ss = ligand.npts
        llist2=['nxpts','nypts','nzpts']
        for i in range(3):
            ceiling=int(math.ceil(ss[i]))
            if ceiling%2==1: ceiling=ceiling+1
            if ceiling>=127: ceiling=126
            val = eval('self.'+ llist2[i]+'.get()')
            if ceiling>val:
                eval('self.'+ llist2[i]+'.set(ceiling)')
        self.updateTotalPtsVar()
        #for some reason, have to do a print to get desired result
        print ' '


    # center on autodock macromolecule
    def autoCenter(self, event=None):
        #called from 'Center on macromolecule' button in Center menu
        self.gridCenterType = 'auto'
        self.findAutoMacroCenter()
        self.zeroOffsets()
        self.cenVal.set(-1)


    def findAutoMacroCenter(self):
        if not hasattr(self.vf.gpo, 'receptor'):
            self.vf.warningMsg(' no current macromolecule')
            if self.ifd.entryByName.has_key('Auto Center'):
                self.ifd.entryByName['Auto Center']['widget'].toggle()
            return
        receptor = self.vf.gpo.receptor 
        self.setCenter(receptor)
        if self.vf.hasGui:
            if self.ifd.entryByName.has_key('Auto Center'):
                self.ifd.entryByName['Auto Center']['widget'].toggle()


    # center on atom found from its full name: 1crn: :THR1:N
    def updateCenFromName(self, event=None):
        #called from 'Center on named atom' button in Center menu
        self.gridCenterType = 'set'
        ifd = InputFormDescr(title= 'Center on Named Atom')
        ifd.append({'name':'cenName',
            'widgetType':Tkinter.Entry,
            'wcfg':{
                'label':'enter full name of atom:',
                'textvariable':self.nameCen.get()},
            'gridcfg':{'sticky':Tkinter.E,'columnspan':2}}),
        vals = self.vf.getUserInput(ifd)
        if vals is not None and len(vals):
            cenName = vals['cenName']
            self.nameCen.set(cenName)
            atList=self.vf.Mols.NodesFromName(cenName)
            cenAtom=atList[0]
            self.vf.ADgpf_selectCenter(cenAtom)
            # because xCen,yCen+zCen are set don't have to call updateCoords
            # can just updateBox geometry
            self.updateBox()
        else:
            #toggle menu entry 
            self.cenVal.set(0)
        self.cenVal.set(-1)


    # center on coords entered in entries
    def setCenter(self, mol):
        #called from hitting "<Return>" in one of _cen entries
        if not hasattr(mol, 'center'):
            mol.getCenter()
        v = mol.center
        centerL = []
        for item in v:
            centerL.append(round(item,3))
        self.gridcenter = centerL
        cen = centerL
        #cen = mol.center
        #self.gridcenter = cen
        if self.vf.hasGui:
            self.xCen.set(str(cen[0]))
            self.yCen.set(str(cen[1]))
            self.zCen.set(str(cen[2]))
            cenSph.Set(vertices=(cen,))
            cenSph.Set(visible=0)
            cenCross.Set(vertices=(cen,),visible=1)
            #cenCross.Set(visible=1)
            box.Set(visible=1)
            self.showBox.set(1)
            # because xCen,yCen+zCen are set don't have to call updateCoords
            # can just updateBox geometry
            self.updateBox()
            self.vf.GUI.VIEWER.Redraw()
            self.cenVal.set(-1)
        

    #------------------------------------------------------------------
    # OFFSET METHODS:
    #       changes in offset change coords of center and center entries
    #       this forces update of Box geometry and center marker
    #------------------------------------------------------------------
    

    # set all three offset thumbwheels back to 0
    def zeroOffsets(self):
        #called whenever center is changed
        for item in [self.xwheel, self.ywheel, self.zwheel]:
            item.set(0)


    def set_xoffset(self, val):
        # callback for xoffset Thumbwheel
        newval = float(val)
        _newval = round((newval-self.oldx)+float(self.xCen.get()), 3)
        self.oldx = newval
        self.xCen.set(str(_newval))
        #this changes center so call updateCoofds
        self.updateCoords()
        

    def set_yoffset(self, val):
        # callback for yoffset Thumbwheel
        newval = float(val)
        _newval = round((newval-self.oldy)+ float(self.yCen.get()), 3)
        self.oldy = newval
        self.yCen.set(str(_newval))
        #this changes center so call updateCoofds
        self.updateCoords()
        

    def set_zoffset(self, val):
        # callback for zoffset Thumbwheel
        newval = float(val)
        _newval = round((newval-self.oldz)+float(self.zCen.get()), 3)
        self.oldz = newval
        self.zCen.set(str(_newval))
        #this changes center so call updateCoofds
        self.updateCoords()
        


    #------------------------------------------------------------------
    # CHANGED CENTER -> 
    #                   update COORDS ->
    #                                   update BOX GEOMETRY
    #------------------------------------------------------------------


    # changing centering method, center ipso, its coords or its offset
    # triggers this:
    def updateCoords(self, event=None):
        try:
            self.gridcenter = (round(float(self.xCen.get()),3), round(float(self.yCen.get()),3),round(float(self.zCen.get()),3))
            #also make sure auto is turned off
            self.gridCenterType = 'set'
            self.updateBox()
        except ValueError:
            pass



    #------------------------------------------------------------------
    # CHANGING BOX DIMENSIONS:
    #       spacing * number of points => length of side
    #       changing either one forces updateBox
    #------------------------------------------------------------------


    #------------------------------------------------------------------
    # TOTAL POINTS METHODS to maintain label showing total:
    #------------------------------------------------------------------


    #updates label on widget showing current nxpts*nypts*nzpts
    def updateTotalPtsVar(self):
        nxpts=int(self.nxpts.get())+1
        nypts=int(self.nypts.get())+1
        nzpts=int(self.nzpts.get())+1
        self.totalPtsVar.set('Current Total Grid Pts per map: %8s'%str(nxpts*nypts*nzpts))


    #------------------------------------------------------------------
    # CHANGED NUMBER of POINTS -> 
    #                   update BOX GEOMETRY
    #                   update TOTALPTS LABEL  
    #------------------------------------------------------------------


    # changes in number of points requires updating both
    # the total points AND the box
    def updateBoth(self, event=None):
        self.updateBox()
        self.updateTotalPtsVar()



    #------------------------------------------------------------------
    # BOX GEOMETRY UPDATE METHOD:
    #       NB: changing spacing calls this directly
    #------------------------------------------------------------------


    def updateBox(self, event=None):
        if self.gridcenter == 'auto':
            if hasattr(self.vf.gpo, 'receptor'):
                v = self.vf.gpo.receptor.center
                vL = []
                for item in v:
                    vL.append(round(item,3))
                self.gridcenter = vL
                #self.gridcenter = self.vf.gpo.receptor.center
            else:
                self.vf.warningMsg('no receptor specified')
                self.gridcenter = (0,0,0)
        if not self.showBox.get(): return
        spacing = self.spacewheel.get()
        xnum = self.nxpts.get()
        ynum = self.nypts.get()
        znum = self.nzpts.get()
        #xlen = spacing*xnum
        #ylen = spacing*ynum
        #zlen = spacing*znum
        xlen = round(spacing*xnum, 4)
        ylen = round(spacing*ynum, 4)
        zlen = round(spacing*znum, 4)
        c = self.gridcenter
        pts = [ (c[0]+xlen*0.5, c[1]+ylen*0.5, c[2]-zlen*0.5),
                    (c[0]-xlen*0.5, c[1]+ylen*0.5, c[2]-zlen*0.5),
                    (c[0]-xlen*0.5, c[1]-ylen*0.5, c[2]-zlen*0.5),
                    (c[0]+xlen*0.5, c[1]-ylen*0.5, c[2]-zlen*0.5),
                    (c[0]+xlen*0.5, c[1]+ylen*0.5, c[2]+zlen*0.5),
                    (c[0]-xlen*0.5, c[1]+ylen*0.5, c[2]+zlen*0.5),
                    (c[0]-xlen*0.5, c[1]-ylen*0.5, c[2]+zlen*0.5),
                    (c[0]+xlen*0.5, c[1]-ylen*0.5, c[2]+zlen*0.5)
                    ]
        box.vertexSet.vertices.array[:] = pts
        box.RedoDisplayList()
        #box.Set(center=self.gridcenter, xside=xlen, yside=ylen, zside=zlen)
        cenCross.Set(vertices=(tuple(self.gridcenter),))
        self.vf.GUI.VIEWER.Redraw()



    #------------------------------------------------------------------
    # VISIBILITY METHODS CALLED FROM MENU:
    #------------------------------------------------------------------


    # link from buttons in menu to various visibility methods below
    # visiDict and visiOpts set up in onAddCmdToViewer
    def setVisiVal(self, val, event=None):
        # do something here
        opt = self.visiOpts[val]
        f = self.visiDict[opt]
        apply(f, (),{})


    def adjustMarker(self, event=None):
        newval = tkSimpleDialog.askfloat('Set Marker Length', 'Enter new marker length', 
                initialvalue = cenCross.offset,
                minvalue=.1, maxvalue=10)
        if not newval: return
        cenCross.Set(offset=newval)
        self.vf.GUI.VIEWER.Redraw()
        self.adjustCross.set(0)


    def showCenterCross(self, event=None):
        cenCross.Set(visible=self.showCross.get())
        self.vf.GUI.VIEWER.Redraw()


    def updateGridBox(self, event=None):
        box.Set(inheritFrontPolyMode = False)
        if self.showBoxMode.get():
            #box.RenderMode(GL.GL_LINE, face=GL.GL_FRONT)
            box.Set(frontPolyMode=GL.GL_LINE)
        else:
            #box.RenderMode(GL.GL_FILL, face=GL.GL_FRONT)
            box.Set(frontPolyMode=GL.GL_FILL)
        self.vf.GUI.VIEWER.Redraw()


    def showGridBox(self,event=None):
        if self.showBox.get():
            self.updateBox()
            box.Set(visible=1)
            cenSph.Set(visible=0)
        else:
            box.Set(visible=0)
            cenSph.Set(visible=0)
        cenCross.Set(visible=self.showCross.get())
        self.vf.GUI.VIEWER.Redraw()


    #------------------------------------------------------------------
    # GPO UPDATE METHOD:
    #                   -> record any changed values in self.vf.gpo
    #                       via call to doit (and log changes)
    #------------------------------------------------------------------


    def __call__(self, gridcenter=(0.,0.,0.), npts=(40,40,40),\
            spacing=.375, **kw):
        # cannot set these defaults to values in self.vf.gpo
        kw['gridcenter'] = gridcenter
        kw['npts'] = npts
        kw['spacing'] = spacing
        kw['topCommand'] = 0
        apply(self.doitWrapper,(), kw)


    def doit(self, *args, **kw):
        changeVals = {}
        gridcenter = kw['gridcenter']
        npts = kw['npts']
        spacing = kw['spacing']
        #update the receptor for possible ADVS usage
        if hasattr(self.vf.gpo, 'receptor'):
            mol = self.vf.gpo.receptor
            mol.gridcenter = gridcenter
            mol.npts = npts
            mol.spacing = spacing
        #check for changes:
        for item in ['gridcenter', 'npts','spacing']:
            if self.vf.gpo[item]['value'] != eval(item):
                changeVals[item] = eval(item)
        if self.vf.hasGui:
            if changeVals.has_key('gridcenter'):
                if changeVals['gridcenter']=='auto':
                    changeVals['gridcenterAuto'] = 1
                    if hasattr(self.vf.gpo, 'receptor'):
                        v = self.vf.gpo.receptor.center
                        gridcenter = [round(v[0],3),round(v[1],3),round(v[2],3)]
                    else:
                        gridcenter = (0., 0., 0.)
                else:
                    changeVals['gridcenterAuto'] = 0
                self.xCen.set(gridcenter[0])
                self.yCen.set(gridcenter[1])
                self.zCen.set(gridcenter[2])
            if changeVals.has_key('npts'):
                self.nxpts.set(npts[0])
                self.nypts.set(npts[1])
                self.nzpts.set(npts[2])
            self.updateCoords()
        if len(changeVals.items()):
            apply(self.vf.ADgpf_setGpo, (), changeVals)
        

SetBoxParametersGUI= CommandGUI()
SetBoxParametersGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['SetGridMB'])



class SetOtherOptions(MVCommand):
    """ allows user to set smooth factor, whether to calculate
        floating point and electrostatic maps AND whether to 
        use a constant or a distance-dependent dielectric constant"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)
        if self.vf.hasGui:
            self.smoothVal = Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.constDiel = Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.MakeFmap = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.DDDielConst = Tkinter.IntVar(master=self.vf.GUI.ROOT)


    def guiCallback(self):
        """called each time the 'set other options ' button is pressed"""
        if not hasattr(self, 'form'):
            self.buildForm()
            self.form = self.vf.getUserInput(self.ifd, modal=0, blocking=0)
            self.form.root.protocol('WM_DELETE_WINDOW',self.Close_cb)
        else:
            self.form.deiconify()
        self.updateValues()


    def buildForm(self):
        ifd = self.ifd = InputFormDescr(title = "Autogpf Options")
        ifd.append( {'name': 'smooth',
            'widgetType':Tkinter.Entry,
            'wcfg':{
                'label': 'SmoothFactor(Angstrom)\n(Radius w/in which to Store Minimum Energy)',
                'textvariable': self.smoothVal
            },
            'gridcfg':{'sticky':Tkinter.W,'columnspan':2}})
        ifd.append({'name': 'YesNo',
            'widgetType':Tkinter.Label,
            'text': 'Yes             No',
            'gridcfg':{'sticky':Tkinter.E, 'columnspan':2}})
        ifd.append({'name': 'FMapLabel',
            'widgetType':Tkinter.Label,
            'text': 'Floating\nPotential Map?',
            'gridcfg':{'sticky':Tkinter.W}})
        ifd.append({'name': 'FMap',
            'widgetType':Tkinter.Radiobutton,
            'wcfg': {'value':1},
            'variable': self.MakeFmap,
            'gridcfg':{'sticky':Tkinter.W, 'row':-1,'column':1}})
        ifd.append({'name': 'NoFMap',
            'widgetType':Tkinter.Radiobutton,
            'wcfg': {'value':0},
            'variable': self.MakeFmap,
            'gridcfg':{'sticky':Tkinter.W, 'row':-1,'column':2}})
        ifd.append({'name': 'DDCONSLabel',
            'widgetType':Tkinter.Label,
            'text': 'Distance Dependent\nDielectric Constant?',
            'gridcfg':{'sticky':Tkinter.W}})
        ifd.append({'name': 'DDConst',
            'widgetType':Tkinter.Radiobutton,
            'wcfg': {'value':1},
            'variable': self.DDDielConst,
            'gridcfg':{'sticky':Tkinter.W, 'row':-1,'column':1},
            'command': self.getDielConst })
        ifd.append({'name': 'NoDDConst',
            'widgetType':Tkinter.Radiobutton,
            'wcfg': {'value':0},
            'variable': self.DDDielConst,
            'gridcfg':{'sticky':Tkinter.W, 'row':-1,'column':2},
            'command': self.getDielConst })
        ifd.append({'name': 'dielConstLabel',
            'widgetType':Tkinter.Label,
            'text': 'Enter Dielectric Constant:',
            'gridcfg':{'sticky':Tkinter.W, 'row':6, 'column':0}})
        ifd.append( {'name': 'dielConst',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'textvariable': self.constDiel},
            'gridcfg':{'sticky':Tkinter.W, 'row':6, 'column':1}})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Accept',
            'wcfg':{'bd':6},
            'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'columnspan':2},
            'command':self.Accept_cb})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Close',
            'wcfg':{'bd':6},
            'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'column':2,'row':-1},
            'command':self.Close_cb})
    

    def Close_cb(self, event=None):
        self.form.withdraw()


    def Accept_cb(self, event=None):

        changeVals = {}

        changeVals['smooth'] = float(self.smoothVal.get())
        changeVals['fmap'] =  self.MakeFmap.get()

        #distance-dep dielectric is <0 and dielNeg = 1
        #constant dielectric >0 and dielNeg=0
        dielNeg = self.DDDielConst.get()
        consD = float(self.constDiel.get())
        if self.DDDielConst.get() == 1:
            changeVals['dielectric'] = -.1146
        else: 
            changeVals['dielectric'] = consD

        changeVals['topCommand'] = 0
        apply(self.doitWrapper,(), changeVals)
        self.form.withdraw()

    def updateValues(self, event=None):
        self.smoothVal.set(str(self.vf.gpo['smooth']['value']))
        self.MakeFmap.set(self.vf.gpo['fmap']['value'])
        self.DDDielConst.set(self.vf.gpo['dielectric']['value']<0)
        self.constDiel.set(str(self.vf.gpo['dielectric']['value']))
        self.getDielConst()


    def getDielConst(self, event=None):
        w=self.ifd.entryByName['dielConst']
        w2=self.ifd.entryByName['dielConstLabel']
        if self.DDDielConst.get():
            w2['widget'].grid_forget()
            w['widget'].grid_forget()
            self.constDiel.set('-.1146')
        else:
            w2['widget'].grid(w2['gridcfg'])
            w['widget'].grid(w['gridcfg'])
            self.constDiel.set('40')


    def __call__(self, smooth=0.5, fmap=0, dielectric=-.1146, **kw):
        kw['topCommand'] = 0
        apply(self.doitWrapper,(smooth, fmap, dielectric), kw)


    def doit(self, smooth, fmap, dielectric):
        changeVals = {}
        for item in ['smooth', 'fmap','dielectric']:
            if self.vf.gpo[item]['value'] != eval(item):
                changeVals[item] = eval(item)

        if len(changeVals.items()):
            apply(self.vf.ADgpf_setGpo,(), changeVals)


SetOtherOptionsGUI= CommandGUI()
SetOtherOptionsGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['SetOtherOptionsMB_AG3'], cascadeName = menuText['SetOtherOptionsMB'])



class Gpf4ParameterFileSelector(MVCommand):
    """ allows user to select a filename for the parameter file"""

    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'select parameter filename ' button is pressed"""
        paramFile = self.vf.askFileOpen(types=[('AD4 parameter files', '*.dat')],
                title = 'AD4 Parameter File:')
        if paramFile:
            filename=os.path.basename(paramFile)
            self.doitWrapper(paramFile,log=1,redraw=0)


    def __call__ (self, paramFile, **kw):
        """None<-ADgpf4_setParameterFilename
        paramFile file for autodock4
"""
        if not os.path.exists(paramFile):
            raise IOError
        apply(self.doitWrapper,(paramFile,),kw)


    def doit(self, paramFile):
        filename = os.path.basename(paramFile)
        self.vf.gpo['custom_parameter_file']['value'] = 1
        self.vf.gpo['parameter_file']['value'] = filename


Gpf4ParameterFileSelectorGUI=CommandGUI()
Gpf4ParameterFileSelectorGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
menuText['SetParameterFilename'], cascadeName = menuText['SetOtherOptionsMB'],\
    separatorBelow=1)



class Gpf4ParameterFileEditor(MVCommand):
    """ allows user to customize a parameter file """


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'edit parameter filename ' button is pressed"""
        paramFile = self.vf.askFileOpen(types=[('AD4 parameter files', '*.dat')],
                title = 'AD4 Parameter File:')
        if paramFile:
            filename=os.path.basename(paramFile)
            self.doitWrapper(paramFile,log=1,redraw=0)



    def __call__ (self, paramFile, **kw):
        """None<-ADgpf4_editParameterFile
        paramFile file for autodock4
"""
        if not os.path.exists(paramFile):
            raise IOError
        apply(self.doitWrapper,(paramFile,),kw)


    def doit(self, paramFile):
        fptr=open(paramFile,'r')
        allLines=fptr.readlines()
        ss=''
        for item in allLines:
            ss=ss+item
        titleStr = 'Edit AutoDock Parameter File'
        self.ifd = ifd  = InputFormDescr(title = titleStr)
        ifd.append({'name': 'pfText',
            'size':[85,30],
            'label':paramFile,
            'defaultValue':ss,
            'widgetType':'ScrolledText',
            'writeFileType': [('AD Parameter Files','*.dat')],
            'readFileType': [('AD Parameter Files','*.dat')],
            'readButton':1,'writeButton':1})
        vals = self.vf.getUserInput(ifd)
        if len(vals)==0:
            return
        #should this also set these?
        #filename = os.path.basename(paramFile)
        #self.vf.gpo['custom_parameter_file']['value'] = 1
        #self.vf.gpo['parameter_file']['value'] = filename


Gpf4ParameterFileEditorGUI=CommandGUI()
Gpf4ParameterFileEditorGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
menuText['EditParameterFile'], cascadeName = menuText['SetOtherOptionsMB'],\
    separatorBelow=1)



class GpfMergeNonPolarHs(MVCommand):
    """ this command is left here until everyone can update his scripts"""


    def onAddCmdToViewer(self):
        if self.vf.hasGui:
            for item in ['readMolecule','writePDBQ','writePDBQS']:
                if not hasattr(self.vf, item):
                    self.vf.loadCommand('fileCommands', item, 'Pmv')
        self.vf.loadModule('editCommands','Pmv')
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'Merge NonPolar Hydrogens' button is pressed"""
        t= 'Is Molecule already in the viewer?'
        d=SimpleDialog(self.vf.GUI.ROOT, text=t, buttons=['Yes','No'], default=0,title='Select Molecule')
        ok = d.go()
        if ok ==0:
            self.chooser = MoleculeChooser(self.vf, 'single', 'Choose Macromolecule')
            self.chooser.ipf.append({'name':'Select Button',
                                 'widgetType':Tkinter.Button,
                                 'text':'Select Molecule',
                                 'wcfg':{'bd':6},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W},
                                 'command': self.chooseMolecule_cb})
            self.form = self.chooser.go(modal=0, blocking=0)
            lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb
            lb.bind("<Double-Button-1>", self.chooseMolecule_cb)
        else:
            macroFile = self.vf.askFileOpen(types=[('PDBQS files','*.pdbqs'),('PDBQ files', '*.pdbq')],
                title = 'Macromolecule File (with NonPolarHydrogens):')
            if macroFile:
                mol= self.vf.readMolecule(macroFile,topCommand=0)[0]
                if not mol.chains[0].hasBonds:
                    mol.buildBondsByDistance()
                    self.vf.centerScene(topCommand=0)
                self.vf.displayLines(mol,topCommand=0)
                self.doitWrapper(mol,log=1,redraw=1)


    def chooseMolecule_cb(self, event = None):
        """called each time the 'choose Molecule' button is pressed"""
        mols = self.chooser.getMolSet()
        if not mols: return
        if issubclass(mols.__class__, TreeNode):
            mols = mols.setClass([mols])
        mol = mols[0]
        try:
            self.chooser.form.withdraw()
        except: 
            pass
        self.doitWrapper(mol, outfile=None, showMsg=1, log=1, redraw=0)


    def __call__(self, mol, outfile=None, showMsg=1, **kw):
        kw['outfile'] = outfile
        kw['showMsg'] = showMsg
        apply(self.doitWrapper,(mol,),kw)


    def doit(self, mol, **kw):
        outfile = kw['outfile']
        showMsg = kw['showMsg']

        for at in mol.allAtoms:
            if not hasattr(at, 'autodock_element'):
                at.autodock_element = at.element

        ats = mol.allAtoms

        if self.vf.hasGui:
            self.vf.mergeNPHSGC(mol)
        else:
            self.vf.mergeNPHS(mol)

        #then write it out
        if outfile == -1:
            return 
        if not outfile and self.vf.hasGui:
            #FIX ME! give highest possible pdbqs type....
            if hasattr(mol.allAtoms[0],'AtSolPar'):
                types=[('PDBQS files', '*.pdbqs'),('PDBQ files', '*.pdbq')]
            else:
                types=[('PDBQ files', '*.pdbq')]
            outfile = self.vf.askFileSave(types=types,
                title = 'Merged Non-Polar Macromolecule File:')

        if not outfile:
            return 'ERROR'

        ftype= split(outfile, '.')[-1]
        if ftype=='pdbqs':
            self.vf.writePDBQS( mol.allAtoms, filename=outfile, 
                                pdbRec=['ATOM','HETATM'],
                                bondOrigin=[],
                                topCommand=0)
        elif ftype=='pdbq':
            self.vf.writePDBQ( mol.allAtoms, filename=outfile, 
                                pdbRec=['ATOM','HETATM'],
                                bondOrigin=[],
                                topCommand=0)
        else:
            self.vf.warningMsg(messages['nphsOutExt'])



#####FOR AUTOGRID4#####        
class Gpf4SetMapTypes(MVCommand):
    """ allows user to enter types of maps to be calculated, directly"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)
        if self.vf.hasGui:
            self.gtypes= Tkinter.StringVar(master=self.vf.GUI.ROOT)
            self.gtypes.set(self.vf.gpo['ligand_types']['value'])


    def guiCallback(self):
        if not hasattr(self, 'form'):
            self.buildForm()
        else:
            self.form.deiconify()


    def buildForm(self):
        self.gtypes.set(self.vf.gpo['ligand_types']['value'])
        ifd = self.ifd = InputFormDescr(title = "AutoGpf4 Ligand")
        ifd.append( {'name': 'MapTypesEntry',
            'widgetType':Tkinter.Entry,
            'wcfg': {
                'label': 'Map Types:',
                'textvariable': self.gtypes,
                'eventType':'<Key>'
             },
            'gridcfg':{'sticky':Tkinter.W,'columnspan':4}})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Accept',
            'wcfg':{'bd':4},
            'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'columnspan':2},
            'command':self.Accept_cb})
        ifd.append({'widgetType': Tkinter.Button,
            'text':'Close',
            'wcfg':{'bd':4},
            'gridcfg':{'sticky':Tkinter.E+Tkinter.W, 'column':2, 'row':-1},
            'command':self.Close_cb})
        self.form = self.vf.getUserInput(self.ifd, modal=0, blocking=0)
        self.form.root.protocol('WM_DELETE_WINDOW',self.Close_cb)
    

    def Close_cb(self, event=None):
        self.form.withdraw()


    def Accept_cb(self, event=None):
        typeString = self.gtypes.get()
        kw={}
        kw['topCommand'] = 0
        apply(self.doitWrapper, (typeString,), kw)
        self.form.withdraw()


    def __call__(self, typeString, **kw):
        """None<-mv.ADgpf4_setMapTypes(typeString)
typeString: string listing types of maps to calculate, eg 'C NA N OA SA HD'
"""
        apply(self.doitWrapper,(typeString,), kw)


    def doit(self, typeString):
        changeVals = {}
        changeVals['ligand_types'] = typeString
        changeVals['topCommand'] = 1
        #L1. set LIGAND_TYPES directly
        self.vf.GPF_LIGAND_TYPES = typeString.split()
        apply(self.vf.ADgpf_setGpo, (), changeVals)
        

Gpf4SetMapTypesGUI= CommandGUI()
Gpf4SetMapTypesGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
    menuText['SetMapDirectly4'], cascadeName = menuText['SetMapTypesMB'])



class Gpf4SetAtomTypes(MVCommand):
    """command to set AutoDock4 atom types for a molecule
        autodock_element is set...
    """


    def __call__(self, mol,  **kw):
        """ad4_types <- ADgpf4_setAtomTypes(mol)           
mol: molecule whose atoms are to be assigned autodock_elements for AutoDock4
ad4_type_str: string built of unique list of types in the mol
        """
        mols = self.vf.expandNodes(mol)
        if not mols:
            return 'ERROR'
        if mols.__class__!=mols.top.__class__:
            mols = mols.top.uniq()
        return apply(self.doitWrapper,(mols[0],), kw)


    def doit(self, mol, **kw):
        #results in addition of  autodock_element to each atom
        msg = 'setting autodock types for ' + os.path.basename(mol.parser.filename) + ':\n'
        #check if this is from a pdbqt file by grabbing last char of filename
        #extension: mol2 or pdb or pdbq or pdbqs or pdbqt
        ad4_typer = AutoDock4_AtomTyper()
        ad4_typer.setAutoDockElements(mol)
        dict = {}
        for a in mol.allAtoms:
            if hasattr(a, 'autodock_element'):
                dict[a.autodock_element] = 1
            elif a.element=='H':
                a.autodock_element='HD'
                dict[a.autodock_element] = 1
            else:
                print "forcing ", a.full_name, " autodock_element to ", a.element
                a.autodock_element=a.element
                dict[a.autodock_element] = 1
        adtypes = dict.keys()
        adtypes.sort()
        mol.types = adtypes
        type_str = mol.types[0]
        for t in mol.types[1:]:
            type_str = type_str + " " + t
        return type_str


    def guiCallback(self):
        sel = self.vf.getSelection()
        if not len(sel):
            self.warningMsg('no molecules in viewer')
            return
        sel = sel.top.uniq()
        for mol in sel:
            self.doitWrapper(mol, log=1, redraw=0)



Gpf4SetAtomTypesGUI= CommandGUI()
Gpf4SetAtomTypesGUI.addMenuCommand('menuRoot', 'Edit','Assign AD4 type', cascadeName = 'Atoms')


class AutoGpf4MacroSetup(MVCommand):
    """performs default actions on designated molecule"""

    def onAddCmdToViewer(self):
        self.receptor = None
        if self.vf.hasGui:
            self.inviewer = Tkinter.IntVar(master=self.vf.GUI.ROOT)
            self.outfileVar = Tkinter.StringVar(master=self.vf.GUI.ROOT)

    def onRemoveObjectFromViewer(self, obj):
        if obj==self.receptor:
            self.receptor = None

    def guiCallback(self):
        if not hasattr(self, 'ifd'):
            self.inviewer.set(2)
            self.buildForm()
        else:
            self.inviewer.set(2)
            self.outfileVar.set('')
            self.form.deiconify()


    def buildForm(self):
        ifd = self.ifd = InputFormDescr(title = 'Automatic Receptor-Setup Parameters')
        ifd.append({'name': 'typeMolLab',
            'widgetType':Tkinter.Label,
            'text':'molecule location:',
            'gridcfg':{'sticky':'w'}})
        ifd.append({'name':    'pickMol',
            'widgetType':Tkinter.Radiobutton,
            'wcfg':{'text':'in viewer',
                    'variable':self.inviewer,
                    'value':0, 
                    'command':self.chooseMol},
            'gridcfg':{'sticky':'w','row':-1,'column':1}})
        ifd.append({'name':    'readMol',
            'widgetType':Tkinter.Radiobutton,
            'wcfg':{'text':'from file',
                    'variable':self.inviewer,
                    'value':1, 
                    'command':self.readMol},
            'gridcfg':{'sticky':'w','row':-1,'column':2}})
        ifd.append({'name':'outputFile',
            'widgetType':Tkinter.Entry,
            'wcfg':{
                'label': 'Output filename:',
                'width': 50,
                'textvariable':self.outfileVar},
            'gridcfg':{'sticky':'w','columnspan':4}})
        ifd.append({'name':    'goBut',
            'widgetType':Tkinter.Button,
            'wcfg':{'text':'Accept',
                    'command':self.go_cb}, 
            'gridcfg':{'sticky':'we', 'columnspan':2}})
        ifd.append({'name':    'closeBut',
            'widgetType':Tkinter.Button,
            'wcfg':{'text':'Cancel',
                    'command':self.cancel_cb}, 
            'gridcfg':{'sticky':'we','row':-1,'column':2}})
        self.form = self.vf.getUserInput(self.ifd, modal=0, blocking=0)
        self.form.root.protocol('WM_DELETE_WINDOW',self.cancel_cb)
            

    def cancel_cb(self, event=None):
        self.form.withdraw()


    def go_cb(self, event=None):
        if not self.receptor:
            if not self.inviewer.get():
                self.readMol()
            else:
                self.chooseMol()
        self.doitWrapper(self.receptor,
                outfile=self.outfileVar.get(), 
                ask_outfile=0)
        

    def chooseMol(self, event=None):
        self.chooser = MoleculeChooser(self.vf, 'single', 'Choose Receptor')
        self.chooser.ipf.append({'name':'Select Button',
             'widgetType':Tkinter.Button,
             'text':'Select Molecule',
             'wcfg':{'bd':6},
             'gridcfg':{'sticky':'e'+'w'},
             'command': self.chooseMolecule_cb})
        self.form2 = self.chooser.go(modal=0, blocking=0)
        lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb
        lb.bind("<Double-Button-1>", self.chooseMolecule_cb)


    def readMol(self, event=None):
        receptor = self.vf.askFileOpen(types=[('MOL2 files', '*.mol2'),
            ('PDB files','*.pdb'), ('all files', '*')], title = 'Receptor File:')
        if receptor:
            self.vf.readMolecule(receptor)
            mol = self.vf.Mols[-1]
            if not mol.chains[0].hasBonds: 
                mol.buildBondsByDistance()
            self.receptor = mol
            filename=os.path.split(receptor)[-1]
            ftype = split(receptor,'.')[-1]
            outfile = None
            if self.vf.hasGui and hasattr(self, 'outfileVar'):
                nameStr = mol.name + '_rec.pdbqt'
                self.outfileVar.set(nameStr)
                outfile = nameStr
            #could it be some other type??? sdf???
            if ftype not in ['pdbq','mol2','pdb','pqr','pdbqt']:
                t= "file must be of type: pdb, pdb, mol2, pqr, pdbq, pdbqt"
                self.vf.warningMsg(t)
                return 'ERROR'
        else: self.receptor=None


    def chooseMolecule_cb(self, event = None):
        """called each time the molecule to be processed is already in viewer"""
        mols = self.chooser.getMolSet()
        if not mols: return
        if issubclass(mols.__class__, TreeNode):
            mols = mols.setClass([mols])
        mol = mols[0]
        if self.vf.hasGui and hasattr(self, 'outfileVar'):
            nameStr = mol.name + '.out.pdbqt'
            self.outfileVar.set(nameStr)
        self.receptor = mol
        self.chooser.form.withdraw()
        stem = mol.name
        filename = stem + "_rec.pdbqt"
        self.outfileVar.set(filename)


    def __call__(self, mol, outfile=None, ask_outfile=1, **kw):
        """None<- ADgpf4_automaticReceptorFormatting
mol: molecule to be receptor
outfile: name of file for formatted pdbqt output
ask_outfile: whether to ask the user about output filename
By default ask is equal to 1 which opens a dialog box to get 
user input for outfilename
if ask_outfile=0, outputfile name is name of molecule + '.out.pdbqt'
"""
        kw['outfile'] = outfile
        kw['ask_outfile'] = ask_outfile
        apply(self.doitWrapper, (mol,), kw)


    def doit(self, mol, **kw):
        outfile = kw['outfile']
        ask_outfile = kw['ask_outfile']
        if hasattr(self, 'form'):
            self.form.withdraw()
        dict = self.vf.atorsDict
        if type(mol)==types.StringType:
            if len(self.vf.Mols) and mol in self.vf.Mols.name:
                mol = self.vf.Mols.NodesFromName(mol)
            else:
                mol = self.vf.readMolecule(mol)
        if issubclass(mol.__class__, TreeNode):
            mol = mol.setClass([mol])
        assert isinstance(mol, TreeNodeSet)
        mol = mol[0]
        mol.getCenter()
        self.vf.gpo.receptor = mol 
        #self.vf.ADgpf4_initMacro(mol)
        apply(self.vf.ADgpf4_initMacro, (mol,), kw)
         
#AutoGpf4MacroSetupGUI=CommandGUI()
#AutoGpf4MacroSetupGUI.addMenuCommand('AutoToolsBar', menuText['AutoTorsMB'], \
#menuText['AutomaticAutotorsSetupMB'], cascadeName = menuText['Input Molecule'])



class Gpf4MacroInit(MVCommand):
    """receptor is initialized as specified in parameters:
            whether receptor is a protein is determined
            if molecule is lacking charges or if charges are all 0.
                Gasteiger charges are added to receptors
            a check is made that total charge per residue is an integer.
            lone pairs merged
            non-polar hydrogens merged unless userpref set not to merge
            macro sidelengths set (???????????)
            autodock_element is set...
            receptor is colored by Atom Type"""


    def onRemoveObjectFromViewer(self, obj):
        if hasattr(self.vf.gpo, 'receptor') and obj==self.vf.gpo.receptor:
            self.vf.gpo.receptor = None


    def onAddCmdToViewer(self):
        #R0: initialize GPF_RECEPTOR_TYPES
        self.vf.GPF_RECEPTOR_TYPES = []
        if self.vf.hasGui:
            for item in ['writePDBQT']:
                if not hasattr(self.vf, item):
                    self.vf.loadCommand('fileCommands', item, 'Pmv')
            self.vf.loadModule('colorCommands','Pmv')
        if not hasattr(self.vf, 'editHist_h'):
            self.vf.loadCommand('repairCommands', 'editHist_h', 'Pmv')
        self.vf.loadModule('editCommands','Pmv')

        checkHasGpo(self.vf)
        self.resKeys = q.keys()
        self.editHISprotonation = None
        if 'Automerge NPHS' not in self.vf.userpref.keys():
            doc = """Automatically merge non-polar hydrogens in macromolecule. Valid values are 1 or 0"""
            self.vf.userpref.add('Automerge NPHS', 1, [1,0],
                callbackFunc = [set_autoMergeNPHS], doc=doc, category='AutoDockTools')
        if 'HIS Protonation' not in self.vf.userpref.keys():
            doc = """Automatically set protonation state of all histidine residues in macromolecule. Valid values are 'HD1', 'HE2', 'HD1HE2', 'No change'.  Default value is 'No change' which has no effect on macromolecule. Any other choice invokes editHist_h method of repairCommand module to edit hydrogens on histidine ring. For example, if userpref is set to 'HD1' each histidine ring will have hydrogen atom 'HD1' and not 'HE2' hydrogen atom."""
            self.vf.userpref.add('HIS Protonation', 'No change', 
                    ['No change', 'HD1', 'HE2', 'HD1HE2'],
                    callbackFunc = [self.set_editHISprotonation], doc=doc ,
                    category='AutoDockTools')
        else:
            self.editHISprotonation = self.vf.ADgpf_initMacro.editHISprotonation


    def set_editHISprotonation(self, name, oldval, newval):
        self.editHISprotonation = newval
        self.vf.ADgpf_initMacro.editHISprotonation = newval


    def checkIsPeptide(self, resSet):
        #check whether each restype is in std list
        #if so, mol is a peptide
        dict = {}
        for r in resSet:
            dict[r.type] = 0
        for t in dict.keys():
            if t not in self.resKeys:
                return 0
        #only get to this point if all
        #residue types were found
        return 1


    def __call__(self, mol, filename=None, **kw):
        """ADgpf4_initMacro"""
        mols = self.vf.expandNodes(mol)
        if not mols:
            return 'ERROR'
        #kw should be mol and possibly filename
        kw['filename'] = filename
        apply(self.doitWrapper,(mols[0],), kw)


    def doit(self, mol, **kw):
        #results in adding these attributes to molecule:
        #   center,  checked_charges,  gpf_init 
        #if 'preserve_input_charges' is set to 1 in kw, use it 
        #if not, set preserve_input_charges to 0
        preserve_input_charges = kw.get('preserve_input_charges', 0)
        filename = os.path.basename(mol.parser.filename)
        msg = 'initializing ' + filename + ':\n'
        #if self.vf.hasGui:
        #    self.vf.GUI.receptorLabelLabel.config(text='Receptor:')
        #    self.vf.GUI.receptorLabel.config(text=mol.name, width=len(mol.name))
        file_type = os.path.splitext(mol.parser.filename)[-1]
        len_atoms = len(mol.allAtoms)
        nbnd_atoms = mol.get_nonbonded_atoms()
        len_nbnds = len(nbnd_atoms)
        check_nphs = True
        write_file = True
        #add autodock_element to each atom
        receptor_type_str = self.vf.ADgpf4_setAtomTypes(mol)
        flexRes = False  #flag for moving sidechains
        has_written_file = False
        if file_type == '.pdbqt':
            msg = msg + "molecule from pdbqt file:autodock_elements and gasteiger charges already added"
            check_nphs = False
            write_file = False
            if hasattr(self.vf, 'flexDict') and self.vf.flexDict.has_key('macroname') \
                and self.vf.flexDict['macroname']==mol.name \
                and self.vf.flexDict.has_key('rigid_filename'):
                filename = self.vf.flexDict['rigid_filename']
                stem = os.path.splitext(filename)[1]
                flexRes = True
                has_written_file = True
                msg += "; using " + os.path.basename(filename) + " for autogrid calculation"
            elif hasattr(self.vf, 'flexDict') and self.vf.flexDict.has_key('macromol'): 
                if self.vf.flexDict['macromol']==mol:
                    if 'rigid_filename' not in self.vf.flexDict.keys(): 
                        msg = "\nCAUTION: currently no file has been written for rigid residues in " + mol.name 
                        stem = os.path.splitext(filename)[0]
                        msg += ". All of "+filename + "  will be used for autogrid!!"
                    else:
                        filename = self.vf.flexDict.has_key('rigid_filename')
                        has_written_file = True
                        msg += '; this Molecule is currently formatted via Flexible Residues menu-> using '+ filename + ' as the rigid filename'
                    check_nphs= False
            elif hasattr(mol, 'torTree'):
                flexRes = True
                has_written_file = True
                msg = 'CAUTION: this molecule was read in from a flexible residue pdbqt file!'
                check_nphs= False
                self.vf.warningMsg(msg)
            else:
                filename = os.path.basename(mol.parser.filename)
        elif len(mol.allAtoms.get(lambda x: hasattr(x, 'charge')))==len_atoms: 
            if mol.allAtoms.chargeSet == len_atoms*['gasteiger']:
                print mol.name, "already has gasteiger charges"
            elif kw['preserve_input_charges']==1:
                print "preserving input charges on ", mol.name
            else:
                print "adding gasteiger charges to ", mol.name
                self.vf.computeGasteiger(mol, topCommand=0, log=0)
        else:
            print "adding gasteiger charges to ", mol.name
            self.vf.computeGasteiger(mol, topCommand=0, log=0)
        #?first check whether to call setAtomTypes or not
        renumber=0
        if len_nbnds:
            msg = msg + '   -contains ' + str(len_nbnds) + ' non-bonded atoms:\n'
            for nb_at in nbnd_atoms: 
                msg = msg + '          ' + nb_at.full_name() + '\n'
        else:
            msg = msg + '   -contains no non-bonded atoms\n'
        if check_nphs:
            hs = mol.allAtoms.get(lambda x: x.element=='H')
            hs_with_no_bonds = hs.get(lambda x: len(x.bonds)==0)
            hs_with_bonds = hs.get(lambda x: len(x.bonds)>0)
            nphs = hs_with_bonds.get(lambda x: x.bonds[0].atom1.element=='C' or x.bonds[0].atom2.element=='C')
            if len(nphs)!=0:
                msg = msg + '   -found ' + str(len(nphs)) + ' non-polar hydrogens\n'
                if len(nphs) and self.vf.userpref['Automerge NPHS']['value']:
                    #userpref determines whether to automatically merge detected nphs
                    #default is to always merge
                    renumber = 1
                    if self.vf.hasGui:
                        self.vf.mergeNPHSGC(mol, logBaseCmd=0)
                        #redisplay = 1
                    else:
                        self.vf.mergeNPHS(mol)
                    msg = msg + '   -merged nphs\n'
            else:
                if hs_with_no_bonds:
                    m4 = mol.name + " has one or more hydrogens with no bonds: "
                    for at in hs_with_no_bonds:
                        m4 += at.parent.parent.name + ':'+ at.parent.name +':'+ at.name + ','
                    self.vf.warningMsg(m4[:-1], title='AD4 Receptor Summary:')
            #SHOULD THIS BE OPTIONAL???
            hs = self.vf.allAtoms.get(lambda x: x.element=='H')
            if hs: self.vf.fixHNames(hs, topCommand=0)
            #always merge lone pairs
            lps = filter(lambda x: x.element=='Xx' and \
                      (x.name[0]=='L' or x.name[1]=='L'),mol.allAtoms)
            if len(lps):
                renumber = 1
                if self.vf.hasGui:
                    self.vf.mergeLPSGC(mol)
                    #redisplay = 1
                else:
                    self.vf.mergeLPS(mol)
                msg = msg + '   -merged ' + str(len(lps)) + ' lone pairs\n'

            if renumber:
                atSet = mol.allAtoms
                atSet.sort()
                fst = atSet[0].number
                atSet.number = range(fst, len(atSet)+fst)
                #FIX THIS: CHECK THAT DISPLAY GETS UPDATED
                #if self.vf.hasGui and redisplay:
                #    self.vf.displayLines(mol, negate=1, topCommand=0, log=0)
                #    self.vf.displayLines(mol, topCommand=0, log=0)

        if flexRes:
            flexRESIDUES = ResidueSet()
            if 'flex_residues' in self.vf.flexDict.keys():
                flexRESIDUES = self.vf.flexDict['flex_residues']
                flex_t = {}
                for a in flexRESIDUES.atoms:
                    flex_t[a.autodock_element] = 1
                #F1: set FLEXRES_TYPES in ADgpf4_initMacro
                self.vf.GPF_FLEXRES_TYPES = flex_t.keys()    
                print 'set GPF_FLEXRES_TYPES to', self.vf.GPF_FLEXRES_TYPES
            residues = mol.chains.residues - flexRESIDUES
            #set up both receptor types and flexres types here
            mol.center = Numeric.add.reduce(residues.atoms.coords)/len(residues.atoms)
            errCharge, resList = self.vf.checkResCharges(residues)
            fD = self.vf.flexDict
            if fD.has_key('rigid_filename'):
                self.vf.gpo.receptor_filename = self.vf.flexDict['rigid_filename']
                print "set receptor_filename to ", self.vf.gpo.receptor_filename
            if fD.has_key('rigid_types'):
                receptor_type_str = join(fD['rigid_types'])
                self.vf.gpo['receptor_types']['value'] = receptor_type_str
                print 'set GPF_RECEPTOR_TYPES to', self.vf.GPF_RECEPTOR_TYPES
                #R1: set RECEPTOR_TYPES in macro4 init 
                self.vf.GPF_RECEPTOR_TYPES = receptor_type_str.split()    
                print "set self.vf.gpo[receptor_types] to ", self.vf.gpo['receptor_types']['value']
        else:
            errCharge, resList = checkMolCharges(mol, self.vf)
        mol.checked_charges = 1
        # unless the preference is None
        histVal = self.editHISprotonation
        newHs = AtomSet([])
        if histVal!='No change':
            hisRES = mol.chains.residues.get(lambda x: x.type=='HIS')
            if hisRES:
                d = {}
                for res in hisRES:
                    d[res.full_name()] = histVal
                newHs = self.vf.editHist_h(d)
                if len(newHs): 
                    #fix the autodock_element here
                    for h in newHs:
                        h.autodock_element = 'HD'
                    if self.vf.hasGui:
                        event = AddAtomsEvent(objects=newHs)
                        self.vf.dispatchEvent(event)
                msg = msg + '   -edited histidine protonation to userpref:' + histVal + '\n'
        self.vf.warningMsg(msg)
        if write_file:
            filename = kw['filename']
            if filename is None:
                currentPath = os.getcwd()
                defaultFilename = os.path.join(currentPath, mol.name) + '.pdbqt'
                filename = self.vf.askFileSave(idir=currentPath, ifile=defaultFilename,
                    types=[('PDBQT files', '*.pdbqt')],
                    title = 'Modified AutoDock4 Macromolecule File:')
                #filename = self.vf.askFileSave(types=[('PDBQT files', '*.pdbqt')],
                #    title = 'Modified AutoDock4 Macromolecule File:')
                if not filename:
                    #if filename is None: return
                    msg="AutoGrid requires written pdbqt molecule!"
                    self.vf.warningMsg(msg)
                    return 'ERROR'
                else:
                    self.vf.writePDBQT( mol, filename=filename, 
                            pdbRec=['ATOM','HETATM'],
                                bondOrigin=[])

            elif filename=='auto':
                fname = os.path.splitext(os.path.basename(mol.parser.filename))[0]
                filename = fname + '.pdbqt'
                self.vf.writePDBQT( mol, filename=filename, 
                            pdbRec=['ATOM','HETATM'],
                            bondOrigin=[])
            else:
                self.vf.writePDBQT( mol, filename=filename, 
                                pdbRec=['ATOM','HETATM'],
                                bondOrigin=[])
        mol.gpf_init = 1
        self.vf.gpo.receptor = mol
        self.vf.gpo.set_receptor4(filename, receptor_type_str)
        if not hasattr(mol, 'center'):
            mol.getCenter()
        if self.vf.hasGui:
            self.vf.colorByAtomType(mol, ['lines'], topCommand=0, redraw=1)
        zero_charge_atoms = mol.allAtoms.get(lambda x: x.charge==0 and x.element!='C')
        if zero_charge_atoms is not None and len(zero_charge_atoms):
            msg = "These atoms have zero charge:\n"
            for a in zero_charge_atoms:
                msg = msg + a.name + " "
            self.vf.warningMsg(msg)
        if hasattr(mol, 'spacing'):
            self.vf.gpo['spacing']['value'] = mol.spacing
            self.vf.gpo['npts']['value'] = mol.npts
            self.vf.gpo['gridcenter']['value'] = mol.gridcenter



class Gpf4MacroReader(MVCommand):
    """ allows user to select the receptor via a file browser"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'read macromolecule' button is pressed"""
        macroFile = self.vf.askFileOpen(types=[('PDBQT files', '*.pdbqt'), ('PDBQS files', '*.pdbqs'),
            ('PDBQ files','*.pdbq'),('PDB files','*.pdb'),('MOL2 files', '*.mol2'),('all files', '*.*')], 
            title = 'Macromolecule File:')
        #allow user to set typeCharges and addSolPar here
        #if macroFile is not None:
        if macroFile:
            ext = os.path.splitext(macroFile)[1]
            ok = False
            if ext in ['.mol2', '.pdbqt', '.pdbq', '.pdbqs','.pqr']:
                if self.vf.hasGui:
                    msg = macroFile + " may already have per atom partial charges.\nDo you want to preserve these charges instead of adding gasteiger charges?" 
                    d=SimpleDialog(self.vf.GUI.ROOT, text=msg, buttons=['No','Yes'], default=0, title='Preserve input receptor charges?')
                    ok=d.go()
            kw = {'preserve_input_charges':ok}
            apply(self.doitWrapper, (macroFile,), kw)


    def __call__(self, macroFile, **kw):
        if not os.path.exists(macroFile):
            raise IOError
        apply(self.doitWrapper,(macroFile,),kw)


    def doit(self, macroFile, **kw):
        mols = Read(macroFile)
        if len(mols)>1:
            self.vf.warningMsg(messages['multipleMols'])
        mol = mols[0]
        self.vf.addMolecule(mol)
        if not mol.chains[0].hasBonds:
            mol.buildBondsByDistance()
            if self.vf.hasGui:
                self.vf.centerScene(topCommand=0)
                self.vf.displayLines(mol,topCommand=0,redraw=1)
        kw['topCommand'] = 0
        apply(self.vf.ADgpf4_initMacro, (mol,), kw)


Gpf4MacroReaderGUI = CommandGUI()
Gpf4MacroReaderGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
    menuText['ReadMacro4'], cascadeName = menuText['MacromoleculeMB'])



class Gpf4MacroChooser(MVCommand):
    """ allows user to choose a molecule already present for the receptor"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def __init__(self, mode='single', title = 'Choose Macromolecule'):
        MVCommand.__init__(self)
        self.mode = mode
        self.title = title


    def chooseMolecule_cb(self, event = None):
        """called each time the 'choose Molecule' button is pressed"""
        try:
            self.chooser.form.withdraw()
        except:
            pass
        mol = self.chooser.getMolSet()
        if mol: 
            macroFile = os.path.basename(mol.parser.filename)
            ext = os.path.splitext(macroFile)[1]
            ok = False
            if ext in ['.mol2', '.pdbqt', '.pdbq', '.pdbqs','.pqr']:
                if self.vf.hasGui:
                    msg = mol.name + " may already have per atom partial charges.\nDo you want to preserve these charges instead of adding gasteiger charges?" 
                    d=SimpleDialog(self.vf.GUI.ROOT, text=msg, buttons=['No','Yes'], default=0, title='Preserve input receptor charges?')
                    ok=d.go()
            kw = {'preserve_input_charges':ok}
            apply(self.doitWrapper, (mol,), kw)


    def guiCallback(self):
        self.chooser = MoleculeChooser(self.vf, self.mode, self.title)
        self.chooser.ipf.append({'name':'Select Button',
                                 'widgetType':Tkinter.Button,
                                 'text':'Select Molecule',
                                 'wcfg':{'bd':6},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W},
                                 'command': self.chooseMolecule_cb})
        self.form = self.chooser.go(modal=0, blocking=0)
        lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb
        lb.bind("<Double-Button-1>", self.chooseMolecule_cb)


    def __call__(self, nodes, **kw):
        apply(self.doitWrapper,(nodes,),kw)


    def doit(self, nodes, **kw):
        mols = self.vf.expandNodes(nodes)
        if not len(mols):
            return 'ERROR'
        kw['topCommand'] = 0
        apply(self.vf.ADgpf4_initMacro, (mols[0],), kw)


Gpf4MacroChooserGUI = CommandGUI()
Gpf4MacroChooserGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], menuText['ChooseMacro4'], cascadeName = menuText['MacromoleculeMB'])



class Gpf4InitLigand(MVCommand):
    """initializes the ligand for AutoGrid4:
        checkCharges
        getTypes
        getSideLengths
        setAutoDockElements
        colorByAtom + color aromatic C's green
        
        NO GUI necessary which would have allowed user to:
            decide which types of hydrogen bonds to model
            modify list of atom types detected in ligand
        
        """

    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)
        if self.vf.hasGui:
            self.vf.loadModule('colorCommands','Pmv')
        #L0. initialize LIGAND_TYPES in Gpf4InitLigand
        self.vf.GPF_LIGAND_TYPES = []
        #F0. initialize FLEXRES_TYPES in Gpf4InitLigand
        self.vf.GPF_FLEXRES_TYPES = []


    def __call__(self, mol,  **kw):
        """ADgpf4_initLigand """
        apply(self.doitWrapper,(mol,),kw)


    def doit(self, mol, **kw):
        lig = self.vf.expandNodes(mol)[0]
        errCharge, resList = checkMolCharges(lig, self.vf)
        msg = ""
        msg = "set AutoGrid4 ligand to "
        if hasattr(lig, 'outputfile'):
            self.vf.gpo.set_ligand4(lig.outputfile)
            msg = msg + lig.outputfile
            filename = lig.outputfile
        else:
            self.vf.gpo.set_ligand4(lig.parser.filename)
            msg = msg + lig.parser.filename
            filename = lig.parser.filename
        msg = msg + "\n"
        self.vf.gpo.ligand = lig
        d = {}
        for a in lig.allAtoms:
            d[a.autodock_element] = 1
        #L1. set LIGAND_TYPES in Gpf4InitLigand
        newTYPES = self.vf.GPF_LIGAND_TYPES = d.keys()
        for t in self.vf.GPF_FLEXRES_TYPES:
            if t not in newTYPES:
                newTYPES.append(t)
        current_types = join(newTYPES, ' ')        
        spacing = self.vf.gpo['spacing']['value']
        getSideLengths(lig, spacing)
        #now getSideLengths also sets center
        #lig.getCenter()
        #this is bounding box center, not average center
        lig.center = (round(lig.center[0],3), round(lig.center[1],3), round(lig.center[2],3))

        #if it is from a pdbqt, this ligand already has autodock4 types 
        #?#if os.path.splitext(filename)[1]=='.pdbqt':
        #?#    print 'already has autodock4 types'
        #?## else add autodock4 types
        if self.vf.gpo['ligand_types']['value'] != current_types:
            msg = msg + "set ligand_types to %s\n"%current_types
            self.vf.gpo['ligand_types']['value'] = current_types

        if self.vf.hasGui:
            self.vf.displayLines(lig, topCommand=0)
            self.vf.colorByAtomType(lig,['lines'], topCommand=0)
            aromCs = AtomSet(filter(lambda x:x.autodock_element=='A',\
                lig.allAtoms))
            if len(aromCs):
                self.vf.color(aromCs,((0.,1.,0.,),),['lines'],\
                    topCommand=0, redraw=1)



class Gpf4LigandChooser(MVCommand):
    """ allows user to choose a molecule already present for the ligand"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def __init__(self, mode='single', title = 'Choose Ligand'):
        MVCommand.__init__(self)
        self.mode = mode
        self.title = title


    def chooseLigand_cb(self, event = None):
        """called each time the 'choose Ligand' button is pressed"""
        mol = self.chooser.getMolSet()
        if mol: 
            try:
                self.chooser.form.withdraw()
            except:
                pass
            dict = self.vf.atorsDict
            dict2 = None
            if hasattr(self.vf, 'flexDict'):
                dict2 = self.vf.flexDict
            #check that the molecule has autogrid4 types 
            #and 
            #a pdbqt file somewhere
            #check that the molecule has a torTree 
            #OR
            #it is current atorsDict['molecule'] and has outputfile
            ok = 0
            if hasattr(mol, 'torTree') and os.path.splitext(mol.parser.filename)[-1][-1]=='t':
                ok = 1
            elif dict.has_key('molecule') and mol==dict['molecule']:
                ok = hasattr(mol, 'outputfile') and mol.outputfile[-1]=='t'
            elif dict2 is not None and dict2.has_key('ligand_name') and mol.name==dict['ligand_name']:
                ok = 1
            if not ok:
                self.vf.warningMsg('can only select molecule with written autotors pdbqt output file')
                return 'ERROR'
            self.doitWrapper(mol, log=1,redraw=0)
            try:
                self.chooser.form.withdraw()
            except:
                pass


    def guiCallback(self):
        self.chooser = MoleculeChooser(self.vf, self.mode, self.title)
        self.chooser.ipf.append({'name':'Select Button',
                                 'widgetType':Tkinter.Button,
                                 'text':'Select Ligand',
                                 'wcfg':{'bd':6},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W},
                                 'command': self.chooseLigand_cb})
        self.form = self.chooser.go(modal=0, blocking=0)
        lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb
        lb.bind("<Double-Button-1>", self.chooseLigand_cb)


    def __call__(self, nodes, **kw):
        apply(self.doitWrapper,(nodes,),kw)


    def doit(self, nodes):
        ligand = self.vf.expandNodes(nodes)[0]
        if not ligand.chains[0].hasBonds:
            ligand.buildBondsByDistance()
        self.vf.ADgpf4_initLigand(ligand, topCommand=0)


Gpf4LigandChooserGUI= CommandGUI()
Gpf4LigandChooserGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
    menuText['ByChoosingLigand4'], cascadeName = menuText['SetMapTypesMB'])



class Gpf4LigReader(MVCommand):
    """ allows user to choose a ligand file via a file browser"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'select ligand' button is pressed"""

        ligFile = self.vf.askFileOpen(types=[('PDBQT ligand files:', '*.pdbqt')],
                title = 'Ligand File:')
        if ligFile:
            self.doitWrapper(ligFile, log=1, redraw=1)


    def __call__(self, ligFile, **kw):
        if not os.path.exists(ligFile):
            raise IOError
        apply(self.doitWrapper,(ligFile,),kw)


    def doit(self, ligFile):
        ftype=split(ligFile,'.')[-1]
        if ftype not in ['pdbqt', 'pdbq']:
            self.vf.warningMsg(messages['unknownLigExt'])
            return 'ERROR'

        ligs = Read(ligFile)
        if len(ligs)>1:
            self.vf.warningMsg(messages['multipleLigs'])

        lig = ligs[0]
        self.vf.addMolecule(lig)
        if not lig.chains[0].hasBonds:
            lig.buildBondsByDistance()
        self.vf.ADgpf4_initLigand(lig, topCommand=0)


Gpf4LigReaderGUI= CommandGUI()
Gpf4LigReaderGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['ByReadingFile4'], cascadeName = menuText['SetMapTypesMB'])



class Gpf4FlexResChooser(MVCommand):
    """ allows user to choose a molecule already present for the flexible residues"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def __init__(self, mode='single', title = 'Choose Flexible Residues from...'):
        MVCommand.__init__(self)
        self.mode = mode
        self.title = title


    def chooseFlexResMol_cb(self, event = None):
        """called each time the 'Choose Flexible Residues...' button is pressed"""
        mol = self.chooser.getMolSet()
        if mol: 
            try:
                self.chooser.form.withdraw()
            except:
                pass
            dict2 = None
            if hasattr(self.vf, 'flexDict'):
                dict2 = self.vf.flexDict
                dict2_keys = dict2.keys()
            #check that the molecule has been read from a flexible residue 
            # file (it has a torTree)
            # OR
            #it is current flexDict['macromol'] and has flex_filename 
            # ie outputfile exists
            ok = 0
            if hasattr(mol, 'torTree') and os.path.splitext(mol.parser.filename)[-1][-1]=='t':
                nodes = mol.allAtoms
                ok = 1
            elif dict2 is not None and 'macromol' in dict2_keys and mol==dict2['macromol'] \
                        and 'flex_filename' in dict2_keys:
                nodes= dict2['flex_residues'].atoms
                ok = 1
            if not ok:
                self.vf.warningMsg('can only select molecule which was read in from a flexible residue file or one whose flexible residues have been written to a file')
                return 'ERROR'
            self.doitWrapper(nodes, log=1,redraw=0)
            try:
                self.chooser.form.withdraw()
            except:
                pass


    def guiCallback(self):
        self.chooser = MoleculeChooser(self.vf, self.mode, self.title)
        self.chooser.ipf.append({'name':'Select Button',
                                 'widgetType':Tkinter.Button,
                                 'text':'Select molecule providing flexible residues',
                                 'wcfg':{'bd':6},
                                 'gridcfg':{'sticky':Tkinter.E+Tkinter.W},
                                 'command': self.chooseFlexResMol_cb})
        self.form = self.chooser.go(modal=0, blocking=0)
        lb = self.chooser.ipf.entryByName['Molecule']['widget'].lb
        lb.bind("<Double-Button-1>", self.chooseFlexResMol_cb)


    def __call__(self, nodes, **kw):
        nodes = self.vf.expandNodes(nodes)
        if not len(nodes):
            return "ERROR"
        nodes = nodes.findType(Atom)
        apply(self.doitWrapper,(nodes,),kw)


    def doit(self, nodes):
        if not hasattr(self.vf, 'flexDict'): 
            self.vf.flexDict = {}
        type_d = {}
        for atom in nodes:
            type_d[atom.autodock_element] = 1
        #F2: set FLEXRES_TYPES in ADgpf4_chooseFormattedFlexRes
        new_types = self.vf.GPF_FLEXRES_TYPES = type_d.keys()
        self.vf.flexDict['flex_types'] = new_types
        msg = 'set flex_types to ' 
        for t in self.vf.flexDict['flex_types']:
            msg += t + ' '
        self.vf.warningMsg(msg, title='flexible types for autogrid4 from:')
        lig_types = self.vf.GPF_LIGAND_TYPES
        for t in lig_types:
            type_d[t] = 1
        type_list = join(type_d.keys(),' ')
        self.vf.gpo['ligand_types']['value'] = type_list
            

Gpf4FlexResChooserGUI= CommandGUI()
Gpf4FlexResChooserGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'],\
    menuText['ByChoosingFlexRes4'], cascadeName = menuText['SetMapTypesMB'])



class Gpf4FlexResReader(MVCommand):
    """ allows user to get types for a FlexRes file via a file browser"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)


    def guiCallback(self):
        """called each time the 'select flexres' button is pressed"""

        flexResFile = self.vf.askFileOpen(types=[('PDBQT flexres files:', '*.pdbqt')],
                title = 'Flexible Residue File:')
        if flexResFile:
            self.doitWrapper(flexResFile, log=1, redraw=1)


    def __call__(self, flexResFile, **kw):
        if not os.path.exists(flexResFile):
            raise IOError
        apply(self.doitWrapper,(flexResFile,),kw)


    def doit(self, flexResFile):
        ftype=split(flexResFile,'.')[-1]
        if ftype not in ['pdbqt']:
            self.vf.warningMsg(messages['unknownFlexResExt'])
            return 'ERROR'

        flexRes = Read(flexResFile)
        if len(flexRes)>1:
            self.vf.warningMsg(messages['multipleFlexRes'])

        flexRes = flexRes[0]
        self.vf.addMolecule(flexRes)
        if not flexRes.chains[0].hasBonds:
            flexRes.buildBondsByDistance()
        dict = {}
        for at in flexRes.chains.residues.atoms:
            dict[at.autodock_element] = 1
        if not hasattr(self.vf, 'flexDict'):
            self.vf.flexDict = {}
        self.vf.flexDict['flex_types'] = dict.keys()
        #F2: set FLEXRES_TYPES in ADgpf4_readFormattedFlexRes
        self.vf.GPF_FLEXRES_TYPES = dict.keys()
        alltypes = dict.keys()
        for t in self.vf.GPF_LIGAND_TYPES:
            if t not in alltypes:
                alltypes.append(t)
        lig_types = "%s" %(alltypes[0])
        for t in alltypes[1:]:
            lig_types = lig_types + ' ' + t
        self.vf.gpo['ligand_types']['value'] = lig_types
        print "set gpo ligand_types to", lig_types
            

Gpf4FlexResReaderGUI= CommandGUI()
Gpf4FlexResReaderGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['ByReadingFlexResFile4'], cascadeName = menuText['SetMapTypesMB'])



class Gpf4Writer(MVCommand):
    """ allows user to choose an output filename and write it"""


    def onAddCmdToViewer(self):
        checkHasGpo(self.vf)

            
    def __call__(self, outfile, **kw):
        """None <- ADgpf4_writeGPF( outfile)
outfile = filename for AutoGrid4 parameters
"""
        apply(self.doitWrapper,(outfile,),kw)


    def doit(self, outfile):
        if not len(self.vf.gpo.receptor_stem):
            self.vf.warningMsg("You must choose a macromolecule before writing gpf")
            return 'ERROR'
        #check whether a covalent map has been set up
        if len(self.vf.gpo['covalent_coords']['value']):
            parm_list = []
            for item in grid_parameter_list4:
                parm_list.append(item)
            parm_list.append('covalentmap')
            self.vf.gpo.write4(outfile, parm_list)
        else:
            self.vf.gpo.write4(outfile, grid_parameter_list4)
        

    def guiCallback(self):
        if not len(self.vf.gpo.receptor_stem):
            self.vf.warningMsg("You must choose a macromolecule before writing gpf")
            return 'ERROR'
        outfile = self.vf.askFileSave(types=[('gpf file', '*.gpf')],
                title = 'Grid Parameter Output File:')
        if outfile:
            self.doitWrapper(outfile, log=1)


Gpf4WriterGUI= CommandGUI()
Gpf4WriterGUI.addMenuCommand('AutoToolsBar', menuText['AutoGpfMB'], \
    menuText['WriteGpf4MB'], cascadeName=menuText['WriteMB'], separatorBelow=1)

commandList = [
    {'name':'ADgpf_readGPF','cmd':GpfLoadDefaults(),'gui':GpfLoadDefaultsGUI},
    {'name':'ADgpf_initLigand','cmd':GpfInitLigand(),'gui':None},
    {'name':'ADgpf_initMacro','cmd':GpfMacroInit(),'gui':None},
    #AutoGrid4
    {'name':'ADgpf4_initLigand','cmd':Gpf4InitLigand(),'gui':None},
    {'name':'ADgpf4_initMacro','cmd':Gpf4MacroInit(),'gui':None},
    {'name':'ADgpf4_readMacromolecule','cmd':Gpf4MacroReader(),'gui':Gpf4MacroReaderGUI},
    {'name':'ADgpf4_chooseMacromolecule','cmd':Gpf4MacroChooser(),'gui':Gpf4MacroChooserGUI},
    {'name':'ADgpf4_setMapTypes','cmd':Gpf4SetMapTypes(),'gui':Gpf4SetMapTypesGUI},
    {'name':'ADgpf4_chooseFormattedLigand','cmd':Gpf4LigandChooser(),'gui':Gpf4LigandChooserGUI},
    {'name':'ADgpf4_readFormattedLigand','cmd':Gpf4LigReader(),'gui':Gpf4LigReaderGUI},
    {'name':'ADgpf4_chooseFormattedFlexRes','cmd':Gpf4FlexResChooser(),'gui':Gpf4FlexResChooserGUI},
    {'name':'ADgpf4_readFormattedFlexRes','cmd':Gpf4FlexResReader(),'gui':Gpf4FlexResReaderGUI},
    {'name':'ADgpf_setUpCovalentMap4','cmd':SetUpCovalentMap4(),'gui':SetUpCovalentMap4GUI},
    #set grid
    {'name':'ADgpf_setGrid','cmd':SetBoxParameters(),'gui':SetBoxParametersGUI},
    #AutoGrid4
    {'name':'ADgpf4_setParameterFilename','cmd':Gpf4ParameterFileSelector(),'gui':Gpf4ParameterFileSelectorGUI},
    {'name':'ADgpf4_editParameterFile','cmd':Gpf4ParameterFileEditor(),'gui':Gpf4ParameterFileEditorGUI},
    {'name':'ADgpf4_writeGPF','cmd':Gpf4Writer(),'gui':Gpf4WriterGUI},
    {'name':'ADgpf4_setAtomTypes','cmd':Gpf4SetAtomTypes(),'gui':Gpf4SetAtomTypesGUI},
    #AutoGrid3
    {'name':'ADgpf_setGpo','cmd':GpfSetGpo(),'gui':None},
    {'name':'ADgpf_checkMacroTypes','cmd':CheckMacroAtomTypes(),'gui':None},
    {'name':'ADgpf_readMacromolecule','cmd':GpfMacroReader(),'gui':GpfMacroReaderGUI},
    {'name':'ADgpf_chooseMacromolecule','cmd':GpfMacroChooser(),'gui':GpfMacroChooserGUI},
    {'name':'ADgpf_addSolvationParameters','cmd':GpfAddSol(),'gui':GpfAddSolGUI},
    {'name':'ADgpf_setMapTypes','cmd':SetMapTypes(),'gui':SetMapTypesGUI},
    {'name':'ADgpf_chooseFormattedLigand','cmd':GpfLigandChooser(),'gui':GpfLigandChooserGUI},
    {'name':'ADgpf_readFormattedLigand','cmd':GpfLigReader(),'gui':GpfLigReaderGUI},
    {'name':'ADgpf_defineAtomParameters','cmd':DefineNewAtomParms(),'gui':DefineNewAtomParmsGUI},
    {'name':'ADgpf_setUpCovalentMap','cmd':SetUpCovalentMap(),'gui':SetUpCovalentMapGUI},
    {'name':'ADgpf_setOtherOptions','cmd':SetOtherOptions(),'gui':SetOtherOptionsGUI},
    {'name':'ADgpf_writeGPF','cmd':GpfWriter(),'gui':GpfWriterGUI},
    {'name':'ADgpf_editGPF','cmd':GpfEditor(),'gui':GpfEditorGUI},
    {'name':'ADgpf_selectCenter','cmd':SelectCenter(),'gui':None},
    {'name':'ADgpf_mergeNonPolarHydrogens','cmd':GpfMergeNonPolarHs(),'gui':None},
    ]


def initModule(vf):

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

    if hasattr(vf, 'GUI'):
        for item in vf.GUI.menuBars['AutoToolsBar'].menubuttons.values():
            item.configure(background = 'tan')
            item.configure(underline = '-1')
        if not hasattr(vf.GUI, 'adtBar'):
            vf.GUI.adtBar = vf.GUI.menuBars['AutoToolsBar']
            vf.GUI.adtFrame = vf.GUI.adtBar.menubuttons.values()[0].master


