#/*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#############################################################################*/

__author__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "10/01/2018"


from silx.gui import qt
from tomwer.gui.H5StructEditor import H5StructEditor
from tomwer.core.ReconsParams import ReconsParam
import logging

logger = logging.getLogger(__name__)


class FTWidget(H5StructEditor, qt.QWidget):
    """
    Definition of the Main tab to edit the FT parameters
    """

    def __init__(self, parent=None):
        H5StructEditor.__init__(self, structID='FT')
        qt.QWidget.__init__(self, parent)

        self.setLayout(qt.QVBoxLayout())
        self.layout().addWidget(self.__buildReconsOneSlice())
        self.layout().addWidget(self.__buildSelectSlice())
        self.layout().addWidget(self.__buildVolFile())
        self.layout().addWidget(self.__buildVolumeSelection())
        self.layout().addWidget(self.__buildPreviousVolumeSelection())
        self._qcbVolumeSelection.currentIndexChanged.connect(
            self._updatePreviousSelection)
        self.layout().addWidget(self.__buildSpikeThreshokd())
        self.layout().addWidget(self.__buildRingCorrection())
        # spacer
        spacer = qt.QWidget(self)
        spacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
        self.layout().addWidget(spacer)

        self._makeConnection()

    def _makeConnection(self):
        self._qcbDoTestSlice.toggled.connect(self._reconsOneSliceChanged)
        self._qleSliceN.editingFinished.connect(self._reconsSelectSliceChanged)
        self._qcbSelectSlice.currentIndexChanged.connect(self._reconsSelectSliceChanged)
        self._qcbEDFStack.toggled.connect(self._volFileChanged)
        self._qcbVolumeSelection.currentIndexChanged.connect(self._volSelectChanged)
        self._qcbVolSelRemenber.toggled.connect(self._volSelectRemenberChanged)
        self._grpThreshold.toggled.connect(self._spikethresholdChanged)
        self._qleThresholdSpikesRm.editingFinished.connect(self._spikethresholdChanged)
        self._qcbRingsCorrection.toggled.connect(self._ringsCorrectionChanged)

    def __buildReconsOneSlice(self):
        self._qcbDoTestSlice = qt.QCheckBox('Reconstruct one slice',
                                            parent=self)
        self.linkCheckboxWithH5Variable(self._qcbDoTestSlice, 'DO_TEST_SLICE')
        return self._qcbDoTestSlice

    def _reconsOneSliceChanged(self, b):
        if self._isLoading is False:
            ReconsParam().setValue(structID='FT',
                                   paramID='DO_TEST_SLICE',
                                   value=int(b))

    def __buildSelectSlice(self):
        widget = qt.QWidget()
        widget.setLayout(qt.QHBoxLayout())
        widget.layout().addWidget(qt.QLabel('Select slice to be reconstructed'))
        self._qcbSelectSlice = qt.QComboBox(parent=widget)
        self._qcbSelectSlice.addItem('middle')
        self._qcbSelectSlice.addItem('on radio')
        self._qcbSelectSlice.addItem('row n')
        self._qcbSelectSlice.currentIndexChanged.connect(self._setEditableSliceIndex)
        widget.layout().addWidget(self._qcbSelectSlice)

        # LineEdit position value
        self._qleSliceN = qt.QLineEdit('', parent=widget)
        widget.layout().addWidget(self._qleSliceN)
        validator = qt.QIntValidator(parent=widget)
        validator.setBottom(0)
        self._qleSliceN.setValidator(validator)
        self._qleSliceN.hide()
        self.linkGroupWithH5Variable(group=self._qleSliceN,
                                     h5ParamName='FIXEDSLICE',
                                     setter=self._setFixedSlice,
                                     getter=self._getFixedSlice)

        widget.layout().addWidget(self._qleSliceN)
        return widget

    def _reconsSelectSliceChanged(self):
        if self._isLoading is False:
            value = self._getFixedSlice()
            ReconsParam().setValue(structID='FT',
                                   paramID='FIXEDSLICE',
                                   value=value)

    def _setFixedSlice(self, val):
        if val == 'middle':
            self._qcbSelectSlice.setCurrentIndex(0)
        elif val == 'on radio':
            self._qcbSelectSlice.setCurrentIndex(1)
        else:
            try:
                nbslice = int(str(val))
            except ValueError as e:
                warning = 'Cannot set nb slice value, '
                if len(e.args) > 0:
                    warning += e.args[0]
                logger.warning(warning)
            else:
                self._qcbSelectSlice.setCurrentIndex(2)
                self._qleSliceN.setText(str(nbslice))

    def _getFixedSlice(self):
        if self._qcbSelectSlice.currentIndex() == 2:
            return self._qleSliceN.text()
        else:
            return self._qcbSelectSlice.currentText()

    def _setEditableSliceIndex(self):
        self._qleSliceN.setVisible(self._qcbSelectSlice.currentIndex() == 2)

    def __buildVolFile(self):
        group = qt.QGroupBox('Select output mode :', parent=self)
        group.setLayout(qt.QHBoxLayout())
        self._qcbEDFStack = qt.QRadioButton('Stack of edf files', parent=group)
        group.layout().addWidget(self._qcbEDFStack)
        self._qcbEDFStack.setChecked(True)
        self._qcbSingleVolFile = qt.QRadioButton('Single vol file', parent=group)
        group.layout().addWidget(self._qcbSingleVolFile)
        self.linkGroupWithH5Variable(group=group,
                                     h5ParamName='VOLOUTFILE',
                                     setter=self._setSingleVolOrStack,
                                     getter=self._getSingleVolOrStack)
        return group

    def _volFileChanged(self):
        if self._isLoading is False:
            value = self._getSingleVolOrStack()
            ReconsParam().setValue(structID='FT',
                                   paramID='VOLOUTFILE',
                                   value=value)

    def __buildVolumeSelection(self):
        widget = qt.QWidget(self)
        widget.setLayout(qt.QVBoxLayout())
        widget.layout().addWidget(qt.QLabel('Volume selection :'))
        self._qcbVolumeSelection = qt.QComboBox(self)
        self._qcbVolumeSelection.addItem('total')
        self._qcbVolumeSelection.addItem('manual')
        self._qcbVolumeSelection.addItem('graphics')
        self.linkComboboxWithH5Variable(self._qcbVolumeSelection, 'VOLSELECT')
        widget.layout().addWidget(self._qcbVolumeSelection)
        return widget

    def _volSelectChanged(self):
        if self._isLoading is False:
            value = self._qcbVolumeSelection.currentText()
            ReconsParam().setValue(structID='FT',
                                   paramID='VOLSELECT',
                                   value=value)

    def __buildPreviousVolumeSelection(self):
        self._qcbVolSelRemenber = qt.QCheckBox('Remember previous volume selection',
                                               parent=self)
        self.linkCheckboxWithH5Variable(self._qcbVolSelRemenber,
                                        h5ParamName='VOLSELECTION_REMEMBER')
        return self._qcbVolSelRemenber

    def _volSelectRemenberChanged(self, b):
        if self._isLoading is False:
            value = int(b)
            ReconsParam().setValue(structID='FT',
                                   paramID='VOLSELECTION_REMEMBER',
                                   value=value)

    def __buildSpikeThreshokd(self):
        self._grpThreshold = qt.QGroupBox(title='Correct spikes', parent=self)
        self._grpThreshold.setCheckable(True)
        self._grpThreshold.setChecked(True)

        self._grpThreshold.setLayout(qt.QHBoxLayout())
        self._grpThreshold.layout().addWidget(qt.QLabel('Threshold for spikes removal'))
        self._qleThresholdSpikesRm = qt.QLineEdit('', parent=self._grpThreshold)
        self._grpThreshold.layout().addWidget(self._qleThresholdSpikesRm)
        self.linkGroupWithH5Variable(group=self._grpThreshold,
                                     h5ParamName='CORRECT_SPIKES_THRESHOLD',
                                     setter=self._setSpikeThreshold,
                                     getter=self._getSpikeThreshold)
        return self._grpThreshold

    def _spikethresholdChanged(self):
        if self._isLoading is False:
            value = self._getSpikeThreshold()
            ReconsParam().setValue(structID='FT',
                                   paramID='CORRECT_SPIKES_THRESHOLD',
                                   value=value)

    def __buildRingCorrection(self):
        self._qcbRingsCorrection = qt.QCheckBox('Perform rings corrections in PyHST',
                                                parent=self)
        self.linkCheckboxWithH5Variable(self._qcbRingsCorrection, 'RINGSCORRECTION')
        return self._qcbRingsCorrection

    def _ringsCorrectionChanged(self, b):
        if self._isLoading is False:
            value = int(b)
            ReconsParam().setValue(structID='FT',
                                   paramID='RINGSCORRECTION',
                                   value=value)

    def _getSingleVolOrStack(self):
        """return:
            - 0 if we want to use a single file for volume
            - 1 if we want to use a stack of edf file for volume
        """
        return int(not self._qcbEDFStack.isChecked())

    def _setSingleVolOrStack(self, val):
        """Set the value of the volume file selection
        """
        assert(type(val) in [int, float])
        assert(int(val) in [0, 1])
        if val == 0:
            self._qcbEDFStack.setChecked(True)
        else:
            self._qcbSingleVolFile.setChecked(True)

    def _enableVolumeSelection(self, disable):
        """Do we give the user access to the volume selection or is it set to
        total
        """
        self._qcbVolumeSelection.setEnabled(not disable)
        if not disable:
            self._qcbVolumeSelection.setCurrentIndex(0)

    def _updatePreviousSelection(self):
        self._qcbVolSelRemenber.setEnabled(
            self._qcbVolumeSelection.currentIndex() == 1)

    def _setSpikeThreshold(self, value):
        if type(value) is str:
            assert(value.lower() == 'inf')
            self._grpThreshold.setChecked(False)
        else:
            assert(type(value) is float)
            self._grpThreshold.setChecked(True)
            self._qleThresholdSpikesRm.setText(str(value))

    def _getSpikeThreshold(self):
        if self._grpThreshold.isChecked():
            return float(self._qleThresholdSpikesRm.text())
        else:
            return 'Inf'
