from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtCore, QtGui, QtWidgets

# import notify2
import sys
import os
import time
import threading as thd
import tushare as ts
import Txt2Png


class Mythread(QThread):
    # 定义信号,定义参数为str类型
    _signal = pyqtSignal()

    def __init__(self):
        super(Mythread, self).__init__()

    def run(self):
        while True:
            # 发出信号通知主线程
            self._signal.emit()
            # 让程序休眠
            time.sleep(2)


class Start:
    codes = []
    # 实时行情
    df = []
    # 托盘集合
    tpList = []
    # 最新price集合，用于和前后两次比较
    priceList = []
    # 提示上下限
    code_list = []
    # 行情时间
    current_time = ''

    # 装载view的集合
    codeView = []
    maxView = []
    minView = []
    tipView = []

    def update_ui(self):
        # 计算时间，如果开市时间则去获取行情
        s = self.current_time.split(':')
        if len(s) > 1:
            h = int(s[0])
            if h < 9 or 13 > h >= 12 or h >= 15:
                return

        # 获取实时行情
        self.df = ts.get_realtime_quotes(self.codes)

        for i in self.df.index:
            # 昨收盘价
            pre = self.df.loc[i]['pre_close']
            # 当前时间
            self.current_time = self.df.loc[i]['time']
            # 当前价
            p = self.df.loc[i]['price']
            # 小数点后有3位，舍弃最后一位
            price = p[0:len(p) - 1]
            # 如果本次得到的price和上一次不一样，则刷新托盘图标
            if price != self.priceList[i]:
                # 记录变动后的新price
                self.priceList[i] = price

                # 转成图标
                Txt2Png.Price2Png(i, price, pre)

                # 刷新托盘图标
                self.tpList[i].setIcon(QIcon(str(i)+'.png'))

                # 判断是否需要提示
                if self.code_list[i]['tip'] is False:
                    price = float(self.df.loc[i]['price'])
                    pre = float(self.df.loc[i]['pre_close'])
                    percent = (price - pre) / pre * 100
                    # 检查预警上限
                    if price >= self.code_list[i]['max'] != 0:
                        self.show_message(self.df.loc[i]['name'], '恭喜！已达预期值' + str(self.code_list[i]['max']))
                        self.code_list[i]['tip'] = True
                    # 检查预警下限
                    elif price <= self.code_list[i]['min'] != 0:
                        self.show_message(self.df.loc[i]['name'], '小心！已到预警线' + str(self.code_list[i]['min']))
                        self.code_list[i]['tip'] = True
                    # 波动大于5个点需要提示
                    elif abs(percent) >= 5:
                        self.show_message(self.df.loc[i]['name'], str(format(percent, '.2f') + '%，注意波动！！！'))
                        self.code_list[i]['tip'] = True

    # 弹出提示
    def show_message(self, title, content):
        self.tpList[0].showMessage(title, content, icon=0)

    # 打开详情窗
    def show_window(self):
        # self.tpList[0].showMessage("提示", "你点了消息", icon=0)

        # 关闭所有窗口,也不关闭应用程序
        QApplication.setQuitOnLastWindowClosed(False)

        # QWidget窗口是PyQt5中所有用户界口对象的基本类.我们使用了QWidget默认的构造器.默认的构造器没有父类.一个没有父类的窗口被称为一个window.
        self.w = QWidget()
        # resize()方法调整了窗口的大小.被调整为250像素宽和250像素高.
        self.w.resize(1000, 100)
        # move()方法移动了窗口到屏幕坐标x=300, y=300的位置.
        self.w.move(300, 300)
        # 在这里我们设置了窗口的标题.标题会被显示在标题栏上.
        self.w.setWindowTitle('List')

        # 创建一个底layout
        form_layout = QFormLayout()

        # 标题
        layout = QHBoxLayout()
        layout.addWidget(QLabel('名称(代码)'))
        layout.addWidget(QLabel('当前价'))
        layout.addWidget(QLabel('百分比'))
        layout.addWidget(QLabel('最高价'))
        layout.addWidget(QLabel('最低价'))
        layout.addWidget(QLabel('开盘价'))
        layout.addWidget(QLabel('昨收价'))
        layout.addWidget(QLabel('成交量'))
        layout.addWidget(QLabel('成交额'))
        # 添加一行
        form_layout.addRow(layout)

        # 获取大盘指数
        zs = ts.get_index()
        for i in zs.index:
            code = zs.loc[i]['code']
            if code == '000001' or code == '399001' or code == '399006':
                name = zs.loc[i]['name']
                price = format(float(zs.loc[i]['close']), '.2f')
                percent = format(float(zs.loc[i]['change']), '.2f')
                high = format(float(zs.loc[i]['high']), '.2f')
                low = format(float(zs.loc[i]['low']), '.2f')
                open = format(float(zs.loc[i]['open']), '.2f')
                pre = format(float(zs.loc[i]['preclose']), '.2f')
                volume = zs.loc[i]['volume']
                amount = zs.loc[i]['amount']

                layout = QHBoxLayout()
                layout.addWidget(QLabel(name + '\n(' + code + ')'))
                layout.addWidget(QLabel(price))
                if float(percent) > 0:
                    layout.addWidget(QLabel("<font color='#C3281C'>" + str(percent) + ' %</font>'))
                elif float(percent) < 0:
                    layout.addWidget(QLabel("<font color='#369B5C'>" + str(percent) + ' %</font>'))
                else:
                    layout.addWidget(QLabel(str(percent) + ' %'))
                layout.addWidget(QLabel(high))
                layout.addWidget(QLabel(low))
                layout.addWidget(QLabel(open))
                layout.addWidget(QLabel(str(pre)))
                layout.addWidget(QLabel(str(volume)))
                layout.addWidget(QLabel(str(amount)))
                # 间距为0
                layout.setSpacing(0)
                # 添加一行
                form_layout.addRow(layout)

        # 自选个股
        for i in self.df.index:
            price = float(self.df.loc[i]['price'])
            pre = float(self.df.loc[i]['pre_close'])
            percent = format((price - pre) / pre * 100, '.2f')

            name = self.df.loc[i]['name']
            code = self.df.loc[i]['code']
            high = format(float(self.df.loc[i]['high']), '.2f')
            low = format(float(self.df.loc[i]['low']), '.2f')
            open = format(float(self.df.loc[i]['open']), '.2f')
            volume = self.df.loc[i]['volume']
            amount = self.df.loc[i]['amount']

            layout = QHBoxLayout()
            layout.addWidget(QLabel(name+'\n('+code+')'))
            layout.addWidget(QLabel(str(price)))
            if float(percent) > 0:
                layout.addWidget(QLabel("<font color='#C3281C'>" + str(percent) + ' %</font>'))
            elif float(percent) < 0:
                layout.addWidget(QLabel("<font color='#369B5C'>" + str(percent) + ' %</font>'))
            else:
                layout.addWidget(QLabel(str(percent) + ' %'))
            layout.addWidget(QLabel(high))
            layout.addWidget(QLabel(low))
            layout.addWidget(QLabel(open))
            layout.addWidget(QLabel(str(pre)))
            layout.addWidget(QLabel(volume))
            layout.addWidget(QLabel(amount))
            # 间距为0
            layout.setSpacing(0)
            # 添加一行
            form_layout.addRow(layout)

        self.w.setLayout(form_layout)

        # show()方法将窗口显示在屏幕上.一个窗口是先在内存中被创建,然后显示在屏幕上的.
        self.w.show()

    # 打开设置窗
    def show_setting(self):
        # self.tpList[0].showMessage("提示", "你点了消息", icon=0)

        # 关闭所有窗口,也不关闭应用程序
        QApplication.setQuitOnLastWindowClosed(False)

        # QWidget窗口是PyQt5中所有用户界口对象的基本类.我们使用了QWidget默认的构造器.默认的构造器没有父类.一个没有父类的窗口被称为一个window.
        self.w = QWidget()
        # resize()方法调整了窗口的大小.被调整为250像素宽和250像素高.
        self.w.resize(666, 100)
        # move()方法移动了窗口到屏幕坐标x=300, y=300的位置.
        self.w.move(300, 300)
        # 在这里我们设置了窗口的标题.标题会被显示在标题栏上.
        self.w.setWindowTitle('SETTING')

        # 创建一个底layout
        form_layout = QFormLayout()

        self.codeView = []
        self.maxView = []
        self.minView = []
        self.tipView = []
        for i in range(len(self.code_list)):
            layout = QHBoxLayout()
            layout.addWidget(QLabel('Code'))
            code_edit = QLineEdit(self.code_list[i]['code'])
            layout.addWidget(code_edit)
            self.codeView.append(code_edit)

            layout.addWidget(QLabel('Max'))
            max_edit = QLineEdit(str(self.code_list[i]['max']))
            layout.addWidget(max_edit)
            self.maxView.append(max_edit)

            layout.addWidget(QLabel('Min'))
            min_edit = QLineEdit(str(self.code_list[i]['min']))
            layout.addWidget(min_edit)
            self.minView.append(min_edit)

            tip_btn = QCheckBox('Tip')
            tip_btn.setChecked(self.code_list[i]['tip'])
            layout.addWidget(tip_btn)
            self.tipView.append(tip_btn)

            del_btn = QPushButton('Del')
            del_btn.setChecked(True)
            del_btn.setObjectName(str(i))
            del_btn.clicked.connect(lambda: self.del_code())
            layout.addWidget(del_btn)

            # 添加一行
            form_layout.addRow(layout)

        # 添加两个按钮
        layout = QHBoxLayout()

        add_btn = QPushButton('Add')
        add_btn.setChecked(True)
        add_btn.setObjectName(str(i))
        add_btn.clicked.connect(lambda: self.add_code())
        layout.addWidget(add_btn)

        save_btn = QPushButton('Save + Restart')
        save_btn.setChecked(True)
        save_btn.setObjectName(str(i))
        save_btn.clicked.connect(lambda: self.save_code())
        layout.addWidget(save_btn)

        # 添加一行
        form_layout.addRow(layout)

        self.w.setLayout(form_layout)
        # show()方法将窗口显示在屏幕上.一个窗口是先在内存中被创建,然后显示在屏幕上的.
        self.w.show()

    @pyqtSlot()
    def add_code(self):
        # 先保存界面上全部数据
        for i in range(len(self.codeView)):
            self.code_list[i]['code'] = self.codeView[i].text()
            self.code_list[i]['max'] = float(self.maxView[i].text())
            self.code_list[i]['min'] = float(self.minView[i].text())
            self.code_list[i]['tip'] = self.tipView[i].isChecked()
            f = open('code.txt', '+w')
            f.write(str(self.code_list))
            f.close()

        # 新增一条空记录
        n = {'code': '', 'max': 0, 'min': 0, 'tip': False}
        self.code_list.append(n)
        self.show_setting()

    @pyqtSlot()
    def del_code(self):
        if len(self.code_list) > 1:
            source = self.MainWindow.sender()
            print(source.text())
            print(source.objectName())
            i = int(source.objectName())
            self.codeView.remove(self.codeView[i])
            self.maxView.remove(self.maxView[i])
            self.minView.remove(self.minView[i])
            self.tipView.remove(self.tipView[i])

            self.code_list.remove(self.code_list[i])
            f = open('code.txt', '+w')
            f.write(str(self.code_list))
            f.close()

            self.show_setting()

    @pyqtSlot()
    def save_code(self):
        # source = self.MainWindow.sender()
        # print(source.text())
        # print(source.objectName())
        # i = int(source.objectName())
        for i in range(len(self.codeView)):
            if self.codeView[i].text() != '':
                self.code_list[i]['code'] = self.codeView[i].text()
                self.code_list[i]['max'] = float(self.maxView[i].text())
                self.code_list[i]['min'] = float(self.minView[i].text())
                self.code_list[i]['tip'] = self.tipView[i].isChecked()

        f = open('code.txt', '+w')
        f.write(str(self.code_list))
        f.close()

        self.restart_program()

    # 退出应用程序
    def quit_app(self):
        # 关闭窗体程序
        QCoreApplication.instance().quit()
        # 在应用程序全部关闭后，TrayIcon其实还不会自动消失，
        # 直到你的鼠标移动到上面去后，才会消失，
        # 这是个问题，（如同你terminate一些带TrayIcon的应用程序时出现的状况），
        # 这种问题的解决我是通过在程序退出前将其setVisible(False)来完成的。
        for i in range(len(self.tpList)):
            self.tpList[i].setVisible(False)
            # 删除生成托盘图标
            os.remove(str(i)+'.png')

    # 初始化应用
    def __init__(self, code_list):
        super(Start, self).__init__()

        # 要关注的代码
        self.code_list = code_list

        for i in range(len(self.code_list)):
            self.codes.append(self.code_list[i]['code'])

        # pyqt窗口必须在QApplication方法中使用
        # 每一个PyQt5应用都必须创建一个应用对象.sys.argv参数是来自命令行的参数列表.Python脚本可以从shell里运行.这是我们如何控制我们的脚本运行的一种方法.
        app = QApplication(sys.argv)

        self.MainWindow = QtWidgets.QMainWindow()
        # 设置系统托盘图标的菜单
        menu = QMenu()
        a1 = QAction('&显示(Show)', triggered=self.show_window)  # 直接退出可以用qApp.quit
        a2 = QAction('&设置(Setting)', triggered=self.show_setting)  # 直接退出可以用qApp.quit
        a3 = QAction('&退出(Exit)', triggered=self.quit_app)  # 直接退出可以用qApp.quit
        menu.addAction(a1)
        menu.addAction(a2)
        menu.addAction(a3)

        for i in range(len(self.code_list)):
            # 在系统托盘处显示图标
            tp = QSystemTrayIcon()
            tp.setIcon(QIcon('./bg.png'))

            # 设置右键弹出菜单
            tp.setContextMenu(menu)

            # 不调用show不会显示系统托盘
            tp.show()

            # 添加托盘到list中
            self.tpList.append(tp)

            # 定义好要保存的最新price
            self.priceList.append('')

        # 创建线程
        self.thread = Mythread()
        # 注册信号处理函数
        self.thread._signal.connect(self.update_ui)
        # 启动线程
        self.thread.start()

        # sys为了调用sys.exit(0)退出程序
        # 最后,我们进入应用的主循环.事件处理从这里开始.主循环从窗口系统接收事件,分派它们到应用窗口.如果我们调用了exit()方法或者主窗口被销毁,则主循环结束.sys.exit()方法确保一个完整的退出.环境变量会被通知应用是如何结束的.
        # exec_()方法是有一个下划线的.这是因为exec在Python中是关键字.因此,用exec_()代替.
        sys.exit(app.exec_())

    # 重启自身
    def restart_program(self):
        python = sys.executable
        os.execl(python, python, * sys.argv)

# if __name__ == "__main__":
#     Start(['000014', '002358'])

