#!/usr/bin/env python
# IMPORTANT: the parameter (variable) names used in the web pages should be consistent to those used in Python and R.
# the above line is not need now, since a name map is used.

import sys, os, cgi, re, string #, tempfile
import tools

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

error_msg = []

src_params = { # use '.' instead of '_' in this dict since the related R scipt use '.'
	#'Final.Chart.Title' : "Final_Results_Plot.png",
	#'PrintTip.Chart.Title' : "PrintTip_Plot_PrintTip_Norm.png",
	#'Scale.Chart.Title' : "Box_Plot_Scale_Norm.png",
	#'Array.Chart.Title' : "Array_Image_Plot.png",
	#'result.data.file' : "output.txt",
	
	#'result.norm.data' = "output.normalized.data.txt",
	#'result.analyzed.data' = "output.analyzed.data.txt",
	
	'graphDir' : os.path.join("ResultsData_Output", "Results_Charts") + os.sep, #note the tailing "/" !  '/' is required by webPNG from CGIwithR
	'raw.data.dir' : data_subdirs['intensity']['name_full'],
	'result.data.dir' : "ResultsData_Output",
	'chart.dir' : os.path.join("ResultsData_Output", "Results_Charts"),
	
	'design.file' : '',
	'gal.file.name' : '',
	'location.file' : '',
	'targets.file' : '',
	'spot.types.files' : '',
	'controlspots' : "",
	'sample.info.file' : '', # didn't used

	'Num.of.Dup' : 1,
	'gal' : 'GAL',
	'design.ch1' : [],
	'design.ch2' : [],
	'design.ref' : False,
	'simple.design' : True, # special: should be determined by design file
	'contrast.design' : [], # special: need to be tranformed from string to a list
	
	#'normal.method' : "print-tip lowess",
	'work.dir' : os.curdir,
	'script.dir' :  os.path.join(script_path_file, R_code_dir),
	'path.sep' : os.sep,
	
	'use.targets.file' : False, # special: should be determined by target file
	'slides' : [],
	
	'MA.File.Format' : "quantarray",
	'WithinArray.Nor' : "printtiploess", # should be 'print-tip lowess'?
	'BetweenArra.Nor' : "scale",
	#'tau' : 0.001,
	#'gamma' : 0.05,
	
	'BG.Sub' : True,  
	'wt.fun' : None,
	'wt.para' : 0, # special: should be calculated from wt_param.area or wt.param.flag
	'spot.types' : False, # special: should be determined by spot.types.files
	'analysis' : 'linear model analysis',
	'Output.Format' : "SpotID",
	
	'affy.method' : 'rma', 
	'affy.bg.correct' : True, 
	'affy.normalize.method' : 'constant', 
	'affy.pmcorrect.method' : 'pmonly', 
	'affy.summary.method' : 'avgdiff',
	
	'plot.analyzed.results' : True,
	'plot.affy.image' : True,
	'plot.affy.RNAdeg' : True,
	'plot.affy.boxplot' : True,
	'plot.affy.hist' : True,
	'plot.affy.MAplot' : True,
	'plot.affy.CGH' : True,
	'plot.pdf' : False,
	
	'genome.sorting' : True, # special: should be determined by location.file
	'genomes' : 'human',
	'genome.no' : 10,
	'span' : 0.8, 
	'chr.thre.1' : 1.8, 
	'chr.thre.2' : 0.001,
	'chr.lim.1' : 1.5, 
	'chr.lim.2' : 3,

	'pca.sig.level' : 0.025,
	'pca.ave.num' : 20,
	'req_name' : ''
	}

user_params = src_params.copy() # these params will be passed to R
form_params = {} # accept params from web users

#necessary_data = {'cannot be empty':['intensity_file', 'gal_file'], 'cannot be zero':[]}
necessary_data = {'cannot be empty':[], 'cannot be zero':[]}

# map name used by python to names in R, 
# the key is a name used by python, the value is the name used by R. 
# Names not included here will be simply use ('_' to '.') rules for translation

# Now this map is imported from cgitools
namemap = namemap_limma_linear
#namemap = {'intensity_file':'slides', 'gal_file':'gal.file.name', 'norm_in_array':'WithinArray.Nor',
#	'norm_bt_array':'BetweenArra.Nor', 'output_format':'Output.Format', 'bg_substraction':'BG.Sub',
#	'intensity_format':'MA.File.Format', 'replicates_in_array':'Num.of.Dup', 'ch1':'design.ch1', 'ch2':'design.ch2',
#	'contrast':'contrast.design'} 




