#coding:utf-8

# 导入matplotlib模块并使用Qt5Agg
import typing
from PyQt5.QtCore import QObject
import matplotlib
matplotlib.use('Qt5Agg')
# 使用 matplotlib中的FigureCanvas (在使用 Qt5 Backends中 FigureCanvas继承自QtWidgets.QWidget)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import matplotlib.pyplot as plt
import sys
import scheme_data
import numpy as np
import threading
import os
import build_html


plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.rcParams['figure.max_open_warning'] = False


# 定义一个可以嵌入到qt的figure
class QFigure(QObject):
    def __init__(self,title:str) -> None:
        QObject.__init__(self)
        self._figure = plt.figure(figsize=(14,7))
        self._canvas = FigureCanvas(self._figure)
        self._ax = self._figure.add_axes([0.1,0.1,0.8,0.8])
        self._ax.set_title(title)
        self._title=title
        self._line_min=None
        self._line_max=None
        self._max=0
        self._min=0

    def set_lines(self,x,y,lable:str=None,limit_max:int=None,limit_min:int=None):
        line,=self._ax.plot(x,y,)
        if(lable!=None):
            line.set_label(lable)
            self._ax.legend()
        self.set_max(limit_max)
        self.set_min(limit_min)
        self._ax.grid(visible=True,which="major",axis="y")
    def draw(self):
        # start, end = self._ax.get_ylim() 
        start=self._min
        end=self._max
        step=(end-start)//20
        bond=(end-start)//100+1
        self._ax.set_ylim(start-bond,end+bond) 
        if(step>0):
            ticks=np.arange(start, end,step)
            self._ax.yaxis.set_ticks(ticks,minor=True) 
        # ticks=self._ax.yaxis.get_ticklocs()
        # self._ax.yaxis.set_ticks(minor=True)
        # self._ax.yaxis.set_ticks(ticks)
        # self._ax.autoscale(enable=True, axis='both', tight=None)
        self._canvas.draw()
    def set_max(self,limit_max:int=None):
        if(limit_max is not None):
            if(self._line_max is not None):
                self._line_max.remove()
                self._line_max=None
                print("remove max line")
            self._line_max=self._ax.axhline(y=limit_max,color='g',linestyle='--')
            self._max=limit_max
    def set_min(self,limit_min:int=None):
        if(limit_min is not None):
            if(self._line_min is not None):
                print("remove min line")
                self._line_min.remove()
                self._line_min=None
            self._line_min=self._ax.axhline(y=limit_min,color='r',linestyle='--')
            self._min=limit_min

    def save(self,path:str,perfix:str):
        path=os.path.join(path,"pic")
        if not os.path.exists(path):
            os.makedirs(path)
        name=os.path.join(path,perfix+self._title)
        self._figure.savefig(name+'.png')
    def lable(self,lablex,labley):
        self._ax.set_ylabel(labley)
        self._ax.set_xlabel(lablex)
    def canvas(self):
        return self._canvas


# 定义一个任务需要的参数布局
class TParamLayout(QObject):
    item_change_signal =pyqtSignal([int,str,str])
    def __init__(self,index) -> None:
        QObject.__init__(self)
        self._layout=QFormLayout()
        self._items=[]
        self._index=index
    def change_slot(self,text:str):
        edit=self.sender()
        # name=self.find_label(edit)
        # print(edit.text()) 不用转换类型，直接就可以用 QLineEdit 的方法
        name=edit.objectName()
        # print(name,"text changed",text)
        self.item_change_signal.emit(self._index,name,text)
    def find_label(self,edit):
        for i in self._items:
            if(i[1]==edit):
                return i[0].text()
        return "none"
    def add_item(self,name:str,value:str="",tooltip:str=None):
        line_edit = QLineEdit()
        line_edit.setObjectName(name)
        line_edit.setText(value)
        line_edit.textChanged.connect(self.change_slot)
        line_edit_label = QLabel()
        line_edit_label.setObjectName(name)
        line_edit_label.setText(name)
        line_edit_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        if(tooltip!=None):
            line_edit_label.setToolTip(tooltip)
            line_edit.setToolTip(tooltip)
        self._layout.addRow(line_edit_label,line_edit)
        self._items.append((line_edit_label,line_edit))
    def item_value(self,name:str):
        for i in self._items:
            if(i[0].text()==name):
                return i[1].text()
        return None
    def values(self):
        vals=[]
        for i in self._items:
            vals.append((i[0].text(),i[1].text()))
        return vals
    def layout(self):
        return self._layout

