#!/usr/bin/env python

# command line 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)

#---------------------------------------------------------------------------------------------------
import os, sys
from copy import deepcopy
from optparse import OptionParser

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

from qmxWRITE import writeData

#---------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------
def getline(section, subsection, lines):
    nline = -1
    for iline in xrange(len(lines)):
        if lines[iline][0].strip() == subsection:
            if nline != -1:
                sys.stderr.write("section: <"+section+separator+subsection+"> has been definied more than once\n")
                sys.exit(1)
            nline = iline
    if nline == -1:
        return None
    return lines[nline][1].strip()

#---------------------------------------------------------------------------------------------------
def analyzeSection(definitions, section, lines):
    line = getline(section, "program", lines)
    if line is None:
        print "section <" + section + "> does not contain program"
        sys.exit(1)
        
    myDefinition = None
    for definition in definitions:
        if definition.name == line:
            myDefinition = deepcopy(definition)
            break
            
    if myDefinition is None:
        print "the program <" + line + "> is not defined for the section <" + section + ">"
        sys.exit(1)
        
    myDefinition.system = section

    subsections = []
    for line in lines:
        subsections.append(line[0].strip().lower())

    for subsection in subsections:
        line = getline(section, subsection, lines)
        if line is None:
            print "input error in <"+section+"."+subsection+">"
            sys.exit(1)
        if subsection == "program":
            continue
        if subsection == "options":
            subsection = 'class.options'
        
        myDefinition.keywords[subsection] = line    
        print subsection, myDefinition.keywords[subsection]
    
    return myDefinition

#---------------------------------------------------------------------------------------------------
#--- setting default values ------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------

#define separators
separator=":"
subseparator="."
lineseparator="\n"

#--- parse arguments -------------------------------------------------------------------------------
#parse arguments (python 2.6)
parser = OptionParser()
parser.add_option("-i", "--infile",  dest="inputFile",  help="specifies the input file", metavar="FILE", default="qmx.in")
parser.add_option("-o", "--outfile", dest="outputFile", help="specifies the output file", metavar="FILE")
parser.add_option("-f", action="store_true", dest="overwrite")
(options, args) = parser.parse_args()

#--- check wether output file exists ---------------------------------------------------------------
if options.outputFile is not None and os.path.exists(options.outputFile) and not options.overwrite:
    sys.stderr.write(lineseparator+"the output file <"+options.outputFile+"> already exists"+lineseparator)
    sys.exit(1)

#--- read intput file ------------------------------------------------------------------------------
file=open(options.inputFile, "r")
lines = file.readlines()
file.close()

#--- remove comments -------------------------------------------------------------------------------
for iline in xrange(len(lines)):
    lines[iline] = lines[iline].split("#")[0]    

#--- collect data in class -------------------------------------------------------------------------
definitions=[]
definitions.append(QmxCalcDefinition())

#--- analyze the input file ------------------------------------------------------------------------
for section in "high-level", "low-level", "cluster", "system", "job":
    #search lines for section
    lines_section=[]
    for line in lines:
        line = line.split(separator)
        if line[0].find(section) >= 0:
            line[0] = line[0].replace(section+subseparator, "")
            lines_section.append(line)

    #calculators
    if section == "high-level" or section == "low-level":
        definitions.append(analyzeSection(calcDefinitions, section, lines_section))
        
    #structures (atoms)
    if section == "cluster" or section == "system":
        definitions.append(analyzeSection(strDefinitions, section, lines_section))
        
    #job
    if section == "job":
        definitions.append(analyzeSection(jobDefinitions, section, lines_section))
        
    #embed
    if section == "embed":
        definitions.append(analyzeSection(embedDefinitions, section, lines_section))

output = None
if options.outputFile is None:
    output=sys.stdout
else:
    output=open(options.outputFile, "w")
    
writeData(output, definitions)
output.close()







#
##--- write header ----------------------------------------------------------------------------------
#output.write("#!/usr/bin/env python\n")
#
##--- write import lines ----------------------------------------------------------------------------
#xlines=[]
#for data in data_collection:
#    value = data.str_import
#    if value is None or value in xlines:
#        continue
#    xlines.append(value)
#    output.write(value+lineseparator)
#output.write(lineseparator)
#
##--- define the methods ----------------------------------------------------------------------------
#for system in 'high', 'low':
#    for data in data_collection:
#        if data.__name__ == system+"-level":
#            output.write(system+"Level = "+data.str_class+"("+data.str_option+")"+lineseparator)
#output.write(lineseparator)
#
##--- qmx class (substraction scheme ----------------------------------------------------------------
#for data in data_collection:
#    if data.__name__ == "qmx":
#        output.write("qmx = "+data.str_class+"("+data.str_option+")"+lineseparator)
#output.write(lineseparator)
#
##--- read all the systems --------------------------------------------------------------------------
#for system in "cluster", "system":
#    for data in data_collection:
#        if data.__name__ == system:
#            if data.str_structure is None:
#                continue
#            output.write(system+" = "+data.str_class+"(\""+data.str_structure+"\")"+lineseparator)
#output.write(lineseparator)
#
##--- embeding class --------------------------------------------------------------------------------
#for data in data_collection:
#    if data.__name__ == "embed":
#        output.write("embed = "+data.str_class+"("+data.str_option+")"+lineseparator)
#        for method in data.str_methods:
#            output.write("embed."+method+lineseparator)
#output.write(lineseparator)
#
##--- dynamics class --------------------------------------------------------------------------------
#for data in data_collection:
#    if data.__name__ == "dynamics":
#        output.write("dyn="+data.str_class+"(embed)"+lineseparator)
#        output.write("dyn.run("+data.str_option+")"+lineseparator)
#
#
#
#
#
#def getline(section, subsection, lines):
#    nline = -1
#    for iline in xrange(len(lines)):
#        if lines[iline][0].strip() == subsection:
#            if nline != -1:
#                sys.stderr.write("section: <"+section+separator+subsection+"> has been definied more than once\n")
#                sys.exit(1)
#            nline = iline
#    if nline == -1:
#        return None
#    return lines[nline][1].strip()
#
##def analyzeAtoms(section, lines):
##    data = Data(section)
##    line = getline(section, "program", lines)
##    if line is None:
##        line=""
##    if line.lower() == "turbomole":
##        data.str_import = "from ase.io.turbomole import read_turbomole"
##        data.str_class = "read_turbomole"
##    elif line.lower() == "vasp":
##        data.str_import = "from ase.io.vasp import read_vasp"
##        data.str_class = "read_vasp"
##        
##    data.str_structure = getline(section, "structure", lines)
##    return data
##
##def analyzeCalculator(section, lines):
##    data = Data(section)
##    #read programs
##    line = getline(section, "program", lines)
##    if line.lower() == "turbomole":
##        data.str_import = "from ase.calculators.turbomole import Turbomole"
##        data.str_class = "Turbomole"
##    elif line.lower() == "vasp":
##        data.str_import = "from ase.calculators.vasp import Vasp"
##        data.str_class = "Vasp"
##    
##    str = getline(section, "class", lines)
##    if str is not None:
##        data.str_class = str
##
##    str = getline(section, "import", lines)
##    if str is not None:
##        data.str_import = str
##
##    str = getline(section, "options", lines)
##    if str is not None:
##        data.str_option = str
##    return data
##
##def analyzeDynamics(section, lines):
##    data = Data(section)
##    line = getline(section, "method", lines)
##    if line.lower() == "optimizer":
##        data.str_import = "from ase.optimize import QuasiNewton"
##        data.str_class = "QuasiNewton"
##    return data

