# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
#
# 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.
#
# ###########################################################################*/

__authors__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "03/07/2019"


from silx.gui.dialog.DataFileDialog import DataFileDialog
from silx.io.url import DataUrl
from silx.gui import qt
from est.core.io import read as read_xas, read_frm_file
from est.io import InputType
import logging

_logger = logging.getLogger(__name__)


class _InputType(qt.QWidget):
    def __init__(self, parent=None):
        qt.QWidget.__init__(self, parent)
        self.setLayout(qt.QHBoxLayout())
        self.layout().addWidget(qt.QLabel('input type:'))
        self._inputTypeCB = qt.QComboBox(parent=self)
        for input_type in InputType.values():
            self._inputTypeCB.addItem(input_type)
        self.layout().addWidget(self._inputTypeCB)

        # expose API
        self.currentChanged = self._inputTypeCB.currentIndexChanged

    def getInputType(self):
        """Return the current input type"""
        return InputType.from_value(self._inputTypeCB.currentText())

    def setInputType(self, input_type):
        _input_type = InputType.from_value(input_type)
        idx = self._inputTypeCB.findText(_input_type.value)
        assert idx >= 0
        self._inputTypeCB.setCurrentIndex(idx)


class XASObjectDialog(qt.QWidget):
    """
    Interface used to select inputs for defining a XASObject
    """
    editingFinished = qt.Signal()

    def __init__(self, parent=None):
        qt.QWidget.__init__(self, parent)
        self.setLayout(qt.QGridLayout())
        spacer = qt.QWidget(parent=self)
        spacer.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Minimum)
        self.layout().addWidget(spacer, 0, 0)
        self._inputType = _InputType(parent=self)
        self.layout().addWidget(self._inputType, 0, 1)

        self._singleSpectrumDialog = _XASObjectFrmSingleSpectrum(parent=self)
        self.layout().addWidget(self._singleSpectrumDialog, 1, 0, 1, 2)
        self._h5Dialog = _XASObjFrmH5(parent=self)
        self.layout().addWidget(self._h5Dialog, 2, 0, 1, 2)

        spacer = qt.QWidget(parent=self)
        spacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
        self.layout().addWidget(spacer, 3, 0)

        # connect signal / slot
        self._inputType.currentChanged.connect(self._updateWidgetVisibility)
        self._singleSpectrumDialog._inputLe.textChanged.connect(self._editingIsFinished)
        self._h5Dialog.editingFinished.connect(self._editingIsFinished)

        # expose API
        self.getCurrentType = self._inputType.getInputType
        self.setCurrentType = self._inputType.setInputType
        self.setDatFile = self._singleSpectrumDialog.setFileSelected
        self.getDatFile = self._singleSpectrumDialog.getFileSelected
        self.setSpectraUrl = self._h5Dialog.setSpectraUrl
        self.getSpectraUrl = self._h5Dialog.getSpectraUrl
        self.setEnergyUrl = self._h5Dialog.setEnergyUrl
        self.getEnergyUrl = self._h5Dialog.getEnergyUrl
        self.setConfigurationUrl = self._h5Dialog.setConfigurationUrl
        self.getConfigurationUrl = self._h5Dialog.getConfigurationUrl

        # default setting
        self._updateWidgetVisibility()

    def _updateWidgetVisibility(self):
        self._singleSpectrumDialog.setVisible(self._inputType.getInputType() in (InputType.dat_spectrum, InputType.xmu_spectrum))
        self._h5Dialog.setVisible(self._inputType.getInputType() == InputType.hdf5_spectra)

    def buildXASObject(self):
        if self.getCurrentType() in (InputType.dat_spectrum, InputType.xmu_spectrum):
            return read_frm_file(file_path=self._singleSpectrumDialog.getFileSelected())
        elif self.getCurrentType() == InputType.hdf5_spectra:
            spectra_url = self._h5Dialog.getSpectraUrl()
            energy_url = self._h5Dialog.getEnergyUrl()

            def check_url(url_path, name):
                if url_path in (None, ''):
                    raise ValueError(' '.join(('No', name, 'url defined')))
                url = DataUrl(path=url_path)
                if not url.is_valid():
                    raise ValueError(' '.join((name, 'url is invalid. Does the file / path still exists ?')))

            check_url(spectra_url, 'spectra')
            check_url(energy_url, 'energy / channel')
            return read_xas(spectra_url=self._h5Dialog.getSpectraUrl(),
                            channel_url=self._h5Dialog.getEnergyUrl(),
                            config_url=self._h5Dialog.getConfigurationUrl())
        else:
            raise ValueError('unmanaged input type')

    def _editingIsFinished(self, *args, **kwargs):
        self.editingFinished.emit()


