#  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 float64, full, zeros
from .xyz   import _XYZ

class BQs(_XYZ):
    '''Hold background point charges as memory view of fragObj._master'''

# FIXME: rename to something like "_keywords"
    _kwargs = {
                'coords'   : zeros(shape=(1,3), dtype=float64),
                'charges'  : zeros(shape=(1,) , dtype=float64),
                'gradients': zeros(shape=(1,3), dtype=float64),
                'names'    : full((1,), ''    , dtype='S8'),
                'nbqs'     : 0
              }

    _internals = {
                 }

    _fields = 'names', 'coords', 'charges', 'gradients'

    synons = { 'nbqs'  : 'npts',
               'coords': 'xyz' }
    _synons = {
                'nbqs'  : 'npts',
                'coords': 'xyz'
              }


    @property
    def names(self):
        '''BQ names'''

        return self._master.names


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

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


    @property
    def nbqs(self):
        '''Number of background point charges'''

        return self.natoms


    @nbqs.setter
    def nbqs(self, val):
        ''''''

        self.natoms = val


    @property
    def charges(self):
        '''Charges'''

        return self._master.charges


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

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


    @property
    def gradients(self):
        '''Gradients on background point charges'''

        return self._master.gradients


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

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


    @property
    def atomqs(self):
        '''Point charges from atoms'''

        return self.stacks['Fragment']


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

        self._atomqs = val


    @property
    def shellqs(self):
        '''Point charges from shells'''

        return self.stacks['Shells']


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

        self._shellqs = val


    @property
    def shiftqs(self):
        '''Point charges from charge shifts'''

        return self.stacks['ShiftQs']


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

        self._shiftqs = val


    @property
    def centroid(self):
        '''Centroid of the fragment'''

        from numpy import mean

        return mean(self.coords, axis=0)

    # END OF ENQUIRIES #
    # SELECTION METHODS #

# YL 18/11/2019: removed
#    def selectByRadius(self, radius, centre=None, unit='a.u.'):
#        '''Return an indices list containing all atoms within given radius from centre (default centre is centroid)'''
#
#        from numpy  import argwhere, linalg, subtract, where
#        from ..data import unitconvert
#
#        # default centre is the centroid
#        if not centre:
#            centre = self.centroid
#
#        # centre could be the position of a given atom index (integer)
#        if isinstance(centre, int):
#            centre = self.coords[centre]
#
#        # table of distances
#        dists = linalg.norm(subtract(self.coords, centre), axis=1)
#
#        # radius (distance from centre)
#        radius *= unitconvert.unit2au.get(unit.lower(), 'a.u.')
#
#        return where(dists<radius)[0]

    __all__ = 'coords', 'charges', 'gradients'



