#!/usr/bin/python
# -*- coding: cp1252 -*-
#
# Copyright (C) 2005 Noel O'Boyle <oboylen2@mail.dcu.ie>
#
# This program is free software; you can redistribute and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.

from Tkinter import *   # GUI stuff
import tkMessageBox     # For the About Dialog
import tkFileDialog     # For the Open File and Save File
import webbrowser
import tkSimpleDialog
import traceback
import copy             # For deepcopy...until I find a better way of doing this
import ConfigParser     # For writing the settings to an .ini file

from GaussSum.Filetype.Gaussian03 import Gaussian03
from GaussSum.Filetype.GAMESS import GAMESS
from GaussSum.Filetype.Hyperchem import Hyperchem

from GaussSum.plot import Gnuplot

import GaussSum.SCF
import GaussSum.GeoOpt
import GaussSum.IR_Raman
import GaussSum.Find
import GaussSum.UVVis
import GaussSum.MO
import GaussSum.EDDM
import GaussSum.NMR

import os
import sys
import string


class App:    # This sets up the GUI
    

    def __init__(self,root,argv):

        root.resizable(False,False)
        self.addmenubar(root)

        self.frame1=Frame(root)
        self.frame1.grid()
        frame2=Frame(root)
        frame2.grid(row=1)
        
        self.scrollbar=Scrollbar(frame2)
        self.scrollbar.pack(side=RIGHT,fill=Y)
        self.txt=Text(frame2,font=("Courier New",8),yscrollcommand=self.scrollbar.set,width=90,height=21)
        self.txt.pack(expand=1,fill=Y)
        self.scrollbar.config(command=self.txt.yview)

        self.screen=Redirect(self.txt.insert,root,[END,self.txt]) # Oh yeah! Could I have done it in a more roundabout way?

        frame3=Frame(self.frame1,relief=GROOVE,borderwidth=3)
        frame3.pack(side=LEFT,anchor=W)
        
        self.middleframe=Frame(self.frame1,width=380,height=140)
        self.middleframe.pack(side=LEFT)
        # Thanks to the students from Ulm for the next line
        # which prevents self.middleframe resizing when you choose a different option    
        self.middleframe.pack_propagate(0)
        self.frame4=Frame(self.middleframe)
        self.frame4.pack(side=LEFT)


        self.script = StringVar()

        self.b3=Radiobutton(frame3, text="Find.py", variable=self.script, value="FIND",command=self.option,state=DISABLED)
        self.b3.pack(anchor=W)
        self.b0=Radiobutton(frame3, text="SCF.py", variable=self.script, value="SCF",command=self.option,state=DISABLED)
        self.b0.pack(anchor=W)
        self.b1=Radiobutton(frame3, text="GeoOpt.py", variable=self.script, value="GEOOPT",command=self.option,state=DISABLED)
        self.b1.pack(anchor=W)
        self.b2=Radiobutton(frame3, text="IR_Raman.py", variable=self.script, value="IR_RAMAN",command=self.option,state=DISABLED)
        self.b2.pack(anchor=W)
        self.b5=Radiobutton(frame3, text="MO.py", variable=self.script, value="MO",command=self.option,state=DISABLED)
        self.b5.pack(anchor=W)
        self.b4=Radiobutton(frame3, text="UVVis.py", variable=self.script, value="UVVIS",command=self.option,state=DISABLED)
        self.b4.pack(anchor=W)
        self.b6=Radiobutton(frame3, text="EDDM.py", variable=self.script, value="EDDM", command=self.option,state=DISABLED)
        self.b6.pack(anchor=W)
        self.b7=Radiobutton(frame3, text="NMR.py (beta)", variable=self.script, value="NMR", command=self.option,state=DISABLED)
        self.b7.pack(anchor=W)

        self.b3.select(); 

        self.frame5=Frame(self.frame1)
        self.frame5.pack(side=LEFT)
        self.photo = PhotoImage(file="/usr/share/gausssum/mesh2.gif") # Doesn't work if don't use self.
        Button(self.frame5,image=self.photo,command=self.runscript).pack(side=LEFT)        
        root.bind("<Return>", self.runscript)
        
        x=(root.winfo_screenwidth()-652)/2 # The window is 652x480
        y=(root.winfo_screenheight()-580)/2
        root.geometry("652x480+"+str(x)+"+"+str(y)) # Get the window dead-centre

        self.error=ErrorCatcher()

# Read in the preferences from the preferences file.
# If it doesn't exist, create one using the defaults.
        self.readprefs()

        if len(argv)>1: # What to do if a filename is passed as an argument
            if os.path.isfile(argv[1]): # Does it exist?
                self.inputfilename=os.path.basename(argv[1])
                t=os.path.dirname(argv[1])
                if t:
                    os.chdir(t)
                self.fileopenednow()
                filetype=self.settings['global settings.filetype']
                if filetype=="Gaussian":
                    self.logfile=Gaussian03(self.inputfilename)
                elif filetype=="GAMESS":
                    self.logfile=GAMESS(self.inputfilename)
                else:
                    self.logfile=Hyperchem(self.inputfilename)
            else:
                self.screen.write(argv[1]+" does not exist or is not a valid filename\n")
                self.inputfilename=None
        else:
            self.inputfilename=None

# Read in the nmr standards file (if it exists)
        self.nmrstandards = NMRstandards(self.settings['nmr.data'])

    def option(self):
