from silx.gui import qt

from tomwer.core.scan.scanfactory import ScanFactory
from tomwer.core.tomwer_object import TomwerObject
from tomwer.core.volume.edfvolume import EDFVolume, EDFVolumeIdentifier
from tomwer.core.volume.hdf5volume import HDF5Volume, HDF5VolumeIdentifier
from tomwer.core.volume.jp2kvolume import JP2KVolumeIdentifier
from tomwer.core.volume.tiffvolume import (
    MultiTIFFVolume,
    MultiTiffVolumeIdentifier,
    TIFFVolume,
    TIFFVolumeIdentifier,
)
from tomoscan.esrf.volume.utils import guess_volumes
from tomwer.gui.qfolderdialog import QDataDialog


class SingleTomoObj(qt.QWidget):

    sigTomoObjChanged = qt.Signal(str)
    """signal emit when the tomo object changed. Parameter is the identifier"""

    def __init__(self, parent=None, *args, **kwargs) -> None:
        super().__init__(parent, *args, **kwargs)
        self.setLayout(qt.QHBoxLayout())

        self._tomoObjIdentifierLineQLE = _TomoObjQLE("", self)
        self.layout().addWidget(self._tomoObjIdentifierLineQLE)

        self._selectScanPB = qt.QPushButton("select", self)
        self.layout().addWidget(self._selectScanPB)

        self.setToolTip(
            "Define a Tomo object. You can also copy / paster folder or files to use the automatic detection. Each time it changed if fit a valid scan then this scan will be triggered"
        )

        # signal / slot connect
        self._tomoObjIdentifierLineQLE.editingFinished.connect(self._scanChanged)
        self._selectScanPB.released.connect(self._selectObject)

    def getTomoObjIdentifier(self) -> str:
        return self._tomoObjIdentifierLineQLE.text()

    def _selectObject(self, *args, **kwargs):
        dialog = QDataDialog(self, multiSelection=True)
        dialog.setNameFilters(
            [
                "HDF5 files (*.h5 *.hdf5 *.nx *.nexus)",
                "Nexus files (*.nx *.nexus)",
                "Any files (*)",
            ]
        )

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

        added_tomo_objs = []
        for path in dialog.selectedFiles():
            try:
                objs = self.guessTomoObj(path=path)
            except:  # noqa E722
                pass
            else:
                if objs is not None:
                    added_tomo_objs.extend(objs)
        if len(added_tomo_objs) > 0:
            self.setTomoObject(added_tomo_objs[0])

    def _scanChanged(self):
        self.sigTomoObjChanged.emit(self.getTomoObjIdentifier())

    def setTomoObject(self, scan):
        if isinstance(scan, TomwerObject):
            text = scan.get_identifier().to_str()
        else:
            text = scan
        self._tomoObjIdentifierLineQLE.setText(text)
        self.sigTomoObjChanged.emit(self.getTomoObjIdentifier())

    def guessTomoObj(self, path):
        try:
            return ScanFactory.create_scan_objects(path)
        except:  # noqa E722
            try:
                return guess_volumes(
                    path,
                    scheme_to_vol={
                        EDFVolumeIdentifier.scheme: EDFVolume,
                        HDF5VolumeIdentifier.scheme: HDF5Volume,
                        TIFFVolumeIdentifier.scheme: TIFFVolume,
                        MultiTiffVolumeIdentifier.scheme: MultiTIFFVolume,
                        JP2KVolumeIdentifier.scheme: JP2KVolumeIdentifier,
                    },
                )
            except:  # noqa E722
                pass
        return None


class _TomoObjQLE(qt.QLineEdit):
    """QLineEdit that try to get a Tomo object identifier once dropped"""

    def dropEvent(self, a0) -> None:
        if hasattr(a0, "mimeData") and a0.mimeData().hasFormat("text/uri-list"):
            for url in a0.mimeData().urls():
                try:
                    new_objs = self.parent().guessTomoObj(url.path())
                except:  # noqa E722
                    pass
                else:
                    if new_objs is None or len(new_objs) == 0:
                        continue
                    self.setText(new_objs[0].get_identifier().to_str())
            a0.accept()
        else:
            return super().dropEvent(a0)
