#!/usr/bin/env python
import os, sys
from optparse import OptionParser

class Data:
    def __init__(self, name):
        self.__name__ = name
        self.str_option = ""
        self.str_import = None
        self.str_class  = None
        self.str_methods = []
        self.str_structure = None
                
    def __str__(self):
       return self.__name__

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 True or line.lower() == "turbomole":
        data.str_import = "from ase.io.turbomole import read_turbomole"
        data.str_class = "read_turbomole"
        
    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

#--- 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()

file=open(options.inputFile, "r")
lines = file.readlines()
file.close()


#--- split intput file -----------------------------------------------------------------------------

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

#--- collect data in class -------------------------------------------------------------------------
data_collection=[]

#--- settings for QMX class ------------------------------------------------------------------------
data = Data("qmx")
data.str_class = "Qmx"
data.str_import = "from ase.calculators.qmx import Qmx"
data.str_option = "highLevel, lowLevel"

data_collection.append(data)

#--- settings for Embed class ----------------------------------------------------------------------
data = Data("embed")
data.str_class = "Embed"
data.str_import = "from ase.embed import Embed"
data.str_option = "system, cluster"
data.str_methods = ["embed()", "set_calculator(qmx)"]

data_collection.append(data)


#--- analyze the input file ------------------------------------------------------------------------
for section in "high-level", "low-level", "cluster", "system", "dynamics":
    #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":
        data_collection.append(analyzeCalculator(section, lines_section))
        
    #systems
    if section == "cluster" or section == "system":
        data_collection.append(analyzeAtoms(section, lines_section))
        
    #dynamics
    if section == "dynamics":
        data_collection.append(analyzeDynamics(section, lines_section))

#--- write output file -----------------------------------------------------------------------------
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)

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

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

output.close()
sys.exit(0)
