#!/usr/bin/env python
"""
================================================================================
:mod:`analysis` -- Analysis (0D collection)
================================================================================

.. module:: analysis
   :synopsis: Analysis

.. inheritance-diagram:: analysis

"""

# Standard library modules.

# Third party modules.
import numpy as np

# Local modules.
from pyhmsa.spec.datum.datum import _Datum
from pyhmsa.spec.condition.detector import DetectorSpectrometer

# Globals and constants variables.

class _Analysis(_Datum):
    """
    Stores a single measurement of a specimen at a single point in space or
    time.
    """
    pass

    TEMPLATE = "Analysis"

class Analysis0D(_Analysis):
    """
    Data with 0 collection dimensions and 0 datum dimensions implies a dataset
    comprising of one single-valued measurement.
    """

    CLASS = "0D"

    def __new__(cls, value, dtype=np.float32,
                offset=0, strides=None, order=None,
                conditions=None):
        buffer = np.array(value, dtype=dtype)
        return _Analysis.__new__(cls, (), dtype,
                                 buffer, offset, strides, order, conditions)

class Analysis1D(_Analysis):
    """
    Stores a measurement of a specimen at a single point in space or time
    with one datum dimension.
    """

    CLASS = "1D"

    def __new__(cls, channels, dtype=np.float32,
                buffer=None, offset=0, strides=None, order=None,
                conditions=None):
        if channels <= 0:
            raise ValueError('Number of channel must be greater than 0')
        shape = (channels,)
        return _Analysis.__new__(cls, shape, dtype,
                                 buffer, offset, strides, order, conditions)

    def get_xy(self, with_labels=False):
        xs = range(self.channels)
        xlabel = 'Channels'
        ylabel = 'Values'

        conditions = self.conditions.findvalues(DetectorSpectrometer)
        if conditions:
            condition = next(iter(conditions))
            calibration = condition.calibration
            xs = list(map(calibration, xs))
            xlabel = '%s (%s)' % (calibration.quantity, calibration.unit)
            if condition.measurement_unit is not None:
                ylabel += ' (%s)' % condition.measurement_unit

        outarr = np.transpose(np.array([xs, self]))

        if with_labels:
            return xlabel, ylabel, outarr
        else:
            return outarr

    @property
    def channels(self):
        return np.uint32(len(self))

    @property
    def datum_dimensions(self):
        dims = _Analysis.datum_dimensions.fget(self) # @UndefinedVariable
        dims['Channel'] = self.channels
        return dims

class Analysis2D(_Analysis):
    """
    Store a single measurement of the specimen at a single point in space or
    time with two datum dimensions, such as a diffraction pattern.

    .. note::

       This dataset type shall not be used to store 2 dimensional images
       rastered over the specimen, such as a conventional TEM or SEM image.
       Instead, such data shall be stored using the :class:`ImageRaster2D`.
    """

    CLASS = "2D"

    def __new__(cls, u, v, dtype=np.float32,
                buffer=None, offset=0, strides=None, order=None,
                conditions=None):
        if u <= 0 or v <= 0:
            raise ValueError('Dimension must be greater than 0')
        shape = (u, v)
        return _Analysis.__new__(cls, shape, dtype,
                                 buffer, offset, strides, order, conditions)

    @property
    def u(self):
        return np.uint32(self.shape[0])

    @property
    def v(self):
        return np.uint32(self.shape[1])

    @property
    def datum_dimensions(self):
        dims = _Analysis.datum_dimensions.fget(self) # @UndefinedVariable
        dims['U'] = self.u
        dims['V'] = self.v
        return dims

@@ -1795,33 +1795,17 @@
 et_x
-y
+data
 (self
-, with_labels=False
 ):%0A 
@@ -1840,62 +1840,8 @@
 els)
-%0A        xlabel = 'Channels'%0A        ylabel = 'Values'
 %0A%0A  
@@ -2074,359 +2074,815 @@
 s))%0A
-            xlabel = '%25s (%25s)' %25 (calibration.quantity, calibration.unit)%0A            if condition.measurement_unit is not None:%0A                ylabel += ' (%25s)' %25 condition.measurement_unit%0A%0A        outarr = np.transpose(np.array(%5Bxs, self%5D))%0A%0A        if with_labels:%0A            return xlabel, ylabel, outarr%0A        else:%0A            return outarr
+%0A        return np.array(xs)%0A%0A    def get_xlabel(self):%0A        xlabel = 'Channels'%0A%0A        conditions = self.conditions.findvalues(DetectorSpectrometer)%0A        if conditions:%0A            condition = next(iter(conditions))%0A            calibration = condition.calibration%0A            xlabel = '%25s (%25s)' %25 (calibration.quantity, calibration.unit)%0A%0A        return xlabel%0A%0A    def get_ylabel(self):%0A        ylabel = 'Values'%0A%0A        conditions = self.conditions.findvalues(DetectorSpectrometer)%0A        if conditions:%0A            condition = next(iter(conditions))%0A            if condition.measurement_unit is not None:%0A                ylabel += ' (%25s)' %25 condition.measurement_unit%0A%0A        return ylabel%0A%0A    def get_xy(self):%0A        xs = self.get_xdata()%0A        return np.transpose(np.array(%5Bxs, self%5D))
 %0A%0A  

Add separate methods to get x and y labels.