#! /usr/bin/python
# $Header: https://oberon.oapd.inaf.it/shins/branches/drot_init/shins/src/obs_ctrl/panels/shark_eng_panel.py 2213 2019-10-17 15:23:18Z depa $

from PySide import QtUiTools, QtCore
from PySide.QtCore import QFile, QLocale, Slot
from PySide import QtGui
import json
import os
import sys
import time

import Ice
import Nice
import BasdaMoccaWheel as moccaW
import BasdaMoccaX as moccaX
import BasdaMoccaXY as moccaXY
import SharknirDrot as Drot
from Basda import Basdard

# trunkPath = os.environ['TRUNK']

# dir_path = os.path.dirname(os.path.realpath(__file__))
ui_path = os.environ["INSROOT"] + "/share/ui/Sharknir/"
# print(dir_path)
# sys.path.append(dir_path+'/tpl')
# sys.path.append('../../../../templates')
# sys.path.append('{}/templates'.format(trunkPath))
import tpl

class ResultObject(QtCore.QObject):
    def __init__(self, val):
        self.val = val

class engGuiThread(QtCore.QThread):
    def __init__(self, aliasName="", ins_s=None,
                 det_s=None, tel_s=None, rtc_s=None,
                 tplScript=None, callback=None, parent=None):
        QtCore.QThread.__init__(self, parent)
        self.exiting = False
        self._aliasName = aliasName
        self._ins_s = ins_s
        self._tel_s = tel_s
        self._det_s = det_s
        self._rtc_s = rtc_s
        self._tplScript = tplScript
        self._kwargs= dict()
        if callback:
            self.finished.connect(callback)
        else:
            self.finished = None
        self._unit = None
        self._absolute = None
        self._relative = None
        self._status = 1 # exit failure

    @property
    def ins_s(self):
        return self._ins_s
    @ins_s.setter
    def ins_s(self, ins_s):
        self._ins_s = ins_s

    @property
    def tel_s(self):
        return self._tel_s
    @tel_s.setter
    def tel_s(self, tel_s):
        self._tel_s = tel_s

    @property
    def det_s(self):
        return self._det_s
    @det_s.setter
    def det_s(self, det_s):
        self._det_s = det_s

    @property
    def rtc_s(self):
        return self._rtc_s
    @rtc_s.setter
    def rtc_s(self, rtc_s):
        self._rtc_s = rtc_s
 
    @property
    def tplScript(self):
        return self._tplScript
    @tplScript.setter
    def tplScript(self, tplScript):
        self._tplScript = tplScript

    @property
    def unit(self):
        return self._unit
    @unit.setter
    def unit(self, unit):
        self._unit = unit

    @property
    def absolute(self):
        return self._absolute
    @absolute.setter
    def absolute(self, absolute):
        self._absolute = absolute

    @property
    def relative(self):
        return self._relative
    @relative.setter
    def relative(self, relative):
        self._relative = relative

    @property
    def kwargs(self):
        return self._kwargs
    @kwargs.setter
    def kwargs(self, kwargs):
        self._kwargs.update(kwargs)

    def run(self):
        # if ((self._ins_s) and (self._tplScript)):
        if (self._tplScript):
            self._kwargs = {"EXIT": False}
            if (self._relative):
                self._kwargs["rel"] = self._relative
            if (self._absolute):
                self._kwargs["abs"] = self._absolute
            if (self._unit):
                self._kwargs.update(self._unit)

            # print("calling {} script".format(self._tplScript.__name__))
            self.fun()
            # self._status = self._tplScript(self._ins_s, self._det_s, self._tel_s, self._rtc_s, **kwargs)
            # print("status = {}".format(self._status))
            # print("called")
        else:
            print("No widget or template script set")

    def fun(self):
        self._status = self._tplScript(self._ins_s, self._det_s, self._tel_s, self._rtc_s, **self._kwargs)
        if self.finished:
            self.finished.emit(ResultObj())