# What to do when they choose a script
        s=self.script.get()
        self.frame4.destroy()
        self.frame4=Frame(self.middleframe,width=380)
        self.frame4.pack(side=LEFT)

        if s=="SCF" or s=="GEOOPT":
            Label(self.frame4,text="Leave out the first n points").pack(side=LEFT)
            self.numpts=Entry(self.frame4,width=3)
            
            self.numpts.pack(side=LEFT)
            self.numpts.insert(0,"0")

        elif s=="IR_RAMAN":
            frame5=Frame(self.frame4)
            frame5.pack(side=TOP)
            frame6=Frame(self.frame4)
            frame6.pack(side=TOP)

            Label(frame5,text="Start:").pack(side=LEFT)
            self.start=Entry(frame5,width=5)
            self.start.pack(side=LEFT)
            self.start.insert(0,self.settings['ir_raman.start'])
            Label(frame5,text="End:").pack(side=LEFT)
            self.end=Entry(frame5,width=5)
            self.end.pack(side=LEFT)
            self.end.insert(0,self.settings['ir_raman.end'])
            Label(frame5,text="Num pts:").pack(side=LEFT)
            self.numpts=Entry(frame5,width=6)
            self.numpts.pack(side=LEFT)
            self.numpts.insert(0,self.settings['ir_raman.numpoints'])
            Label(frame5,text="FWHM").pack(side=LEFT)
            self.FWHM=Entry(frame5,width=3)
            self.FWHM.pack(side=LEFT)
            self.FWHM.insert(0,self.settings['ir_raman.fwhm'])

            Label(frame6,text="Scaling factors:").pack(side=LEFT)
            self.scale=StringVar()
            r=Radiobutton(frame6,text="General",variable=self.scale,value="Gen")
            r.pack(side=LEFT)
            self.scalefactor=Entry(frame6,width=5)
            self.scalefactor.insert(0,'1.00')
            self.scalefactor.pack(side=LEFT)
            r2=Radiobutton(frame6,text="Individual",variable=self.scale,value="Indiv")
            r2.pack(side=LEFT)
            r.select()
            
        elif s=="FIND":
            frame6=Frame(self.frame4)
            frame6.pack(side=LEFT)
            frame7=Frame(self.frame4)
            frame7.pack(side=LEFT)
            self.searchrad=StringVar()
            for i in range(4):
                t="find.text%d" % (i+1)
                Radiobutton(frame6, text=self.settings[t], variable=self.searchrad, value=self.settings[t]).grid(sticky=W)
            r=Radiobutton(frame6, text="Custom", variable=self.searchrad, value="Custom")
            r.grid(sticky=W)
            r.select()

            self.customsearch=Entry(frame6,width=15)
            self.customsearch.grid(row=4,column=1)
            self.customsearch.insert(END,"Enter phrase here")

            self.casesensitive=IntVar()
            casetick=Checkbutton(frame6,text="Case sensitive",variable=self.casesensitive)
            casetick.grid(row=4,column=2)

        elif s=="MO":
            frame8=Frame(self.frame4)
            frame6=Frame(self.frame4)
            frame7=Frame(self.frame4)

            frame8.pack()
            frame6.pack(side=TOP)
            frame7.pack(side=TOP)

            self.MOplot=IntVar()
            self.MODOS=Radiobutton(frame8, text="DOS", variable=self.MOplot, command=self.MOupdate, value=False)
            self.MODOS.pack(anchor=W)
            self.MOCOOP=Radiobutton(frame8, text="COOP", variable=self.MOplot, command=self.MOupdate, value=True)
            self.MOCOOP.pack(anchor=W)
            self.MODOS.select()
            
            Label(frame6,text="Start:").pack(side=LEFT)
            self.start=Entry(frame6,width=5)
            self.start.pack(side=LEFT)
            self.start.insert(0,self.settings['mo.start'])
            Label(frame6,text="End:").pack(side=LEFT)
            self.end=Entry(frame6,width=5)
            self.end.pack(side=LEFT)
            self.end.insert(0,self.settings['mo.end'])
            Label(frame6,text="FWHM:").pack(side=LEFT)
            self.FWHM=Entry(frame6,width=5)
            self.FWHM.pack(side=LEFT)
            self.FWHM.insert(0,self.settings['mo.fwhm'])

            self.useold=IntVar()
            self.useoldbtn=Checkbutton(frame7,text="Use existing orbital_data.txt?",variable=self.useold)
            self.useoldbtn.pack(anchor=W)

            self.makeorigin=IntVar()
            self.makeoriginbtn=Checkbutton(frame7,text="Create originorbs.txt?",variable=self.makeorigin)
            self.makeoriginbtn.pack(anchor=W)
            

	elif s=="UVVIS":
	    frame7=Frame(self.frame4)
	    frame7.pack(side=TOP)
	    frame6=Frame(self.frame4)
	    frame6.pack()

            self.UVplot=IntVar()
            self.UVbox=Radiobutton(frame7, text="UV-Visible", variable=self.UVplot, command=self.UVupdate, value=True)
            self.UVbox.pack(anchor=W)
            self.CDbox=Radiobutton(frame7, text="Circular dichroism", variable=self.UVplot, command=self.UVupdate, value=False)
            self.CDbox.pack(anchor=W)
            self.UVbox.select()

            Label(frame6,text="Start:").grid(row=0,column=0)
            Label(frame6,text="nm").grid(row=1,column=1)
            self.start=Entry(frame6,width=5)
            self.start.grid(row=0,column=1)
            self.start.insert(0,self.settings['uvvis.start'])
            Label(frame6,text="End:").grid(row=0,column=2)
            Label(frame6,text="nm").grid(row=1,column=3)            
            self.end=Entry(frame6,width=5)
            self.end.grid(row=0,column=3)
            self.end.insert(0,self.settings['uvvis.end'])
            Label(frame6,text="Num pts:").grid(row=0,column=4)
            self.numpts=Entry(frame6,width=5)
            self.numpts.grid(row=0,column=5)
            self.numpts.insert(0,self.settings['uvvis.numpoints'])

            self.fwhmlabel=Label(frame6,text="FWHM",width=6)
            self.fwhmlabel.grid(row=0,column=6)
            self.fwhmunits=Label(frame6,text="1/cm")
            self.fwhmunits.grid(row=1,column=7)
            self.FWHM=Entry(frame6,width=5)
            self.FWHM.grid(row=0,column=7)
            self.FWHM.insert(0,self.settings['uvvis.fwhm'])


	elif s=="EDDM":
            Label(self.frame4,text="Transitions:").pack(side=LEFT)
            self.trans=Entry(self.frame4,width=10)
            self.trans.pack(side=LEFT)
            self.trans.insert(0,"1-3,7,9")

        elif s=="NMR":
            self.createnmrpanel(self.frame4)


    def createnmrpanel(self,parent):
