#  Copyright (C) 2017 The authors of Py-ChemShell
#
#  This file is part of Py-ChemShell.
#
#  Py-ChemShell is free software: you can redistribute it and/or modify
#  it under the terms of the GNU Lesser General Public License as
#  published by the Free Software Foundation, either version 3 of the
#  License, or (at your option) any later version.
#
#  Py-ChemShell is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public
#  License along with Py-ChemShell.  If not, see
#  <http://www.gnu.org/licenses/>.

from numpy       import dtype, float64, int64, zeros
from .xyz        import _XYZ
from .resultbase import ResultBase
from ..dl_py2f   import utils
from ..io        import keyword

### FIXME: TWK run after run: overwritten?

class Result(ResultBase):
    '''Result object containing energy, gradient, etc.'''

    _kwargs = {
                # "energy" cannot be a scalar, because <float> is immutable and assignment will create a new instance (address changed)
                'energy'      : zeros(shape=(1)  , dtype=float64),
                'excitations' : zeros(shape=(0,) , dtype=dtype([('energies'   , float64),
                                                                ('f'          , float64),
                                                                ('wavelengths', float64),
                                                                ('symmetries' , 'S8'),      # 1 U = 32 bit
                                                                ('spins'      , 'S8')])),
                'frequencies' : zeros(shape=(1,3), dtype=float64),
                'gradients'   : zeros(shape=(1,3), dtype=float64),
                'hessian'     : zeros(shape=(1,3), dtype=float64),
                'convergences': zeros(shape=(5,) , dtype=float64),
                'natoms'      : 0,
                'potential'   : zeros(shape=(1,3), dtype=float64),
                'znums'       : zeros(shape=(1,) , dtype=int64),
              }

    

    _fields = 'znums', 'gradients', 'hessian', 'potential'#, 'excitations')

    synons = { 'natoms':'npts' }
    _synons = {
                'natoms'     :'npts',
                'gradients'  :'xyz',
                'frequencies':'freq'
              }


    @property
    def energy(self):
        '''Energy'''

        return self._energy


    @energy.setter
    def energy(self, val):
        '''Setter of energy'''

        utils.nputils.setField(self._energy, val)

        

    @property
    def gradients(self):
        '''Gradients'''

        return self._master.xyz


    @gradients.setter
    def gradients(self, val):
        '''Setter of gradients'''

        self._master.setField(val, field='xyz')


    @property
    def hessian(self):
        '''Hessian'''

        return self._master.hessian


    @hessian.setter
    def hessian(self, val):
        '''Setter of hessian'''

        self._master.setField(val, field='hessian')


    @property
    def potential(self):
        return self._master.potential


    @property
    def znums(self):
        '''Atomic numbers: (natoms,1)'''

        return self._master.znums


    @znums.setter
    @_XYZ._resize1D
    def znums(self, val):
        '''Setter of znums'''

        self._master.setField(val, field='znums')


    @property
    def excitations(self):
        '''Excited state results'''

        return self._excitations


    @excitations.setter
    def excitations(self, val):
        '''Setter of excitations'''

        self._excitations = val


    @property
    def E0(self):
        '''Ground state energy'''

        return self._E0


    @E0.setter
    def E0(self, val):
        '''Setter of E0'''

        self._E0 = val


    @property
    def max_gradient(self):
        '''Maximum gradient component'''

        return self.convergences[1]


    @max_gradient.setter
    def max_gradient(self, val):
        '''Setter of max_gradient'''

        self.convergences[1] = val


    @property
    def max_step(self):
        '''Maximum step'''

        return self.convergences[2]


    @max_step.setter
    def max_step(self, val):
        '''Setter of max_step'''

        self.convergences[2] = val


    @property
    def RMS_gradient(self):
        '''RMS gradient'''

        return self.convergences[3]


    @RMS_gradient.setter
    def RMS_gradient(self, val):
        '''Setter of RMS_gradient'''

        self.convergences[3] = val


    @property
    def RMS_step(self):
        '''RMS step'''

        return self.convergences[4]


    @RMS_step.setter
    def RMS_step(self, val):
        '''Setter of RMS_step'''

        self.convergences[4] = val