class Analysis(QWidget):
    data_recv_end_signal =pyqtSignal([list,list])
    calc_item_end_signal =pyqtSignal([list])
    def __init__(self,parent=None):
        super(Analysis,self).__init__(parent)
        self.setWindowTitle("检测数据分析")
        self.calc_item_end_signal.connect(self.calc_item_end_slot)
        self.data_recv_end_signal.connect(self.data_recv_end_slot)
        self._import_but = QPushButton("导入方案",self)
        self._import_but.clicked.connect(self.import_but_clicked)
        self._import_but.setGeometry(QRect(0,0,100,27))
        self._export_but = QPushButton("导出数据")
        self._export_but.clicked.connect(self.export_but_clicked)
        
        self._scroll=QScrollArea(self)
        self._scroll.setGeometry(0,30,1230,700)
        # 设置布局
        self._layout = QFormLayout()
        self._layout.addRow('                                                                                                                  ',self._export_but)
        self._items=[]
    def item_changed_slot(self,index:int,name:str,value:str):
        print(index,name,value)
        if(len(value)==0):
            return
        figure=self._items[index][0]
        if(name.find("LimitMax")>=0):
            figure.set_max(int(value))
        if(name.find("LimitMin")>=0):
            figure.set_min(int(value))
        figure.draw()
    def add_item(self,data_dict:dict):
        data=data_dict["data"]
        x=data_dict["x"]
        name=data_dict["name"]
        max=data_dict["max"]
        min=data_dict["min"]
        avg=data_dict["avg"]
        mid=data_dict["mid"]
        std=data_dict["std"]
        limit_max=data_dict["limit_max"]
        limit_min=data_dict["limit_min"]
        dat_count=data_dict["dat_count"]
        y=data_dict["y"]
        figure = QFigure(name)
        figure.lable("序号","数值")
        tplayout=TParamLayout(self._item_index)
        tplayout.add_item(name+":Max",str(max))
        tplayout.add_item(name+":Min",str(min))
        tplayout.add_item(name+":Avg",str(avg))
        tplayout.add_item(name+":Mid",str(mid))
        tplayout.add_item(name+":Std",str(std))
        tplayout.add_item(name+":LimitMax",str(limit_max))
        tplayout.add_item(name+":LimitMin",str(limit_min))
        tplayout.item_change_signal.connect(self.item_changed_slot)
        self._layout.addRow(figure.canvas(),tplayout.layout())
        figure.set_lines(range(len(data)),data,lable="原始值",limit_max=limit_max,limit_min=limit_min)
        figure.set_lines(dat_count,y,lable="权重")
        figure.draw()
        # figure.save(self._save_path,str(self._item_index)+".")
        self._items.append((figure,tplayout,self._item_index))
        self._item_index+=1
    def calc_item_end_slot(self,data:list):
        print("calc_item end.")
        widget=QWidget()
        widget.setGeometry(QRect(0,0,1200,20000))
        for i in data:
            self.add_item(i)
        widget.setLayout(self._layout)
        self._scroll.setWidget(widget)

    def calc_item(self,data,name:str):
        length=len(data)
        # 排序,从小到大
        sort_list=np.sort(data)
        dat_count=np.bincount(data)
        avg=round(np.average(data))
        max=sort_list[-1]
        min=sort_list[0]
        mid=sort_list[len(sort_list)//2]
        std=round(np.std(data))
        # 把众数和原始值对齐
        dat_count=dat_count[min:]
        dat_count_max=np.max(dat_count)
        dat_zoom=length//dat_count_max
        dat_count=np.multiply(dat_count,dat_zoom)
        # 去掉极大值,去掉极小值,使用99.8%的数据来统计区间
        limit_max_t=sort_list[-(length//1000)]
        limit_min_t=sort_list[(length//1000)]
        limit_max=limit_max_t+(limit_max_t-limit_min_t)//5
        limit_min=limit_min_t-(limit_max_t-limit_min_t)//5

        # 使用3倍标准差来统计区间
        # limit_max=avg+3*std
        # limit_min=avg-3*std
        if(limit_min<0):
            limit_min=0
        x=range(length)
        y=np.add(range(len(dat_count)),min)
        dat_struct={"name":name,"max":max,"min":min,"avg":avg,"mid":mid,"std":std,"limit_max":limit_max,
                    "limit_min":limit_min,"dat_count":dat_count,"y":y,"x":x,"data":data}
        # self.add_item_signal.emit(dat_struct)
        return dat_struct

    # 连接的绘制的方法
    def import_but_clicked(self):
        self.sch_data=scheme_data.sch_data()
        self._import_but.setEnabled(False)
        ack=self.sch_data.select_scheme()
        if(ack!=True):
            return
        self._save_path="file/"+self.sch_data.scheme_name.split('/')[-1].split('.')[0]
        print(self._save_path)
        self.recv_data()
    def recv_data(self):
        self._item_index=0
        def recv_data_thread(sch_data:scheme_data.sch_data):
            titles,data,num=sch_data.datas_sql()
            print("recv data,len=",num)
            self.data_recv_end_signal.emit(titles,data)
            if(num<1000):
                print("data len too less.")
                return
            items_data=[]
            for i in range(len(titles)):
                a=self.calc_item(data[i],titles[i])
                items_data.append(a)
            self.calc_item_end_signal.emit(items_data)
            
        t = threading.Thread(target=recv_data_thread, args=(self.sch_data,))
        t.start()
    def data_recv_end_slot(self,titles:list,data:list):
        self.titles=titles
        self.sql_data=data
        print("data recv end.")
    def export_but_clicked(self):
        ret_limit=[]
        ret_values=[]
        for i,t in zip(self._items,self.titles):
            max=i[1].item_value(t+":LimitMax")
            min=i[1].item_value(t+":LimitMin")
            ret_limit.append((max,min))
            ret_values.append(i[1].values())
            i[0].save(self._save_path,str(i[2])+".")
        self.sch_data.export_scheme(self._save_path,ret_limit)
        self.sch_data.export_check_data(self._save_path)
        build_html.html_build(self._save_path,self.titles,ret_values)
# 运行程序
if __name__ == '__main__':
    QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
    app = QApplication(sys.argv)
    main_window = Analysis()
    main_window.show()
    app.exec()