#!/usr/bin/env python2

###
#    Copyright (c) 2015 Timothy Savannah <kata198@gmail.com> LGPL v2.1
#    See LICENSE for more information, or https://gnu.org/licenses/old-licenses/lgpl-2.1.txt
###


import select
import socket
import sys
import threading
import time

try:
    from queue import Queue, Empty as QueueEmpty
except ImportError:
    from Queue import Queue, Empty as QueueEmpty


from socket_gatekeeper.GatekeeperSocket import GatekeeperSocket

from socket_gatekeeper.utils import closeSocket

def printUsage():
    sys.stderr.write('''Usage: %s Addr:port

Connects to a gatekeeper socket. This is basically the same as telnetting to the socket, except it will not echo the password
back on the screen, so this is more secure.

''' %(sys.argv[0], )
    )

def errorUsageAndExit(msg):
    sys.stderr.write(msg)
    sys.stderr.write('\n\n')
    time.sleep(1.5)
    printUsage()
    sys.exit(1)

if __name__ == '__main__':
    if len(sys.argv) != 2 or '--help' in sys.argv:
        printUsage()
        sys.exit(1)

    addrSplit = sys.argv[1].split(':')
    if len(addrSplit) != 2 or addrSplit[1].isdigit() is False:
        sys.stderr.write('Address must be in the form of addr:port. Example: 127.0.0.1:50001\n')
        sys.exit(1)


    sock = GatekeeperSocket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect( (addrSplit[0], int(addrSplit[1])) )
    except socket.error:
        sys.stderr.write('Failed to connect to %s\n' %(sys.argv[1],))
        sys.exit(1)


    sock.doAuthenticationFromInput()

    dataQueue = Queue()

    def readInput():
        while True:
            nextData = sys.stdin.readline()
            dataQueue.put(nextData)


    thread = threading.Thread(target=readInput)
    thread.daemon = True
    thread.start()

    hasError = False
    nextData = None
    while True:
        waitingToWrite = []

        if nextData is None:
            try:
                nextData = dataQueue.get(False)
            except QueueEmpty:
                pass

        if nextData:
            waitingToWrite.append(sock)

        (hasDataForRead, readyForWrite, hasError) = select.select( [sock], waitingToWrite, [sock], .1)
        if hasError:
            break

        if sock in hasDataForRead:
            data = sock.recv(4096)
            if not data:
                break
            sys.stdout.write(data)
            sys.stdout.flush()

        if sock in readyForWrite:
            sock.send(nextData)
            dataQueue.task_done()
            nextData = None

    if hasError:
        sys.stderr.write('Connection closed.\n')

    closeSocket(sock)
    thread.join(.1)
    sys.exit(int(bool(hasError)))
# vim: ts=4 sw=4 expandtab
