"""
Calculations provided by plugin

Register calculations via the "aiida.calculations" entry point in setup.json.
"""

from aiida.orm.calculation.job import JobCalculation
from aiida.common.utils import classproperty
from aiida.common.exceptions import (InputValidationError, ValidationError)
from aiida.common.datastructures import (CalcInfo, CodeInfo)
from aiida.orm import DataFactory

ParameterData = DataFactory('parameter')
SinglefileData = DataFactory('singlefile')


class PoreSurfaceCalculation(JobCalculation):
    """
    AiiDA calculation plugin for simple "multiplication"
    
    Simple AiiDA plugin for wrapping a code that adds two numbers.
    """

    def _init_internal_params(self):
        """
        Init internal parameters at class load time
        """
        # reuse base class function
        super(PoreSurfaceCalculation, self)._init_internal_params()

        self._default_parser = 'phtools.surface'

    @classproperty
    def _use_methods(cls):
        """
        Add use_* methods for calculations.
        
        Code below enables the usage
        my_calculation.use_parameters(my_parameters)
        """
        use_dict = JobCalculation._use_methods
        use_dict.update({
            "parameters": {
                'valid_types': ParameterData,
                'additional_parameter': None,
                'linkname': 'parameters',
                'docstring': 'add command line parameters',
            },
            "structure": {
                'valid_types': SinglefileData,
                'additional_parameter': None,
                'linkname': 'structure',
                'docstring': "add input structure to be analyzed",
            },
            "surface_sample": {
                'valid_types': SinglefileData,
                'additional_parameter': None,
                'linkname': 'surface_sample',
                'docstring': "surface sample generated by zeo++",
            },
        })
        return use_dict

    def _validate_inputs(self, inputdict):
        """ Validate input links.
        """
        # Check inputdict
        try:
            parameters = inputdict.pop(self.get_linkname('parameters'))
        except KeyError:
            raise InputValidationError("No parameters specified for this "
                                       "calculation")
        if not isinstance(parameters, ParameterData):
            raise InputValidationError("parameters not of type "
                                       "ParameterData")
        # Check code
        try:
            code = inputdict.pop(self.get_linkname('code'))
        except KeyError:
            raise InputValidationError("No code specified for this "
                                       "calculation")

        # Check input files
        try:
            structure = inputdict.pop(self.get_linkname('structure'))
            if not isinstance(structure, SinglefileData):
                raise InputValidationError(
                    "structure not of type SinglefileData")
        except KeyError:
            raise InputValidationError(
                "No input structure specified for calculation")

        try:
            surface_sample = inputdict.pop(self.get_linkname('surface_sample'))
            if not isinstance(surface_sample, SinglefileData):
                raise InputValidationError(
                    "surface_sample not of type SinglefileData")
        except KeyError:
            raise InputValidationError(
                "No surface sample specified for calculation")

        # Check that nothing is left unparsed
        if inputdict:
            raise ValidationError("Unrecognized inputs: {}".format(inputdict))

        return parameters, code, structure, surface_sample

    def _prepare_for_submission(self, tempfolder, inputdict):
        """
        Create input files.

            :param tempfolder: aiida.common.folders.Folder subclass where
                the plugin should put all its files.
            :param inputdict: dictionary of the input nodes as they would
                be returned by get_inputs_dict
        """
        parameters, code, structure, surface_sample = \
                self._validate_inputs(inputdict)

        # Prepare CalcInfo to be returned to aiida
        calcinfo = CalcInfo()
        calcinfo.uuid = self.uuid
        calcinfo.local_copy_list = [
            [structure.get_file_abs_path(), structure.filename],
            [surface_sample.get_file_abs_path(), surface_sample.filename],
        ]
        calcinfo.remote_copy_list = []
        calcinfo.retrieve_list = parameters.output_files

        codeinfo = CodeInfo()
        # will call ./code.py in.json out.json
        codeinfo.cmdline_params = parameters.cmdline_params(
            structure_file_name=structure.filename,
            surface_sample_file_name=surface_sample.filename)
        codeinfo.code_uuid = code.uuid
        calcinfo.codes_info = [codeinfo]

        return calcinfo
