#!/usr/bin/python
# -*- coding: utf-8 -*-

# configure

'''
Created on 2015.9.25
'''

from conf.constants import *
import json
from json import *
import atexit
import redis
#import warnings

# viewer defined
from viewer.user import *
from viewer.menuBar import *
from viewer.statusBar import *
from viewer.mainSet import *
from viewer import logWindow
# model defined
from model import neonReceiver

class mywindow(QtGui.QMainWindow):

    def __init__(self, parent):
        super(mywindow, self).__init__()
        self.parent = parent
        self.setupUi(self)

    def setupUi(self, MainWindow):

        self.myMenuBar = menuBar(self)
        self.setMenuBar(self.myMenuBar)

        self.myStatusBar = statusBar(self)
        self.setStatusBar(self.myStatusBar)

        self.mainSplitter = QtGui.QSplitter(QtCore.Qt.Horizontal, self)

        self.userWidget = CSNSUserInfo(self)
        self.mainSetWidget = CSNSMainSetInfo(self)

        self.mainSplitter.addWidget(self.userWidget)
        self.mainSplitter.addWidget(self.mainSetWidget)
    
        self.ip = "" 
        self.port = 0 
        self.myStatus = 'waiting'
        logging.info("Status is waiting")
        self.myCommand = None
        self.dataThread = None
        self.started = True
        # data update time
        self.refreshtime = 1.0
        # progress value
        self.progressName = ''
        self.progressValue = 0
        self.protonValue = 0
        self.neutronValue = 0
        self.pulseValue = 0

        self.setCentralWidget(self.mainSplitter)
        self.loadConfigure()
        self.setConfigure()
   
        self.createDataThread()

    def updateDiffractionSimulator(self):
        self.upRightTab.updateDiffractionSimulator()

    def updateDataStreaming(self):
        self.upRightTab.updateDataStreaming()

    def updateProton(self, threadID):
        self.upRightTab.updateProton(threadID)
    
    def getIP(self):
        _ip=None
        try:
	        _ip=self.userWidget.getIP()
        except:
            _ip=None
        return _ip

    def getPort(self):
        _port=None
        try:
	        _port=self.userWidget.getPort()
        except:
	        _port=None
        return _port

    def getDisplay(self):
        screen_resolution = self.parent.desktop().screenGeometry()
        return screen_resolution.width(), screen_resolution.height()

    def loadConfigure(self):
        _confFile='./conf/configure.json'
        _mainWidth, _mainHeight=self.getDisplay()

        if not os.path.exists(_confFile):
            self.mainWidth=_mainWidth
            self.mainHeight=_mainHeight
            self.firstLayout=1
            self.ip="10.1.53.240"
            self.port=9000
            self.mainSplitterLeft=(self.mainWidth + 50) / 7.0
            self.mainSplitterRight=self.mainWidth / 7.0 * 6
        else:
            try:
                layoutParameter = json.loads(open(_confFile, "r").read())
                self.firstLayout= layoutParameter['firstLayout']
                self.mainWidth=layoutParameter['mainWidth']
                self.mainHeight=layoutParameter['mainHeight']
                self.ip=layoutParameter['ip']
                self.port=layoutParameter['port']
                self.mainSplitterLeft=layoutParameter['mainSplitterLeft']
                self.mainSplitterRight=layoutParameter['mainSplitterRight']
            except:
                self.mainWidth=_mainWidth
                self.mainHeight=_mainHeight
                self.firstLayout=1
                self.ip="10.1.53.240"
                self.port=9000

    def setConfigure(self):
        self.resize(self.mainWidth, self.mainHeight)
        self.mainSplitter.setSizes([self.mainSplitterLeft,self.mainSplitterRight])
        self.userWidget.hostTextEdit.setText(self.ip+":"+str(self.port))

    def saveConfigure(self):
        _mainWidth=self.mainSplitter.geometry().width()
        _mainHeight=self.mainSplitter.geometry().height()
        _firstLayout=self.firstLayout+1
        _ip=self.userWidget.getIP()
        _port=self.userWidget.getPort()
        _mainSplitterLeft=self.mainSplitter.sizes()[0]
        _mainSplitterRight=self.mainSplitter.sizes()[1]

        _data = {"mainWidth": _mainWidth, "firstLayout": _firstLayout, "mainHeight": _mainHeight, "mainSplitterLeft":_mainSplitterLeft,"mainSplitterRight":_mainSplitterRight, "ip":_ip, "port":_port }
        
        _confFile='./conf/configure.json'
        if not os.path.exists(_confFile):
            with open(_confFile, "w") as _f:
                json.dump(_data, _f)
        else:
            with open(_confFile, "w") as _f:
                json.dump(_data, _f)

    def setNeonButton(self, value):
	    self.userWidget.setNeonButton(value)
 
    def getNeon(self):
	    self.neonStatus, self.neonServer=self.userWidget.getNeon()
	    return self.neonStatus, self.neonServer
  
    def getStatus(self):
    	return self.myStatus
    
    def setHeartBeat(self):
    	neonpath="/GPPD/heartbeat/pilot"

    	logging.info("Creating heartbeat thread")
    	heartbeatThread = neonReceiver.setHeartbeat(self.neonServer, 1.0, neonpath, self.getStatus())
    	heartbeatThread.setDaemon(True)
    	heartbeatThread.start()
    	logging.info("Start heartbeat successfully")

    def getApp(self):
        return self.parent

    def getCommand(self, parent, gui):
        logging.info("Creating Command Thread...")
        commandPath = '/GPPD/stateMachine/command'
        #commandPath = '/GPPD/command/pilot'
        userPath = '/GPPD/cockpit/user_information'
        self.commandThread = neonReceiver.commandThread(parent, gui, self.neonServer, commandPath, userPath, 5.0)
        logging.info("Start Command Thread successfully")

    @QtCore.pyqtSlot(str)
    def setCommand(self, value):
        if self.myCommand!=value:
            #logging.info(str("Received command: " + value ))
            #_timen=str(datetime.datetime.now())
            #self.userWidget.setCommandTimeLabel(_timen)
            #self.userWidget.setCommandValueLabel(value)
            self.userWidget.setCommandLabel(value)
            # start stateMachine
            self.stateMachine(value) 
            
            self.myCommand = value

    @QtCore.pyqtSlot(str)
    def setLog(self, value):
        logging.info(value)
   
    def getCanvasData(self, parent, gui):
        logging.info("Creating Canvas data Thread...")
     
        progressPath='/GPPD/cockpit/progress_setting'        
 
        protonPath='/GPPD/drone/proton_charge'
        neutronPath='/GPPD/workspace/MantidData/neutron_counts'
        pulsePath='/GPPD/drone/pulse_counts'
                
        self.dataThread = neonReceiver.dataThread(parent, gui, self.neonServer, progressPath, protonPath, neutronPath, pulsePath, self.refreshtime)
        logging.info("Start Canvas Data Thread successfully")
 
    def setDataPath(self, kwargs):
        if not self.dataThread:
            logging.info("No data availabel")
        else:
            self.dataThread.setDataPath(kwargs)

    def getDetectorIndex(self):
        return self.mainSetWidget.upRightTab.detectorPage.getDetectorIndex()
    
    @QtCore.pyqtSlot(object)
    def setCanvasData(self, value):
        tabIndex = self.dataThread.getTabIndex()
        _started = self.started
        if tabIndex == 0:
            self.mainSetWidget.upRightTab.histogramPage.updateCanvas(value, _started)      
        elif tabIndex == 1:
            self.mainSetWidget.upRightTab.detectorPage.updateBankCanvas(value, _started)
        elif tabIndex == 2:
            self.mainSetWidget.upRightTab.monitorPage.updateCanvas(value, _started)
        elif tabIndex == 3:    
            self.mainSetWidget.upRightTab.experimentPage.updateCanvas(value, _started) 
    
    @QtCore.pyqtSlot(object)
    def setMonitorCanvas(self, value):
        xdata = self.dataThread.getMonitorTOF()
        self.userWidget.updateMonitorCanvas(xdata,value)
    
    @QtCore.pyqtSlot(str)
    def setUserInfo(self, value):
        self.userWidget.setUserInfo(value)

    @QtCore.pyqtSlot(object, object)
    def setUserData(self, _proton, _neutron):
        self.userWidget.setProtonNeutron(_proton, _neutron)
        self.protonValue = int(_proton)
        self.neutronValue = int(_neutron)
        #self.pulseValue = int(_pulse)

    @QtCore.pyqtSlot(str)
    def setProgressData(self, value):
        _value = json.loads(str(value))
        self.progressName = _value['name']
        self.setProgressBar(_value['min'], _value['max'])

    # set max and min value for progressBar
    def setProgressBar(self, mini, maxi):
        self.mainSetWidget.createProgressBar(mini, maxi)

    #get current value for progressBar
    def getProgressValue(self):
        if self.progressName=='proton_charge':
            self.progressValue = self.protonValue
        elif self.progressName=='neutron_counts':
            self.progressValue = self.neutronValue
        elif self.progressName=='pulse_counts':
            self.progressValue = self.pulseValue
        else:
            pass
        #value=random.randint(0,300)
        return self.progressValue
    
    def createDataThread(self):
        # connect neon
        _neonStatus, _neonServer = self.getNeon()
        self.setNeonButton(_neonStatus)
        if _neonStatus:
            # set heartbeat
            self.setHeartBeat()
            # get command
            self.getCommand(self.parent, self)
            #self.getCanvasData(self.parent, self)
            self.myStatus = 'unconfigured'
            logging.info("Status change to unconfigured")

    def stateMachine(self, command):
        _command = command
        _status = self.getStatus()

        if _command == 'configure':
            if _status == 'waiting':
                logging.info("waiting status cannot receive configure command")
            elif _status == 'unconfigured':
                _status = 'configuring'
                logging.info("status change to configuring")
                # start get data from neon
                self.getCanvasData(self.parent, self)
                self.started = False
                self.dataThread.pause()
                self.mainSetWidget.upRightTab.tabChange()
                _status = 'ready'
                logging.info("status change to ready")
            elif _status == 'configuring':
                logging.info("configuring status cannot receive configure command")
            elif _status == 'ready':
                logging.info("ready status cannot receive configure command")
            elif _status == 'running':
                logging.info("running status cannot receive configure command")
            elif _status == 'paused':
                logging.info("paused status cannot receive configure command")
        elif _command == 'unconfigure':
            if _status == 'waiting':
                logging.info("waiting status cannot receive unconfigure command")
            elif _status == 'unconfigured':
                logging.info("unconfigured status cannot receive unconfigure command")
            elif _status == 'configuring':
                logging.info("configuring status cannot receive unconfigure command")
            elif _status == 'ready':
                self.started = False
                self.dataThread.pause()
                _status = 'unconfigured'
                logging.info("status change to unconfigured")
            elif _status == 'running':
                logging.info("running status cannot receive unconfigure command")
            elif _status == 'paused':
                logging.info("paused status cannot receive unconfigure command")
        elif _command == 'start':
            if _status == 'waiting':
                logging.info("waiting status cannot receive start command")
            elif _status == 'unconfigured':
                logging.info("unconfigured status cannot receive start command")
            elif _status == 'configuring':
                logging.info("configuring status cannot receive start command")
            elif _status == 'ready':
                self.started = True
                self.dataThread.resume()
                _status = 'running'
                logging.info("status change to running")
            elif _status == 'running':
                logging.info("running status cannot receive start command")
            elif _status == 'paused':
                logging.info("paused status cannot receive start command")
        elif _command == 'pause':
            if _status == 'waiting':
                logging.info("waiting status cannot receive pause command")
            elif _status == 'unconfigured':
                logging.info("unconfigured status cannot receive pause command")
            elif _status == 'configuring':
                logging.info("configuring status cannot receive pause command")
            elif _status == 'ready':
                logging.info("ready status cannot receive pause command")
            elif _status == 'running':
                # pause get date from neon
                self.dataThread.pause()
                _status = 'paused'
                logging.info("status change to paused")
            elif _status == 'paused':
                logging.info("paused status cannot receive pause command")
        elif _command == 'resume':
            if _status == 'waiting':
                logging.info("waiting status cannot receive resume command")
            elif _status == 'unconfigured':
                logging.info("unconfigured status cannot receive resume command")
            elif _status == 'configuring':
                logging.info("configuring status cannot receive resume command")
            elif _status == 'ready':
                logging.info("ready status cannot receive resume command")
            elif _status == 'running':
                logging.info("running status cannot receive resume command")
            elif _status == 'paused':
                self.dataThread.resume()
                _status = 'running'
                logging.info("status change to runninig")
        elif _command == 'stop':
            if _status == 'waiting':
                logging.info("waiting status cannot receive stop command")
            elif _status == 'unconfigured':
                logging.info("unconfigured status cannot receive stop command")
            elif _status == 'configuring':
                logging.info("configuring status cannot receive stop command")
            elif _status == 'ready':
                logging.info("ready status cannot receive stop command")
            elif _status == 'running':
                self.started = False
                time.sleep(self.refreshtime)
                self.dataThread.pause()
                _status = 'ready'
                logging.info("status change to ready")
            elif _status == 'paused':
                logging.info("paused status cannot receive stop command")
        elif _command == 'abort':
            if _status == 'waiting':
                logging.info("waiting status cannot receive abort command")
            elif _status == 'unconfigured':
                logging.info("unconfigured status cannot receive abort command")
            elif _status == 'configuring':
                self.started = False
                time.sleep(self.refreshtime)
                self.dataThread.pause()
                _status = 'unconfigured'
                logging.info("status change to unconfigured")
            elif _status == 'ready':
                logging.info("ready status cannot receive abort command")
            elif _status == 'running':
                self.started = False
                time.sleep(self.refreshtime)
                self.dataThread.pause()
                _status = 'ready'
                logging.info("status change to ready")
            elif _status == 'paused':
                logging.info("paused status cannot receive abort command")

        self.userWidget.setStatusLabel(_status)  
        self.myStatus = _status
        self.myCommand = _command

def exit_handler(top):
    top.saveConfigure()

if __name__ == '__main__':
    
    myapp = QtGui.QApplication(sys.argv)
    
    mytop = mywindow(myapp)
    icon = QtGui.QIcon('img/logo.jpg')
    mytop.setWindowIcon(icon)
    mytop.setWindowTitle('GPPD')
    mytop.show()
    time.sleep(0.1)

    atexit.register(exit_handler, mytop)
    sys.exit(myapp.exec_())
