'''
Docstring for pyClient
A simple server client program

The following protocol is in use:

Handshake:
Client -> Server: "Gday to you"
Server -> Client: "mkay"

Data Exchange:
Client -> Server: "MyWish"
Server -> Client: "YourStuff"

Termination:
Client -> Server: "Done"
Server -> Client: "GoAway"

Error:
Server -> Client: "Not expected"

This client uses proper message framing with newline ('\\n') as a
delimiter. This makes the client robust against TCP's stream nature,
where recv() may split a single send() across multiple recv() calls
or coalesce multiple sends into one recv().

Framing rule:
    Every message ends with a single newline ('\\n'). The newline is
    *not* part of the application-level message -- it only marks where
    one message ends and the next begins. Messages must therefore not
    contain newlines themselves.


'''
import socket

HOST = "127.0.0.1"
PORT = 1337


def recv_message(sock, buffer):
    """Return (message, new_buffer). message is None if the peer closed.

    TCP is a byte stream, so a single recv() may give us only part of a
    message or several messages concatenated. We therefore keep reading
    until the buffer contains a '\\n', then split off exactly one message
    and keep the rest in the buffer for the next call.
    """
    while b"\n" not in buffer:
        chunk = sock.recv(4096)
        if not chunk:
            return None, buffer
        buffer += chunk
    line, buffer = buffer.split(b"\n", 1)
    return line.decode("utf-8"), buffer


def send_message(sock, msg):
    """Send one message, automatically appending the framing newline."""
    sock.sendall(msg.encode("utf-8") + b"\n")


if __name__ == '__main__':
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((HOST, PORT))
    buffer = b""

    try:
        # Handshake
        send_message(sock, "Gday to you")
        answer, buffer = recv_message(sock, buffer)
        if answer != 'mkay':
            raise SystemExit(f"Handshake failed, got: {answer!r}")

        # Data exchange setup
        send_message(sock, "MyWish")
        answer, buffer = recv_message(sock, buffer)
        if answer != 'YourStuff':
            raise SystemExit(f"Data exchange failed, got: {answer!r}")

        # Interactive loop
        while True:
            print("Ready to send data")
            msg = input("message: ")

            if msg == "exit":
                send_message(sock, "Done")
                answer, buffer = recv_message(sock, buffer)
                if answer == 'GoAway':
                    print("Connection closed successfully")
                break

            # User input must not contain a newline -- that would break
            # framing. input() already strips the trailing '\n'.
            send_message(sock, msg)
            answer, buffer = recv_message(sock, buffer)
            print(answer)
    finally:
        sock.close()
