import socket
import threading
from datetime import datetime

MULTICAST_GROUP_IP = '224.1.1.1'

# Broadcast address and port

CLIENT_MULTICAST_PORT = 5973

# Local host information
MY_HOST = socket.gethostname()
MY_IP = socket.gethostbyname(MY_HOST)

class Client():
    def __init__(self):
        self.currentLeader = ''
        self.server_socket = None

    # print the current date and time
    def printwt(self, msg):
        current_date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print(f'[{current_date_time}] {msg}')    

    # dynamic discoverey: client sends request to server group and gets the IP of server as reply
    def MulticastSendAndReceive(self):
        # Create a UDP socket
        multicast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        # Set the time-to-live for messages to 1 so they do not go past the local network segment
        multicast_socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)

        # Send message on multicast address
        message = 'New client wants to connect: ' + MY_IP
        multicast_socket.sendto(str.encode(message), (MULTICAST_GROUP_IP, CLIENT_MULTICAST_PORT))

        self.printwt("Sent my IP to server group")

        while True:     
            try:
                # receive reply data (server IP) from the other participants
                reply, addr = multicast_socket.recvfrom(1024)

                if reply:
                    # decode received data
                    reply_addr = reply.decode()
                    self.currentLeader = reply_addr
                    self.printwt(f'Got Leader address: {self.currentLeader}')

                    # Connect to the server using TCP
                    self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    self.server_socket.connect((self.currentLeader, 5555))
                    print("You have entered the chat room")

                     # Starte einen Thread, um Nachrichten zu empfangen
                    receive_thread = threading.Thread(target=self.receive_messages)
                    receive_thread.start()

                    # Haupt-Thread zum Senden von Nachrichten
                    while True:
                        message = input()
                        timestamped_message = f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}] {message}'
                        self.server_socket.send(timestamped_message.encode('utf-8'))
                        
            except socket.timeout:
                pass

    def receive_messages(self):
        while True:
            try:
                data = self.server_socket.recv(1024)
                if not data:
                    break
                print(data.decode('utf-8'))
            except:
                break




# starting all simultaneously working procedures
if __name__ == "__main__":
    client = Client()

    thread1 = threading.Thread(target = client.MulticastSendAndReceive)
    thread1.start()
    thread1.join()