# Sets up the Panel for the NMR options
        frame6=Frame(parent)
        frame6.grid(row=0,column=0)
        # Set up the Radiobuttons
        self.nmrrb = StringVar() # Extract, Comment, Listbox
        self.nmrrb1=Radiobutton(frame6, text="Just extract NMR data", variable=self.nmrrb, value="Extract",command=self.nmrrbcb)
        self.nmrrb1.pack(anchor=W)
        self.nmrrb2=Radiobutton(frame6, text="Take level of theory from comment", variable=self.nmrrb, value="Comment",command=self.nmrrbcb)
        self.nmrrb2.pack(anchor=W)
        self.nmrrb3=Radiobutton(frame6, text="Take level of theory from listbox", variable=self.nmrrb, value="Listbox",command=self.nmrrbcb)
        self.nmrrb3.pack(anchor=W)
        self.nmrrb1.select()

        # Set up the Listbox
        frame7=Frame(parent)
        frame7.grid(row=1,column=0)
        nmrscrlbar=Scrollbar(frame7,orient=VERTICAL)
        self.nmrlbx1=Listbox(frame7,yscrollcommand=nmrscrlbar.set,height=5)
        nmrscrlbar.config(command=self.nmrlbx1.yview)
        nmrscrlbar.pack(side=RIGHT,fill=Y)
        self.nmrlbx1.pack(side=LEFT,fill=BOTH,expand=1)
        for x in self.nmrstandards:
            self.nmrlbx1.insert(END,x['theory'])
        self.nmrlbx1.select_set(0)
        self.nmrlbx1.configure(state=DISABLED)

        # Set up more Radiobuttons
        frame8=Frame(parent)
        frame8.grid(row=0,column=1)
        self.nmrrb2 = StringVar() # Calculate, Standard
        self.nmrrb2a=Radiobutton(frame8, text="Calculate relative ppm", variable=self.nmrrb2, value="Calculate")
        self.nmrrb2a.pack(anchor=W)
        self.nmrrb2b=Radiobutton(frame8, text="Add new standard", variable=self.nmrrb2, value="Standard")
        self.nmrrb2b.pack(anchor=W)
        self.nmrrb2a.select()
        self.nmrrb2a.configure(state=DISABLED)
        self.nmrrb2b.configure(state=DISABLED)

 
    def nmrrbcb(self):
# What to do when the user chooses one of the NMR radiobuttons
# (NMR RadioButton CallBack)
        value=self.nmrrb.get()
        if value=="Listbox": # Configure the listbox
            self.nmrlbx1.configure(state=NORMAL)
        else:
            self.nmrlbx1.configure(state=DISABLED)
        
        if value=="Extract": # Configure everything
            self.nmrrb2a.configure(state=DISABLED)
            self.nmrrb2b.configure(state=DISABLED)
        elif value=="Listbox":
            self.nmrrb2a.configure(state=NORMAL)
            self.nmrrb2b.configure(state=DISABLED)
        else:
            self.nmrrb2a.configure(state=NORMAL)
            self.nmrrb2b.configure(state=NORMAL)


    def UVupdate(self):
# What to do when the user chooses UVVis or CD for UVVis.py
        if self.UVplot.get()==False:
            # Choose CD
            self.fwhmlabel.configure(text="sigma:")
            self.fwhmunits.configure(text="eV")            
            self.FWHM.delete(0,END)
            self.FWHM.insert(0,self.settings['uvvis.sigma'])
        else:
            # Choose UVVis
            self.fwhmlabel.configure(text="FWHM:")
            self.fwhmunits.configure(text="1/cm")            
            self.FWHM.delete(0,END)
            self.FWHM.insert(0,self.settings['uvvis.fwhm'])


    def MOupdate(self):
# What to do when the user chooses DOS or COOP for MO.py
        if self.MOplot.get()==False:
            self.useoldbtn.configure(state=NORMAL)
        else:
            self.useoldbtn.configure(state=DISABLED)


    def runscript(self,event=None):