# mkdir temp dir for users
#users_dir = home_dir+'users'
#user_dir = tempfile.mkdtemp( , , users_dir)
#user_id = os.path.basename(user_dir)

#user_id = tools.UniqueNameRand(prefix='', suffix='', dir=os.path.abspath(users_dir))
#user_dir = os.path.abspath(os.path.join(users_dir, user_id))
#user_relative_dir = os.path.join(users_relative_dir, user_id)
#os.mkdir(user_dir)

# Set default values
# transform relative path to absolute path, then create these paths

#for k in ['graphDir', 'work.dir', 'raw.data.dir', 'result.data.dir', 'chart.dir']:
#	user_params[k] = tmpdir = os.path.normpath(os.path.join(user_dir, user_params[k]))
#	if k == 'graphDir': user_params[k] = tmpdir+os.sep
#	if not os.path.exists(tmpdir): os.makedirs(tmpdir)

# Lists of parameters that should be offered by users
data_str2log = ['plot_pdf']
data_user_str = ['intensity_file', 'gal_file', 'spot_file', 'location_file', 'target_file', 'design_file',
		'ch1', 'ch2', 'intensity_format', 'gal_format', 'bg_substraction', 'wt_fun', 'contrast', 'controlspots',
		'analysis', 'output_format', 'norm_in_array', 'norm_bt_array', 'request_name', 'genomes', 
		'affy_method', 'affy_bg_correct', 'affy_normalize_method', 'affy_pmcorrect_method', 'affy_summary_method']
data_user_int = ['replicates_in_array', 'wt_param_area', 'genome_no', 'pca_ave_num']
data_user_float = ['tau', 'gamma', 'wt_param_flag', 'span', 'chr_thre_1', 'chr_thre_2', 'chr_lim_1', 'chr_lim_2', 'pca_sig_level']
#data_user_logic = ['Final_Chart', 'Array_Image_Plot', 'M_A_Plot', 'plot_density', 'Box_Plot', 'plot_printtiploess']
data_user_logic = ['plot_analyzed_results', 'plot_affy_image', 'plot_affy_MAplot', 'plot_affy_hist', 'plot_affy_boxplot', 'plot_affy_RNAdeg', 'plot_affy_CGH']
data_user_file = {
	# with format "file:info", and "info" is a dictionary with keys "need_entry", "location", etc.
	#'raw.data.files' : {'need_entry':0, 'location':user_params['raw.data.dir']}, 
	#'gal.file.name' : {'need_entry':1, 'location':user_params['work.dir']},
	#'sample.info.file' : {'need_entry':1, 'location':user_params['work.dir']}
	} 

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

#print "Content-type:text/html\n\n"
#print form

for name_html in data_str2log:
	if form.has_key(name_html):
		form_params[name_html] = form.getvalue(name_html).strip()!='no' and True or False

for name_html in data_user_str:
	if form.has_key(name_html): 
		a = form.getvalue(name_html)
		if type(a) == type(''): a = a.strip()
		else: # should be a seq
			a = map(lambda b:b.strip(), a)
		form_params[name_html] = a
for name_html in data_user_int:
	if form.has_key(name_html): form_params[name_html] = int(form.getvalue(name_html))

#print cgi_token
#print '<p>',form,'<p>'
for name_html in data_user_logic:
	if form.has_key(name_html):
		form_params[name_html] = True
		#v = form.getvalue(name_html).strip().lower()
		#if v == 'on': form_params[name_html] = True
		#else: form_params[name_html] = False
		#print name_html, ' ----------- ', form[name_html], '====', form_params[name_html]
	else: form_params[name_html] = False
for name_html in data_user_float:
	if form.has_key(name_html): 
		v = form.getvalue(name_html).strip()
		if v and v[-1]=='%': 
			form_params[name_html] = float(v[:-1])*0.01
		else:
			form_params[name_html] = float(v)
		#print '<br>', v, form_params[name_html]

for name_html, info in data_user_file.items(): # won't use this recently, need to revise if use
	if form.has_key(name_html):
		#files = form.getlist(name) # raw_data_files should have several files
		files = form[name_html]
		if type(files) != type([]): files = [files]
		for file in files:
			if not file.file or not file.value: continue
			filename = os.path.join(info["location"], file.filename)
			fp = open(filename, "wb")
			fp.write(file.value)
			fp.close()
			if info['need_entry']: form_params[name_html] = filename # microarray data file need no entry in this dictionary

