
##############################################################################
#engine
##############################################################################
import sys,time,getpass,threading,Queue

def _prtn(begin='',slp=0.1,cols=80):
    '''
    minimalist threaded user interface
    return potter function
    usage:
    potter(["hello"]) ->print hello
    potter([[]])
    '''
    def clr():
        for i in range(cols):
            sys.stdout.write('\b \b')
    def prtn(msg):
        assert isinstance(msg,str), 'string only'
        clr()
        sys.stdout.write(msg.replace('\n',' ').replace('\r',''))
        sys.stdout.flush()
    q = Queue.Queue()
    def getter():
        if not q.empty():
            r = q.get(False)
        else:
            r = []
        return r
    def potter(msg):
        q.put(msg,False)
    def loop(slp):
        framelst = begin
        while True:
            msg = getter()
            if isinstance(msg,list) and msg:
                framelst = msg
            if framelst:
		frame = framelst[0]
		framelst = framelst[1:]+[framelst[0]]
		if not frame:
        	#animation can be stoped by using null
			framelst = [framelst[-1]]
		elif isinstance(frame,str):
			#each frame are cycled
			prtn(frame)
			time.sleep(slp)
		elif isinstance(frame,float):
			#can change timing live
			slp = frame
		elif isinstance(frame,list):
			#can build a multiline static header
			clr()          #clear current anim
			for l in frame:
			    print(l)
			#display it only once so delete them when encountered
			framelst.remove(frame)
		else:
			pass
    t = threading.Thread(target=loop,args=(slp,))
    t.setDaemon(True)
    t.start()
    return potter

def _npt():
	'''
	minimalist threaded silent user input
	with timeout
    return getter function
    usage:
    getter() -> block until user press enter, then return the result
    getter(1.5) -> wait 1.5 sec for the user to press entre , then return 'timeout' or result
	'''
	q = Queue.Queue()
	def getter(timeout=-1):
		try:
			ret = q.get(True,timeout)
		except:
			ret = 'timeout'
		return ret
	def loop():
		while True:
			msg = getpass.getpass('')
			if msg:
				q.put(msg,False)
	t = threading.Thread(target=loop,args=())
	t.setDaemon(True)
	t.start()
	return getter

potter = _prtn()
getter = _npt()

def wait(milli=1):
    time.sleep(milli)

def co(fn,payload={},potter=potter,getter=getter):
    assert hasattr(fn,'__call__')
    while hasattr(fn,'__call__'):
        fn,payload = fn(payload,potter,getter)
    return payload

def bot(fn,payload={}):
    '''
    co(loop) in a thread connected by using queue
    '''
    iq = Queue.Queue()
    oq = Queue.Queue()
    def potter(msg):
        q.put(msg,False)
    def getter(timeout=-1):
	try:
        	ret = q.get(timeout)
	except:
		ret = 'timeout'
	return ret
    def loop():
        while True:
            payload = fn(payload,potter,getter)
        payload
    t = threading.Thread(target=loop,args=(slp,))
    t.setDaemon(True)
    t.start()
    #will return something that will enable communication with the bot

##############################################################################
#test
##############################################################################

def test():
    anim1 = ['B==D /-:',
             'B==D p-:',
             'B==D q-:',
             'B==D d-:',
             'B==D ():',
             ' B==D():',
             '  B==D):',
             '   B==);',
             '    B=)=',
             '   B==):',
             ' B==D():',
             'B==D~():']
    anim2 = [0.1,
             '/ ',
             '- ~',
             '\\  ~',
             1.0,
             '|   ~',
             ['  \\',
              '===>',
              '  /'
             ]]
    pot = potter
    get = getter
    def lp(payload,pot,get):
        pot(anim2)
        if 'q' in get():
            return
        return test,payload
    co(lp,pot,get)

##############################################################################
#
##############################################################################

'''
there is only one ploter
but many coroutine

'''
def flipthetable(payload,potter,getter):
	if not payload:
		payload = {
			'damagePerTable' : 10.0,
			'damageSoFar' : 0.0,
			'tableFliped' : 0,
			'napLvl' : 0,
			'napPrice' : 10.0
		}
	anim =  [
            ['']*50,	
	    [
		'Flip the Table!!!',
		'Fliped %s table for %s$ of damage'%(payload['tableFliped'],payload['damageSoFar']),
		'[q]uit',
		'buy a [n]ap lvl %s %s' % (payload['napLvl'],payload['napPrice'])
	    ],
            '(o_o) TT   ',0.9,
	    '(-_-) TT   ',0.2,
	    '(o_o) TT   ',0.3,
	    '/^o^)/ TT  ',0.1,
	    '/o_o)/  =| ',0.3,
	    '(o_o)_   L|',0.9,
	]

	potter(anim)
	cmd = getter(2.0).strip()
	if not cmd:
		return flipthetable,payload
	elif cmd == 'timeout':
		payload['tableFliped'] = payload['tableFliped'] + 1 
		payload['damageSoFar'] = payload['damageSoFar'] + payload['damagePerTable']
                
		return flipthetable,payload
	elif cmd[0] == 'q':
		return None,payload
	elif cmd[0] == 'n':
		return flipthetable,payload
	return flipthetable,payload

##############################################################################
#main
##############################################################################

if __name__ == '__main__':
    #test()
    co(flipthetable)
    '''
    c = ''
    while c!='q':
        c = getter(1)
        print (c)
    '''
