import socket
import threading
import time
import struct

HOST = "0.0.0.0"
PORT = 12345
FRAME_SIZE = 10000  # Increased to avoid fragmenting voice frames
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}")
    recv_buffer = bytearray()
    
    try:
        while True:
            other_client = None
            with clients_lock:
                if len(clients) == 2 and client_id < len(clients):
                    other_client = clients[1 - client_id]
            
            try:
                chunk = client_sock.recv(4096)
                if not chunk:
                    print(f"Client {client_id} disconnected or no data received")
                    break
                    
                # Add to buffer
                recv_buffer.extend(chunk)
                
                # Process complete messages
                while len(recv_buffer) >= 4:
                    # Read message length
                    msg_len = struct.unpack('>I', recv_buffer[:4])[0]
                    
                    # Check if we have the complete message
                    if len(recv_buffer) >= 4 + msg_len:
                        # Extract complete message (including length prefix)
                        complete_msg = bytes(recv_buffer[:4+msg_len])
                        # Remove from buffer
                        recv_buffer = recv_buffer[4+msg_len:]
                        
                        # Forward complete message to other client
                        if other_client:
                            try:
                                other_client.send(complete_msg)
                                print(f"Forwarded {len(complete_msg)} bytes from Client {client_id} to Client {1 - client_id}")
                            except Exception as e:
                                print(f"Error forwarding from Client {client_id}: {e}")
                        else:
                            print(f"No other client to forward to from Client {client_id}")
                    else:
                        # Wait for more data
                        break
                        
            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()