#!/usr/bin/env python

##############################################################################
##
# 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/>.
##
##############################################################################

import PyTango

import taurus
from taurus.external.qt import Qt
from taurus.core.taurusbasetypes import TaurusEventType
from taurus.qt.qtgui.base import TaurusBaseWidget
from taurus.qt.qtgui.input import TaurusAttrListComboBox
from taurus.qt.qtgui.container import TaurusMainWindow
from taurus.qt.qtgui.resource import getThemeIcon, getIcon


def str2bool(text):
    return text in ("True", "1")


def standardPlotablesFilter(column_desc_dict):
    """This is a standard plotables filter emitted with "plotablesFilter" signal.
       Its purpose is to filterout point_nr columnf from scanline"""
    if column_desc_dict.get("label", None) == "point_nb":
        return False
    return True


class MSAttrListComboBox(TaurusAttrListComboBox):
    _elementType = ''

    def handleEvent(self, evt_src, evt_type, evt_value):
        if evt_type in (TaurusEventType.Config, TaurusEventType.Error):
            return
        text = str(self.currentText())
        self.clear()
        parentModelObj = self.getParentModelObj()
        if parentModelObj is None:
            return
        items = sorted(parentModelObj.getElementNamesWithInterface(self._elementType))
        self.addItems(items)
        if text in items:
            self.setCurrentText(text)

    def setCurrentText(self, text):
        idx = self.findText(text)
        self.setCurrentIndex(idx)

    def setElementType(self, elementType):
        self._elementType = elementType

    def getElementType(self):
        return self._elementType

    def resetElementType(self):
        self._elementType = MSAttrListComboBox._elementType

    elementType = Qt.pyqtProperty(
        "QString", getElementType, setElementType, resetElementType)


class MacroComboBox(Qt.QComboBox, TaurusBaseWidget):
    """ComboBox representing list of macros"""

    def __init__(self, parent=None):
        name = self.__class__.__name__
        self.call__init__wo_kw(Qt.QComboBox, parent)
        self.call__init__(TaurusBaseWidget, name)
        self.setSizeAdjustPolicy(Qt.QComboBox.AdjustToContentsOnFirstShow)
        self.setToolTip("Choose a macro name...")

    def setModel(self, model):
        if isinstance(model, Qt.QAbstractItemModel):
            Qt.QAbstractItemView.setModel(self, model)
        else:
            TaurusBaseWidget.setModel(self, model)
            self.__loadMacroNames()

    def parentModelChanged(self, parentmodel_name):
        TaurusBaseWidget.parentModelChanged(self, parentmodel_name)
        self.__loadMacroNames()

    def onMacrosUpdated(self):
        self.__loadMacroNames()

    def __loadMacroNames(self):
        self.clear()
        ms = self.getModelObj()
        if ms is None:
            return
        macros = ms.getElementsWithInterface('MacroCode')
        macroNames = sorted([macro.name for macro in macros.values()])
        macroNames.insert(0, '')  # adding blank item
        self.addItems(macroNames)
        self.updateStyle()

    def selectMacro(self, macroName):
        currentIdx = self.currentIndex()
        index = self.findText(macroName)
        self.setCurrentIndex(index)
        if currentIdx == index:
            self.currentIndexChanged['QString'].emit(macroName)

