#!/usr/bin/env python

# GRAPHICAL interface for setup of QMX calculations
#
# Torsten Kerber, ENS LYON: 2011, 07, 11
#
# This work is supported by Award No. UK-C0017, made by King Abdullah
# University of Science and Technology (KAUST)

#---------------------------------------------------------------------------------------------------
from Tkinter import *
from copy import deepcopy
import tkFileDialog
import StringIO, os

#---------------------------------------------------------------------------------------------------
from qmxEMBED import embedDefinitions
from qmxJOB import jobDefinitions
from qmxSTR import strClusterDefinitions, strSystemDefinitions
from qmxCALC import calcDefinitions, QmxCalcDefinition

from qmxWRITE import writeData

#---------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
class MyLabelFrame(LabelFrame):
    def __init__(self, mainWnd, master, title, name, def_list, fields):
        LabelFrame.__init__(self, master, text=title)
        self.mainWnd = mainWnd
        self.definitions=[]

        for definition in def_list:
            definition_new = deepcopy(definition)
            definition_new.system = name
            self.definitions.append(definition_new)

        if fields is None:
            fields = ['']

        self.entries=[]
        for key in fields:
            text=StringVar()
            text.set('')
            self.entries.append((key, text, Entry(self, textvariable=text, width=25)))
            
    def grid(self, **arguments):
        LabelFrame.grid(self, arguments, sticky=(N+W+E))
        self.listbox.selection_set(first=0)
        self.select(None)
        
    def doLayout(self):
        irow=0
        for (key, text, textfield) in self.entries:
            Label(self, text=key, width=15, anchor=W).grid(row=irow,  column=2)
            textfield.grid(row=irow, column=3)
            textfield.bind("<KeyRelease>", self.update)
            irow+=1
        
        scrollbar=Scrollbar(self, orient=VERTICAL)
        self.listbox=Listbox(self, yscrollcommand=scrollbar.set, height=5, width=15, selectmode=SINGLE, exportselection=0)
        self.listbox.grid(row=0, column=0, rowspan=irow, sticky=NS)
        self.listbox.bind('<ButtonRelease-1>', self.select)

        scrollbar.config(command=self.listbox.yview)
        scrollbar.grid(row=0, column=1, rowspan=irow, sticky=NS)
       
        for item in self.definitions:
            self.listbox.insert(END, item.name)
        
    def select(self, event):
        selection=self.listbox.curselection()
        if len(selection) == 1:
            self.curr_definition=deepcopy(self.definitions[int(selection[0])])
            for (key, text, textfield) in self.entries:
                text.set(self.curr_definition.getValue(key))
        self.mainWnd.preview()
    
    def getSelection(self):
        return self.curr_definition
        
    def update(self, event):
        for (key, text, textfield) in self.entries:
            self.curr_definition.keywords[key]=text.get()
        self.mainWnd.preview()

