import socket
import threading
import time

HOST = "0.0.0.0"
PORT = 12345
FRAME_SIZE = 1000
FRAME_DELAY = 0.02

clients = []
clients_lock = threading.Lock()

def handle_client(client_sock, client_id):
    print(f"Starting handle_client for Client {client_id}")
    try:
        while True:
            other_client = None
            with clients_lock:
                if len(clients) == 2 and client_id < len(clients):
                    other_client = clients[1 - client_id]
            print(f"Client {client_id} waiting for data, other_client exists: {other_client is not None}")
            
            try:
                data = client_sock.recv(1024)
                if not data:
                    print(f"Client {client_id} disconnected or no data received")
                    break
                if other_client:
                    for i in range(0, len(data), FRAME_SIZE):
                        frame = data[i:i + FRAME_SIZE]
                        other_client.send(frame)
                        time.sleep(FRAME_DELAY)
                    print(f"Forwarded {len(data)} bytes from Client {client_id} to Client {1 - client_id}")
            except socket.error as e:
                print(f"Socket error with Client {client_id}: {e}")
                break
    finally:
        print(f"Closing connection for Client {client_id}")
        with clients_lock:
            if client_id < len(clients) and clients[client_id] == client_sock:
                clients.pop(client_id)
                print(f"Removed Client {client_id} from clients list")
        client_sock.close()

def start_simulator():
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((HOST, PORT))
    server.listen(2)
    print(f"GSM Simulator listening on {HOST}:{PORT}...")

    try:
        while True:
            client_sock, addr = server.accept()
            client_sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)  # Keep connection alive
            with clients_lock:
                if len(clients) < 2:
                    clients.append(client_sock)
                    client_id = len(clients) - 1
                else:
                    # Replace a closed socket or reject if both slots are active
                    replaced = False
                    for i in range(len(clients)):
                        if clients[i].fileno() == -1:  # Check if socket is closed
                            clients[i] = client_sock
                            client_id = i
                            replaced = True
                            break
                    if not replaced:
                        print(f"Rejecting new client from {addr}: max clients (2) reached")
                        client_sock.close()
                        continue
            print(f"Client {client_id} connected from {addr}")
            threading.Thread(target=handle_client, args=(client_sock, client_id), daemon=True).start()
    except KeyboardInterrupt:
        print("Shutting down simulator...")
    finally:
        with clients_lock:
            for client in clients:
                client.close()
            clients.clear()
        server.close()

if __name__ == "__main__":
    start_simulator()