class _XASObjectFrmSingleSpectrum(qt.QWidget):
    """
    Interface used to define a XAS object from a single .dat file
    """
    def __init__(self, parent=None):
        qt.QWidget.__init__(self, parent)
        self.setLayout(qt.QGridLayout())

        self.layout().addWidget(qt.QLabel('file', parent=self), 0, 0)
        self._inputLe = qt.QLineEdit('', parent=self)
        self.layout().addWidget(self._inputLe, 0, 1)
        self._selectPB = qt.QPushButton('select', parent=self)
        self.layout().addWidget(self._selectPB, 0, 2)

        spacer = qt.QWidget(parent=self)
        spacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
        self.layout().addWidget(spacer, 2, 0)

        # signal / slot connection
        self._selectPB.pressed.connect(self._selectFile)

        # expose api
        self.getFileSelected = self._inputLe.text

    def _selectFile(self, *args, **kwargs):
        old = self.blockSignals(True)
        dialog = qt.QFileDialog(self)
        dialog.setFileMode(qt.QFileDialog.ExistingFile)
        dialog.setNameFilters(["spectrum (*.dat, *.xmu)", ])

        if not dialog.exec_():
            dialog.close()
            return

        fileSelected = dialog.selectedFiles()
        if len(fileSelected) == 0:
            return
        else:
            assert len(fileSelected) == 1
            self.setFileSelected(fileSelected[0])

        self.blockSignals(old)

    def setFileSelected(self, file_path):
        self._inputLe.setText(file_path)


class _URLSelector(qt.QWidget):
    def __init__(self, parent, name, layout=None, position=None):
        qt.QWidget.__init__(self, parent)
        self.name = name
        if layout is None:
            layout = self.setLayout(qt.QGridLayout())
            position = (0, 0)
        layout.addWidget(qt.QLabel(name + ':', parent=self), position[0], position[1])
        self._qLineEdit = qt.QLineEdit('', parent=self)
        layout.addWidget(self._qLineEdit, position[0], position[1] + 1)
        self._qPushButton = qt.QPushButton('select', parent=self)
        layout.addWidget(self._qPushButton, position[0], position[1] + 2)

        # expose API
        self.getUrlPath = self._qLineEdit.text
        self.setUrlPath = self._qLineEdit.setText

        # connect signal / slot
        self._qPushButton.clicked.connect(self._selectFile)

    def _selectFile(self, *args, **kwargs):
        dialog = DataFileDialog(self)

        if not dialog.exec_():
            dialog.close()
            return None

        if dialog.selectedUrl() is not None:
            self._qLineEdit.setText(dialog.selectedUrl())


class _XASObjFrmH5(qt.QWidget):
    """
    Interface used to define a XAS object from h5 files and data path
    """
    editingFinished = qt.Signal()
    def __init__(self, parent=None):
        qt.QWidget.__init__(self, parent)
        self.setLayout(qt.QGridLayout())
        # spectra url
        self._spectraSelector = _URLSelector(parent=self, name='spectra url',
                                             layout=self.layout(), position=(0, 0))
        # energy / channel url
        self._energySelector = _URLSelector(parent=self, name='energy /channel url',
                                            layout=self.layout(), position=(1, 0))
        # configuration url
        self._configSelector = _URLSelector(parent=self, name='configuration url',
                                            layout=self.layout(),
                                            position=(2, 0))

        # connect signal / slot
        self._spectraSelector._qLineEdit.textChanged.connect(self._editingIsFinished)
        self._energySelector._qLineEdit.textChanged.connect(self._editingIsFinished)
        self._configSelector._qLineEdit.textChanged.connect(self._editingIsFinished)

    def getSpectraUrl(self):
        return self._spectraSelector.getUrlPath()

    def getEnergyUrl(self):
        return self._energySelector.getUrlPath()

    def getConfigurationUrl(self):
        return self._configSelector.getUrlPath()

    def setSpectraUrl(self, url):
        self._spectraSelector.setUrlPath(url)

    def setEnergyUrl(self, url):
        self._energySelector.setUrlPath(url)

    def setConfigurationUrl(self, url):
        self._configSelector.setUrlPath(url)

    def _editingIsFinished(self, *args, **kwargs):
        self.editingFinished.emit()


if __name__ == '__main__':
    app = qt.QApplication([])
    dialog = XASObjectDialog()
    dialog.show()
    app.exec_()