#---------------------------------------------------------------------------------------------------
class MainWindow(Frame):
    frames=[]
    text=None
    def __init__(self, master):
        Frame.__init__(self, master)
        
        fields=['import', 'class', 'class.options']
        
        irow=0
        for calcLabel, strLabel, strDefinitions in (
                ("high-level",  "cluster", strClusterDefinitions), 
                ("low-level",  "system", strSystemDefinitions)):
            #column
            icolLocal=0;
            #build outFrame
            outFrame = LabelFrame(self, text=calcLabel+" method - "+strLabel)
            outFrame.grid(row=irow, columnspan=3,  sticky=W, pady=5)
            irow+=1
            
            for title, def_list in ((calcLabel, calcDefinitions),  (strLabel, strDefinitions)):
                # build frame
                myFrame=MyLabelFrame(self, outFrame, title, title, def_list, fields)
                myFrame.doLayout()
                myFrame.grid(row=0, column=icolLocal, padx=5, pady=5)
                # add frame for analyssis
                self.frames.append(myFrame)
                # move column
                icolLocal += 1
            
        outFrame = LabelFrame(self, text="General")
        outFrame.grid(row=irow, columnspan=3, pady=5); irow+=1
        for title, name, def_list, extra_list,  irowLocal, icolLocal,  irspan in (
            ("Optimization Method",  "job", jobDefinitions, fields + ['method', 'method.options'], 0, 0, 2), 
            ("Embedding Method", "embed", embedDefinitions, fields + ['set_calculator'], 0, 1, 1), 
            ("Hybrid Method", "hybrid", [QmxCalcDefinition()], fields, 1, 1, 1)):
            # build frame
            myFrame=MyLabelFrame(self, outFrame, title, name, def_list, extra_list)
            myFrame.doLayout()
            myFrame.grid(row=irowLocal, column=icolLocal,  rowspan=irspan, padx=5, pady=5)
            # add frame for analyssis
            self.frames.append(myFrame)
            
        outFrame=LabelFrame(self, text="PREVIEW")
        scrollbar=Scrollbar(outFrame, orient=VERTICAL)
        scrollbar.set(0.0, 1.0)
        self.text=Text(outFrame, yscrollcommand=scrollbar.set, width=80, heigh=10, state=DISABLED)
        self.text.grid(sticky=(N+W+S+E))
        scrollbar.config(command=self.text.yview)
        scrollbar.grid(row=0, column=1, sticky=NS)        
        outFrame.grid(row=irow, column=0, sticky=W, pady=5);

        myFrame = Frame(self)
        buttonExit=Button(myFrame, text="Quit!", command=self.quit)
        buttonExit.grid(row=1, column = 1, rowspan=3, sticky= W+E+N+S)
        
        buttonSave=Button(myFrame, text='save settings', state=DISABLED)
        buttonSave.grid(row=1, column = 2, sticky=(EW))

        buttonScript=Button(myFrame, text='Write SCRIPT file', command=self.writeScript)
        buttonScript.grid(row=2, column = 2, sticky=EW)

        buttonPython=Button(myFrame, text='Write PYTHON file', command=self.writePython)
        buttonPython.grid(row=3, column = 2, sticky=EW)

        myFrame.grid(row=irow, column=2, sticky=SE)

        #--- MainWindow ---
        self.grid(sticky=(W+N+S+E))
        self.preview()
        
    def quit(self):
        quit()
    
    def writePython(self):
        fileName = tkFileDialog.asksaveasfile(mode='w')
        if fileName is None:
            return
        file = open(fileName,"w")
        definitions=[]
        for frame in self.frames:
            definition = frame.getSelection()
            if definition is not None:
                definitions.append(definition)

        writeData(file, definitions)
        file.close()
        os.system("chmod u+x qmx.py")
        
        
    def writeScript(self):
        fileName = tkFileDialog.asksaveasfile(mode='w')
        if fileName is None:
            return
        file = open(fileName,"w")
        for frame in self.frames:
            definition = frame.getSelection()
            if definition is None:
                continue

            system = definition.system.lower()
            data = system+".program : "+definition.name.lower()+"\n"
            file.write(data)
            for key in definition.keywords:
                data=system+"."+key+" : "+definition.getValue(key)+"\n"
                file.write(data)
            file.write("\n")
        file.close()

    def preview(self):
        stream = StringIO.StringIO()
        definitions=[]
        for frame in self.frames:
            definition = frame.getSelection()
            if definition is not None:
                definitions.append(definition)

        writeData(stream, definitions)
        s = stream.getvalue()
        
        if self.text is not None:
            pos, end = self.text.yview()
            self.text.config(state=NORMAL)
            self.text.delete(1.0, END)
            self.text.insert(END, s)
            self.text.config(state=DISABLED)
            self.text.yview(MOVETO, pos)

#---------------------------------------------------------------------------------------------------
mainWnd=MainWindow(Tk())
mainWnd.mainloop()