# decide experiment design
data_filenames = form_params.get('intensity_file', []) # must be a list
ch1, ch2 = form_params.get('ch1', []), form_params.get('ch2', [])
#chs = [(fm1[i], fm2[i]) for i in range(len(data_filenames)) if data_filenames[i].strip()]
#design = tools.ExpDesign(chs)

# clean file data
a = range(len(data_filenames))
a.reverse()
for i in a:
	if not data_filenames[i]: 
		data_filenames.pop(i) # or del data_filenames[i]
		ch1.pop(i)
		#ch2.pop(i)
#chs = zip(ch1, ch2)
#design = tools.ExpDesign(chs)

# Check validation of form data here
reqname = form_params.get('request_name', '')
if not reqname: pass #error_msg.append('Error: no request name offered!<br>')
elif not re.match(r'^[a-zA-Z0-9_]+$', reqname): error_msg.append('Error: Invalid characters in the request name!<br>') 

if not form_params.get('intensity_file', '') and not form_params.get('target_file', ''): error_msg.append('Error: No intensity data offered!<br>')

if form_params.get('target_file', '') and not form_params.get('design_file', ''): error_msg.append('Error: no design file selected while using targets file!<br>')

#if form_params.get('intensity_format', '') == 'affy':
#	if form_params.get('norm_bt_array', '') not in ['none', 'quantile']: error_msg.append('Error: between-array normalization for Affymetrix data should be either "nNone" or "Quantile"!<br>')
#else:
#	if not form_params.get('gal_file', ''): error_msg.append('Error: a Gal file should be selected for non-Affymetrix data!<br>')


for tp, names in necessary_data.items():
	for name in names:
		if not form_params.get(name, None): error_msg.append(name + ' ' + tp + '!<br>')



######### pass params to user_params ###############

#if design.get('error_msg', None):
#	error_msg.append(design['error_msg'])
#else:
#	user_params['design'] = design['design']

for k in form_params.keys():
	kr = namemap.get(k, '') or k.replace('_', '.')
	if user_params.has_key(kr):
		user_params[kr] = form_params[k]

###### Special parameters.

contrast = form_params.get('contrast', '').strip()
if contrast: 
	##contrast = map(string.strip, contrast.split(','))
	#contrast = map(lambda a:map(string.strip, a.split('-')), contrast.split(','))
	contrast = map(string.strip, contrast.split(','))
	for i in contrast[:]: 
		if not i: contrast.remove(i)
	contrast_design = map(lambda a:map(string.strip, a.split('-')), contrast)
	user_params['contrast.design'] = contrast_design
else: contrast = []
user_params['contrast'] = contrast

#check data validation further
if user_params['analysis'] != 'normalization':
	# must have replicates
	ch1 = user_params.get('design.ch1', [])[:]
	ch1.sort()
	while ch1:
		n = ch1.count(ch1[0])
		if n == 1:
			error_msg.append('Sample (%s) have no replicate, analysis cannot be done!<br>' % ch1[0])
			#break
		ch1 = ch1[n:]
	# must offer contrast design
	if not user_params.get('contrast.design', None): error_msg.append('A contrast design must be offered for analysis!<br>')
	# contrast design must use names from ch1
	ch1 = user_params.get('design.ch1', [])[:]
	for nms in user_params.get('contrast.design', []):
		for nm in nms:
			if nm not in ch1: error_msg.append('The contrast design used unknown name (%s)!<br>' % nm)

if error_msg: 
	error_msg.append('<p><A href ="javascript:history.go(-1)" >Please correct it</a>')
	exitWithInfo('<br>'.join(error_msg))

# prepare necessary directories.
result_subdirs = prepareResultDirs(form_params.get('request_name', ''))

wtfun = form_params.get('wt_fun', '')
#if wtfun == 'none': user_params['wt.fun'] = None
if wtfun == 'spot': user_params['wt.para'] = form_params.get('wt_param_area', 150)
elif wtfun == 'genepix': user_params['wt.para'] = form_params.get('wt_param_flag', 0.1)

user_params['wt.param.area'] = form_params.get('wt_param_area', 150)
user_params['wt.param.flag'] = form_params.get('wt_param_flag', 150)

user_params['simple.design'] = (not user_params.get('design.file', '')) and True or False
user_params['design.ref'] = 'ref' in ch1#+ch2
user_params['use.targets.file'] = user_params.get('targets.file','') and True or False
user_params['spot.types'] = user_params.get('spot.types.files','') and True or False
user_params['genome.sorting'] = user_params.get('location.file','') and True or False

