import tkinter as tk
from tkinter import ttk, messagebox
import serial
import serial.tools.list_ports
import threading
import time
from datetime import datetime
import struct
from PIL import Image, ImageTk, ImageDraw, ImageFont
import os

class ModbusGasAnalyzer:
    def __init__(self, root):
        self.root = root
        self.root.title("HFC-RapidScan多通道灭火剂气体快检仪")
        self.custom_blue = "#0161DA"  # 这是你的RGB颜色

        # 使用PNG图片作为图标
        try:
            img = Image.open("logo.png")
            photo = ImageTk.PhotoImage(img)
            self.root.iconphoto(True, photo)  # False表示不用于子窗口
            # 保存引用防止垃圾回收
            self.icon_image = photo
        except Exception as e:
            print(f"设置图标失败: {e}")

        # 设置黄金比例窗口大小 (800x495)
        window_width = 800
        window_height = 495
        self.root.geometry(f"{window_width}x{window_height}")
        self.root.configure(bg=self.custom_blue)
        
        # Modbus通信参数
        self.serial_port = None
        self.is_connected = False
        self.is_testing = False
        
        # 测试数据
        self.concentration = 0.0
        self.start_time = None
        self.test_duration = 0
        self.last_concentrations = []  # 用于检测浓度变化
        
        # 用户信息 - 初始化空值
        self.user_info = {
            "测试人员": "",
            "测试时间": "",
            "样品信息": "",
            "出厂日期": "",
            "产品型号": "",
            "编号": ""
        }
        
        # 创建页面
        self.create_page1()
        
    def create_page1(self):
        """创建第一个页面"""
        self.clear_window()
        
        # 主框架
        main_frame = tk.Frame(self.root, bg=self.custom_blue)
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 左侧区域
        left_frame = tk.Frame(main_frame, bg=self.custom_blue)
        left_frame.pack(side='left', fill='both', expand=True, padx=(0, 10))
        
        # 右侧区域
        right_frame = tk.Frame(main_frame, bg=self.custom_blue)
        right_frame.pack(side='right', fill='both', expand=True, padx=(10, 0))
        
        # 左侧内容
        # 测试人员
        tk.Label(left_frame, text="测试人员:", font=('Arial', 12), bg=self.custom_blue).pack(anchor='w', pady=5)
        self.tester_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
        self.tester_entry.pack(fill='x', pady=5)
        # 保留之前填写的信息
        if self.user_info["测试人员"]:
            self.tester_entry.insert(0, self.user_info["测试人员"])
        
        # 测试时间
        tk.Label(left_frame, text="测试时间:", font=('Arial', 12), bg=self.custom_blue).pack(anchor='w', pady=5)
        self.test_time_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
        self.test_time_entry.pack(fill='x', pady=5)
        # 自动填入当前时间，但如果已有信息则保留
        if self.user_info["测试时间"]:
            self.test_time_entry.insert(0, self.user_info["测试时间"])
        else:
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            self.test_time_entry.insert(0, current_time)
        
        # 样品信息
        tk.Label(left_frame, text="样品信息:", font=('Arial', 12), bg=self.custom_blue).pack(anchor='w', pady=5)
        self.sample_info_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
        self.sample_info_entry.pack(fill='x', pady=5)
        if self.user_info["样品信息"]:
            self.sample_info_entry.insert(0, self.user_info["样品信息"])
        
        # 出厂日期
        tk.Label(left_frame, text="出厂日期:", font=('Arial', 12), bg=self.custom_blue).pack(anchor='w', pady=5)
        self.production_date_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
        self.production_date_entry.pack(fill='x', pady=5)
        if self.user_info["出厂日期"]:
            self.production_date_entry.insert(0, self.user_info["出厂日期"])
        
        # 产品型号
        tk.Label(left_frame, text="产品型号:", font=('Arial', 12), bg=self.custom_blue).pack(anchor='w', pady=5)
        self.model_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
        self.model_entry.pack(fill='x', pady=5)
        if self.user_info["产品型号"]:
            self.model_entry.insert(0, self.user_info["产品型号"])
        
        # 编号
        tk.Label(left_frame, text="编号:", font=('Arial', 12), bg=self.custom_blue).pack(anchor='w', pady=5)
        self.serial_number_entry = tk.Entry(left_frame, font=('Arial', 12), width=20)
        self.serial_number_entry.pack(fill='x', pady=5)
        if self.user_info["编号"]:
            self.serial_number_entry.insert(0, self.user_info["编号"])
        
        # 右侧内容 - 标题
        title_label = tk.Label(right_frame, text="HFC-RapidScan多通道\n灭火剂气体快检仪", 
                              font=('Arial', 18, 'bold'), bg=self.custom_blue, 
                              justify='center')
        title_label.pack(pady=40)
        
        # 开始测试按钮
        self.start_button = tk.Button(right_frame, text="开始测试", font=('Arial', 16, 'bold'), 
                                     bg='green', fg='white', width=15, height=2,
                                     command=self.start_test)
        self.start_button.pack(pady=40)
    
    def create_page2(self):
        """创建第二个页面"""
        self.clear_window()
        
        main_frame = tk.Frame(self.root, bg=self.custom_blue)
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 标题
        title_label = tk.Label(main_frame, text="HFC-RapidScan多通道灭火剂气体快检仪", 
                              font=('Arial', 16, 'bold'), bg=self.custom_blue)
        title_label.pack(pady=10)
        
        # 通道信息
        channel_frame = tk.Frame(main_frame, bg=self.custom_blue)
        channel_frame.pack(fill='x', pady=20)
        
        tk.Label(channel_frame, text="通道一：七氟丙烷", font=('Arial', 20, 'bold'), 
                bg=self.custom_blue).pack()
        
        # 浓度显示
        concentration_frame = tk.Frame(main_frame, bg=self.custom_blue)
        concentration_frame.pack(fill='both', expand=True)
        
        self.concentration_label = tk.Label(concentration_frame, text="0.00%", 
                                           font=('Arial', 48, 'bold'), bg=self.custom_blue,
                                           fg='red')
        self.concentration_label.pack(expand=True)
        
        # 返回按钮
        back_button = tk.Button(main_frame, text="返回", font=('Arial', 12),
                               command=self.back_to_page1, bg='orange')
        back_button.pack(pady=10)
        
        # 开始Modbus通信
        self.start_modbus_communication()
    
    def create_page3(self):
        """创建第三个页面 - 结果汇总"""
        self.clear_window()
        
        main_frame = tk.Frame(self.root, bg=self.custom_blue)
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 标题
        title_label = tk.Label(main_frame, text="HFC-RapidScan多通道灭火剂气体快检仪", 
                              font=('Arial', 16, 'bold'), bg=self.custom_blue)
        title_label.pack(pady=10)
        
        # 结果显示框架
        result_frame = tk.Frame(main_frame, bg='white', relief='raised', bd=2)
        result_frame.pack(fill='both', expand=True, padx=20, pady=10)
        
        # 创建滚动框架以适应所有内容
        canvas = tk.Canvas(result_frame, bg='white')
        scrollbar = tk.Scrollbar(result_frame, orient="vertical", command=canvas.yview)
        scrollable_frame = tk.Frame(canvas, bg='white')
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # 左侧信息框架
        info_frame = tk.Frame(scrollable_frame, bg='white')
        info_frame.pack(side='left', fill='both', expand=True, padx=20, pady=20)
        
        # 显示所有用户信息
        info_items = [
            ("测试人员:", self.user_info["测试人员"]),
            ("测试时间:", self.user_info["测试时间"]),
            ("样品信息:", self.user_info["样品信息"]),
            ("出厂日期:", self.user_info["出厂日期"]),
            ("产品型号:", self.user_info["产品型号"]),
            ("编号:", self.user_info["编号"])
        ]
        
        for label, value in info_items:
            label_frame = tk.Frame(info_frame, bg='white')
            label_frame.pack(fill='x', pady=8)
            
            tk.Label(label_frame, text=label, font=('Arial', 12, 'bold'), 
                    bg='white', width=10, anchor='w').pack(side='left')
            tk.Label(label_frame, text=value, font=('Arial', 12), 
                    bg='white', anchor='w').pack(side='left', fill='x', expand=True)
        
        # 右侧结果框架
        result_right_frame = tk.Frame(scrollable_frame, bg='white')
        result_right_frame.pack(side='right', fill='both', expand=True, padx=20, pady=20)
        
        tk.Label(result_right_frame, text="最终浓度", font=('Arial', 16, 'bold'), 
                bg='white').pack(pady=10)
        
        final_concentration = max(0.0, min(self.concentration, 99.6))
        concentration_label = tk.Label(result_right_frame, text=f"{final_concentration:.2f}%", 
                font=('Arial', 36, 'bold'), bg='white', fg='blue')
        concentration_label.pack(pady=20)
        
        tk.Label(result_right_frame, text=f"测试时长: {self.test_duration}秒", 
                font=('Arial', 12), bg='white').pack(pady=10)
        
        # 打包canvas和scrollbar
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        # 按钮框架
        button_frame = tk.Frame(main_frame, bg=self.custom_blue)
        button_frame.pack(fill='x', pady=10)
        
        tk.Button(button_frame, text="重新测试", font=('Arial', 12),
                 command=self.back_to_page1, bg='green', fg='white').pack(side='left', padx=20)
        
        tk.Button(button_frame, text="保存报告", font=('Arial', 12),
                 command=self.save_report, bg='blue', fg='white').pack(side='left', padx=20)
        
        tk.Button(button_frame, text="退出", font=('Arial', 12),
                 command=self.root.quit, bg='red', fg='white').pack(side='right', padx=20)
        
        # 自动保存报告
        self.save_report()
    
    def save_report(self):
        """保存汇总信息为JPG图片"""
        try:
            # 创建图片 - 增大高度以容纳所有信息
            img_width = 1000
            img_height = 800
            img = Image.new('RGB', (img_width, img_height), color=self.custom_blue)
            draw = ImageDraw.Draw(img)
            
            # 尝试加载字体
            try:
                title_font = ImageFont.truetype("simhei.ttf", 36)  # 黑体
                header_font = ImageFont.truetype("simhei.ttf", 24)
                content_font = ImageFont.truetype("simhei.ttf", 18)
                small_font = ImageFont.truetype("simhei.ttf", 16)
            except:
                # 如果系统没有中文字体，使用默认字体
                title_font = ImageFont.load_default()
                header_font = ImageFont.load_default()
                content_font = ImageFont.load_default()
                small_font = ImageFont.load_default()
            
            # 绘制标题
            title = "HFC-RapidScan多通道灭火剂气体快检仪"
            draw.text((img_width//2 - 250, 35), title, fill='black', font=title_font)
            
            # 绘制分隔线
            draw.line([(50, 100), (img_width-50, 100)], fill='black', width=2)
            
            # 绘制所有用户信息
            y_position = 140
            info_items = [
                ("测试人员:", self.user_info["测试人员"]),
                ("测试时间:", self.user_info["测试时间"]),
                ("样品信息:", self.user_info["样品信息"]),
                ("出厂日期:", self.user_info["出厂日期"]),
                ("产品型号:", self.user_info["产品型号"]),
                ("编号:", self.user_info["编号"])
            ]
            
            for label, value in info_items:
                # 标签
                draw.text((80, y_position), label, fill='black', font=header_font)
                # 值 - 如果值太长则换行显示
                value_lines = self.wrap_text(value, content_font, img_width - 300)
                for line in value_lines:
                    draw.text((200, y_position), line, fill='darkblue', font=content_font)
                    y_position += 30
                y_position += 10
            
            # 绘制浓度结果
            result_y = 140
            final_concentration = max(0.0, min(self.concentration, 99.6))
            
            draw.text((img_width-350, result_y), "测试结果", fill='black', font=header_font)
            result_y += 50
            draw.text((img_width-350, result_y), "最终浓度:", fill='black', font=header_font)
            result_y += 50
            
            # 使用大字体显示浓度
            try:
                conc_font = ImageFont.truetype("simhei.ttf", 48)
            except:
                conc_font = ImageFont.load_default()
                
            draw.text((img_width-350, result_y), f"{final_concentration:.2f}%", fill='blue', font=conc_font)
            result_y += 80
            draw.text((img_width-350, result_y), f"测试时长: {self.test_duration}秒", fill='black', font=content_font)
            
            # 保存图片
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"测试报告_{timestamp}.jpg"
            img.save(filename, quality=95)
            
            messagebox.showinfo("成功", f"报告已保存为: {filename}")
            
        except Exception as e:
            messagebox.showerror("错误", f"保存报告失败: {str(e)}")
    
    def wrap_text(self, text, font, max_width):
        """文本换行处理"""
        lines = []
        words = text.split(' ')
        current_line = []
        
        for word in words:
            # 估算文本宽度
            test_line = ' '.join(current_line + [word])
            bbox = font.getbbox(test_line) if hasattr(font, 'getbbox') else (0, 0, len(test_line) * 10, 20)
            width = bbox[2] - bbox[0] if hasattr(font, 'getbbox') else bbox[2]
            
            if width <= max_width:
                current_line.append(word)
            else:
                if current_line:
                    lines.append(' '.join(current_line))
                current_line = [word]
        
        if current_line:
            lines.append(' '.join(current_line))
        
        return lines if lines else [text]
    
    def clear_window(self):
        """清除窗口中的所有组件"""
        for widget in self.root.winfo_children():
            widget.destroy()
    
    def start_test(self):
        """开始测试"""
        # 保存用户信息
        self.user_info = {
            "测试人员": self.tester_entry.get(),
            "测试时间": self.test_time_entry.get(),
            "样品信息": self.sample_info_entry.get(),
            "出厂日期": self.production_date_entry.get(),
            "产品型号": self.model_entry.get(),
            "编号": self.serial_number_entry.get()
        }
        
        # 切换到第二个页面
        self.create_page2()
    
    def back_to_page1(self):
        """返回到第一个页面"""
        self.stop_modbus_communication()
        self.create_page1()
    
    def get_com_port(self):
        """获取COM端口"""
        try:
            # 尝试从配置文件读取COM口
            if os.path.exists("com_config.txt"):
                with open("com_config.txt", "r", encoding='utf-8') as f:
                    com_port = f.read().strip()
                    # 验证COM口是否存在
                    ports = [port.device for port in serial.tools.list_ports.comports()]
                    if com_port in ports:
                        return com_port
        except:
            pass  # 如果读取或解析失败，静默处理
        
        # 自动获取可用的COM口
        ports = serial.tools.list_ports.comports()
        if ports:
            return ports[0].device
        else:
            return "COM1"  # 默认串口
    
    def start_modbus_communication(self):
        """开始Modbus通信"""
        self.is_testing = True
        self.start_time = time.time()
        self.last_concentrations = []
        
        # 尝试连接串口
        try:
            com_port = self.get_com_port()
            self.serial_port = serial.Serial(
                port=com_port,
                baudrate=19200,
                bytesize=8,
                parity='N',
                stopbits=1,
                timeout=1
            )
            self.is_connected = True
        except Exception as e:
            messagebox.showerror("错误", f"无法连接串口: {str(e)}")
            self.is_connected = False
            return
        
        # 启动通信线程
        self.communication_thread = threading.Thread(target=self.modbus_communication_loop)
        self.communication_thread.daemon = True
        self.communication_thread.start()
        
        # 启动UI更新线程
        self.ui_update_thread = threading.Thread(target=self.ui_update_loop)
        self.ui_update_thread.daemon = True
        self.ui_update_thread.start()
    
    def stop_modbus_communication(self):
        """停止Modbus通信"""
        self.is_testing = False
        if self.serial_port and self.serial_port.is_open:
            self.serial_port.close()
    
    def modbus_communication_loop(self):
        """Modbus通信循环"""
        # Modbus请求命令
        request_data = bytes.fromhex('01 04 05 20 00 02 70 CD')
        
        while self.is_testing and self.is_connected:
            try:
                # 清空输入和输出缓冲区
                self.serial_port.reset_input_buffer()   # 清空接收缓冲区
                self.serial_port.reset_output_buffer()  # 清空发送缓冲区

                # 发送请求
                self.serial_port.write(request_data)
                
                # 读取响应
                response = self.serial_port.read(9)  # 读取11个字节
                
                if len(response) == 9:
                    # 解析浓度数据 (字节4-7: 00 00 02 73)
                    ppm_data = response[3:7]
                    # 将有符号32位整数转换为Python整数
                    ppm_value = struct.unpack('>i', ppm_data)[0]

                    # 在终端打印原始的ppm_value用于调试
                    print(f"DEBUG - 原始ppm值: {ppm_value}")

                    # 将ppm转换为百分比 (假设10000ppm = 1%)
                    # 根据实际转换公式调整
                    self.concentration = ppm_value / 10000.0
                    
                    # 限制浓度范围
                    if self.concentration < 0:
                        self.concentration = 0.0
                    elif self.concentration > 99.6:
                        self.concentration = 99.6
                    
                    # 记录浓度用于变化检测
                    current_time = time.time()
                    self.last_concentrations.append((current_time, self.concentration))
                    
                    # 只保留最近10秒的数据
                    self.last_concentrations = [(t, c) for t, c in self.last_concentrations 
                                              if current_time - t <= 10]
                
                # 更新测试时间
                self.test_duration = int(time.time() - self.start_time)
                
                # 检查停止条件 (20秒或浓度稳定)
                if self.check_stop_conditions():
                    self.root.after(0, self.create_page3)
                    break
                
                time.sleep(1)  # 每秒通信一次
                
            except Exception as e:
                print(f"Modbus通信错误: {e}")
                time.sleep(1)
    
    def ui_update_loop(self):
        """UI更新循环"""
        while self.is_testing:
            try:
                # 更新浓度显示
                concentration_display = max(0.0, min(self.concentration, 99.6))
                concentration_text = f"{concentration_display:.2f}%"
                
                # 在主线程中更新UI
                self.root.after(0, self.update_concentration_display, concentration_text)
                
                time.sleep(0.5)  # 每0.5秒更新一次UI
            except:
                break
    
    def update_concentration_display(self, concentration_text):
        """更新浓度显示"""
        try:
            if hasattr(self, 'concentration_label'):
                self.concentration_label.config(text=concentration_text)
        except:
            pass
    
    def check_stop_conditions(self):
        """检查停止条件"""
        # 条件1: 测试时间达到120秒
        if self.test_duration >= 120:
            print(f"DEBUG - 检测时间到")
            return True
        
        # 条件2: 10秒内浓度变化小于2%
        if len(self.last_concentrations) >= 10:
            recent_concentrations = [c for t, c in self.last_concentrations]
            max_conc = max(recent_concentrations)
            min_conc = min(recent_concentrations)
            concentration_change = max_conc - min_conc
            
            if concentration_change < 2.0:
                print(f"DEBUG - 浓度变化小于2%")
                return True
        
        return False

def main():
    root = tk.Tk()
    app = ModbusGasAnalyzer(root)
    root.mainloop()

if __name__ == "__main__":
    main()