class TaurusMacroConfigurationDialog(Qt.QDialog):

    macroserverNameChanged = Qt.pyqtSignal('QString')
    doorNameChanged = Qt.pyqtSignal('QString')

    def __init__(self, parent=None, initMacroServer=None, initDoor=None):
        Qt.QDialog.__init__(self, parent)
        self.initMacroServer = initMacroServer
        self.initDoor = initDoor
        configureAction = Qt.QAction(getThemeIcon(
            "folder-open"), "Change custom macro editors paths", self)
        configureAction.triggered.connect(self.onReloadMacroServers)
        configureAction.setToolTip("Change custom macro editors paths")
        configureAction.setShortcut("F11")
        self.refreshMacroServersAction = Qt.QAction(
            getThemeIcon("view-refresh"), "Reload macroservers", self)
        self.refreshMacroServersAction.triggered.connect(
            self.onReloadMacroServers)
        self.refreshMacroServersAction.setToolTip(
            "This will reload list of all macroservers from Tango DB")
        self.refreshMacroServersAction.setShortcut("F5")
        self.initComponents()

    def initComponents(self):
        self.setModal(True)
        macroServerLabel = Qt.QLabel("MacroServer:", self)
        self.macroServerComboBox = Qt.QComboBox()
        ms_stateIcons = self.__retriveMacroServersFromDB()
        self.__fillMacroServerComboBox(ms_stateIcons, self.macroServerComboBox)
        refreshMacroServersButton = Qt.QToolButton()
        refreshMacroServersButton.setDefaultAction(
            self.refreshMacroServersAction)
        doorLabel = Qt.QLabel("Door:", self)
        self.doorComboBox = TaurusAttrListComboBox(self)
        self.doorComboBox.setModel(
            self.macroServerComboBox.currentText() + "/doorList")

        self.buttonBox = Qt.QDialogButtonBox(Qt.QDialogButtonBox.Ok |
                                             Qt.QDialogButtonBox.Cancel)
        gridLayout = Qt.QGridLayout()
        gridLayout.addWidget(macroServerLabel, 0, 0)
        gridLayout.addWidget(self.macroServerComboBox, 0, 1)
        gridLayout.addWidget(refreshMacroServersButton, 0, 2)
        gridLayout.addWidget(doorLabel, 1, 0)
        gridLayout.addWidget(self.doorComboBox, 1, 1)

        self.setLayout(Qt.QVBoxLayout())
        self.layout().addLayout(gridLayout)
        self.layout().addWidget(self.buttonBox)
        self.adjustSize()

        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        self.macroServerComboBox.currentIndexChanged['QString'].connect(
            self.onMacroServerComboBoxChanged)
        self.selectMacroServer(self.initMacroServer)
        self.selectDoor(self.initDoor)

    def accept(self):
        self.macroserverNameChanged.emit(
            str(self.macroServerComboBox.currentText()))
        self.doorNameChanged.emit(
            str(self.doorComboBox.currentText()))
        Qt.QDialog.accept(self)

    def __retriveMacroServersFromDB(self):
        ms_stateIcons = []
        db = taurus.Database()
        macroServerList = db.getValueObj().get_device_name('*', 'MacroServer')
        for macroServer in macroServerList:
            #state = Device(macroServer).getState()
            state = None
            try:
                ms_name = "{0}/{1}".format(db.getNormalName(), macroServer)
                state = PyTango.DeviceProxy(ms_name).state()
            except:
                pass
            icon = None
            if state == PyTango.DevState.ON:
                icon = getIcon(":/leds/images24/ledgreen.png")
            elif state == PyTango.DevState.FAULT:
                icon = getIcon(":/leds/images24/ledred.png")
            elif state is None:
                icon = getIcon(":/leds/images24/ledredoff.png")
            ms_stateIcons.append((macroServer, icon))
        return ms_stateIcons

    def onReloadMacroServers(self):
        ms_stateIcons = self.__retriveMacroServersFromDB()
        self.__fillMacroServerComboBox(ms_stateIcons, self.macroServerComboBox)

    def onMacroServerComboBoxChanged(self, macroServerName):
        self.doorComboBox.setModel(macroServerName + "/doorList")
        self.doorComboBox.fireEvent(self.doorComboBox, taurus.core.taurusbasetypes.TaurusEventType.Change,
                                    self.doorComboBox.getModelValueObj())  # fake event

    def onMacroServerNameChanged(self, macroServerName):
        self.__selectMacroServer(macroServerName)

    def onDoorNameChanged(self, doorName):
        self.__selectDoor(doorName)

    def __fillMacroServerComboBox(self, ms_stateIcons, comboBox):
        comboBox.clear()
        for ms_stateIcon in ms_stateIcons:
            macroServer = ms_stateIcon[0]
            icon = ms_stateIcon[1]
            comboBox.addItem(icon, macroServer)

    def selectDoor(self, doorName):
        if doorName is None:
            return
        #@todo: Change that it will be able to handle also full device names
        "/".join(doorName.split("/")[-3:])
        index = self.doorComboBox.findText(doorName)
        if index != -1:
            self.doorComboBox.setCurrentIndex(index)

    def selectMacroServer(self, macroServerName):
        if macroServerName is None:
            return
        #@todo: Change that it will be able to handle also full device names
        "/".join(macroServerName.split("/")[-3:])
        index = self.macroServerComboBox.findText(macroServerName)
        if index != -1:
            self.macroServerComboBox.setCurrentIndex(index)


