import socket
import threading
from queue import Queue
import logging
import time

from tkinter import Tk, Frame, Label, Entry, Checkbutton, Text, Button, filedialog
from tkinter.scrolledtext import ScrolledText


logging.basicConfig(filename='TCPClient.log', level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')
PACKET_FILE_PATH = ''
MAX_RETRY_TIMES = 3

class TCPPacketSender:
    def init(self, server_ip, server_port, file_path, send_interval, wait_for_response, loop_send):
        self.server_ip = server_ip
        self.server_port = server_port
        self.file_path = file_path
        self.send_interval = send_interval
        self.wait_for_response = wait_for_response
        self.loop_send = loop_send

        # 读取16进制报文
        self.packets = self._read_hex_packets()

        # 记录发送的状态(是否正在发送)
        self.sending = False

        # 创建TCP客户端socket
        self.client_socket = None
        try:
            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        except socket.error as e:
            logging.error(f"创建socket失败: {str(e)}")

    # 读取文件中的16进制报文
    def _read_hex_packets(self):
        packets = []
        try:
            with open(self.file_path, "r") as f:
                for line in f:
                    # 去掉换行符和空格
                    line = line.strip()
                    if not line:
                        continue
                    try:
                        packet = bytes.fromhex(line)
                    except ValueError:
                        logging.error(f"无效的报文格式: {line}")
                        continue
                    packets.append(packet)
        except IOError as e:
            logging.error(f"读取文件 {self.file_path} 失败: {str(e)}")
        return packets

    # 发送所有报文
    def send_packets(self, send_done_callback=None):
        if self.sending:  # 如果已经在发送中,先停止发送再重新发送
            self.stop_sending()
        if not self.client_socket:  # 如果socket创建失败,不能发送报文
            return
        if not self.packets:  # 如果报文为空,直接返回
            return

        # 连接服务器
        retry_count = 0
        while retry_count < MAX_RETRY_TIMES:
            try:
                self.client_socket.connect((self.server_ip, self.server_port))
                break
            except socket.error as e:
                logging.error(f"连接服务器失败,Retry {retry_count}: {str(e)}")
                time.sleep(1)  # 连接失败后等待1秒再尝试连接
                retry_count += 1
        else:
            logging.error(f"连接服务器 {self.server_ip}:{self.server_port} 失败")
            return
        
        self.sending = True

        # 循环发送报文
        while self.sending:
            for i, packet in enumerate(self.packets):
                # 发送报文
                send_success = False
                retry_count = 0
                while not send_success and retry_count < MAX_RETRY_TIMES:
                    try:
                        self.client_socket.sendall(packet)
                        send_success = True
                    except socket.error as e:
                        logging.error(f"发送第{i+1}帧报文失败,Retry {retry_count}: {str(e)}")
                        time.sleep(1)  # 发送失败后等待1秒再尝试发送
                        retry_count += 1
                if not send_success:  # 如果连续 MAX_RETRY_TIMES 次发送失败,停止发送
                    self.sending = False
                    break

                # 打印日志和更新UI
                logging.info(f"发送第{i+1}帧报文: {packet.hex()}")
                self.send_progress('发送第%d帧报文: %s' % (i+1, packet.hex()))

                # 等待服务器回传
                if self.wait_for_response:
                    try:
                        response_packet = self.client_socket.recv(1024)
                        logging.info(f"收到第{i+1}帧回传报文: {response_packet.hex()}")
                        self.recv_progress(response_packet.hex())
                    except socket.error as e:
                        logging.error(f"接收第{i+1}帧回传报文失败: {str(e)}")

                # 等待一定时间再发送下一帧报文
                if i != len(self.packets) - 1:
                    time.sleep((self.send_interval + 500) / 1000)  # 加上500ms的传输延迟

            if not self.loop_send:  # 如果不循环发送,发送一轮后退出发送
                break

        self.client_socket.close()
        self.sending = False
        if send_done_callback:
            send_done_callback()

    # 停止发送报文
    def stop_sending(self):
        self.sending = False

    # 更新发送进度
    def send_progress(self, message):
        pass

    # 更新接收进度
    def recv_progress(self, message):
        pass


class TCPSenderUI:
    def init(self, sender):
        self.sender = sender

        # 创建UI界面
        self.root = Tk()
        self.root.title("TCP客户端")

        # 服务器ip和端口号输入框
        server_frame = Frame(self.root)
        server_frame.pack(side='top', padx=10, pady=10)
        server_ip_label = Label(server_frame, text="服务器IP: ")
        server_ip_label.pack(side='left')
        self.server_ip_entry = Entry(server_frame, width=15, textvariable='')
        self.server_ip_entry.pack(side='left')
        self.server_ip_entry.insert(0, sender.server_ip)
        server_port_label = Label(server_frame, text="服务器端口号: ")
        server_port_label.pack(side='left', padx=10)
        self.server_port_entry = Entry(server_frame, width=5, textvariable='')
        self.server_port_entry.pack(side='left')
        self.server_port_entry.insert(0, sender.server_port)

        # 选择报文文件和发送间隔输入框
        file_frame = Frame(self.root)
        file_frame.pack(side='top', padx=10, pady=10)
        open_file_button = Button(file_frame, text="选择报文文件", command=self.open_file_dialog)
        open_file_button.pack(side='left')
        self.file_path_label = Label(file_frame, text=sender.file_path)
        self.file_path_label.pack(side='left', padx=10)
        send_interval_label = Label(file_frame, text="发送间隔(ms): ")
        send_interval_label.pack(side='left')
        self.send_interval_entry = Entry(file_frame, width=5, textvariable='')
        self.send_interval_entry.pack(side='left')
        self.send_interval_entry.insert(0, sender.send_interval)

        # "发送每一帧报文之后都等待服务器回传数据"勾选框和"循环发送报文"勾选框
        options_frame = Frame(self.root)
        options_frame.pack(side='top', padx=10, pady=10)
        self.wait_for_response_var = tk.BooleanVar()
        wait_for_response_checkbox = Checkbutton(options_frame, text="发送每一帧报文之后都等待服务器回传数据", variable=self.wait_for_response_var)
        wait_for_response_checkbox.pack(side='left')
        self.wait_for_response_var.set(sender.wait_for_response)
        loop_send_var = tk.BooleanVar()
        loop_send_checkbox = Checkbutton(options_frame, text="循环发送报文", variable=loop_send_var)
        loop_send_checkbox.pack(side='left', padx=10)
        loop_send_var.set(sender.loop_send)

        # 发送和接收框
        text_frame = Frame(self.root)
        text_frame.pack(side='top', padx=10, pady=10)
        send_label = Label(text_frame, text='发送内容:')
        send_label.pack(side='left')
        self.send_text = ScrolledText(text_frame, height=10, width=50)
        self.send_text.pack(expand=True, fill='both', side='left', padx=10)
        recv_label = Label(text_frame, text='接收内容:')
        recv_label.pack(side='left', padx=10)
        self.response_text = ScrolledText(text_frame, height=10, width=50)
        self.response_text.pack(expand=True, fill='both', side='right')

        # 发送按钮和停止按钮
        button_frame = Frame(self.root)
        button_frame.pack(side='bottom', pady=10)
        self.send_button = Button(button_frame, text="发送", width=10, height=2, command=self.send_packets)
        self.send_button.pack(side='left')
        self.stop_button = Button(button_frame, text="停止发送", width=10, height=2, command=self.stop_sending)
        self.stop_button.pack(side='left')

        self.sender.send_progress = self.update_send_progress
        self.sender.recv_progress = self.update_recv_progress

    # 打开文件对话框
    def open_file_dialog(self):
        global PACKET_FILE_PATH
        PACKET_FILE_PATH = filedialog.askopenfilename(filetypes=(("Text files", "*.txt"),))
        self.file_path_label.config(text=PACKET_FILE_PATH)

    # 发送报文
    def send_packets(self):
        if self.sender.sending:
            return
        # 获取输入的服务器ip和端口号
        self.sender.server_ip = self.server_ip_entry.get()
        self.sender.server_port = int(self.server_port_entry.get())

        # 获取报文发送间隔和是否等待服务器回传信息
        self.sender.send_interval = int(self.send_interval_entry.get())
        self.sender.wait_for_response = self.wait_for_response_var.get()

        # 获取是否勾选"循环发送报文"
        self.sender.loop_send = loop_send_var.get()

        # 读取16进制报文
        self.sender.file_path = self.file_path_label['text']
        self.sender.packets = self.sender._read_hex_packets()

        self.sender.send_packets(self.send_done_callback)

    # 停止发送报文
    def stop_sending(self):
        if self.sender.sending:
            self.sender.stop_sending()

    # 更新发送进度
    def update_send_progress(self, message):
        if self.root:
            self.send_text.insert('end', message + '\n')
            self.send_text.see('end')

    # 更新接收进度
    def update_recv_progress(self, message):
        if self.root:
            self.response_text.insert('end', message + '\n')
            self.response_text.see('end')

    # 发送完成后的回调函数
    def send_done_callback(self):
        if self.root:
            self.send_button['state'] = 'normal'
            self.stop_button['state'] = 'disabled'

    # 运行程序
    def run(self):
        self.root.mainloop()


if __name__ == 'main':
    sender = TCPPacketSender("127.0.0.1", 8000, "", 0, False, False)
    app = TCPSenderUI(sender)
    app.run()