# What to do when the user clicks on the GaussSum logo
# to run the script
        if not self.inputfilename:
            self.screen.write("You need to open a log file first\n")
            return   # Do nothing if no file opened
        
        s=self.script.get()
        self.txt.delete(1.0, END)

        worked=False

        try:
            if s=="SCF":
                worked=GaussSum.SCF.SCF(root,self.screen,self.logfile,self.numpts.get(),self.settings['global settings.gnuplot'])
            elif s=="GEOOPT":
                worked=GaussSum.GeoOpt.GeoOpt(root,self.screen,self.logfile,self.numpts.get(),self.settings['global settings.gnuplot'])                
            elif s=="IR_RAMAN":
                worked=GaussSum.IR_Raman.IR_Raman(root,self.screen,self.logfile,self.start.get(),self.end.get(),self.numpts.get(),self.FWHM.get(),self.scale.get(),self.scalefactor.get(),self.settings['global settings.gnuplot'])
            elif s=="FIND":
                if self.searchrad.get()=="Custom":
                    worked=GaussSum.Find.Find(self.screen,self.logfile,self.customsearch.get(),self.casesensitive.get())
                else:
                    worked=GaussSum.Find.Find(self.screen,self.logfile,self.searchrad.get(),1)
            elif s=="MO":
                worked=GaussSum.MO.MO(root,self.screen,self.logfile,self.start.get(),self.end.get(),self.useold.get(),self.MOplot.get(),self.FWHM.get(),self.makeorigin.get(),self.settings['global settings.gnuplot'])
            elif s=="UVVIS":
                worked=GaussSum.UVVis.UVVis(root,self.screen,self.logfile,self.start.get(),self.end.get(),self.numpts.get(),self.FWHM.get(),self.UVplot.get(),self.settings['global settings.gnuplot'])
            elif s=="EDDM":
                worked=GaussSum.EDDM.EDDM(self.screen,self.logfile,self.trans.get(),self.settings['eddm.cubman'],self.settings['eddm.formchk'],self.settings['eddm.cubegen'])
            elif s=="NMR":
                listboxvalue=self.nmrlbx1.curselection()
                try: # Works for both list of strings and list of ints (see Tkinter documentation for details)
                    listboxvalue=map(int,listboxvalue)
                except ValueError: pass
                if len(listboxvalue)>0:
                    selected = self.nmrlbx1.get(listboxvalue[0])
                else:
                    selected = []
                worked=GaussSum.NMR.NMR(self.screen,self.logfile,self.nmrrb.get(),
                                        selected,self.nmrrb2.get(),self.nmrstandards)
        except:
            traceback.print_exc(file=self.error) # Catch errors from the python scripts (user GIGO errors, of course!)
            tkMessageBox.showerror(title="The script is complaining...",message=self.error.log)
            self.error.clear()
        root.update()

     
    def addmenubar(self,root): # Sets up the menubar
        menu = Menu(root)
        root.config(menu=menu)

        filemenu = Menu(menu)
        menu.add_cascade(label="File", underline=0, menu=filemenu)
        filemenu.add_command(label="Open...", underline=0, command=self.fileopen)
        filemenu.add_command(label="Settings...",underline=0, command=self.preferences)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", underline=1, command=self.fileexit)

        viewmenu=Menu(menu)
        menu.add_cascade(label="View", underline=0, menu=viewmenu)
        viewmenu.add_command(label="Error messages", underline=1, command=self.showerrors)

        helpmenu = Menu(menu)
        menu.add_cascade(label="Help", underline=0, menu=helpmenu)
        helpmenu.add_command(label="Documentation",underline=0, command=self.webdocs)
        helpmenu.add_separator()
        helpmenu.add_command(label="About...", underline=0, command=self.aboutdialog)
        
    def aboutdialog(self,event=None): # Soaks up event if provided
        d=AboutPopupBox(root,title="About GaussSum")

    def showerrors(self):
        self.screen.write("Log of error messages\n%s\n%s\n" % ('*'*20,self.error.longlog) )
                              
    def fileexit(self):
        root.destroy()

    def fileopen(self):
        if self.inputfilename!=None:
            mydir=os.path.dirname(self.inputfilename)
        else:
            mydir="."
        filetype=self.settings['global settings.filetype']                
        if filetype=="Gaussian":
            inputfilename=tkFileDialog.askopenfilename(
                filetypes=[
                    ("GaussianW03 Output Files",".out"),
                    ("Gaussian03 Log Files",".log"),
                    ("Gaussian03 Checkpoint Files",".chk"),
                    ("Gaussian03 Formatted Checkpoint",".fch"),
                    ("All files",".*")
                    ],
                initialdir=mydir
                )

        elif filetype=="GAMESS":
            inputfilename=tkFileDialog.askopenfilename(filetypes=[ ("GAMESS Log Files",".log") ], initialdir=mydir)
        else:
            inputfilename=tkFileDialog.askopenfilename(filetypes=[ ("Hyperchem Log Files",".log") ], initialdir=mydir)
            
        if inputfilename!="":
            self.inputfilename=os.path.basename(inputfilename)
            os.chdir(os.path.dirname(inputfilename))
            if filetype=="Gaussian":
                self.logfile=Gaussian03(self.inputfilename)
            elif filetype=="GAMESS":
                self.logfile=GAMESS(self.inputfilename)
            else:
                self.logfile=Hyperchem(self.inputfilename)
            self.fileopenednow()

    def fileopenednow(self):
        self.screen.write("Opened %s\n" % self.inputfilename)

        self.b0.configure(state=NORMAL)
        self.b1.configure(state=NORMAL)
        self.b2.configure(state=NORMAL)
        self.b3.configure(state=NORMAL)
        self.b4.configure(state=NORMAL)
        self.b5.configure(state=NORMAL)
        self.b6.configure(state=NORMAL)
        self.b7.configure(state=NORMAL) 
        self.b3.invoke() # Click on Find.py
        root.title("GaussSum - "+self.inputfilename)

    def preferences(self):
        # The Preferences Dialog Box
        oldsettings=copy.deepcopy(self.settings) # Remember the old settings
        d=PreferencesPopupBox(root,self.settings,title="Settings")
        if self.settings!=oldsettings: # if there are any changes
            self.saveprefs()

    def saveprefs(self):
        # Save the settings
        appdata=os.getenv("HOME")
        settingsfile=os.path.join(appdata,".GaussSum1.0","GaussSum.ini")
        writeoutconfigfile(self.settings,settingsfile)


    def readprefs(self):
        # Check for GaussSum.ini in $HOME/GaussSum1.0 (XP)
        #                        or $HOME/.gausssum1.0 (Linux)

        appdata=os.getenv("HOME")
        self.settings={}

        if appdata==None: # Must not be a Windows machine!!
            self.screen.write("Environmental variable HOME is not defined!\n\
                               I cannot continue, as I need HOME to know\
                               where to store GaussSum settings.\n")
        else: # If everything is normal so far
            settingsdir=os.path.join(appdata,".GaussSum1.0")
            settingsfile=os.path.join(settingsdir,"GaussSum.ini")

            if os.path.isfile(settingsfile): # Check for settings file
                # Found it! - so read it in.
                self.settings=readinconfigfile(settingsfile)
                
            else: # Initialise the settings file (and directory)
                if not os.path.isdir(settingsdir):
                    os.mkdir(settingsdir)
                self.settings={'global settings.filetype':'Gaussian',
                               'global settings.gnuplot':'/usr/bin/gnuplot',
                               'find.text1':'SCF Done',
                               'find.text2':'k 501%k502',
                               'find.text3':'imaginary',
                               'find.text4':'Framework',
                               'ir_raman.start':'0',
                               'ir_raman.end':'4000',
                               'ir_raman.numpoints':'500',
                               'ir_raman.fwhm':'3',
                               'mo.start':'-20',
                               'mo.end':'0',
                               'mo.fwhm':'0.3',
                               'uvvis.start':'300',
                               'uvvis.end':'800',
                               'uvvis.numpoints':'500',
                               'uvvis.fwhm':'3000',
                               'uvvis.sigma':'0.2',
                               'eddm.cubman':'C:\\Gaussian\\cubman.exe',
                               'eddm.formchk':'C:\\Gaussian\\formchk.exe',
                               'eddm.cubegen':'C:\\Gaussian\\cubegen.exe',
                               'nmr.data':os.path.join(settingsdir,"nmrdata.txt")
                               }
                self.saveprefs() # Save the inital settings file

 
    def webdocs(self):
        webbrowser.open("/usr/share/doc/gausssum/html/index.html")

        

