#!/usr/bin/env python

import socket
import os
import readline
import atexit
import random
import signal
import errno

histfile = os.path.join(os.path.expanduser("~"), ".controller")
try: readline.read_history_file(histfile)
except IOError: pass
readline.parse_and_bind('tab: complete')
def complete(commands, text, state):
    matches = []
    if state == 0: matches = [ c for c in commands if c.startswith(text) ]
    return matches[state] if state < len(matches) else None
readline.set_completer(lambda text, state: complete(['more_pigeon_please', 'less_pigeon_please', 'solve', 'exit'], text, state))
atexit.register(readline.write_history_file, histfile)

def handleMessages(conn):
    def interrupt(conn):
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        conn.sendall("interrupt\n")
    signal.signal(signal.SIGINT, lambda a, b: interrupt(conn))
    data = bytearray()
    while True:
        while True:
            try: data.extend(conn.recv(4096))
            except socket.error as (code, msg):
                if code != errno.EINTR: raise
            else: break
        pos = data.find("\n")
        while pos >= 0:
            (msg, data) = data.split("\n", 1)
            if msg.startswith("finish:"):
                msg = msg.split(":")
                print(msg[1] + (" (interrupted)" if len(msg) > 2 else ""))
                return
            elif msg.startswith("Answer:"):
                print(msg)
                pos = data.find("\n")
    signal.signal(signal.SIGINT, signal.SIG_IGN)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    for i in range(0,10):
        try:
            p = random.randrange(1000, 60000)
            s.bind(("", p))
        except socket.error as (code, msg):
            if code != errno.EADDRINUSE: raise
            continue
        else:
            with open(".controller.PORT", "w") as f: f.write(str(p))
            print "waiting for connections..."
            break
        raise "no port found"
    s.listen(1)
    conn, addr = s.accept()
    print
    print "this prompt accepts the following commands:"
    print "  solve              - start solving"
    print "  exit/EOF           - terminate the solver"
    print "  Ctrl-C             - interrupt current search"
    print "  less_pigeon_please - select an easy problem"
    print "  more_pigeon_please - select a difficult problem"
    print

    pyInt = signal.getsignal(signal.SIGINT)
    while True:
        signal.signal(signal.SIGINT, pyInt)
        try:
            line = raw_input('> ')
            signal.signal(signal.SIGINT, signal.SIG_IGN)
        except EOFError:
            signal.signal(signal.SIGINT, signal.SIG_IGN)
            line = "exit"
            print line
        except KeyboardInterrupt:
            signal.signal(signal.SIGINT, signal.SIG_IGN)
            print
            continue
        if line == "solve":
            conn.sendall("solve\n")
            handleMessages(conn)
        elif line == "exit":
            conn.sendall("exit\n")
            break
        elif line in ["less_pigeon_please", "more_pigeon_please"]:
            conn.sendall(line + "\n")
        else:
            print "unknown command: " + line
except KeyboardInterrupt:
    raise
finally:
    s.close()