user_params['result.data.dir'] = result_subdirs['request']['name_full']
user_params['chart.dir'] = result_subdirs['chart']['name_full']
user_params['graphDir'] = os.path.join(user_params['chart.dir'], '') # add a tail '/'
user_params['req_name'] = os.path.basename(os.path.normpath(result_subdirs['request']['name_full']))
if user_params['design.file']: user_params['design.file'] = os.path.join(data_subdirs['design']['name_full'], user_params['design.file'])
if user_params['gal.file.name']: user_params['gal.file.name'] = os.path.join(data_subdirs['gal']['name_full'], user_params['gal.file.name'])
if user_params['location.file']: user_params['location.file'] = os.path.join(data_subdirs['location']['name_full'], user_params['location.file'])
if user_params['targets.file']: user_params['targets.file'] = os.path.join(data_subdirs['target']['name_full'], user_params['targets.file'])
if user_params['spot.types.files']: user_params['spot.types.files'] = os.path.join(data_subdirs['spot']['name_full'], user_params['spot.types.files'])
if user_params['controlspots']: user_params['controlspots'] = os.path.join(data_subdirs['composite']['name_full'], user_params['controlspots'])


#has_ref = None

#print cgi_token
#print 'Requests submitted!'
#sys.exit(0)

# for debug
#print cgi_token
#print form
#print '<p><p>'
#print user_params
#sys.exit(0)

req_type = TYPE_LINEAR_AFFY #TYPE_NORM_ANALYSIS
req_name = os.path.basename(os.path.normpath(result_subdirs['request']['name_full']))
n = saveReq(req_type, req_name, user_params, username)
#if n is False: exitMsg('An error ocurred when accessing database!')
if not n: 
	#exitMsg('An error ocurred when accessing database!<p><A href ="javascript:history.go(-1)" >Please correct it</a>')
	exitMsg('An error ocurred when accessing database!<p><input type="button" value="Go back" onClick="javascript:history.go(-1)"/></p>')

'''
# SAVE user_params to database
import cPickle, time
req_str = cPickle.dumps(user_params)
connection = connectDB()
cursor = connection.cursor()
sql_statement = 'SELECT id FROM users WHERE user_name="%s"' % username
n = cursor.execute(sql_statement)
if n < 1: # failed
	print cgi_token
	print "Error occurs when reading user database"
	cursor.close()
	connection.close()
	sys.exit(0)
user_id = cursor.fetchone()[0]
req_type = TYPE_NORM_ANALYSIS
date_time = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime())
req_name = os.path.basename(os.path.normpath(result_subdirs['request']['name_full']))
sql_statement = 'INSERT INTO requests (user_id, req_name, req_time, req_info, category) VALUES (%d, "%s", "%s", "%s", %d)' % (user_id, req_name, date_time, req_str, req_type)

n = cursor.execute(sql_statement)
cursor.close()
connection.close()
'''

tellDaemon('New requests')

import time
time.sleep(1)

print cgi_token

print '''<body onload=javascript:window.location.href="%s/ui/browse?page_type='webarray'"></body>''' % (script_path_url)
sys.exit(0)

#print '<body><iframe width=%s, height=%s frameborder=0 src="%s/ui/browse"</body>' % ('100%', '100%', script_path_url)
from PythonInsideHTML import PIH
exec PIH(script_path_file + '/pages/ui_browse.pih').pythonCode()
sys.exit(0)

print '<META HTTP-EQUIV="refresh" CONTENT="5;URL=%s">' % (script_path_url+'/ui/browse')
print '''
<script language=javascript>
<!--
function go() {location.href="%s";}
setTimeout("go();", 10000); // wait 10 seconds
//-->
</script>
<body bgcolor='white'>
''' % (script_path_url+'/ui/browse')
if n < 1: # failed
	print 'Error occurs when summit requests to database!'
else: 
	print 'Request ("%s") submitted!<p>Wait 5 seconds, or click <a href=%s >here</a> to visit the result page.' % (req_name, script_path_url+'/ui/browse')
	tellDaemon('New requests')

print '</body>'
#print form, '<p>form_params:<br>'
#for k,v in form_params.items(): print k, '----', v,'<br>'
#print '<p>user_params:<br>'
#for k,v in user_params.items(): print k, '----', v,'<br>'