class ErrorCatcher:
    def __init__(self):
        self.log=""
        self.longlog=""
    def write(self,text):
        self.log=self.log+text
    def clear(self):
        self.longlog=self.longlog+self.log
        self.log=""

class PreferencesPopupBox(tkSimpleDialog.Dialog):

    def __init__(self, parent, settings, title = None): # Override (just to set the geometry!)

        Toplevel.__init__(self, parent)
        self.transient(parent)
        self.settings=settings                    # Note that changes to self.settings will affect the global self.settings thru 'settings'
        self.oldsettings=settings.copy()          # Remember the current settings
        self.filetype=StringVar()
        self.filetype.set(self.settings['global settings.filetype'])

        if title:
            self.title(title)

        self.parent = parent
        self.result = None
        body = Frame(self)
        self.initial_focus = self.body(body)
        body.pack(padx=5, pady=5)

        self.buttonbox()
##        self.grab_set()

        if not self.initial_focus:
            self.initial_focus = self

        self.protocol("WM_DELETE_WINDOW", self.cancel)

        self.initial_focus.focus_set()
        self.wait_window(self)

   
    def body(self,master): # Override
        # The content of the settings dialog box

        # Creation of the main sections
        self.resizable(False,False)
        self.frame1=Frame(master,relief=SUNKEN,borderwidth=2)
        self.frame1.pack()
        Label(self.frame1,text="Global Settings").pack()
        self.frame2=Frame(self.frame1)
        self.frame2.pack()
        Label(self.frame1,text="").pack()
        
        Label(self.frame1,text="Find.py").pack()
        self.frame3=Frame(self.frame1)
        self.frame3.pack()
        Label(self.frame1,text="").pack()
        
        Label(self.frame1,text="IR_Raman.py").pack()
        self.frame4=Frame(self.frame1)
        self.frame4.pack()
        Label(self.frame1,text="").pack()
        
        Label(self.frame1,text="MO.py").pack()
        self.frame5=Frame(self.frame1)
        self.frame5.pack()
        Label(self.frame1,text="").pack()
        
        Label(self.frame1,text="UVVis.py").pack()
        self.frame6=Frame(self.frame1)
        self.frame6.pack()
        Label(self.frame1,text="").pack()

        Label(self.frame1,text="EDDM.py").pack()
        self.frame8=Frame(self.frame1)
        self.frame8.pack()
        Label(self.frame1,text="").pack()
        
        Label(self.frame1,text="NMR.py").pack()
        self.frame7=Frame(self.frame1)
        self.frame7.pack()

        # The Global Settings section
        self.frame2a=Frame(self.frame2)
        self.frame2a.pack()
        Label(self.frame2a,text="File type:").pack(side=LEFT)
        self.b0=Radiobutton(self.frame2a, text="Gaussian", variable=self.filetype, value="Gaussian", command=self.update)
        self.b0.pack(side=LEFT)
        self.b2=Radiobutton(self.frame2a, text="GAMESS", variable=self.filetype, value="GAMESS", command=self.update)
        self.b2.pack(side=LEFT)
        self.b1=Radiobutton(self.frame2a, text="Hyperchem", variable=self.filetype, value="Hyperchem", command=self.update)
        self.b1.pack(side=LEFT)
        self.frame2b=Frame(self.frame2)
        self.frame2b.pack()
        Label(self.frame2b,text="Gnuplot:").grid(row=0,column=0)
        self.gnuplot=Entry(self.frame2b,width=35)
        self.gnuplot.grid(row=0,column=1)
        self.gnuplot.delete(0,END)
        self.gnuplot.insert(0,self.settings['global settings.gnuplot'])
        Button(self.frame2b,text="Test",command=self.testgnuplot).grid(row=0,column=2,padx=5)

        
        
        # The Find.py section
        Label(self.frame3,text="Search for:").grid(row=0,column=0)
        self.find=[None]*4
        self.find[0]=Entry(self.frame3,width=15)
        self.find[1]=Entry(self.frame3,width=15)
        self.find[2]=Entry(self.frame3,width=15)
        self.find[3]=Entry(self.frame3,width=15)
        self.find[0].grid(row=0,column=1)
        self.find[1].grid(row=1,column=1)
        self.find[2].grid(row=0,column=2)        
        self.find[3].grid(row=1,column=2)
        for i in range(4):
            self.find[i].delete(0,END)
            self.find[i].insert(0,self.settings[ 'find.text%d'%(i+1) ])

        # The IR_Raman.py section
        self.irraman=[None]*4
        Label(self.frame4,text="Start:").grid(row=0,column=0)
        self.irraman[0]=Entry(self.frame4,width=5)
        self.irraman[0].grid(row=0,column=1)
        Label(self.frame4,text="End:").grid(row=0,column=2)        
        self.irraman[1]=Entry(self.frame4,width=5)
        self.irraman[1].grid(row=0,column=3)
        Label(self.frame4,text="Num pts:").grid(row=0,column=4)                
        self.irraman[2]=Entry(self.frame4,width=5)
        self.irraman[2].grid(row=0,column=5)
        Label(self.frame4,text="FWHM:").grid(row=0,column=6)                
        self.irraman[3]=Entry(self.frame4,width=5)
        self.irraman[3].grid(row=0,column=7)
        a=['start','end','numpoints','fwhm']
        for i in range(4):
            self.irraman[i].delete(0,END)
            self.irraman[i].insert(0,self.settings[ 'ir_raman.%s'%a[i] ])

        # The MO.py section
        self.mo=[None]*3
        Label(self.frame5,text="Start:").grid(row=0,column=0)
        self.mo[0]=Entry(self.frame5,width=5)
        self.mo[0].grid(row=0,column=1)
        Label(self.frame5,text="End:").grid(row=0,column=2)        
        self.mo[1]=Entry(self.frame5,width=5)
        self.mo[1].grid(row=0,column=3)
        Label(self.frame5,text="FWHM").grid(row=0,column=4)                
        self.mo[2]=Entry(self.frame5,width=5)
        self.mo[2].grid(row=0,column=5)
        a=['start','end','fwhm']
        for i in range(3):
            self.mo[i].delete(0,END)
            self.mo[i].insert(0,self.settings['mo.%s'%(a[i])])


        # UVVis.py section
        self.uvvis=[None]*5
        Label(self.frame6,text="Start:").grid(row=0,column=0)
        self.uvvis[0]=Entry(self.frame6,width=5)
        self.uvvis[0].grid(row=0,column=1)
        Label(self.frame6,text="End:").grid(row=0,column=2)        
        self.uvvis[1]=Entry(self.frame6,width=5)
        self.uvvis[1].grid(row=0,column=3)
        Label(self.frame6,text="Num pts:").grid(row=0,column=4)                
        self.uvvis[2]=Entry(self.frame6,width=5)
        self.uvvis[2].grid(row=0,column=5)
        Label(self.frame6,text="FWHM:").grid(row=0,column=6)                
        self.uvvis[3]=Entry(self.frame6,width=5)
        self.uvvis[3].grid(row=0,column=7)
        Label(self.frame6,text="sigma:").grid(row=0,column=8)                
        self.uvvis[4]=Entry(self.frame6,width=5)
        self.uvvis[4].grid(row=0,column=9)

        a=['start','end','numpoints','fwhm','sigma']
        for i in range(5):
            self.uvvis[i].delete(0,END)
            self.uvvis[i].insert(0,self.settings['uvvis.%s'%(a[i])])

        # The EDDM.py section
        Label(self.frame8,text="Path to cubman:").grid(row=0,column=0)
        self.cubman=Entry(self.frame8,width=35)
        self.cubman.grid(row=0,column=1)
        self.cubman.delete(0,END)
        self.cubman.insert(0,self.settings['eddm.cubman'])
        Button(self.frame8,text="Check",command=self.checkcubman).grid(row=0,column=2,padx=5)
        Label(self.frame8,text="Path to formchk:").grid(row=1,column=0)
        self.formchk=Entry(self.frame8,width=35)
        self.formchk.grid(row=1,column=1)
        self.formchk.delete(0,END)
        self.formchk.insert(0,self.settings['eddm.formchk'])
        Button(self.frame8,text="Check",command=self.checkformchk).grid(row=1,column=2,padx=5)
        Label(self.frame8,text="Path to cubegen:").grid(row=2,column=0)
        self.cubegen=Entry(self.frame8,width=35)
        self.cubegen.grid(row=2,column=1)
        self.cubegen.delete(0,END)
        self.cubegen.insert(0,self.settings['eddm.cubegen'])
        Button(self.frame8,text="Check",command=self.checkcubegen).grid(row=2,column=2,padx=5)


        # The NMR.py section
        Label(self.frame7,text="NMR reference info:").grid(row=0,column=0)
        self.nmrdata=Entry(self.frame7,width=30)
        self.nmrdata.grid(row=0,column=1)
        self.nmrdata.delete(0,END)
        self.nmrdata.insert(0,self.settings['nmr.data'])
	Label(self.frame7,text="").grid(row=1)


