class PolarizerWAMP(BaseWAMP):
    __wampname__ = 'polarizer server'
    ANGLE = 0
    DEGREES_PER_STEP = - .10 / 9.998686
    MESSAGES = {
        'calibration-changed':'polarization calibration has changed'
    }

    @inlineCallbacks
    def initializeWAMP(self):        
        protocol = yield getProtocol(
            TEST_STEPPER_MOTOR_SERVER
            if DEBUG else
            STEPPER_MOTOR_SERVER
        )
        self.polSM = ChunkedStepperMotorClient(protocol,POL)
        angle = yield getType(float,'enter polarizer angle: ')
        self.offset = {}
        BaseWAMP.initializeWAMP(self)        
        yield self.calibrateAngle(angle)       

    @command('calibrate-angle','recalibrate polarizer angle')
    @inlineCallbacks
    def calibrateAngle(self,angle):
        position = yield self.polSM.getPosition()
        self.offset['position'] = position
        self.offset['angle'] = angle
        self.dispatch('calibration-changed',self.offset)

    @command('get-angle','get calibrated polarizer angle')
    def _getAngle(self):
        return self.polSM.getPosition().addCallback(self.getAngle)
        
    def getAngle(self,step):
        return self.DEGREES_PER_STEP*(step - self.offset['position']) + self.offset['angle']

        
    @command('set-angle','set angle')
    @inlineCallbacks
    def setAngle(self,angle):
        # find desired polarizer step, inverted form of getAngle
        targetStep = int( round(
                (angle - self.offset['angle']) / self.DEGREES_PER_STEP + self.offset['position']
            )
        )
        # set the positions all at once, and wait for them to finish
        yield self.polSM.setPosition(targetStep)
        angle = yield self._getAngle()
        returnValue(angle)
        
        
    @command('cancel-angle-set','abort most recent angle set call')
    def cancelWavelengthCall(self):
        self.polSM.cancel()
