# -*- coding: utf-8 -*-
"""
Created on 2020-05-11
@author: Vincent Michaud-Rioux
"""
from nanotools.base import Base
from nanotools.energy import Energy
from nanotools.io.calculators import solve_generic
from nanotools.solver import Solver
from nanotools.system import System
from nanotools.totalenergy import TotalEnergy
from nanotools.utils import dict_converter
import attr
import numpy as np
[docs]
@attr.s
class MullikenData(Base):
    """``Mulliken`` class' data holder.
    Args:
    Returns:
    """
    atom_populations: np.ndarray = attr.ib(
        default=[],
        converter=attr.converters.optional(np.array),
        validator=attr.validators.optional(attr.validators.instance_of(np.ndarray)),
    )
    orbital_populations: np.ndarray = attr.ib(
        default=[],
        converter=attr.converters.optional(np.array),
        validator=attr.validators.optional(attr.validators.instance_of(np.ndarray)),
    )
    orbital_atom: np.ndarray = attr.ib(
        default=[],
        converter=attr.converters.optional(np.array),
        validator=attr.validators.optional(attr.validators.instance_of(np.ndarray)),
    )
    orbital_index: np.ndarray = attr.ib(
        default=[],
        converter=attr.converters.optional(np.array),
        validator=attr.validators.optional(attr.validators.instance_of(np.ndarray)),
    )
    orbital_l: np.ndarray = attr.ib(
        default=[],
        converter=attr.converters.optional(np.array),
        validator=attr.validators.optional(attr.validators.instance_of(np.ndarray)),
    )
    orbital_m: np.ndarray = attr.ib(
        default=[],
        converter=attr.converters.optional(np.array),
        validator=attr.validators.optional(attr.validators.instance_of(np.ndarray)),
    )
    orbital_species: np.ndarray = attr.ib(
        default=[],
        converter=attr.converters.optional(np.array),
        validator=attr.validators.optional(attr.validators.instance_of(np.ndarray)),
    ) 
[docs]
@attr.s
class Mulliken(Base):
    """``Mulliken`` class.
    Examples::
        from nanotools import Mulliken
        import numpy as np
        calc = Mulliken.from_totalenergy("nano_scf_out.json")
        calc.solve()
    Attributes:
        system:
           Object containing system related parameters.
        energy:
           Object containing the total energy and its derivatives (force, stress, etc.).
        mulliken:
           Object containing the Mulliken population data.
        solver:
           Object containing solver related parameters.
    """
    # input is dictionary with default constructor
    system: System = attr.ib(
        converter=lambda d: dict_converter(d, System),
        validator=attr.validators.instance_of(System),
    )
    # optional
    energy: Energy = attr.ib(
        factory=Energy,
        converter=lambda d: dict_converter(d, Energy),
        validator=attr.validators.instance_of(Energy),
    )
    mulliken: MullikenData = attr.ib(
        factory=MullikenData,
        converter=lambda d: dict_converter(d, MullikenData),
        validator=attr.validators.instance_of(MullikenData),
    )
    solver: Solver = attr.ib(
        factory=Solver,
        converter=lambda d: dict_converter(d, Solver),
        validator=attr.validators.instance_of(Solver),
    )
    classname: str = attr.ib()
    @classname.default
    def _classname_default_value(self):
        return self.__class__.__name__
    def __attrs_post_init__(self):
        pass
    @classmethod
    def from_totalenergy(cls, totalenergy, **kwargs):
        if isinstance(totalenergy, TotalEnergy):
            pass
        else:
            totalenergy = TotalEnergy.read(totalenergy)
        sys = totalenergy.system.copy()
        calc = cls(sys, solver=totalenergy.solver, **kwargs)
        calc.energy = totalenergy.energy.copy()
        return calc
[docs]
    def solve(self, input="nano_mul_in", output="nano_mul_out"):
        """Performs a non.self-consistent calculation calling ``rescuplus``.
        Args:
            filename (str):
                The object is saved to an input file ``filename`` which is read by ``rescuplus``.
            output (str):
                The results (with various extensions) are moved to files ``output`` and the results are
                loaded to the object.
        """
        self._check_mul()
        output = solve_generic(self, "mul", input, output)
        self._update(output + ".json") 
    def _check_mul(self):
        return