#        Label(master,text="").pack(side=TOP) # Creates a bit of spacing at the bottom

#        self.frame2=Frame(master)
#        self.frame2.pack()
#        self.scrollbar=Scrollbar(self.frame2,orient=VERTICAL)
#        self.listbox=Listbox(self.frame2, height=1,yscrollcommand=self.scrollbar.set)
#        self.scrollbar.config(command=self.listbox.yview)
#        self.scrollbar.pack(side=RIGHT)
#        self.listbox.insert(END,"A list entry")
#        for item in ["one","two","three"]:
#            self.listbox.insert(END,item)
#        self.listbox.pack(side=LEFT,fill=BOTH,expand=1)
#        self.listbox.pack(side=LEFT)


        x=(652-450)/2+root.winfo_rootx()
        y=(480-610)/2+root.winfo_rooty()
        
        self.geometry("450x610+"+str(x)+"+"+str(y)) # Place it in the centre of the root window

    def buttonbox(self): # Override
        box = Frame(self)
        cancel=Button(box,text="Cancel",width=10,command=self.cancel,default=ACTIVE)
        cancel.pack(side=LEFT,padx=5,pady=5)
        self.save = Button(box, text="Save", width=10, command=self.ok, default=ACTIVE)
        self.save.pack(side=LEFT, padx=5, pady=5)
        self.bind("<Return>",self.ok)
        self.bind("<Escape>",self.cancel)
        box.pack()

    def checkcubman(self, event=None): # Checks for existence of cubman at specificed location
        if not os.path.isfile(self.cubman.get()):
            tkMessageBox.showerror(title="No such file",
                                   message='''
There isn't any file with this name.
                                   
Make sure you include the full path, filename and extension (if any).

For example (in Windows): C:\\Program Files\\Gaussian\\cubman.exe'''
                                   )
            
    def checkformchk(self, event=None): # Checks for existence of formchk at specificed location
        if not os.path.isfile(self.formchk.get()):
            tkMessageBox.showerror(title="No such file",
                                   message='''
There isn't any file with this name.
                                   
Make sure you include the full path, filename and extension (if any).

For example (in Windows): C:\\Program Files\\Gaussian\\formchk.exe'''
                                   )

    def checkcubegen(self, event=None): # Checks for existence of formchk at specificed location
        if not os.path.isfile(self.cubegen.get()):
            tkMessageBox.showerror(title="No such file",
                                   message='''
There isn't any file with this name.
                                   
Make sure you include the full path, filename and extension (if any).

For example (in Windows): C:\\Program Files\\Gaussian\\cubegen.exe'''
                                   )



    def testgnuplot(self, event=None): # Tests Gnuplot!!
        if os.path.isfile(self.gnuplot.get()):
            Gnuplot(root,self.gnuplot.get(), # test the current value for Gnuplot
                "set isosample 50\nset hidden3d\nunset border\n"
                "unset xtics\nunset ytics\nunset ztics\n"
                "set xrange [-1.5:1.5]\nset yrange [-1.5:1.5]\n"
                "set zrange [0:1]\nset view 50,50,,1.4\n"
                "splot exp(-x*x-y*y) notitle\n",
                "You should see the GaussSum logo below...drawn by Gnuplot")
        else:
            tkMessageBox.showerror(title="No such file",
                                   message='''
There isn't any file with this name.
                                   
Make sure you include the full path, filename and extension (if any).

For example (in Windows): C:\\Program Files\\Gnuplot\\bin\\Wgnuplot.exe'''
                                   )
            
 

    def ok(self, event=None): # Override
        # Remembers the settings
        # If they are different from before, they will be saved by 'preferences()'

        self.settings['global settings.filetype']=self.filetype.get()
        self.settings['global settings.gnuplot']=self.gnuplot.get()
        self.settings['eddm.cubman']=self.cubman.get()
        self.settings['eddm.formchk']=self.formchk.get()
        self.settings['eddm.cubegen']=self.cubegen.get()        
        self.settings['nmr.data']=self.nmrdata.get()    
        a=['start','end','numpoints','fwhm']
        for i in range(4):
            self.settings['find.text%d'%(i+1)]=self.find[i].get()
            self.settings['ir_raman.%s'%(a[i])]=self.irraman[i].get()
            self.settings['uvvis.%s'%(a[i])]=self.uvvis[i].get()
        self.settings['uvvis.sigma']=self.uvvis[4].get()
        a=['start','end','fwhm']
        for i in range(3):
            self.settings['mo.%s'%(a[i])]=self.mo[i].get()            

        if not self.validate():
            self.initial_focus.focus_set() # put focus back
            return

        self.withdraw()
        self.update_idletasks()

        self.apply()

        self.cancel()


