#!/usr/bin/env python

import sys, os, cgi, re, string, types, sets #, tempfile

import cgitb; cgitb.enable(display=0, logdir='/tmp')

from cgitools import *
#home_dir = '/home/xxia/public_html' # user data will based on this dir
#users_relative_dir = "users"
#users_dir = os.path.join(home_dir, users_relative_dir)
#R_code_dir = 'R_code' # under cgi-bin

# Retrieve data from user
form = cgi.FieldStorage()

monoVars = {'search_type':1, 'user_equ':1, 'dbname':1, 'tbname':1, 'fixcols':1}
requiredVars = {} # these key names should be offered at least once, values are used for error msg

op_dict = {'=':'%s.%s = %s', '>':'%s.%s > %s', '<':'%s.%s < %s', '>=':'%s.%s >= %s', '<=':'%s.%s <= %s', '!=':'%s.%s != %s',
	'equal to':'%s.%s = "%s"', 'start with':'%s.%s like "%s%%"', 'end with':'%s.%s like "%%%s"', 'contain':'%s.%s like "%%%s%%"',
	'is':'%s.%s = "%s"', 'before':'%s.%s < "%s"', 'after':'%s.%s > "%s"', 'no later than':'%s.%s <= "%s"', 'no earlier than':'%s.%s >= "%s"'
	}

pages = {'project':'dbs_browse_prj.pih', 'array':'dbs_browse_array.pih', 'sample':'dbs_browse_samp.pih', 'protocol':'dbs_browse_prot.pih', 'platform':'dbs_browse_pf.pih', 'probe':'dbs_browse_probe.pih'}

# put all data into a dict
page_values = {}
for k in form.keys():
	v = form.getvalue(k) #form[k] 
	if type(v) == types.ListType or monoVars.has_key(k): page_values[k] = v
	else: page_values[k] = [v.strip()]

################ validation ##################
err_msg = []

def goBack(s=None):
	if s: err_msg.append(s)
	err_msg.append('<p><input type="button" value="Go back" onClick="javascript:history.go(-1)"/></p>')
	exitWithInfo('<br>'.join(err_msg))

# check required named first
for k,webname in requiredVars.items():
	if not page_values[k]: err_msg.append('%s should be offered!' % webname)

if 'colname' not in page_values or 'op' not in page_values or 'val' not in page_values: goBack('No criteria offered, please correct it!')
cols, ops, vals = page_values['colname'], page_values['op'], page_values['val']
search_type, equ = page_values['search_type'], page_values['user_equ']
cur_db, cur_tb = page_values['dbname'], page_values['tbname']
fixcols = eval(decodeStr(page_values['fixcols']))
# convert tuple to string
fixcols = map(lambda a:((type(a) is types.StringType) and [a] or a)[0], fixcols)
fixcols = dict(zip(fixcols, [1]*len(fixcols)))

tbalias_dict = {'array':'a', 'project':'p', 'platform':'pf', 'protocol':'pr', 'sample':'s', 'dyncol':'d', 'dyncoldef':'dcf', 'keyword':'k', 'probe':'pb', 'dbkw':'dk', 'dbxref':'dx'}
tbalias, tbd, tbdf, tbk, tbdk, tbdx = tbalias_dict[cur_tb], tbalias_dict['dyncol'], tbalias_dict['dyncoldef'], tbalias_dict['keyword'], tbalias_dict['dbkw'], tbalias_dict['dbxref']
pih_vars = {'cur_db':cur_db, 'cur_tb':cur_tb, 'tbalias':tbalias_dict}

if search_type != 'user_mode': # in ('any', 'all'). 
	# remove rows with empty items
	for i in range(len(ops)-1, -1, -1):
		if not cols[i].strip() or not ops[i].strip() or not vals[i].strip():
			cols.pop(i)
			ops.pop(i)
			vals.pop(i)
if not cols: goBack('No valid criteria offered!')