class MacroExecutionWindow(TaurusMainWindow):

    doorChanged = Qt.pyqtSignal('QString')

    def __init__(self, parent=None, designMode=False):
        TaurusMainWindow.__init__(self, parent, designMode)
        self.statusBar().showMessage("")
        self.setModelInConfig(True)
        self._doorName = ""
        self.registerConfigProperty("doorName", "setDoorName", "doorName")
        self._customMacroEditorPaths = ""
        self.registerConfigProperty(
            "customMacroEditorPaths", "setCustomMacroEditorPaths", "customMacroEditorPaths")
        self._qDoor = None
        self.setWindowIcon(getIcon(":/apps/preferences-system-session.svg"))
        toolBar = self.basicTaurusToolbar()
        toolBar.setIconSize(Qt.QSize(24, 24))
        self.configureAction = self.createConfigureAction()
        toolBar.addAction(self.configureAction)
        self.taurusMenu.addAction(self.configureAction)
        self.customMacroEditorsPathsAction = self.createCustomMacroEditorPathsAction()
        self.taurusMenu.addAction(self.customMacroEditorsPathsAction)
        self.addToolBar(toolBar)
        self.initComponents()
        self.splashScreen().finish(self)
        self.doorChanged.connect(self.onDoorChanged)

    def doorName(self):
        return self._doorName

    def setDoorName(self, doorName):
        self._doorName = doorName

    def onDoorChanged(self, doorName):
        self.setDoorName(doorName)

    def customMacroEditorPaths(self):
        return self._customMacroEditorPaths

    def setCustomMacroEditorPaths(self, customMacroEditorPaths):
        self._customMacroEditorPaths = customMacroEditorPaths
#        ParamEditorManager().parsePaths(customMacroEditorPaths)
#        ParamEditorManager().browsePaths()

    def onCustomMacroEditorPaths(self):
        paths = str(Qt.QInputDialog.getText(self,
                                            "Edition of custom macro editors paths",
                                            "Paths:", Qt.QLineEdit.Normal,
                                            str(self.customMacroEditorPaths()))[0])
        self.setCustomMacroEditorPaths(paths)

    def initComponents(self):
        pass

    def setModel(self, model):
        """Sets new model for application, and change window title witn new macroserver name."""
        TaurusMainWindow.setModel(self, model)
        self.setWindowTitle(Qt.QApplication.applicationName() + ": " + model)

    def createConfigureAction(self):
        configureAction = Qt.QAction(getThemeIcon(
            "preferences-system-session"), "Change configuration", self)
        configureAction.triggered.connect(self.changeConfiguration)
        configureAction.setToolTip("Configuring MacroServer and Door")
        configureAction.setShortcut("F10")
        return configureAction

    def createCustomMacroEditorPathsAction(self):
        configureAction = Qt.QAction(getThemeIcon(
            "folder-open"), "Change custom macro editors paths", self)
        configureAction.triggered.connect(self.onCustomMacroEditorPaths)
        configureAction.setToolTip("Change custom macro editors paths")
        configureAction.setShortcut("F11")
        return configureAction

    def changeConfiguration(self):
        """This method is used to change macroserver as a model of application.
           It shows dialog with list of all macroservers on tango host, if the user
           Cancel dialog it doesn't do anything."""
        dialog = TaurusMacroConfigurationDialog(
            self, self.modelName, self.doorName())
        if dialog.exec_():
            self.setModel(str(dialog.macroServerComboBox.currentText()))
            self.doorChanged.emit(str(dialog.doorComboBox.currentText()))
        else:
            return

    def onShortMessage(self, msg):
        ''' Slot to be called when there is a new short message. Currently, the only action
        taken when there is a new message is to display it in the main window status bar.

        :param msg: (str) the short descriptive message to be handled
        '''
        self.statusBar().showMessage(msg)


def test_macrocombobox(ms_name):
    mcb = MacroComboBox()
    mcb.setModel(ms_name)
    mcb.show()

if __name__ == "__main__":
    import sys
    from taurus.qt.qtgui.application import TaurusApplication
    app = TaurusApplication()
    args = app.get_command_line_args()
    ms_name = args[0]
    test_macrocombobox(ms_name)
    sys.exit(app.exec_())
