# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program 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 General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Module authors:
#   Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************

from frappy.core import Parameter, Property
from frappy.datatypes import ValueType


class AddrParam(Parameter):
    """parameter with an address field

    instead of implementing read_<param> and write_<param>, just implement
    addressed_read and addressed_write.
    """
    addr = Property('address', ValueType())


class AddrMixin:
    """mixin for addressed parameters

    in case a read_<param> and/or write_<param> are not implemented,
    they are created with a call to addressed_read and/or addressed_write
    """
    def __init_subclass__(cls):
        for aname, aobj in list(cls.__dict__.items()):
            if isinstance(aobj, AddrParam):
                methodname = f'read_{aname}'

                if not hasattr(cls, methodname):
                    def rfunc(self, pname=aname):
                        return self.addressed_read(self.accessibles[pname])

                    setattr(cls, methodname, rfunc)

                if not aobj.readonly:
                    methodname = f'write_{aname}'
                    if not hasattr(cls, methodname):
                        def wfunc(self, value, pname=aname):
                            return self.addressed_write(self.accessibles[pname], value)

                        setattr(cls, methodname, wfunc)
        super().__init_subclass__()

    def addressed_read(self, pobj):
        """addressed read

        :param pobj: the AddrParam
        :return: the value read
        """
        return getattr(self, pobj.name)

    def addressed_write(self, pobj, value):
        """addressed write

        :param pobj: the AddrParam
        :param value: the value to be written
        :return: the value written or None
        """