col_type = dict(inquireDB('SELECT col_name, col_type FROM %s.dyncoldef WHERE tb_name="%s"' % (cur_db, cur_tb), fetch=True))
tp_col = {'int':'value_int', 'float':'value_float', 'string':'value_str'}
DYNCOL = False
KEYWORD = False
OTHERDB = False
def mapCond(i, f=fixcols, c=cols, v=vals, op=ops, od=op_dict, tb=tbalias, tbd=tbd, tbk=tbk, tbdf=tbdf, tp_col=tp_col):
	if not c[i] or not op[i] or not v[i]: return ''
	if f.has_key(c[i]): # search in cur_tb
		return od[op[i]] % (tb, c[i], v[i])
	elif c[i] == 'keyword': # search in keyword
		global KEYWORD
		if not KEYWORD: KEYWORD = True
		return '%s AND %s' % ('%s.tb_name="%s" AND %s.rec_id=%s.id' % (tbk, cur_tb, tbk, tbalias), od[op[i]] % (tbk, 'kw', v[i]))
		return od[op[i]] % (tbk, 'kw', v[i])
	elif cur_tb == 'probe': # search in dbkw
		global OTHERDB
		if not OTHERDB: OTHERDB = True
		return '%s AND %s' % ('%s.id=%s.dbkw_id AND %s.probe_id=%s.id' % (tbdk, tbdx, tbdx, tbalias), od[op[i]] % (tbdk, 'kw', v[i]))
		return od[op[i]] % (tbdk, 'kw', v[i])
	else: # should search in dyncols
		global DYNCOL
		if not DYNCOL: DYNCOL = True
		cnd = od[op[i]] % (tbd, tp_col[col_type[c[i]]], v[i])
		cnd = '%s.col_name="%s" AND %s' % (tbdf, c[i], cnd)
		return '%s AND %s' % ('%s.id=%s.col_id AND %s.tb_name="%s" AND %s.rec_id=%s.id' % (tbdf, tbd, tbdf, cur_tb, tbd, tbalias), cnd)
		return cnd

if search_type != 'user_mode': 
	#conds = map(lambda i:op_dict[ops[i]] % (tbalias, cols[i], vals[i]), range(len(cols)))
	conds = map(mapCond, range(len(cols)))
	conds = filter(lambda a:a, conds)
	if conds:
		if search_type == 'all': conds = ' AND '.join(conds)
		else: conds = ' OR '.join(conds) # search_type should be 'any'
	else: goBack('No valid criteria offered!')
else: # for user defined mode
	if not equ: goBack('No search mode offered!')
	items = map(lambda a:int(a), re.findall(r'\d+', equ) )
	if not items: goBack('Mode is invalid!')
	#items.sort()
	#if items[-1] > len(cols): goBack('Mode in invalid!')
	if max(items) > len(cols): goBack('Mode is invalid!')
	# make conditions
	item_set = sets.Set(items)
	conds = {}
	err_conds = []
	for i in item_set:
		if not cols[i-1].strip() or not ops[i-1].strip() or not vals[i-1].strip(): goBack('No valid criteria offered for user-defined mode!')
		#conds[i] = op_dict[ops[i-1]] % (tbalias, cols[i-1], vals[i-1])
		cond = mapCond(i-1)
		if not cond: err_conds.append(str(i))
		else: conds[i] = cond
	if err_conds: goBack('Criteria (%s) are invalid!' % ','.join(err_conds))
	conds = tuple(map(lambda a:conds[a], items))
	conds = re.sub(r'\d+', '%s', equ) % conds

if err_msg: goBack()

pih_vars['conditions'] = ['( %s )' % conds]
if DYNCOL:
	#pih_vars['conditions'].insert(0, '%s.id=%s.col_id AND %s.tb_name="%s" AND %s.rec_id=%s.id' % (tbdf, tbd, tbdf, cur_tb, tbd, tbalias) )
	pih_vars['dyn_tb'] = ', %s.dyncoldef %s, %s.dyncol %s' % (cur_db, tbdf, cur_db, tbd)
if KEYWORD:
	#pih_vars['conditions'].insert(0, '%s.tb_name="%s" AND %s.rec_id=%s.id' % (tbk, cur_tb, tbk, tbalias) )
	pih_vars['dyn_tb'] = '%s, %s.keyword %s' % (pih_vars.get('dyn_tb', ''), cur_db, tbk)
if OTHERDB:
	#pih_vars['conditions'].insert(0, '%s.id=%s.dbkw_id AND %s.probe_id=%s.id' % (tbdk, tbdx, tbdx, tbalias) )
	pih_vars['dyn_tb'] = '%s, %s.dbxref %s, %s.dbkw %s' % (pih_vars.get('dyn_tb', ''), cur_db, tbdx, cur_db, tbdk)

if False and (DYNCOL or KEYWORD or OTHERDB): pih_vars['conditions'] = '( %s )' % ' AND '.join(pih_vars['conditions'])
else: pih_vars['conditions'] = pih_vars['conditions'][0]

saveEvent(user_id=username, ev_catcode="search", ev_valstr='%s::%s' % (cur_db, cur_tb))

print cgi_token

from PythonInsideHTML import PIH
exec PIH('%s/pages/%s' % (script_path_file, pages[cur_tb])).pythonCode()
#page = '%s/pages/%s' % (script_path_file, pages[cur_tb])
#open('tmpfile.py', 'w').write(PIH(page).pythonCode())
#execfile('tmpfile.py')

#tellDaemon('New requests')

