#!/usr/bin/env python2.4

"""
Interactive interpreter for calling CTL components
Copyright 2006 Boris Buegling <boris@icculus.org>
"""

import os, re, sys
from jpype import JPackage
from PyCTL import CTL, javaSys, L, NCLib, ReflWrap

def findCIs ():
	dummy, res = L.Object(), []
	for cls in NCLib.Classes.getClasses('javaSys').toArray():
		try:
			cls(dummy)
			res.append(cls.__javaclassname__)
		except RuntimeError:
			pass
	return res

def findMethod (methods, name):
	for method in methods:
		if str(method.name()) == name:
			return method

def listMethods (fqcn):
	pkg, clname = splitFQCN(fqcn)
	cinfo = ReflWrap.ClassInfo(str(fqcn))
	return [ReflWrap.MethodInfo(method) for method in cinfo.meth_here()]

def listParams (method):
	params = re.sub(r' arg[0-9]', '', str(method.paramsToString())[:-1]).split(', ')
	return [param for param in params if not param == '']

def methodCall (clname, method, args):
	args = ', '.join([str(arg) for arg in args])
	loc = CTL.Types.Location.parseFile('../locs.txt')
	proc = CTL.Process(loc[0])
	code = """%s.use(proc)
foo = %s()
res = foo.%s(%s)
L.System.out.println("Calling %s.%s(%s): "+str(res))
""" %(clname, clname, method, args, clname, method, args)
	code = compile(code, '<STRING>', 'exec')
	try:
		exec(code)
		if __batch:
			print >>sys.stderr, res
	except Exception, err:
		if __batch:
			sys.exit(2)
		print >>sys.stderr, err
	proc.stopService()

def splitFQCN (fqcn):
	pkg 	= '.'.join(fqcn.split('.')[:-1])
	clname	= str(fqcn.split('.')[-1])
	pkg		= JPackage(pkg)
	return pkg, clname

# TODO: Possibly check argument types here
def selectArgs (method):
	print
	args = []
	for arg in listParams(method):
		print '\t%s parameter: ' % arg,
		tmp = sys.stdin.readline()[:-1]
		args.append(tmp)
	print
	return args

def selectCI ():
	CIs = findCIs()
	CIs.sort()
	print 'Available CIs:\n\t%s\nSelect one: ' % '\n\t'.join(CIs),
	CI = sys.stdin.readline()[:-1]
	if not CI in CIs:
		print >>sys.stderr, '%s: No such CI.' % CI
		sys.exit(1)
	return CI

def selectMethod (CI):
	pkg, clname = splitFQCN(CI)
	base = CTL.RUtil.getBase(CI)
	methods = listMethods(base)
	print '\nAvailable methods:\n\t%s\nSelect one: ' % \
		'\n\t'.join([str(method) for method in methods]),
	meth = sys.stdin.readline()[:-1]
	if not meth in [str(method.name()) for method in methods]:
		print >>sys.stderr, '%s: No such method.' % meth
		sys.exit(1)
	return findMethod(methods, meth)

def no_stdout ():
	devnull = file('/dev/null', 'w+')
	os.dup2(devnull.fileno(), 1)

__batch = False
__debug = False

if __name__ == '__main__':
	if len(sys.argv) > 1:
		__batch = True
		no_stdout()
		arg = sys.argv[1].split('.')
		CI = '.'.join(arg[:-1])
		method = findMethod(listMethods(CTL.RUtil.getBase(CI)), arg[-1].split('(')[0])
		args = arg[-1].split('(')[1][:-1].split(', ')
	else:
		if __debug:
			CI = 'javaSys.CTestCI'
			method = findMethod(listMethods(CTL.RUtil.getBase(CI)), "add")
			args = [3, 4]
		else:
			CI = selectCI()
			method = selectMethod(CI)
			args = selectArgs(method)
	
	methodCall(CI, method.name(), args)
