##############################################################################
##
# This file is part of Sardana
##
# http://www.sardana-controls.org/
##
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
# Sardana 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.
##
# Sardana 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 Sardana.  If not, see <http://www.gnu.org/licenses/>.
##
##############################################################################

"""Library of specific macros for performing specific experimental techniques

"""

__all__ = ["xas_acq"]

__docformat__ = 'restructuredtext'

import numpy

from sardana.macroserver.macro import *
from sardana.macroserver.scan import *


class xas_acq(Macro, Hookable):
    """
    .. warning:: This macro is still under development. It may change.

    Perform an X-ray absorption scan experiment. Data is stored in a NXxas-compliant file.
    """
    hints = {'scan': 'xas_acq', 'allowsHooks': (
        'pre-move', 'post-move', 'pre-acq', 'post-acq', 'post-step')}
    # env = ('MonochromatorEnergy', )#'AbsorbedBeam', 'IncomingBeam',
    # 'Monitor') #this hints that the macro requires the ActiveMntGrp
    # environment variable to be set

    param_def = [
        ['start',  Type.Float,    None, 'start energy in keV'],
        ['final',  Type.Float,    None, 'final energy in keV'],
        ['nr_interv',  Type.Integer,  None, 'Number of energy intervals'],
        ['integ_time', Type.Float,    None, 'Integration time in s']
    ]

    def prepare(self, start, final, nr_interv, integ_time, **opts):
        # parse the user parameters
        self.starts = numpy.array([start], dtype='d')
        self.finals = numpy.array([final], dtype='d')
        self.integ_time = integ_time

        self.nb_points = nr_interv + 1
        self.interv_sizes = (self.finals - self.starts) / nr_interv
        self.name = 'xas_acq'
        # the "env" dictionary may be passed as an option
        env = opts.get('env', {})
        env['integ_time'] = integ_time

        # print "!!!!!", type(self.getInstrument('/instrument/monochromator')), self.getEnv('MonochromatorEnergy', macro_name=self.name)
        # ElementWithInterface('Instrument','monochromator')
        for n, e in self.getElementsWithInterface('Instrument').items():
            inst = e.getObj()
            # ,inst.getElements()
            print(n, e.name, inst.getFullName(), type(e), type(inst),
                  type(inst.getPoolObj()))

        # maybe I should use the instrument interface to obtain the right
        # counters

        env['monochromator'] = monochromator = self.getEnv(
            'MonochromatorEnergy', macro_name=self.name)
        energymotor = self.getMoveable(monochromator)
        xasMntGrp = self.getMeasurementGroup(
            self.getEnv('xasMntGrp', macro_name=self.name))

        xasMntGrp = xasMntGrp.getObj()
        monitor, incbeam, absbeam = xasMntGrp.getChannelNames()[:3]
        env['monitor'] = monitor
        env['absbeam'] = absbeam
        env['incbeam'] = incbeam

#        print "!!!!!!!!",xasMntGrp.getObj().getElements()


#        absbeam =  self.getExpChannel(self.getEnv('AbsorbedBeam')) #this should be get measurement group (e.g., second channel?)
#        incbeam =  self.getExpChannel(self.getEnv('IncomingBeam')) #this should be get measurement group (e.g., first channel?)
# monitor =  self.getExpChannel(self.getEnv('Monitor')) #this should be
# get from the monitor of the measurement group

        # create an instance of GScan (in this case, of its child, SScan
        self._gScan = SScan(self, generator=self._generator,
                            moveables=[energymotor], env=env)

    def _generator(self):
        step = {}
        step["integ_time"] = self.integ_time
        step[
            "post-acq-hooks"] = self.getHooks('post-acq') + self.getHooks('_NOHINT_')
        step["post-step-hooks"] = self.getHooks('post-step')
        step["check_func"] = []
        for point_no in range(self.nb_points):
            step["positions"] = self.starts + point_no * self.interv_sizes
            step["point_id"] = point_no
            yield step

    def run(self, *args):
        for step in self._gScan.step_scan():  # just go through the steps
            yield step

    @property
    def data(self):
        return self._gScan.data  # the GScan provides scan data

    def _get_nr_points(self):
        msg = ("nr_points is deprecated since version 3.0.3. "
               "Use nb_points instead.")
        self.warning(msg)
        return self.nb_points

    nr_points = property(_get_nr_points)
