"""
@package pmsco.msc_calculator
Kaduwela MSC program interface.

This module is currently not maintained.

@author Matthias Muntwiler

@copyright (c) 2015 by Paul Scherrer Institut @n
Licensed under the Apache License, Version 2.0 (the "License"); @n
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import pmsco.calculators.calculator as calculator
import pmsco.data as md
import subprojects.msc.msc as msc
import logging

logger = logging.getLogger(__name__)


class MscCalculator(calculator.Calculator):
    def write_input_file(self, params, filepath):
        with open(filepath, "w") as f:
            f.write(" %s\n" % (params.title))
            f.write(" %s\n" % (params.comment))
            l_init = "spdf".index(params.initial_state[1])
            f.write(" %4u\n" % (l_init))
            f.write(" %4u\n" % (params.spherical_order))
            f.write(" %s\n" % (params.polarization))
            f.write(" %4u\n" % (params.scattering_level))
            f.write("  %7.2f%7.2f\n" % (params.fcut, params.cut))
            f.write(" %12.6f\n" % (params.angular_resolution))
            f.write(" %12.6f\n" % (params.lattice_constant))
            f.write(" %12.6f\n" % (params.z_surface))
            f.write(" %4u\n" % (params.atom_types))
            for iat in range(params.atom_types):
                f.write(" %4u %s\n" % (params.atomic_number[iat], "..."))
                f.write(" %4u %s\n" % (params.atomic_number[iat], params.phase_file[iat]))
                f.write(" %12.6f\n" % (params.msq_displacement[iat]))
            f.write(" %12.6f\n" % (params.planewave_attenuation))
            f.write(" %12.6f\n" % (params.inner_potential))
            f.write(" %12.6f\n" % (params.symmetry_range))
            f.write(" %12.6f\n" % (params.polar_incidence_angle))
            f.write(" %12.6f\n" % (params.azimuthal_incidence_angle))
            f.write(" %s\n" % (params.vibration_model))
            f.write(" %12.6f\n" % (params.substrate_atomic_mass))
            f.write(" %12.6f\n" % (params.experiment_temperature))
            f.write(" %12.6f\n" % (params.debye_temperature))
            f.write(" %12.6f\n" % (params.debye_wavevector))
            f.write(" %12.6f%7.3f\n" % (params.rme_minus_value, params.rme_minus_shift))
            f.write(" %12.6f%7.3f\n" % (params.rme_plus_value, params.rme_plus_shift))
            f.write(" %4u\n" % (1))
            f.write(" %4u %12.6f\n" % (1, 1.0))

    def run(self, params, cluster, scan, output_file):
        """
        run the MSC program with the given parameters and cluster.

        @param params: a project.CalculatorParams() object with all necessary values except cluster and output files set.

        @param cluster: a cluster.Cluster(format=FMT_MSC) object with all atom positions set.

        @param scan: a project.Scan() object with all relevant parameters set.
            in particular, a scan file is required.

        @param output_file: base name for all intermediate and output files

        @return: result_file, files_cats

        the scan file must be in ETP(IS) format:
        * column 0: kinetic energy in eV
        * column 1: polar angle in degrees
        * column 2: azimuthal angle in degrees
        * further columns are ignored
        """

        # generate file names
        base_filename = output_file
        clu_filename = base_filename + ".clu"
        out_filename = base_filename + ".list"
        par_filename = base_filename + ".par"
        dat_filename = base_filename + ".plt1"
        etpi_filename = base_filename + ".etpi"

        # fix MSC particularities
        # singularity at theta == polar_incidence_angle
        if params.polar_incidence_angle == 60.0:
            params.polar_incidence_angle += 0.1

        # save parameter files
        cluster.save_to_file(clu_filename)
        self.write_input_file(params, par_filename)

        if logger.isEnabledFor(logging.INFO):
            options = "11"
        else:
            options = "00"
        revision = ""

        # run MSC
        msc.mscmain(par_filename, clu_filename, scan.filename, base_filename, revision, options)

        # load results
        result_etpi = md.load_plt(dat_filename)
        md.save_data(etpi_filename, result_etpi)

        files = {clu_filename: 'input', par_filename: 'input', dat_filename: 'output', base_filename: 'log',
                 out_filename: 'log', etpi_filename: 'energy'}
        return etpi_filename, files