class SurfViewer(QtGui.QMainWindow):

    def handle_result(self, result):
        val = result.val
        #self.container.
    #
    # Slots relative to UI buttons
    #

    @Slot()
    def init(self, w):
        '''Device initialization.
        @param self self
        @param w calling widget
        '''

        ins_s = []
        aliasLow = w.deviceLabel.text().lower()
        ins_s.append(w.deviceLabel.text())

        self.threadDict[aliasLow]["init"].ins_s = ins_s
        self.threadDict[aliasLow]["init"].det_s = None
        self.threadDict[aliasLow]["init"].tel_s = None
        self.threadDict[aliasLow]["init"].rtc_s = None
        ret = self.threadDict[aliasLow]["init"].start()

        # initDict = {w.deviceLabel.text(): 0.0}

        # kwargs = {"EXIT": False}
        # ins_s = []
        # ins_s.append(w.deviceLabel.text())
        # # tpl.SHARKNIR_gen_init.SHARKNIR_gen_init(ins_s, **kwargs)
        # asyncResMotion, asyncResCalibUnit, asyncResTracking = \
        #     tpl.SHARKNIR_gen_init_start.SHARKNIR_gen_init_start(ins_s, **kwargs) # this call blocks anyway

        # self.status(w,"online")
        # print(__name__ + w.deviceLabel.text())

    @Slot()
    def on(self, w):
        '''Switching Lamp On.
        @param self self
        @param w calling widget
        '''
        aliasUp = w.deviceLabel.text().upper()
        aliasLow = w.deviceLabel.text().lower()
        print("Switching Lamp {} On...".format(w.deviceLabel.text()))
        self.threadDict[aliasLow]["lamp"].ins_s = None
        self.threadDict[aliasLow]["lamp"].det_s = None
        self.threadDict[aliasLow]["lamp"].tel_s = None
        self.threadDict[aliasLow]["lamp"].rtc_s = {w.deviceLabel.text():"on"}
        ret = self.threadDict[aliasLow]["lamp"].start()

        self.threadDict[aliasLow]["lampState"].ins_s = None
        self.threadDict[aliasLow]["lampState"].det_s = None
        self.threadDict[aliasLow]["lampState"].tel_s = None
        self.threadDict[aliasLow]["lampState"].rtc_s = {w.deviceLabel.text():""}
        ret = self.threadDict[aliasLow]["lampState"].start()
        w.valInput.setText(self.threadDict[aliasLow]["lampState"].rtc_s[aliasUp])

    @Slot()
    def off(self, w):
        '''Switching Lamp Off.
        @param self self
        @param w calling widget
        '''
        aliasUp = w.deviceLabel.text().upper()
        aliasLow = w.deviceLabel.text().lower()
        print("Switching Lamp {} Off...".format(w.deviceLabel.text()))
        self.threadDict[aliasLow]["lamp"].ins_s = None
        self.threadDict[aliasLow]["lamp"].det_s = None
        self.threadDict[aliasLow]["lamp"].tel_s = None
        self.threadDict[aliasLow]["lamp"].rtc_s = {w.deviceLabel.text():"off"}
        ret = self.threadDict[w.deviceLabel.text().lower()]["lamp"].start()

        self.threadDict[aliasLow]["lampState"].ins_s = None
        self.threadDict[aliasLow]["lampState"].det_s = None
        self.threadDict[aliasLow]["lampState"].tel_s = None
        self.threadDict[aliasLow]["lampState"].rtc_s = {w.deviceLabel.text():""}
        ret = self.threadDict[aliasLow]["lampState"].start()
        w.valInput.setText(self.threadDict[aliasLow]["lampState"].rtc_s[aliasUp])

    @Slot()
    def go(self, w):
        '''Go to position.
        @param self self
        @param w calling widget
        '''
        ins_s = {w.deviceLabel.text(): None}
        kwargs = {"EXIT": False}
        aliasLow = w.deviceLabel.text().lower()

        if w.absRadio.isChecked():
            # kwargs["abs"] = True
            # kwargs["unit"] = w.unitCombo.currentText() # Ice.Unset
            print("abs radio checked")
            ins_s[w.deviceLabel.text()] = w.absInput.value()

            self.threadDict[aliasLow]["go"].ins_s = ins_s
            self.threadDict[aliasLow]["go"].det_s = None
            self.threadDict[aliasLow]["go"].tel_s = None
            self.threadDict[aliasLow]["go"].rtc_s = None
            self.threadDict[aliasLow]["go"].unit = {w.deviceLabel.text():w.unitCombo.currentText()}
            self.threadDict[aliasLow]["go"].absolute = True
            self.threadDict[aliasLow]["go"].relative = False
            ret = self.threadDict[aliasLow]["go"].start()

        if w.relRadio.isChecked():
            # kwarg["rel"] = True
            # kwargs["unit"] = w.unitCombo.currentText() # Ice.Unset
            print("rel radio checked")
            ins_s[w.deviceLabel.text()] = w.relInput.value()

            self.threadDict[aliasLow]["go"].ins_s = ins_s
            self.threadDict[aliasLow]["go"].det_s = None
            self.threadDict[aliasLow]["go"].tel_s = None
            self.threadDict[aliasLow]["go"].rtc_s = None
            self.threadDict[aliasLow]["go"].unit = {w.deviceLabel.text():w.unitCombo.currentText()}
            self.threadDict[aliasLow]["go"].absolute = False
            self.threadDict[aliasLow]["go"].relative = True
            self.threadDict[aliasLow]["go"].start()

        if hasattr(w, 'absRadio_x'):
            pass
            # print(entering if clause for absRadio_x")
            # print(absRadio_x.isChecked())
            # print(absInput_x.value())

        if hasattr(w, 'absRadio_y'):
            pass
            # print("entering if clause for absRadio_y")
            # print(w.absRadio_y.isChecked())
            # print(w.absInput_y.value())

        if hasattr(w, 'relRadio_x'):
            pass
            # print("entering if clause for relRadio_x")
            # print(w.relRadio_x.isChecked())
            # print(w.relInput_x.value())

        if hasattr(w, 'relRadio_y'):
            pass
            # print("entering if clause for relRadio_y")
            # print(w.relRadio_y.isChecked())
            # print(w.relInput_y.value())

        # named position
        if w.positionRadio.isChecked():
            # kwargs["abs"] = True
            # kwargs["unit"] = w.unitCombo.currentText()
            index = w.positionCombo.currentIndex()
            nodeName = "1.CFG.NAMED_POS.ABS.{:d}".format(index)
            print("Node name for index {:02d} is {}".format(index, nodeName))
            print(self.deviceDict[aliasLow].config().node(nodeName).getWithDefaultAsDouble(0.0))
            ins_s[w.deviceLabel.text()] = self.deviceDict[aliasLow].config().node(nodeName).getWithDefaultAsDouble(0.0)
            print(ins_s)
            self.threadDict[aliasLow]["go"].ins_s = ins_s
            self.threadDict[aliasLow]["go"].det_s = None
            self.threadDict[aliasLow]["go"].tel_s = None
            self.threadDict[aliasLow]["go"].rtc_s = None
            self.threadDict[aliasLow]["go"].unit = {w.deviceLabel.text():w.unitCombo.currentText()}
            self.threadDict[aliasLow]["go"].absolute = True
            self.threadDict[aliasLow]["go"].Relative = False
            self.threadDict[aliasLow]["go"].start()


            # print(ins_s)
            # print(kwargs)
            # tpl.SHARKNIR_gen_motion.SHARKNIR_gen_motion(ins_s, **kwargs)
            # print(w.positionRadio.isChecked())
            # print("{} ({})= {}".format(w.positionCombo.currentText(),  index, ins_s[w.deviceLabel.text()]))

        self.statusBar().showMessage("Going to position...")
        # print("Going to position...")

    @Slot()
    def stop(self, w):
        '''Stop the command
        @param self self
        @param w calling widget
        '''
        kwargs = {"EXIT": False}
        ins_s = []
        aliasLow = w.deviceLabel.text().lower()
        print("Stopping {} ...".format(w.deviceLabel.text()))
        ins_s.append(w.deviceLabel.text())
        self.threadDict[aliasLow]["stop"].ins_s = ins_s
        self.threadDict[aliasLow]["stop"].det_s = None
        self.threadDict[aliasLow]["stop"].tel_s = None
        self.threadDict[aliasLow]["stop"].rtc_s = None
        self.threadDict[aliasLow]["stop"].start()
        # tpl.SHARKNIR_gen_stop(ins_s, **kwargs)
        print("Stopping the command...")

    @Slot()
    def abort(self, w):
        '''Abort the command.
        @param self self
        @param w calling widget
        '''
        print("Implement abort QtSlot")
        ins_s = []
        aliasLow = w.deviceLabel.text().lower()

        ins_s.append(w.deviceLabel.text())

        self.threadDict[aliasLow]["abort"].ins_s = ins_s
        self.threadDict[aliasLow]["abort"].det_s = None
        self.threadDict[aliasLow]["abort"].tel_s = None
        self.threadDict[aliasLow]["abort"].rtc_s = None
        # check if other threads moving device are running
        # if exit them
        if self.threadDict[aliasLow]["go"].isRunning():
            print("Exiting \"go\" thread")
            self.threadDict[aliasLow]["go"].exit(1)
        if self.threadDict[aliasLow]["init"].isRunning():
            print("Exiting \"init\" thread")
            self.threadDict[aliasLow]["init"].exit(1)

        # start abort thread
        self.threadDict[aliasLow]["abort"].start()

    @Slot()
    def state_change(self, w):
        '''online command
        @param w calling widget
        '''
        ins_s = [w.deviceLabel.text()]
        kwargs = {"EXIT": False,
                  "state": w.stateCombo.currentText()}
        # print(w.stateCombo.currentIndex())
        tpl.SHARKNIR_gen_change_state.SHARKNIR_gen_change_state(ins_s, **kwargs)
        self.status(w, w.stateCombo.currentText().lower())

    @Slot()
    def unit_change(self, w):
        '''slot for current index changed signal
        from unit combo box. Converts the content of
        abs and rel spin boxes to the selected unit
        @param w calling widget'''
        # get convertion factor
        # get spin boxes values
        # convert
        # write new values
        # if w.deviceLabel.text().lower() != "derot":
        #     aliasName = w.deviceLabel.text().lower()
        # else:
        #     aliasName = "drot1"
        # transJoint = self.deviceDict[aliasName].config().node("1.CFG.TRANS")

        # if transJoint.exist("DEGREE") or transJoint.exist("DEG"):
        #     unitNode = transJoint.node("DEGREE") if transJoint.exist("DEGREE") else transJoind.node("DEG")



        # unit = w.unitCombo.currentText()
        # inputVal = 0
        # if w.prevUnit == "steps":
        #     if unit
        #     inputVal = w.absInput.value() * conv + offset
        # if w.prevUnit == "mm":
        #     if transJoint.exist("")
        #     w.unitDict["deg"] = [unitNode.leaf().Point.x(), unitNode.leaf().Point.y()]
        #     convertCoeff = 2
        # elif w.prevUnit == "micron":
        #     convertCoeff = 2000
        # elif w.prevUnit == "deg":
        #     ceonvertCoeff = 3.14
        # else:
        #     convertCoeff = 1

        # w.prevUnit = w.unitCombo.currentText()
        # w.absInput.setValue(w.absInput.value()*convertCoeff)

    @Slot()
    def on_radio_toggled(self, w):
        '''slot to change present position value for input val
        text. connected to radio buttons toggling signals
        @param w calling widget'''

        aliasName = w.deviceLabel.text().lower()
        endPoint = "[ALIAS={}]".format(w.deviceLabel.text().lower())
        nodeName = "{}.VAR.NAMED_POSITION".format(w.deviceLabel.text())
        if hasattr(w, 'absRadio'):
            # which radio button toggled the slot?
            if (w.absRadio.isChecked()):
                # get absolute position from device
                position = self.serviceDict[aliasName].getPosition()
                # w.absInput.setValue(service.getPosition())
                w.absInput.setValue(position)
                # w.valInput.setText("{}".format(service.getPosition()))
                w.valInput.setText("{}".format(position))

            # elif (w.relRadio.isChecked()):
            #     # do nothing
            #     pass

        elif hasattr(w, 'absRadio_y'):
            if (w.absRadio_x.isChecked() or w.absRadio_y.isChecked()) and w.positionRadio.isChecked():
                w.buttonGroup_x.setExclusive(False)
                w.positionRadio.setChecked(False)
                w.buttonGroup_x.setExclusive(True)

        if (w.positionRadio.isChecked() and w.isEnabled()):
            # get named position from device
            if hasattr(w, 'absRadio_y'):
                # print ("Is XY Device: unchecking...")
                w.buttonGroup_y.setExclusive(False)
                w.absRadio_y.setChecked(False)
                w.relRadio_y.setChecked(False)
                w.buttonGroup_y.setExclusive(True)

            # namedPosition = self.serviceDict[aliasName].config().node("VAR.NAMED_POSITION").leaf().Int
            # print (namedPosition)
            # if hasattr(w, 'valInput_y'):

            #     w.valInput_y.setText(namedPosition)
            # else:
            #     w.valInput.setText(namedPosition)
            # pass

    @Slot()
    def on_named_pos_clicked(self, w):
        '''Slot to toggle named position radio button to true
        '''
        print("Implement on_named_pos_clicked Slot")
        w.positionRadio.setChecked(True)

    @Slot()
    def exit_app(self):
        QtGui.QApplication.quit()

    ##########
    # Status #
    ##########

    def status(self, w, d):
        '''Changes the device status
        @param self self
        @param w calling widget
        @param d required device status
        '''

        def online():
            '''Puts the device in the "ONLINE" status.
            '''
            # print("ONLINE")
            # print(w.deviceLabel.text())
            return "ONLINE"

        def standby():
            # print("STANDBY")
            return "STANDBY"

        def offline():
            '''Puts the device in the "OFFLINE" status.
            '''
            # print("OFFLINE")
            return "OFFLINE"

        def moving():
            '''Puts the device in the "MOVING" status.
            '''
            # print("MOVING")
            return "MOVING"

        def error():
            '''Puts the device in the "ERROR" status.
            '''
            # print("ERROR")
            return "ERROR"

        # Map the inputs to the function blocks.
        options = {"online": [online, "green"],
                   "standby": [standby, "darkorange"],
                   "offline": [offline, "gray"],
                   "moving": [moving, "blue"],
                   "error": [error, "red"],
                   }

        # print("Changing the status to: " + d + "...")
        result = options[d][0]()  # Call the status function (element 0 of the array).
        color = options[d][1]    # Read the color string (element 1 of the array).
        myFont = QtGui.QFont()
        myPalette = w.statusLabel.palette()
        myPalette.setColor(w.statusLabel.foregroundRole(), color)
        myFont.setBold(True)
        w.statusLabel.setFont(myFont)
        w.statusLabel.setPalette(myPalette)
        w.statusLabel.setText(result)


    ########################
    # Get Simulation State #
    ########################
    def isSim(self, w):
        aliasName = str(w.deviceLabel.text().lower())
        # if w.deviceLabel.text() == "DEROT":
        #     aliasName = "drot1"

        if "lamp" not in aliasName:
            if ("Dummy" in self.deviceDict[aliasName].config().node("1.LOAD").String):
                color = "red"
                myFont = QtGui.QFont()
                myPalette = w.simLabel.palette()
                myPalette.setColor(w.simLabel.foregroundRole(), color)
                myFont.setBold(True)
                w.simLabel.setFont(myFont)
                w.simLabel.setPalette(myPalette)
                w.simLabel.setText("SIM")
            else:
                color = "green"
                myFont = QtGui.QFont()
                myPalette = w.simLabel.palette()
                myPalette.setColor(w.simLabel.foregroundRole(), color)
                myFont.setBold(True)
                w.simLabel.setFont(myFont)
                w.simLabel.setPalette(myPalette)
                w.simLabel.setText("NOSIM")


    ###################
    # Add Lamp widget #
    ###################

    def lampWidget(self, d):
        """Load the Lamp-specific UI in a widget variable.
        It contains buttons, labels, input fields etc.
        @param d Device object (from JSON file)
        """
        print("lampWidget(self, d)")
        UIlampWidgetPath = ui_path + "lampWidget.ui"

        w = QtUiTools.QUiLoader().load(UIlampWidgetPath)
        w.valInput.setText(str(d["default"]))

        # Connect Lamp-specific buttons.
        w.onButton.clicked.connect(lambda: self.on(w))
        w.offButton.clicked.connect(lambda: self.off(w))

        return w

    #################
    # Add XY widget #
    #################

    def XYDevicewidget(self, d):
        """Load the xyDevice device UI in a widget variable.
        It contains x ad y buttons, labels, input fields etc.
        @param d Device object (from JSON file)
        """
        print("XYDevicewidget(self, d)")

        # UIxyDeviceWidgetPath = "./xyDeviceWidgetRevisedFinal.ui"
        UIxyDeviceWidgetPath = ui_path + "xydeviceWidgetTable.ui"
        w = QtUiTools.QUiLoader().load(UIxyDeviceWidgetPath)
        # X axis
        w.unitCombo_x.insertItems(0, d["unit_x"])
        w.absInput_x.setValue(d["abs_x"])
        w.relInput_x.setValue(d["rel_x"])
        if (d["default_x"] == "abs_x"):
            w.absRadio_x.setChecked(True)
        if (d["default_x"] == "rel_x"):
            w.relRadio_x.setChecked(True)
        w.valInput_x.setText(str(d[d["default_y"]]))  # "abs" or "rel" values.
        # Y axis
        w.unitCombo_y.insertItems(0, d["unit_y"])
        w.absInput_y.setValue(d["abs_y"])
        w.relInput_y.setValue(d["rel_y"])
        if (d["default_y"] == "abs_y"):
            w.absRadio_y.setChecked(True)
        if (d["default_y"] == "rel_y"):
            w.relRadio_y.setChecked(True)
        w.valInput_y.setText(str(d[d["default_y"]]))  # "abs" or "rel" values.


        # Connect generic buttons.
        w.goButton.clicked.connect(lambda: self.go(w))
        w.stopButton.clicked.connect(lambda: self.stop(w))
        # w.absRadio.toggled.connect(lambda: self.on_radio_toggled(w))
        # w.relRadio.toggled.connect(lambda: self.on_radio_toggled(w))
        w.positionRadio.toggled.connect(lambda: self.on_radio_toggled(w))
        w.positionCombo.activated.connect(lambda: self.on_named_pos_clicked(w))

        return w

    def XDeviceWidget(self, d):
        """Load the generic device UI in a widget variable.
        It contains buttons, labels, input fields etc.
        @param d Device object (from JSON file)
        """
        print("XDeviceWidget(self, d)")
        # UIXdeviceWidgetPath = "./deviceWidgetRevisedFinal.ui"
        UIXdeviceWidgetPath = ui_path + "deviceWidgetTable.ui"
        w = QtUiTools.QUiLoader().load(UIXdeviceWidgetPath)
        w.unitCombo.insertItems(0, d["unit"])
        w.unitCombo.setCurrentIndex(0)
        w.absInput.setValue(d["abs"])
        w.relInput.setValue(d["rel"])
        w.absInput.setWrapping(True)
        w.relInput.setWrapping(True)

        w.valInput.setText(str(d[d["default"]]))  # "abs" or "rel" values.
        w.prevUnit = 'steps'
        # Connect generic buttons.
        w.goButton.clicked.connect(lambda: self.go(w))
        w.stopButton.clicked.connect(lambda: self.stop(w))
        w.unitCombo.currentIndexChanged.connect(lambda: self.unit_change(w))
        w.absRadio.toggled.connect(lambda: self.on_radio_toggled(w))
        w.relRadio.toggled.connect(lambda: self.on_radio_toggled(w))
        w.positionRadio.toggled.connect(lambda: self.on_radio_toggled(w))
        w.positionCombo.activated.connect(lambda: self.on_named_pos_clicked(w))

        return w

    ###########################
    # Populate Unit combo box #
    ###########################

    def populateUnitCombo(self, w):
        # if w.deviceLabel.text().lower() != "derot":
        aliasName = w.deviceLabel.text().lower()
        # else:
        #     aliasName = "drot1"
        transJoint = self.deviceDict[aliasName].config().node("1.CFG.TRANS")
        if transJoint.exist("DEGREE") or transJoint.exist("DEG"):
            unitNode = transJoint.node("DEGREE") if transJoint.exist("DEGREE") else transJoind.node("DEG")

            if ("_TT" not in w.deviceLabel.text()):
                w.unitCombo.addItem(unitNode.name().lower())
            else:
                w.unitCombo_y.addItem(unitNode.name().lower())
                w.unitCombo_x.addItem(unitNode.name().lower())
            #     w.unitDict["deg"] = [[unitNode.leaf().WMatrix.m11(), unitNode.leaf().WMatrix.m12()],
            #                          [unitNode.leaf().WMatrix.m21(), unitNode.leaf().WMatrix.m22()],
            #                          [unitNode.leaf().WMatrix.dx(), unitNode.leaf().WMatrix.dy()]]
        if transJoint.exist("MM"):
            unitNode = transJoint.node("MM")
            if ("_TT" not in w.deviceLabel.text()):
                w.unitCombo.addItem(unitNode.name().lower())
            #     w.unitDict["mm"] = [unitNode.leaf().Point.x(), unitNode.leaf().Point.y()]
            else:
                w.unitCombo_y.addItem(unitNode.name().lower())
                w.unitCombo_x.addItem(unitNode.name().lower())
            #     w.unitDict["mm"] = [[unitNode.leaf().WMatrix.m11(), unitNode.leaf().WMatrix.m12()],
            #                         [unitNode.leaf().WMatrix.m21(), unitNode.leaf().WMatrix.m22()],
            #                         [unitNode.leaf().WMatrix.dx(), unitNode.leaf().WMatrix.dy()]]
        if transJoint.exist("MICRON"):
            unitNode = transJoint.node("MICRON")
            w.unitCombo.addItem(unitNode.name().lower())
            if ("_TT" not in w.deviceLabel.text()):
                w.unitCombo.addItem(unitNode.name().lower())
            #     w.unitDict["micron"] = [unitNode.leaf().Point.x(), unitNode.leaf().Point.y()]
            else:
                w.unitCombo_y.addItem(unitNode.name().lower())
                w.unitCombo_x.addItem(unitNode.name().lower())
            #     w.unitDict["micron"] = [[unitNode.leaf().WMatrix.m11(), unitNode.leaf().WMatrix.m12()],
            #                             [unitNode.leaf().WMatrix.m21(), unitNode.leaf().WMatrix.m22()],
            #                             [unitNode.leaf().WMatrix.dx(), unitNode.leaf().WMatrix.dy()]]

    ###############
    # Add Devices #
    ###############

    def addDevice(self, d):
        '''Adds a Device in the panel.
        @param d Device object (from JSON file)
        '''

        # Devices can be of "lamp" type or generic.
        # Each one has its own widget UI.

        # setting thread for calls to init slot

        if (d["type"] == "lamp"):
            widget = self.lampWidget(d)

        elif (d["type"] == "xyDevice"):
            widget = self.XYDevicewidget(d)
        else:
            # print("else block execute for {}".format(d["type"]))
            widget = self.XDeviceWidget(d)

        # Set device label.
        myFont = QtGui.QFont()
        myFont.setBold(True)
        widget.deviceLabel.setFont(myFont)
        widget.deviceLabel.setText(d["id"])
        self.container.addWidget(widget)

        # Populate named position combo box
        namedPosIdx = 0
        aliasName = str(widget.deviceLabel.text().lower())

        endPoint = "[ALIAS={}]".format(aliasName)
        # pupolating service dictionary with proper BasdaMocca service, also populating thread dictionary:
        # each service has 4 threads: init, go, stop, abort
        try:
            if ("_W" in widget.deviceLabel.text()) or ("ADC" in widget.deviceLabel.text()):
                self.serviceDict[aliasName] = moccaW.Wheel.connectWithEndpoint(str(widget.deviceLabel.text()), endPoint)

            elif ("_DEP" in widget.deviceLabel.text()) or (widget.deviceLabel.text() == "SHUTTER"):
                self.serviceDict[aliasName] = moccaX.X.connectWithEndpoint(str(widget.deviceLabel.text()), endPoint)

            elif ("_TT" in widget.deviceLabel.text()):
                self.serviceDict[aliasName] = moccaXY.XY.connectWithEndpoint(str(widget.deviceLabel.text()), endPoint)

            elif (widget.deviceLabel.text() == "DEROT"):
                print ("Is DEROT")
                self.serviceDict[aliasName] = Drot.DROT.connectWithEndpoint(str(widget.deviceLabel.text()), endPoint)

            # setting state coherent with Basda service state
            if ("LAMP" in widget.deviceLabel.text()):
                pass
            else:
                self.status(widget, self.serviceDict[aliasName].state().name.lower())
        except Nice.Exception as e:
            Nice.A_LOG(e.message)
            self.statusBar().showMessage(e.message)
            widget.setEnabled(False)
            pass
        except Ice.Exception as e:
            Nice.A_LOG(e.message)
            self.statusBar().showMessage(e.message)
            widget.setEnabled(False)
            pass
        except RuntimeError as e:
            if ("IceUtil::NullHandleException" in e.message):
                widget.setEnabled(False)
                self.statusBar().showMessage(aliasName + "   " + widget.deviceLabel.text() + "   " + e.message)
            pass


        self.threadDict[aliasName] = {"init": engGuiThread(aliasName,
                                                           ins_s=None, det_s=None, tel_s=None, rtc_s=None,
                                                           tplScript=tpl.SHARKNIR_gen_init) ,
                                      "stop": engGuiThread(aliasName,
                                                           ins_s=None, det_s=None, tel_s=None, rtc_s=None,
                                                           tplScript=tpl.SHARKNIR_gen_stop),
                                      "go": engGuiThread(aliasName,
                                                         ins_s=None, det_s=None, tel_s=None, rtc_s=None,
                                                         tplScript=tpl.SHARKNIR_gen_motion),
                                      "abort": engGuiThread(aliasName,
                                                            ins_s=None, det_s=None, tel_s=None, rtc_s=None,
                                                            tplScript=tpl.SHARKNIR_gen_abort),
                                      "lamp": engGuiThread(aliasName,
                                                           ins_s=None, det_s=None, tel_s=None, rtc_s=None,
                                                           tplScript=tpl.SHARKNIR_gen_lampSetup),
                                      "lampState": engGuiThread(aliasName,
                                                                ins_s=None, det_s=None, tel_s=None, rtc_s=None,
                                                                tplScript=tpl.SHARKNIR_gen_lampState)
        }


        # alias device dictionary
        if widget.isEnabled():
            print (aliasName)
            try:
                if "lamp" not in aliasName:
                    self.deviceDict[aliasName]  = Basdard.connect("{}-dev".format(aliasName))

                    # filling named position and unit combo boxes, getting string from DEV subtree
                    self.populateUnitCombo(widget)
                    nodeName = "1.CFG.NAMED_POS.ABS.{:d}"
                    while self.deviceDict[aliasName].config().node(nodeName.format(namedPosIdx)).hasLeaf():

                        iNamedPosition = self.deviceDict[aliasName].config().node(nodeName.format(namedPosIdx)).leaf().getAttrString("NAME")

                        widget.positionCombo.addItem(iNamedPosition)
                        namedPosIdx += 1

            except Nice.Exception as e:
                Nice.A_LOG(e.message)
                pass
            except Ice.Exception as e:
                Nice.A_LOG(e.message)
                pass

            # Set range and decimals for spin boxes inputs, depending on unit
            # values are retrived from DEV subtree.
            # Value are specified in the following nodes:
            # For wheel devices in FULLTURN node
            # For linear stages devices (X and XY) in TRAVELRANGE node
            # For derotator either in FULLTURN or TRAVELRANGE
            minValue = 0
            maxValue = 0

            fullturnNodeName    = "1.CFG.FULLTURN"
            travelRangeNodeName = "1.MOD.{}.CFG.DATASHEET.TRAVELRANGE"
            if "_W" in widget.deviceLabel.text():
                if widget.unitCombo.currentText() == "steps":
                    minValue = 0
                    maxValue = self.deviceDict[aliasName].config().node(fullturnNodeName).leaf().Int
                if (d["default"] == "abs"):
                    widget.absRadio.setChecked(True)
                if (d["default"] == "rel"):
                    widget.relRadio.setChecked(True)
            elif ("_DEP" in widget.deviceLabel.text()) or (widget.deviceLabel.text() == "SHUTTER"):
                if widget.unitCombo.currentText() == "steps":
                    minValue = self.deviceDict[aliasName].config().node(travelRangeNodeName.format("X")).leaf().Point.x()
                    maxValue = self.deviceDict[aliasName].config().node(travelRangeNodeName.format("X")).leaf().Point.y()
            elif ("_TT" in widget.deviceLabel.text()):
                if widget.unitCombo_x.currentText() == "steps":
                    minValueXAxis = self.deviceDict[aliasName].config().node(travelRangeNodeName.format("X")).leaf().Point.x()
                    maxValueXAxis = self.deviceDict[aliasName].config().node(travelRangeNodeName.format("X")).leaf().Point.y()
                if widget.unitCombo_y.currentText() == "steps":
                    minValueYAxis = self.deviceDict[aliasName].config().node(travelRangeNodeName.format("Y")).leaf().Point.x()
                    maxValueYAxis = self.deviceDict[aliasName].config().node(travelRangeNodeName.format("Y")).leaf().Point.y()

            elif (widget.deviceLabel.text() == "DEROT"):
                if self.deviceDict[aliasName].config().exist(travelRangeNodeName.format("X")):
                    minValue = self.deviceDict[aliasName].config().node(travelRangeNodeName.format("X")).leaf().Point.x()
                    maxValue = self.deviceDict[aliasName].config().node(travelRangeNodeName.format("X")).leaf().Point.y()
                elif self.deviceDict[aliasName].config().exist(fullturnNodeName):
                    minValue = 0
                    maxValue = self.deviceDict[aliasName].config().node(fullturnNodeName).leaf().Int
                else:
                    Nice.A_LOG("Missing limits in derotator config file")
                    minValue = 0
                    maxValue = 0
            else:
                minValue = 0
                maxValue = 0


            if hasattr(widget, 'absInput_x') and hasattr(widget, 'absInput_y'):
                # absolute
                widget.absInput_x.setRange(minValueXAxis, maxValueXAxis)
                widget.absInput_y.setRange(minValueYAxis, maxValueYAxis)
                widget.absInput_x.setValue(minValueXAxis)
                widget.absInput_y.setValue(minValueYAxis)
                # relative
                widget.relInput_x.setRange(minValueXAxis, maxValueXAxis)
                widget.relInput_y.setRange(minValueYAxis, maxValueYAxis)
                widget.relInput_x.setValue(minValueXAxis)
                widget.relInput_y.setValue(minValueYAxis)

                widget.absInput_x.setDecimals(0)
                widget.absInput_y.setDecimals(0)

                # position = self.serviceDict[aliasName].getPosition()
                # widget.valInput.setText("{}".format(position))

            elif hasattr(widget, 'absInput') and hasattr(widget, 'relInput'):
                widget.absInput.setRange(minValue, maxValue)
                widget.relInput.setRange(minValue, maxValue)
                widget.absInput.setValue(minValue)
                widget.relInput.setValue(minValue)
                widget.absInput.setDecimals(0)
                widget.relInput.setDecimals(0)

                position = self.serviceDict[aliasName].getPosition()
                widget.valInput.setText("{}".format(position))


            # Connect device buttons (common for all device types).
            if "LAMP" not in widget.deviceLabel.text():
                widget.initButton.clicked.connect(lambda: self.init(widget))
                widget.abortButton.clicked.connect(lambda: self.abort(widget))

                widget.stateCombo.currentIndexChanged.connect(lambda: self.state_change(widget))

            # set simulation state label
            self.isSim(widget)



    ###############
    # Constructor #
    ###############

    def __init__(self, parent=None):
        '''Constructor'''

        class QHLine(QtGui.QFrame):
            def __init__(self):
                super(QHLine, self).__init__()
                self.setFrameShape(QtGui.QFrame.HLine)
                self.setFrameShadow(QtGui.QFrame.Sunken)

        super(SurfViewer, self).__init__(parent=parent)

        # Dictonary deviceName, Basda service
        self.serviceDict = {}
        self.deviceDict = {}
        self.threadDict= {}

        self.window = QtGui.QWidget()
        # self.window.setMaximumSize(self.size())
        # self.window.setMinimumSize(self.size())

        self.setCentralWidget(self.window)

        # self.scrollContainer = QtGui.QScrollArea(self.window)
        self.container = QtGui.QVBoxLayout(self.window)
        
        deviceList = ui_path + "deviceList.json"

        # Load a JSON file containing initial parameters for each device.
        f = open(deviceList, "r")
        devices = json.load(f)
        f.close()

        # Add header before widgets
        UIHeaderPath = ui_path + "header.ui"
        headerWidget = QtUiTools.QUiLoader().load(UIHeaderPath)
        self.container.addWidget(headerWidget)

        # Add devices.
        for d in devices:
            if ("CAL_" not in d["id"]):
                self.addDevice(d)

        # Separate devices from calibration unit elements.
        self.container.addWidget(QHLine())
        # self.container.addWidget(QtGui.QStatusBar())

        # self.statusBar().showMessage("Ready")

        # Add calibration unit elements.
        for d in devices:
            if "CAL_" in d["id"]:
                self.addDevice(d)

        # # Add calibration unit elements.
        # for d in devices :
        #     if "INBEAM" in d["id"] :
        #         self.addDevice(d)

        self.statusBar().showMessage("Ready")
        # Menu
        self.menu = self.menuBar()
        self.file_menu = self.menu.addMenu("File")

        # Exit QAction
        exit_action = QtGui.QAction("Exit", self)
        exit_action.setShortcut("Ctrl+Q")
        exit_action.triggered.connect(self.exit_app)
        self.file_menu.addAction(exit_action)

#
# Main
#

if __name__ == "__main__":
    resourcesDir = os.environ["INSROOT"] + "/etc/resourcesQt/" 

    try:
        QLocale.setDefault("en_US")
        QtCore.QDir.addSearchPath("images", resourcesDir + "/images/")

        app = QtGui.QApplication(sys.argv)
        pixmap = QtGui.QPixmap("images:SHINS_splash.png")
        start = time.time()

        splash = QtGui.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint)
        strRevision = "$Rev: 3556 $"
        splash.showMessage(strRevision[1:-1])
        splash.show()
        # loop to make image actually visible
        while time.time() - start < 1:
            time.sleep(0.001)
            splash.showMessage("{} - Connecting to software services ...".format(strRevision[1:-1]),
            alignment=QtCore.Qt.AlignRight)
            app.processEvents()
        ex = SurfViewer()
        # time.sleep(10)
        #splash.showMessage("Started the SurfViewer object")
        ex.setWindowTitle("SHARK Engineering Panel - {}".format(strRevision[1:-1]))

        ex.show()
        splash.finish(ex)
        sys.exit(app.exec_())
    except KeyboardInterrupt as e:
        sys.exit()