class AboutPopupBox(tkSimpleDialog.Dialog):

    def __init__(self, parent, title = None): # Override (just to set the geometry!)

        Toplevel.__init__(self, parent)
        self.transient(parent)

        if title:
            self.title(title)

        self.parent = parent
        self.result = None
        body = Frame(self)
        self.initial_focus = self.body(body)
        body.pack(padx=5, pady=5)

        self.buttonbox()
        self.grab_set()

        if not self.initial_focus:
            self.initial_focus = self

        self.protocol("WM_DELETE_WINDOW", self.cancel)

        self.initial_focus.focus_set()
        self.wait_window(self)

        
    def body(self,master): # Override

        self.resizable(False,False)
        self.canvas2 = Canvas(master,width=340,height=260)
        self.canvas2.pack(side=TOP)

        self.photo2 = PhotoImage(file="/usr/share/gausssum/mesh.gif")
        self.item2 = self.canvas2.create_image(11,11,anchor=NW,image=self.photo2)

        Label(master,text="(c) 2005").pack(side=TOP)
        Label(master,text="Noel O'Boyle",font=("Times",10,"bold")).pack(side=TOP)
        #Button(master,text="GaussSum home page on SourceForge",command=self.openmybrowser).pack(side=TOP)
	Label(master,text="http://gausssum.sourceforge.net").pack(side=TOP)
        Label(master,text="").pack(side=TOP) # Creates a bit of spacing at the bottom

        x=(652-354)/2+root.winfo_rootx() # Popup is 354x389
        y=(480-405)/2+root.winfo_rooty()
        self.geometry("354x405+"+str(x)+"+"+str(y)) # Place it in the centre of the root window

    def openmybrowser(self): # New
        webbrowser.open("http://gausssum.sourceforge.net")
        
    def buttonbox(self): # Override
        box = Frame(self)
        w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
        w.pack(side=LEFT, padx=5, pady=5)
        self.bind("<Return>", self.ok)
        box.pack()


