import socket
import tkinter as tk
from tkinter import messagebox

class TcpClientApp(tk.Frame):

    def init(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.title("TCP Client Application")
        self.master.geometry("600x600")
        self.create_widgets()
        self.client_socket = None

    def create_widgets(self):
        # create message label and textbox
        self.message_label = tk.Label(self.master, text="Message")
        self.message_label.pack(pady=5)
        self.message_box = tk.Entry(self.master)
        self.message_box.pack(pady=5)

        # create send button
        self.send_button = tk.Button(self.master, text="Send", command=self.send_message)
        self.send_button.pack(pady=5)

        # create response label and textbox
        self.response_label = tk.Label(self.master, text="Response")
        self.response_label.pack(pady=5)
        self.response_box = tk.Text(self.master, width=50, height=10)
        self.response_box.pack(pady=5)

        # create connect and disconnect buttons
        self.connect_button = tk.Button(self.master, text="Connect", command=self.connect_to_server)
        self.connect_button.pack(pady=5)
        self.disconnect_button = tk.Button(self.master, text="Disconnect", command=self.disconnect_from_server, state=tk.DISABLED)
        self.disconnect_button.pack(pady=5)

    def connect_to_server(self):
        # Create a TCP/IP socket
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # Connect the socket to the server's IP address and port
        server_address = ('localhost', 10000) # REPLACE 'localhost' with the server's IP address
        try:
            self.client_socket.connect(server_address)
        except ConnectionRefusedError:
            messagebox.showwarning("Connection Error",
                                "Could not connect to the server. "
                                "Make sure the server is running and try again.")
            return

        # Inform the user
        self.response_box.insert(tk.END, f'Connected to {server_address[0]} on port {server_address[1]}\n')
        self.connect_button.config(state=tk.DISABLED)
        self.disconnect_button.config(state=tk.NORMAL)

    def disconnect_from_server(self):
        if not self.client_socket:
            return

        # Close the socket
        self.client_socket.close()
        self.client_socket = None

        # Inform the user
        self.response_box.insert(tk.END, 'Disconnected from the server\n')
        self.connect_button.config(state=tk.NORMAL)
        self.disconnect_button.config(state=tk.DISABLED)

    def send_message(self):
        if not self.client_socket:
            messagebox.showwarning("Connection Error",
                                "You must connect to the server first.")
            return

        # Send data
        message = self.message_box.get()
        try:
            message_bytes = bytes.fromhex(message)
        except ValueError:
            messagebox.showwarning("Invalid Message",
                                "The message is not valid hexadecimal. "
                                "Please enter a valid hexadecimal string.")
            return

        self.client_socket.sendall(message_bytes)

        # Receive response
        response = self.client_socket.recv(4096)
        response_hex = response.hex()
        self.response_box.insert(tk.END, f'Sent: {message.upper()}\n')
        self.response_box.insert(tk.END, f'Received: {response_hex.upper()}\n')

        self.message_box.delete(0, tk.END)

# Run the application
if __name__ =='__main__':
    root = tk.Tk()
    app = TcpClientApp(root)
    app.pack()
    root.mainloop()