#!/usr/bin/env python

import os, sys, re, readline
from tools import getConnectionCursor, inquireDB, escNT, get_dbstr
#from fillall import fillWith, fillBatch
from filldbs import fillWith, fillBatch
import filldbs

exec get_dbstr()

#fillAllMain(fn, cur=None)

def help(cmd=None, *tp, **kw):
	if cmd: cmd=cmd.strip()
	HLP = {
		'quit' : 'Quit the shell',
		'exit' : 'Quit the shell',
		'display' : '''Show the results of the most recent inquiry. \nUsage: \n\tdisplay;''',
		"saveto" : '''Save results of the most recent inquiry to a data file (result.txt). \nUsage: \n\tsaveto <result_filename>;''',
		"fillwith" : '''Input data of one project into database.\nUsage: \n\tfillwith <input_filename>;''',
		"fillbatch" : '''Input data of a batch of projects into database. Usually more forms should be supplied in the input file than that for the command "fillwith".\nUsage: \n\tfillbatch <input_filename>;'''
		}
	if not cmd:
		keys = HLP.keys()
		keys.sort()
		print '''Some commands was implemented (see below) facilitate data access. Some SQL commands, including "SELECT" and "SHOW" can be used too. Commands should be ended up with semi-comma - ";", or followed by a blank line.\n\n"help" usage: \n\thelp [<a_command_name>]; \n\nCommands with help information include: \n\t%s''' % ', '.join(keys)
	else:
		print cmd, '\n\t' + HLP.get(cmd, 'Not supported command or SQL command')
	print

def exit(*tp, **kw):
	print
	sys.exit(0)

def display(param, cur):
	#saveto(sys.stdout, cur)
	#print
	
	#import pprint
	def adjustLine(line, wid):
		line = map(lambda a:a[0].ljust(a[1]), zip(line, wid))
		return '| ' + ' | '.join(line) + ' |'
	def sepLine(wid):
		line = map(lambda a:'-'*a, wid)
		return '+-' + '-+-'.join(line) + '-+'
	rlt = [map(lambda a:a[0], cur.description)]
	if not rlt: return
	#for line in cur.fetchall(): rlt.append(map(lambda a:str(escNT(a)), line))
	for i in range(cur.rowcount): rlt.append(map(lambda a:str(escNT(a)), cur.fetchone()))
	ncol = len(rlt[0])
	wid = [0] * ncol
	for i in range(ncol):
		wid[i] = max(map(lambda a:len(a), map(lambda b:b[i], rlt)))
	print sepLine(wid) #'-'*(sum(wid) + (ncol-1)*3 + 4)
	print adjustLine(rlt[0], wid)
	print sepLine(wid) #'-'*(sum(wid) + (ncol-1)*3 + 4)
	if len(rlt) > 1:
		for line in rlt[1:]: print adjustLine(line, wid)
		print sepLine(wid) #'-'*(sum(wid) + (ncol-1)*3 + 4)
	#pprint.pprint(rlt)
	print

def saveto(fn, cur):
	if type(fn) == type(''): f = file(fn, 'w')
	else: f = fn
	# write column names first
	print >> f, '\t'.join(map(lambda a:a[0], cur.description))
	# write data
	#for line in cur.fetchall(): print >> f, '\t'.join(map(lambda a:str(escNT(a)), line))
	for i in range(cur.rowcount): print >> f, '\t'.join(map(lambda a:str(escNT(a)), cur.fetchone()))
	
	if fn is not f: print fn, 'saved.'

#end_str = re.compile(r'(.*);\s*\Z') # end by ;. use match and groups()[0]
end_str = re.compile(r'((.*);)?\s*\Z') # end by ; or blank line. use match and groups()[1]
cmd_str = re.compile(r'^([a-zA-Z]+)($|\s+.*)')
cmd_dic = {'help':help, 'quit':exit, 'exit':exit, 'display':display, 'saveto':saveto, 'fillwith':fillWith, 'fillbatch':fillBatch}
cmds_need_param = {'saveto':True, 'fillwith':True, 'fillbatch':True}

cmd_valid = cmd_dic.keys()
cmd_valid.extend(['select', 'show'])
ps1 = '%s-> ' % db
ps2 = '%s-> ' % (' '*len(db))

def Shell():
	dbcon, cur = getConnectionCursor()
	while True:
		lines = []
		try:
			line = raw_input(ps1).strip()
			#lines.append(line)
			while not end_str.match(line):
				lines.append(line)
				line = raw_input(ps2).strip()
			else:
				rlt = end_str.match(line)
				m = rlt.groups()[1]
				if m: lines.append(m)
		except EOFError:
			#print 
			#sys.exit(0)
			exit()
		
		#cmds = cmd_str.findall(line)
		line = ' '.join(lines).strip()
		cmds = cmd_str.findall(line)
		if not cmds: continue
			
		cmd = cmds[0][0].strip().lower()
		param = cmds[0][1].strip()
		fun = cmd_dic.get(cmd, None)
		if fun: 
			if cmds_need_param.get(cmd, False) and not param:
				print "%s need a parameter\n" % cmd
				continue
			try:
				fun(param, cur)
			except:
				traceback.print_exc()
		else: # try is as SQL statement
			try: 
				n = inquireDB(line, cursor=cur)
				fetched = False
				print n, 'rows found. Use command "display;" to show them or "saveto <filename>;" to save them.\n'
			except:
				if cmd not in cmd_valid: print 'ERROR: Invalid command!\n'
				else: print 'ERROR: failed in the SQL inquery.'
			if re.match(r'\s*use\s+\S+', line, re.I): # change CUR_DB
				cur_db = inquireDB('SELECT DATABASE()', cursor=cur, fetch=TRUE)
				if cur_db: 
					filldbs.CUR_DB = cur_db[0][0]
	
if __name__ == '__main__': Shell()	