# This class allows Find.py, etc. to write directly to the 'console screen'
# in GaussSum.py.
# It also allows Find.py, etc. to write to stdout when testing.

class Redirect:
    def __init__(self,write_function,root,other):
        self.outputfn=write_function
        self.args=other
        self.root=root
    def write(self,text):
        if self.args=="None":
            self.outputfn(text)
        else:
            self.outputfn(self.args[0],text)
            self.root.update() # so it shows it immediately
            self.args[1].see(END) # scroll if necessary to see last text inserted
        

def readinconfigfile(inifile):
    # Taken from the Python Cookbook (O'Reilly):
    # reads in configuration information from a
    # Windows-style .ini file, and returns a
    # dictionary of settings.
    #
    # Uses the Python module ConfigParser for the complicated stuff.
    cp=ConfigParser.ConfigParser()
    cp.read(inifile)
    config={}
    for sec in cp.sections():
        name=string.lower(sec)
        for opt in cp.options(sec):
            config[name+"."+string.lower(opt)]=string.strip(cp.get(sec,opt))

    return config
            
def writeoutconfigfile(config,inifile):
    # The companion to readinconfigile
    # Written by me!
    cp=ConfigParser.ConfigParser()

    for key,value in config.items():
        sec=key.split('.')[0]
        opt=key.split('.')[1]
        if not cp.has_section(sec):
            cp.add_section(sec)
        cp.set(sec,opt,value)

    out=open(inifile,"w")
    cp.write(out)
    out.close()

class NMRstandards(object):
    def __init__(self,location):
        """
        Read in the nmr standards file (if it exists)
        Returns a list of dictionaries:
            nmrdata=[dict_1,dict_2,dict_3...]
            dict_n=['theory':'B3LYP/6-31G(d)','name':'TMS','C':12.23,'H':123]
        """
        self.location = location
        self.nmrdata = []

        # Check for nmr standards file in location described in settings
        try:
            readin = open(self.location,"r")
        except IOError:
            # File does not exist - i.e. no settings yet
            pass
        else:
            for line in readin:
                if not line.lstrip().startswith("#"): # Ignore comments
                    temp=line.split("\t")
                    adict={}
                    adict['theory']=temp[0]
                    adict['name']=temp[1]
                    for i in range(2,len(temp),2): # Read in the calculated shifts
                        adict[temp[i]]=float(temp[i+1])
                    self.nmrdata.append(adict)
            readin.close()
    def __getitem__(self,index):
        """Shortcut to access the data directly."""
        return self.nmrdata[index]
    def save(self):
        """Write the NMR standards to disk."""
        outputfile = open(self.location,"w")
        lines = []
        for adict in self.nmrdata:
            output = [adict['theory'],adict['name']]
            for k,v in adict.iteritems():
                if k not in ["theory","name"]:
                    output.append(k)
                    output.append(str(v))
            lines.append("\t".join(output))
        outputfile.write("\n".join(lines))
        outputfile.close()
        
        



# The part that runs first
root=Tk()   # Create a root window
root.title("GaussSum")

app=App(root,sys.argv)   # Set up the app...

mainloop()  # ...and sit back

