# encoding: UTF-8

import psutil

from uiBasicWidget import *
from ctaAlgo.uiCtaWidget import CtaEngineManager
from dataRecorder.uiDrWidget import DrEngineManager
from riskManager.uiRmWidget import RmEngineManager

import os

########################################################################
class MainWindow(QtGui.QMainWindow):
    """主窗口"""

    #----------------------------------------------------------------------
    def __init__(self, mainEngine, eventEngine):
        """Constructor"""
        super(MainWindow, self).__init__()
        
        self.mainEngine = mainEngine
        self.eventEngine = eventEngine
        
        self.widgetDict = {}    # 用来保存子窗口的字典

        self.connectGatewayDict = {}

        self.initUi()
        #self.loadWindowSettings()

        self.connected = False
        self.autoDisConnect = False

        self.orderSaveDate = EMPTY_STRING
        self.barSaveDate = EMPTY_STRING


    # ----------------------------------------------------------------------
    def initUi(self):
        """初始化界面"""
        path = os.getcwd().rsplit('\\')[-1]

        self.setWindowTitle(path)
        self.initCentral()
        self.initMenu()
        self.initStatusBar()
        
    # ----------------------------------------------------------------------
    def initCentral(self):
        """初始化中心区域"""
        widgetMarketM, dockMarketM = self.createDock(MarketMonitor, u'行情', QtCore.Qt.RightDockWidgetArea)
        widgetLogM, dockLogM = self.createDock(LogMonitor, u'日志', QtCore.Qt.BottomDockWidgetArea)
        widgetErrorM, dockErrorM = self.createDock(ErrorMonitor, u'错误', QtCore.Qt.BottomDockWidgetArea)
        self.widgetTradeM, dockTradeM = self.createDock(TradeMonitor, u'成交', QtCore.Qt.BottomDockWidgetArea)
        self.widgetOrderM, dockOrderM = self.createDock(OrderMonitor, u'委托', QtCore.Qt.RightDockWidgetArea)
        widgetPositionM, dockPositionM = self.createDock(PositionMonitor, u'持仓', QtCore.Qt.BottomDockWidgetArea)
        widgetAccountM, dockAccountM = self.createDock(AccountMonitor, u'资金', QtCore.Qt.BottomDockWidgetArea)
        widgetTradingW, dockTradingW = self.createDock(TradingWidget, u'交易', QtCore.Qt.LeftDockWidgetArea)
    
        self.tabifyDockWidget(dockTradeM, dockErrorM)
        self.tabifyDockWidget(dockTradeM, dockLogM)
        self.tabifyDockWidget(dockPositionM, dockAccountM)
    
        dockTradeM.raise_()
        dockPositionM.raise_()
    
        # 连接组件之间的信号
        widgetPositionM.itemDoubleClicked.connect(widgetTradingW.closePosition)
        
    #----------------------------------------------------------------------
    def initMenu(self):
        """初始化菜单"""
        # 创建操作
        connectCtpProdAction = QtGui.QAction(u'上海中期CTP', self)
        connectCtpProdAction.triggered.connect(self.connectCtpProd)

        connectCtpPostAction = QtGui.QAction(u'中期盘后CTP', self)
        connectCtpPostAction.triggered.connect(self.connectCtpPost)

        connectCtpTestAction = QtGui.QAction(u'光大CTP', self)
        connectCtpTestAction.triggered.connect(self.connectCtpEBF)

        connectCtpAction = QtGui.QAction(u'连接CTP', self)
        connectCtpAction.triggered.connect(self.connectCtp)
        
        #connectLtsAction = QtGui.QAction(u'连接LTS', self)
        #connectLtsAction.triggered.connect(self.connectLts)
        
        #connectKsotpAction = QtGui.QAction(u'连接金仕达期权', self)
        #connectKsotpAction.triggered.connect(self.connectKsotp)
        
        #connectFemasAction = QtGui.QAction(u'连接飞马', self)
        #connectFemasAction.triggered.connect(self.connectFemas)
        
        #connectXspeedAction = QtGui.QAction(u'连接飞创', self)
        #connectXspeedAction.triggered.connect(self.connectXspeed)
        
        #connectKsgoldAction = QtGui.QAction(u'连接金仕达黄金', self)
        #connectKsgoldAction.triggered.connect(self.connectKsgold)
        
        #connectSgitAction = QtGui.QAction(u'连接飞鼠', self)
        #connectSgitAction.triggered.connect(self.connectSgit)
        
        #connectWindAction = QtGui.QAction(u'连接Wind', self)
        #connectWindAction.triggered.connect(self.connectWind)
        
        #connectIbAction = QtGui.QAction(u'连接IB', self)
        #connectIbAction.triggered.connect(self.connectIb)
        
        #connectOandaAction = QtGui.QAction(u'连接OANDA', self)
        #connectOandaAction.triggered.connect(self.connectOanda)
        
        connectDbAction = QtGui.QAction(u'连接数据库', self)
        connectDbAction.triggered.connect(self.mainEngine.dbConnect)

        autoDisconnetAction = QtGui.QAction(u'自动断开重连', self)
        autoDisconnetAction.triggered.connect(self.setAutoDisconnect)
        
        testAction = QtGui.QAction(u'测试', self)
        testAction.triggered.connect(self.test)
        
        exitAction = QtGui.QAction(u'退出', self)
        exitAction.triggered.connect(self.close)
        
        aboutAction = QtGui.QAction(u'关于', self)
        aboutAction.triggered.connect(self.openAbout)
        
        contractAction = QtGui.QAction(u'查询合约', self)
        contractAction.triggered.connect(self.openContract)
        
        drAction = QtGui.QAction(u'行情数据记录', self)
        drAction.triggered.connect(self.openDr)
        
        ctaAction = QtGui.QAction(u'CTA策略', self)
        ctaAction.triggered.connect(self.openCta)
        
        rmAction = QtGui.QAction(u'风险管理', self)
        rmAction.triggered.connect(self.openRm)        
        
        # 创建菜单
        menubar = self.menuBar()
        
        # 设计为只显示存在的接口
        sysMenu = menubar.addMenu(u'系统')
        sysMenu.addAction(connectCtpProdAction)
        sysMenu.addAction(connectCtpPostAction)
        sysMenu.addAction(connectCtpTestAction)
        if 'CTP' in self.mainEngine.gatewayDict:
            sysMenu.addAction(connectCtpAction)
        #if 'LTS' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectLtsAction)
        #if 'FEMAS' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectFemasAction)
        #if 'XSPEED' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectXspeedAction)
        #if 'KSOTP' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectKsotpAction)
        #if 'KSGOLD' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectKsgoldAction)
        #if 'SGIT' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectSgitAction)
        sysMenu.addSeparator()
        sysMenu.addAction(autoDisconnetAction)
        #if 'IB' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectIbAction)
        #if 'OANDA' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectOandaAction)
        #sysMenu.addSeparator()
        #if 'Wind' in self.mainEngine.gatewayDict:
        #    sysMenu.addAction(connectWindAction)
        sysMenu.addSeparator()
        sysMenu.addAction(connectDbAction)
        sysMenu.addSeparator()
        sysMenu.addAction(exitAction)
        
        functionMenu = menubar.addMenu(u'功能')
        functionMenu.addAction(contractAction)
        functionMenu.addAction(drAction)
        functionMenu.addAction(rmAction)
        
        # 算法相关
        algoMenu = menubar.addMenu(u'算法')
        algoMenu.addAction(ctaAction)
        
        # 帮助
        helpMenu = menubar.addMenu(u'帮助')
        helpMenu.addAction(aboutAction)  
        helpMenu.addAction(testAction)
    
    # ----------------------------------------------------------------------
    def initStatusBar(self):
        """初始化状态栏"""
        self.statusLabel = QtGui.QLabel()
        self.statusLabel.setAlignment(QtCore.Qt.AlignLeft)
        
        self.statusBar().addPermanentWidget(self.statusLabel)
        self.statusLabel.setText(self.getCpuMemory())
        
        self.sbCount = 0
        self.sbTrigger = 10     # 10秒刷新一次
        self.eventEngine.register(EVENT_TIMER, self.updateStatusBar)

        
    # ----------------------------------------------------------------------
    def updateStatusBar(self, event):
        """1、在状态栏更新CPU和内存信息"""
        # 2、定时断开服务器连接
        # 3、定时重连服务器
        # 4、定时保存每日的委托单
        # 5、定时执行策略的保存事件

        self.sbCount += 1

       # 更新任务栏
        if self.sbCount == self.sbTrigger:
            self.sbCount = 0
            info = self.getCpuMemory()

            if self.autoDisConnect:
                info = info + u'[自动断开重连]'

            self.statusLabel.setText(info)

            if self.connectGatewayDict:
                s = u''.join(str(e) for e in self.connectGatewayDict.values())

                if not self.connected:
                    s = s + u' [已断开]'


                self.setWindowTitle(s)

            # 定时断开
            if self.connected and self.trade_off() and self.autoDisConnect:
               self.disconnect()
               self.mainEngine.writeLog(u'断开连接{0}'.format(self.connectGatewayDict.values()))
               self.mainEngine.writeLog(u'清空数据引擎')
               self.mainEngine.clearData()
               self.mainEngine.writeLog(u'清空委托列表')
               self.widgetOrderM.clearData()
               self.mainEngine.writeLog(u'清空交易列表')
               self.widgetTradeM.clearData()

            # 定时重连
            if not self.connected \
                    and self.autoDisConnect \
                    and not self.trade_off()\
                    and len(self.connectGatewayDict) > 0:

                    self.mainEngine.writeLog(u'清空数据引擎')
                    self.mainEngine.clearData()
                    self.mainEngine.writeLog(u'清空委托列表')
                    self.widgetOrderM.clearData()
                    self.mainEngine.writeLog(u'清空交易列表')
                    self.widgetTradeM.clearData()
                    s = u''.join(str(e) for e in self.connectGatewayDict.values())
                    self.mainEngine.writeLog(u'重新连接{0}'.format(s))

                    for key in self.connectGatewayDict.keys():
                        self.mainEngine.connect(key)

                    self.connected = True

            # 交易日收盘后保存所有委托记录，
            dt = datetime.now()
            today = datetime.now().strftime('%y%m%d')
            if dt.hour == 15 and dt.minute == 1 and len(self.connectGatewayDict) > 0 and today!=self.orderSaveDate:
                self.orderSaveDate = today
                self.mainEngine.writeLog(u'保存所有委托记录')
                orderfile = os.getcwd() +'/orders/{0}.csv'.format(self.orderSaveDate)
                if os.path.exists(orderfile):
                    return
                else:
                    self.widgetOrderM.saveToCsv(path=orderfile)

            # 调用各策略保存数据
            if ((dt.hour == 15 and dt.minute == 1) or (dt.hour == 2 and dt.minute == 31))  \
                and len(self.connectGatewayDict) > 0 \
                and today != self.barSaveDate \
                and self.connected:
                self.barSaveDate = today
                self.mainEngine.writeLog(u'调用各策略保存数据')
                self.mainEngine.saveData()

            if not (dt.hour == 15 or dt.hour == 2):
                self.barSaveDate = EMPTY_STRING

    # ----------------------------------------------------------------------
    def getCpuMemory(self):
        """获取CPU和内存状态信息"""
        cpuPercent = psutil.cpu_percent()
        memoryPercent = psutil.virtual_memory().percent
        return u'CPU使用率：%d%%   内存使用率：%d%%' % (cpuPercent, memoryPercent)        
        
    # ----------------------------------------------------------------------
    def connectCtpProd(self):
        """连接上海中期生产环境CTP接口"""

        self.mainEngine.connect('CTP_Prod')
        self.connectGatewayDict['CTP_Prod'] = u'上海中期CTP'
        self.connected = True

    # ----------------------------------------------------------------------
    def connectCtpPost(self):
        """连接上海中期盘后CTP接口"""
        self.mainEngine.connect('CTP_Post')
        self.connectGatewayDict['CTP_Post'] = u'中期盘后CTP'
        self.connected = True

    def connectCtpEBF(self):
        """连接光大期货CTP接口"""
        self.mainEngine.connect('CTP_EBF')
        self.connectGatewayDict['CTP_EBF'] = u'光大CTP'
        self.connected = True

    def connectCtpTest(self):
        """连接SNOW测试环境CTP接口"""
        self.mainEngine.connect('CTP_Test')
        self.connectGatewayDict['CTP_Test'] = u'SNOW测试'
        self.connected = True

    def connectCtp(self):
        """连接CTP接口"""
        self.mainEngine.connect('CTP')
        self.connectGatewayDict['CTP'] = u'CTP'
        self.connected = True

    # ----------------------------------------------------------------------
    def connectLts(self):
        """连接LTS接口"""
        self.mainEngine.connect('LTS')
        self.connectGatewayDict['LTS'] = u'LTS'
        self.connected = True
        
    #----------------------------------------------------------------------
    def connectKsotp(self):
        """连接金仕达期权接口"""
        self.mainEngine.connect('KSOTP')
        self.connectGatewayDict['KSOTP'] = u'金仕达期权'
        self.connected = True
        
    #----------------------------------------------------------------------
    def connectFemas(self):
        """连接飞马接口"""
        self.mainEngine.connect('FEMAS')
        self.connectGatewayDict['FEMAS'] = u'FEMAS飞马'
        self.connected = True
    
    #----------------------------------------------------------------------
    def connectXspeed(self):
        """连接飞马接口"""
        self.mainEngine.connect('XSPEED')
        self.connectGatewayDict['XSPEED'] = u'XSPEED飞马接口'
        self.connected = True
    
    #----------------------------------------------------------------------
    def connectKsgold(self):
        """连接金仕达黄金接口"""
        self.mainEngine.connect('KSGOLD')
        self.connectGatewayDict ['KSGOLD'] = u'金仕达黄金'
        self.connected = True
        
    #----------------------------------------------------------------------
    def connectSgit(self):
        """连接飞鼠接口"""
        self.mainEngine.connect('SGIT')
        self.connectGatewayDict['SGIT'] = u'飞鼠'
        self.connected = True
    
    #----------------------------------------------------------------------
    def connectWind(self):
        """连接Wind接口"""
        self.mainEngine.connect('Wind')
        self.connectGatewayDict['Wind'] = u'Wind'
        self.connected = True
    
    # ----------------------------------------------------------------------

    def connectIb(self):
        """连接Ib"""
        self.mainEngine.connect('IB')
        self.connectGatewayDict['IB'] = u'盈透'
        self.connected = True
        
    #----------------------------------------------------------------------
    def connectOanda(self):
        """连接OANDA"""
        self.mainEngine.connect('OANDA')
        self.connectGatewayDict['OANDA'] = u'OANDA'
        self.connected = True

    def setAutoDisconnect(self):

        if self.autoDisConnect:
            self.autoDisConnect = False
        else:
            self.autoDisConnect = True


    #----------------------------------------------------------------------
    def test(self):
        """测试按钮用的函数"""
        # 有需要使用手动触发的测试函数可以写在这里
        self.mainEngine.saveData()
        pass

    #----------------------------------------------------------------------
    def openAbout(self):
        """打开关于"""
        try:
            self.widgetDict['aboutW'].show()
        except KeyError:
            self.widgetDict['aboutW'] = AboutWidget(self)
            self.widgetDict['aboutW'].show()
    
    # ----------------------------------------------------------------------
    def openContract(self):
        """打开合约查询"""
        try:

            self.widgetDict['contractM'].show()
        except KeyError:
            self.widgetDict['contractM'] = ContractMonitor(self.mainEngine)
            self.widgetDict['contractM'].show()

    # ----------------------------------------------------------------------
    def openCta(self):
        """打开CTA组件"""
        try:
            self.widgetDict['ctaM'].showMaximized()
        except KeyError:
            self.widgetDict['ctaM'] = CtaEngineManager(self.mainEngine.ctaEngine, self.eventEngine)
            self.widgetDict['ctaM'].showMaximized()
            
    #----------------------------------------------------------------------
    def openDr(self):
        """打开行情数据记录组件"""
        try:
            self.widgetDict['drM'].showMaximized()
        except KeyError:
            self.widgetDict['drM'] = DrEngineManager(self.mainEngine.drEngine, self.eventEngine)
            self.widgetDict['drM'].showMaximized()
            
    #----------------------------------------------------------------------
    def openRm(self):
        """打开组件"""
        try:
            self.widgetDict['rmM'].show()
        except KeyError:
            self.widgetDict['rmM'] = RmEngineManager(self.mainEngine.rmEngine, self.eventEngine)
            self.widgetDict['rmM'].show()      
    
    #----------------------------------------------------------------------
    def closeEvent(self, event):
        """关闭事件"""
        reply = QtGui.QMessageBox.question(self, u'退出',
                                           u'确认退出?', QtGui.QMessageBox.Yes | 
                                           QtGui.QMessageBox.No, QtGui.QMessageBox.No)

        if reply == QtGui.QMessageBox.Yes: 
            for widget in self.widgetDict.values():
                widget.close()
            self.saveWindowSettings()
            
            self.mainEngine.exit()
            event.accept()
        else:
            event.ignore()
            
    #----------------------------------------------------------------------
    def createDock(self, widgetClass, widgetName, widgetArea):
        """创建停靠组件"""
        widget = widgetClass(self.mainEngine, self.eventEngine)
        dock = QtGui.QDockWidget(widgetName)
        dock.setWidget(widget)
        dock.setObjectName(widgetName)
        dock.setFeatures(dock.DockWidgetFloatable|dock.DockWidgetMovable)
        self.addDockWidget(widgetArea, dock)
        return widget, dock
    
    #----------------------------------------------------------------------
    def saveWindowSettings(self):
        """保存窗口设置"""
        settings = QtCore.QSettings('vn.py', 'vn.trader')
        settings.setValue('state', self.saveState())
        settings.setValue('geometry', self.saveGeometry())
        
    #----------------------------------------------------------------------
    def loadWindowSettings(self):
        """载入窗口设置"""
        settings = QtCore.QSettings('vn.py', 'vn.trader')
        # 这里由于PyQt4的版本不同，settings.value('state')调用返回的结果可能是：
        # 1. None（初次调用，注册表里无相应记录，因此为空）
        # 2. QByteArray（比较新的PyQt4）
        # 3. QVariant（以下代码正确执行所需的返回结果）
        # 所以为了兼容考虑，这里加了一个try...except，如果是1、2的情况就pass
        # 可能导致主界面的设置无法载入（每次退出时的保存其实是成功了）
        try:
            self.restoreState(settings.value('state').toByteArray())
            self.restoreGeometry(settings.value('geometry').toByteArray())
        except AttributeError:
            pass


    def disconnect(self):
        """"断开底层gateway的连接"""
        self.mainEngine.disconnect()
        self.connected = False

    def trade_off(self):
        """检查现在是否为非交易时间"""
        now = datetime.now()
        a = datetime.now().replace(hour=2, minute=35, second=0, microsecond=0)
        b = datetime.now().replace(hour=8, minute=30, second=0, microsecond=0)
        c = datetime.now().replace(hour=15, minute=30, second=0, microsecond=0)
        d = datetime.now().replace(hour=20, minute=30, second=0, microsecond=0)
        weekend = (now.isoweekday() == 6 and now >= a) or (now.isoweekday() == 7)
        off = (a<= now <= b) or (c <= now <= d) or weekend
        return off

########################################################################
class AboutWidget(QtGui.QDialog):
    """显示关于信息"""

    # ----------------------------------------------------------------------
    def __init__(self, parent=None):
        """Constructor"""
        super(AboutWidget, self).__init__(parent)

        self.initUi()

    # ----------------------------------------------------------------------
    def initUi(self):
        """"""
        self.setWindowTitle(u'关于VnTrader')

        text = u"""
            Developed by traders, for traders.

            License：MIT
            
            Website：www.vnpy.org

            Github：www.github.com/vnpy/vnpy
            
            """

        label = QtGui.QLabel()
        label.setText(text)
        label.setMinimumWidth(500)

        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(label)

        self.setLayout(vbox)
    