class PolarizerWAMP(BaseWAMP):
    __wampname__ = 'polarizer server'
    ANGLE = 0
    DEGREES_PER_STEP = -1.0 / 100.0
    MESSAGES = {'calibration-changed': 'polarization calibration has changed'}

    @inlineCallbacks
    def initializeWAMP(self):
        protocol = yield getProtocol(
            TEST_STEPPER_MOTOR_SERVER if DEBUG else STEPPER_MOTOR_SERVER)
        self.polSM = ChunkedStepperMotorClient(protocol, POL)
        angle = yield getType(float, 'enter polarizer angle: ')
        self.offset = {}
        BaseWAMP.initializeWAMP(self)
        yield self.calibrateAngle(angle)

    @command('calibrate-angle', 'recalibrate polarizer angle')
    @inlineCallbacks
    def calibrateAngle(self, angle):
        position = yield self.polSM.getPosition()
        self.offset['position'] = position
        self.offset['angle'] = angle
        self.dispatch('calibration-changed', self.offset)

    @command('get-angle', 'get calibrated polarizer angle')
    def _getAngle(self):
        return self.polSM.getPosition().addCallback(self.getAngle)

    def getAngle(self, step):
        return self.DEGREES_PER_STEP * (
            step - self.offset['position']) + self.offset['angle']

    @command('set-angle', 'set angle')
    @inlineCallbacks
    def setAngle(self, angle):
        # find desired polarizer step, inverted form of getAngle
        targetStep = int(
            round((angle - self.offset['angle']) / self.DEGREES_PER_STEP +
                  self.offset['position']))
        # set the positions all at once, and wait for them to finish
        yield self.polSM.setPosition(targetStep)
        angle = yield self._getAngle()
        returnValue(angle)

    @command('cancel-angle-set', 'abort most recent angle set call')
    def cancelWavelengthCall(self):
        self.polSM.cancel()
        def onInit():
            config = yield protocol.sendCommand('get-configuration')
            self.show()
            
            #sort the list of dgNames based on guiOrder key in config
            sorted_sms = list()
            for smName in config.keys():
                sorted_sms.append((smName,config[smName]['guiOrder'],config[smName]))
            sorted_sms = sorted(sorted_sms, key=lambda x:x[1])
            
            #create a vertical layout for each sm (thisLayout), when done add to the full horizontal layout (self.layout())
            for id, guiOrder, config in sorted_sms:
                thisLayout = QtGui.QVBoxLayout()
                
                sm = ChunkedStepperMotorClient(protocol,id)
                self.sms[id] = sm
                #create a goto widget for this steppermotor
                PARAMS[POI] = config['pts_of_int']
                gotoWidget = GotoWidget(PARAMS)
                self.gotoWids[sm.id] = gotoWidget
                thisLayout.addWidget(gotoWidget)
                @inlineCallbacks
                def onGotoRequested(sm,payload):
                    position, deferred = payload
                    yield sm.setPosition(int(position))
                    deferred.callback(None)
                gotoWidget.gotoRequested.connect(partial(onGotoRequested,sm))
                #gotoWidget.spin.editingFinished.connect(partial(onGotoRequested,sm))
                sm.addListener(sm.POSITION,gotoWidget.setPosition)
                def onUpdateRequested(stepperMotor,gw):
                    stepperMotor.getPosition().addCallback(gw.setPosition)
                gotoWidget.updateRequested.connect(partial(onUpdateRequested,sm,gotoWidget))
                gotoWidget.cancelRequested.connect(sm.cancel)
                position = yield sm.getPosition()
                gotoWidget.setPosition(position)

                #create an enable toggle button for this sm
                enableButton = QtGui.QPushButton('enable', self)
                self.enbButtons[sm.id] = enableButton
                enableButton.clicked.connect(sm.toggleStatus)
                #handle external application toggling this sm
                def adjustText(sm,status):
                    if status == 'enabled': 
                        self.enbButtons[sm.id].setText('disable')
                        self.gotoWids[sm.id].setEnabled(True)
                    elif status == 'disabled': 
                        self.enbButtons[sm.id].setText('enable')
                        self.gotoWids[sm.id].setEnabled(False)
                sm.addListener(sm.ENABLE,partial(adjustText,sm))
                
                #disable enable button if this sm doesn't have that functionality
                if config['enable_channel'] == None: enableButton.setEnabled(False)
                else: gotoWidget.setEnabled(False)
                thisLayout.addWidget(enableButton)
                
                #create a spinbox to control the step rate for this sm
                rate = yield sm.getStepRate()
                rateSpin = QtGui.QSpinBox()
                thisLayout.addWidget(LabelWidget('rate',rateSpin))
                rateSpin.editingFinished.connect(
                    compose(
                        sm.setStepRate,
                        rateSpin.value
                    )
                )
                rateSpin.setRange(
                    RATE_MIN if rate > RATE_MIN else rate,
                    RATE_MAX if rate < RATE_MAX else rate
                )
                rateSpin.setValue(rate)
                sm.addListener(sm.RATE,rateSpin.setValue)
                
                #add this steppermotor panel to the gui
                self.layout().addWidget(
                    LabelWidget(
                        config['name'],
                        thisLayout
                    )
                )
        def onInit():
            config = yield protocol.sendCommand('get-configuration')
            self.show()

            #sort the list of dgNames based on guiOrder key in config
            sorted_sms = list()
            for smName in config.keys():
                sorted_sms.append(
                    (smName, config[smName]['guiOrder'], config[smName]))
            sorted_sms = sorted(sorted_sms, key=lambda x: x[1])

            #create a vertical layout for each sm (thisLayout), when done add to the full horizontal layout (self.layout())
            for id, guiOrder, config in sorted_sms:
                thisLayout = QtGui.QVBoxLayout()

                sm = ChunkedStepperMotorClient(protocol, id)
                self.sms[id] = sm
                #create a goto widget for this steppermotor
                PARAMS[POI] = config['pts_of_int']
                gotoWidget = GotoWidget(PARAMS)
                self.gotoWids[sm.id] = gotoWidget
                thisLayout.addWidget(gotoWidget)

                @inlineCallbacks
                def onGotoRequested(sm, payload):
                    position, deferred = payload
                    yield sm.setPosition(int(position))
                    deferred.callback(None)

                gotoWidget.gotoRequested.connect(partial(onGotoRequested, sm))
                #gotoWidget.spin.editingFinished.connect(partial(onGotoRequested,sm))
                sm.addListener(sm.POSITION, gotoWidget.setPosition)

                def onUpdateRequested(stepperMotor, gw):
                    stepperMotor.getPosition().addCallback(gw.setPosition)

                gotoWidget.updateRequested.connect(
                    partial(onUpdateRequested, sm, gotoWidget))
                gotoWidget.cancelRequested.connect(sm.cancel)
                position = yield sm.getPosition()
                gotoWidget.setPosition(position)

                #create an enable toggle button for this sm
                enableButton = QtGui.QPushButton('enable', self)
                self.enbButtons[sm.id] = enableButton
                enableButton.clicked.connect(sm.toggleStatus)

                #handle external application toggling this sm
                def adjustText(sm, status):
                    if status == 'enabled':
                        self.enbButtons[sm.id].setText('disable')
                        self.gotoWids[sm.id].setEnabled(True)
                    elif status == 'disabled':
                        self.enbButtons[sm.id].setText('enable')
                        self.gotoWids[sm.id].setEnabled(False)

                sm.addListener(sm.ENABLE, partial(adjustText, sm))

                #disable enable button if this sm doesn't have that functionality
                if config['enable_channel'] == None:
                    enableButton.setEnabled(False)
                else:
                    gotoWidget.setEnabled(False)
                thisLayout.addWidget(enableButton)

                #create a spinbox to control the step rate for this sm
                rate = yield sm.getStepRate()
                rateSpin = QtGui.QSpinBox()
                thisLayout.addWidget(LabelWidget('rate', rateSpin))
                rateSpin.editingFinished.connect(
                    compose(sm.setStepRate, rateSpin.value))
                rateSpin.setRange(RATE_MIN if rate > RATE_MIN else rate,
                                  RATE_MAX if rate < RATE_MAX else rate)
                rateSpin.setValue(rate)
                sm.addListener(sm.RATE, rateSpin.setValue)

                #add this steppermotor panel to the gui
                self.layout().addWidget(LabelWidget(config['name'],
                                                    thisLayout))