#!/usr/bin/python
import sys, os, socket, re
import glob, math, shutil
from glue import cbcwebpage
from glue import lal
from glue import segments
from optparse import OptionParser

from pylal import git_version
__author__ = "Chad Hanna <channa@ligo.caltech.edu>"
__version__ = "git id %s" % git_version.id
__date__ = git_version.date


def parse_command_line():
	parser = OptionParser(version = git_version.verbose_msg, usage = "%prog [options] [file ...]", description = "%prog summary web page")
	parser.add_option("--webserver-dir", help = "Set the directory for the webserver.  Required.  Example /archive/home/channa/public_html/highmass_months_23-24_summary_page")
	parser.add_option("--open-box", action = "store_true", help = "Produce open box page")
	parser.add_option("--output-name-tag",default = "", metavar = "name", help = "Set the basename for image search")

	opts, filenames = parser.parse_args()
	return opts, filenames

# PARSE THE COMMAND LINE
opts, files = parse_command_line()
base_name = opts.output_name_tag
search = base_name.replace('_',' ')

# INITIALIZE THE PAGE OBJECT
page = cbcwebpage.cbcpage(title="Summary " + search )

# WELCOME MESSAGE PAGE
page.front = "<big>Welcome</big><br><br>This page was generated by the post_process_pipe dag by doing <br><pre>"
page.front += "".join(open("hm_post.log").readlines())
#page.front += " ".join(sys.argv)
page.front += "</pre><br><br>"
page.front += "The actual webpage command is<br><br<pre>"
page.front += " ".join(sys.argv)
#page.front += "".join(open("hm_post.log").readlines())
page.front += "</pre><br><br>"

### Summary info. 
page.add_subpage("summary", "Summary information", "Summary information")
page.subpages["summary"].div("""
Summary information
""")
tab, name = cbcwebpage.wiki_table_parse(base_name+'num_trigs_table.txt')
page.subpages["summary"].add_table(tab[0], "This is a summary table", "This is a summary table")


### Bank, Range and Triggers page 
page.add_subpage("bank_range_triggers", "Template bank, inspiral range and single inspiral triggers", "Bank, Range, Inspiral Triggers")
page.subpages["bank_range_triggers"].div("""
<big><b>OVERVIEW:</b></big><br><br>
This page summarizes the template bank, inspiral triggers and range of the analysis.  
""")
# Template bank plots
page.subpages["bank_range_triggers"].add_section("bank", "Template Bank Plots")
page.subpages["bank_range_triggers"].sections["bank"].div("""
In order to decide how to filter the data for the signals in question a bank of matched filter templates
is created such that any signal falling between two templates would have some maximum value of SNR loss.
Typically this value is 3-5%.  The SNR loss between two signals depends on the properties of the noise
since the matched fitler integral uses the PSD.  Therefore the decision about what filters to use is a 
function of time.  <br><br>  The ihope pipeline is slightly more complicated because of its two stage 
nature.  There is a second filtering stage that uses as its template bank the triggers which were found in
coincidence after the first inspiral stage.  
""")
imgtable = cbcwebpage.image_glob("*_plot_num_sngl_inspiral_TMPLTBANK_FULL_DATA-TRIGBANK_SECOND__FULL_DATA.png")
page.subpages["bank_range_triggers"].sections["bank"].add_table(imgtable,"Template / Trig Bank vs time", "The above image displays the number of templates as a function of time for each of the detectors at the first and second bank stage.  Typically the number of templates increases if the PSD is flat.")
# Inspiral Range plots
page.subpages["bank_range_triggers"].add_section("range", "Inspiral Range")
page.subpages["bank_range_triggers"].sections["range"].div("""
The inspiral range is a marker of the detector sensitivity at a fixed SNR threshold.  It does not 
necessarily reflect the true sensitivity of the instruments since non-stationary noise can raise the
effective threshold at which signals can be detected.  The range is often computed for the standard
candle of a (1.4, 1.4) M<sub>Sun</sub> NS-NS binary.  Other mass pairs are often computed but can be 
misleading since as of yet the inspiral code does not integrate beyond the schwarzschild ISCO frequency
(thus neglecting power from the merger and ringdown, which is important for heavy systems).
""")
imgtable = cbcwebpage.image_glob("*_plot_tmpltbank_range_TMPLTBANK_FULL_DATA.png", width=720)
page.subpages["bank_range_triggers"].sections["range"].add_table(imgtable,"Inspiral Range", "The above images depict the inspiral range over the analysis time.  The leftmost figure shows the range for a NS-NS binary (1.4, 1.4) M<sub>Sun</sub> for each template bank job.  The middle plot shows a histogram representing the frequency of obtaining certain ranges to NS-NS binaries (a histogram of the data in the leftmost plot). The rightmost plot shows the mean and standard deviation of the inspiral ranges for equal mass binaries ranging over a broad mass range.  It does not include the effects of merger and ringdown.")
# Inspiral Trigger Plots
page.subpages["bank_range_triggers"].add_section("triggers", "Inspiral Triggers")
page.subpages["bank_range_triggers"].sections["triggers"].div("""
The number of inspiral triggers as well as the max and median snr are useful figures of merit for 
determining the quality of the data analyzed.  The plots in this section describe the number of inspiral 
triggers at the first and second stages as well as statistics on the SNR.
""")
imgtable = cbcwebpage.image_glob("*_plot_num_sngl_inspiral_INSPIRAL_*_FULL_DATA.png", width=350)
page.subpages["bank_range_triggers"].sections["triggers"].add_table(imgtable,"Inspiral Triggers", "")
imgtable = cbcwebpage.image_glob("*_plot_medianmax_sngl_inspiral_INSPIRAL_*_FULL_DATA.png", width=350)
page.subpages["bank_range_triggers"].sections["triggers"].add_table(imgtable,"Inspiral Triggers", "")

### INJ PARAM PAGE ###
page.add_subpage("injection_params","Injection Parameters", "Injection Parameters")

#page.subpages["injection_params"].add_section("overview","Injected Parameters Overview")
page.subpages["injection_params"].div("""
<big><b>OVERVIEW:</b></big><br><br>
Injections are the addition of simulated signals into the gravitational wave strain data.  They are useful 
for diagnosing the pipeline and measuring the sensitivity.  Care is taken to assure that the input 
distribution is sensible.  The remaining sections describe the input distributions for the injections.  
They are not necessarily what is analyzed since the analyzed segments are not used for determining the
injection sets (i.e. injections may be scheduled for times when a detector is not even functioning).
<br><br>The following plots are typically produced by injection waveform type.  Several injection runs
of the same waveform (with different random seeds) are often done.  Here all runs of the same waveform type
are shown together.
""")

page.subpages["injection_params"].add_section("m1_m2","Injected Parameters m1 and m2")
imgtable = cbcwebpage.image_glob(base_name+'6_sim_dist_m1_m2*.png')
page.subpages["injection_params"].sections["m1_m2"].add_table(imgtable, "Injected mass1, mass2", "Above are the injected mass parameters for the simulations done.  Typically injections are done uniformally in component mass unless the waveform approximant cannot support certain mass ratios (the Phenom. waveforms can only support mass ratios of 1:10 for example).")

page.subpages["injection_params"].add_section("time_dist","Injected Parameters time and distance")
imgtable = cbcwebpage.image_glob(base_name+'6_sim_dist_time_distance*.png')
page.subpages["injection_params"].sections["time_dist"].add_table(imgtable, "Injection time and distance", "Unless doing a directed search injections are uniform in time.  Although the correct distance distribution would be uniform in volume typically logarithmic injections are done")

page.subpages["injection_params"].add_section("ra_dec","Injected Parameters RA and DEC")
imgtable = cbcwebpage.image_glob(base_name+'6_sim_dist_ra_dec*.png')
page.subpages["injection_params"].sections["ra_dec"].add_table(imgtable, "Injection RA and DEC", "Unless doing a directed search injections are uniform on the sky.")

page.subpages["injection_params"].add_section("inc_pol","Injected Parameters inclination and polarization")
imgtable = cbcwebpage.image_glob(base_name+'6_sim_dist_inc_pol*.png')
page.subpages["injection_params"].sections["inc_pol"].add_table(imgtable, "Injection Inclination and polarization", "Unless doing a directed search injections are uniform in inclination and polarizations.  Note that there was a bug introduced into inspinj that caused polarizations to be set to zero.")

page.subpages["injection_params"].add_section("spin","Injected Parameters Z component spin")
imgtable = cbcwebpage.image_glob(base_name+'6_sim_dist_spin1z_spin2z*.png')
page.subpages["injection_params"].sections["spin"].add_table(imgtable, "Injection spin 1z and spin2z", "The Z component spins of the injection set.  Often injections are done without spin, so don't be surprised if these are zero.")


### INJ ACC PAGE ###
page.add_subpage("injection_params_acc","Injection Parameters Accuracy", "Injection Accuracy")
page.subpages["injection_params_acc"].div("""
<big><b>OVERVIEW:</b></big><br><br>
The accuracy of recovered parameters aids at diagnosing the performance of the pipeline as well as
hinting at the possibility of measuring certain parameters.  Mass parameters for the low mass search 
are often recovered better than mass parameters for the high mass search.  
""")

page.subpages["injection_params_acc"].add_section("mchirp_param_acc","Mchirp Parameter Accuracy")
imgtable = cbcwebpage.image_glob(base_name+'2_mchirp_acc_frac_*.png')
page.subpages["injection_params_acc"].sections["mchirp_param_acc"].add_table(imgtable, "Mchirp Accuracy", "Accuracy of chirp mass.")
page.subpages["injection_params_acc"].add_section("eta_param_acc","Eta Parameter Accuracy")
imgtable = cbcwebpage.image_glob(base_name+'2_eta_acc_frac_*.png')
page.subpages["injection_params_acc"].sections["eta_param_acc"].add_table(imgtable, "Eta Accuracy", "Accuracy of eta")
page.subpages["injection_params_acc"].add_section("time_param_acc","Time Parameter Accuracy")
imgtable = cbcwebpage.image_glob(base_name+'2_t_acc_*.png')
page.subpages["injection_params_acc"].sections["time_param_acc"].add_table(imgtable, "Time Accuracy", "Accuracy of time")

### MISSED FOUND ###
page.add_subpage("missed_found","Missed Found", "Missed Found")
#page.subpages["missed_found"].add_section("overview","Missed found injections overview")
page.subpages["missed_found"].div("""
<big><b>OVERVIEW:</b></big><br><br>
Measuring the found and missed injections as a function of various parameters aids in diagnosing the 
pipeline as well as providing the expected sensitivity of the pipeline to real signals.  The plots in
this section show the missed and found injections as a for the various IFO times for coincident triggers.
We allow double coincident events so some categories can have multiple types of found injections (for
 example H1L1 and H1H2L1 triggers in H1H2L1 time).  Because of ambiguity concerning the time of an 
injection and the injection window it is occasionally possible to find an injection in more detectors
than what the "time" refers to.  For example, an injection's geocentric end time might be in H1L1 time
but that might occur near a boundary where H2 was also on.  Thus one could find an H1L1 injection in
H1H2L1 time.
""")
tab,name = cbcwebpage.wiki_table_parse(base_name+'injection_summary.txt')
page.subpages["missed_found"].add_table(tab[0], "Injection Summary Table", "Summary of missed and found injections broken up by detector time")

page.subpages["missed_found"].add_section("found_missed_mchirp","Found / Missed Chirp Mass")
imgtable = cbcwebpage.image_glob(base_name+'1_deff_vs_mchirp_*.png')
page.subpages["missed_found"].sections["found_missed_mchirp"].add_table(imgtable, "Missed Found Effective Distance vs Mchirp", "Effective distance of found and missed injections as a function of chirp mass")
imgtable = cbcwebpage.image_glob(base_name+'1_chirpdist_vs_mchirp_*.png')
page.subpages["missed_found"].sections["found_missed_mchirp"].add_table(imgtable, "Missed Found Chirp Distance vs Mchirp", "Chirp distance of found and missed injections as a function of chirp mass.  For low mass systems the chirp mass scales out of the expected amplitude.  The chirp distance utilizes this and rescales the distance to be appropriate for a NS-NS binary.  At low total mass the missed/found barrier should be flat on this plot.")

page.subpages["missed_found"].add_section("found_missed_mtotal","Found / Missed Total Mass")
imgtable = cbcwebpage.image_glob(base_name+'1_deff_vs_mtotal_*.png')
page.subpages["missed_found"].sections["found_missed_mtotal"].add_table(imgtable, "Missed Found Effective Distance vs M total", "Effective distance of found and missed injections as a function of total mass")


page.subpages["missed_found"].add_section("found_missed_time","Found / Missed Time")
imgtable = cbcwebpage.image_glob(base_name+'1_deff_vs_t_*.png')
page.subpages["missed_found"].sections["found_missed_time"].add_table(imgtable, "Missed Found vs Time", "Effective distance of found and missed injections as a function of time")

### CHISQ ###
page.add_subpage("playchisq","Playground Chi-squared", "Playground Chi-squared")
page.subpages["playchisq"].div("""
<big><b>OVERVIEW:</b></big><br><br>
The chi-squared test checks that the snr accumulated in equal-power pieces of the template agrees with the
overall SNR for the entire template.  Glitches tend to have most of their power in a few pieces of the
template rather than being spread out across the template according to expectatation.  The template
is broken down into p orthogonal pieces (p=10,16 usually) and the difference between the expected and
measured snr is squared and summed.  The result is a number that is chi-square distributed with 2p-2 
degrees of freedom in Gaussian noise.  Signals are well separated from glitches by this test.  This page
shows the result of the single detector SNR and chis-squared values.
""")

page.subpages["playchisq"].add_section("chisq","Playground Chi-squared vs SNR")
imgtable = cbcwebpage.image_glob(base_name+'3_playground_chi2_vs_rho_*.png')
page.subpages["playchisq"].sections["chisq"].add_table(imgtable, "Chi-squared Vs SNR", "Chi-squared vs snr for single detectors after coincidence.  Blue points are playground zero lag, red are software injections and black are time slides")

### Effective SNR ###
page.add_subpage("playeffsnr","Playground Effective SNR", "Effective SNR")
page.subpages["playeffsnr"].div("""
<big><b>OVERVIEW:</b></big><br><br>
A combination of snr and chi-squared is used to create the effective SNR.  The effective SNR roughly
maps out regions of constant false alarm probibility in the  SNR, chi-squared plane.  It is used as an
intermediate ranking statistic along with total mass and trigger type / detector time in producing the
Inverse False Alarm Rate statistic (IFAR).  The section below shows scatter plots of the effective
SNR for pairwise detector combinations.
""")

page.subpages["playeffsnr"].add_section("effsnr","Playground Effective SNR")
imgtable = cbcwebpage.image_glob(base_name+'4_playground_rho_*.png')
page.subpages["playeffsnr"].sections["effsnr"].add_table(imgtable, "Effective SNR", "Effective SNR scatter for pairwise detector combinations of coincident triggers.  The squares of effective snr are added from the detectors that participate in a coinc.  The combined effective snr is the square root of the sum of the squares.  The blue points are playground zero lag, the red points are injections and the black points are time slides.")

### Time Slide ###
page.add_subpage("playts","Playground Time slide plots", "Playground Time slides")
page.subpages["playts"].div("""
<big><b>OVERVIEW:</b></big><br><br>
Triggers from different detectors are slid with respect to one another in order to ascertain the expected
background rate of accidental coincidences.  If the statistics of the "Zero Lag" dataset are not consistent
with the time shifted data there may be a candidate event in the data, or the noise may be correlated 
between detectors.  It is known that colocated detectors (such as H1, H2) have correlated noise.  Thus
time slides cannot accurately estimate the false alarm rate for those times.  However sites that are
geographically separated are assumed to be uncorrelated.
""")
page.subpages["playts"].add_section("ts","Playground Time Slides")
imgtable = cbcwebpage.image_glob(base_name+'7_playground_plot_slides_*.png')
page.subpages["playts"].sections["ts"].add_table(imgtable, "Time Slides", "Time Slide vs offset for coincident playground triggers")

### Money Plots ###
page.add_subpage("playmoney","Playground Money Plots", "Playground Money Plots")
page.subpages["playmoney"].div("""
<big><b>OVERVIEW:</b></big><br><br>
This section shows the the loudest events and their significance.  The plots are made for IFAR and SNR.  
""")
#tab,name = cbcwebpage.wiki_table_parse(base_name+'playground_summary_table.txt')
#page.subpages["playmoney"].add_table(tab[0], "Summary Table", "Loudest Playground Events")
page.subpages["playmoney"].add_section("snr","Playground Rate vs. Effective SNR Threshold")
imgtable = cbcwebpage.image_glob(base_name+'5_playground_count_vs_snr_*.png')
page.subpages["playmoney"].sections["snr"].add_table(imgtable, "Rate vs. Effective SNR Threshold", "Comparison of observed zero-lag event rate to event rate expected from background as a function of effective SNR threshold.")
page.subpages["playmoney"].add_section("ifar","Playground Rate vs. IFAR Threshold")
imgtable = cbcwebpage.image_glob(base_name+'5_playground_count_vs_ifar_*.png')
page.subpages["playmoney"].sections["ifar"].add_table(imgtable, "Rate vs. IFAR Threshold", "Comparison of observed zero-lag event rate to event rate expected from background as a function of inverse false-alarm rate (IFAR) threshold.")
page.subpages["playmoney"].add_section("table","Playground Loudest Table")
tab,name = cbcwebpage.wiki_table_parse(base_name+'playground_summary_table.txt')
page.subpages["playmoney"].sections["table"].add_table(tab[0], "Summary Table", "Loudest Playground Events")

### Likelihood plots ###
page.add_subpage("playlikelihood","Playground Likelihood", "Playground Likelihood")
page.subpages["playlikelihood"].div("""
<big><b>OVERVIEW:</b></big><br><br>
This section is for the MVSC ranking.  Currently this is not being used to decide detection candidates, 
but it is being calculated.
""")
page.subpages["playlikelihood"].add_section("MVSC","MVSC Playground Likelihood scatter plot")
imgtable = cbcwebpage.image_glob(base_name+'8_MVSC_likelihood_scatterplot*.png')
page.subpages["playlikelihood"].sections["MVSC"].add_table(imgtable, "MVSC plot", "MVSC Effective SNR scatter plot")

if opts.open_box:
	print >>sys.stderr, "WARNING: OPENING THE BOX"
	### CHISQ ###
	page.add_subpage("chisq","Chi-squared", "Chi-squared")
	page.subpages["chisq"].div("""
<big><b>OVERVIEW:</b></big><br><br>
The chi-squared test checks that the snr accumulated in equal-power pieces of the template agrees with the
overall SNR for the entire template.  Glitches tend to have most of their power in a few pieces of the
template rather than being spread out across the template according to expectatation.  The template
is broken down into p orthogonal pieces (p=10,16 usually) and the difference between the expected and
measured snr is squared and summed.  The result is a number that is chi-square distributed with 2p-2 degrees
of freedom in Gaussian noise.  Signals are well separated from glitches by this test.  This page
shows the result of the single detector SNR and chis-squared values.
	""")
	page.subpages["chisq"].add_section("chisq","Chi-squared vs SNR")
	imgtable = cbcwebpage.image_glob(base_name+'3_chi2_vs_rho_*.png')
	page.subpages["chisq"].sections["chisq"].add_table(imgtable, "Chi-squared Vs SNR", "Chi-squared vs snr for single detectors after coincidence.  Blue points are full data zero lag, red are software injections and black are time slides.")

	### Effective SNR ###
	page.add_subpage("effsnr","Effective SNR", "Effective SNR")
	page.subpages["effsnr"].div("""
<big><b>OVERVIEW:</b></big><br><br>
A combination of snr and chi-squared is used to create the effective SNR.  The effective SNR roughly
maps out regions of constant false alarm probibility in the  SNR, chi-squared plane.  It is used as an
intermediate ranking statistic along with total mass and trigger type / detector time in producing the
Inverse False Alarm Rate statistic (IFAR).  The section below shows scatter plots of the effective
SNR for pairwise detector combinations.
	""")
	page.subpages["effsnr"].add_section("effsnr","Effective SNR")
	imgtable = cbcwebpage.image_glob(base_name+'4_rho_*.png')
	page.subpages["effsnr"].sections["effsnr"].add_table(imgtable, "Effective SNR", "Effective SNR scatter for pairwise detector combinations of coincident triggers.  The squares of effective snr are added from the detectors that participate in a coinc.  The combined effective snr is the square root of the sum of the squares.  The blue points are full data zero lag, the red points are injections and the black points are time slides.")

	### Time Slide ###
	page.add_subpage("ts","Time slide plots", "Time slides")
	page.subpages["ts"].div("""
<big><b>OVERVIEW:</b></big><br><br>
Triggers from different detectors are slid with respect to one another in order to ascertain the expected
background rate of accidental coincidences.  If the statistics of the "Zero Lag" dataset are not consistent
with the time shifted data there may be a candidate event in the data, or the noise may be correlated 
between detectors.  It is known that colocated detectors (such as H1, H2) have correlated noise.  Thus
time slides cannot accurately estimate the false alarm rate for those times.  However sites that are
geographically separated are assumed to be uncorrelated.
	""")
	page.subpages["ts"].add_section("ts","Time Slides")
	imgtable = cbcwebpage.image_glob(base_name+'7_plot_slides_*.png')
	page.subpages["ts"].sections["ts"].add_table(imgtable, "Time Slides", "Time Slide vs offset for coincident triggers")

	### Money Plots ###
	page.add_subpage("money","Money Plots", "Money Plots")
	page.subpages["money"].div("""
<big><b>OVERVIEW:</b></big><br><br>
This section provides the detection statistic plots and a summary of the loudest event.  The ranking statistic is inverse false alarm rate (IFAR) and is
calculated by computing the number of time slides with an effective snr louder than a given trigger in a particular mass range, detector time for a given combination 
of detectors. 
""")
	page.subpages["money"].add_section("snr","Rate vs. Effective SNR Threshold")
	imgtable = cbcwebpage.image_glob(base_name+'5_count_vs_snr_*.png')
	page.subpages["money"].sections["snr"].add_table(imgtable, "Rate vs. Effective SNR Threshold", "Comparison of observed zero-lag event rate to event rate expected from background as a function of effective SNR threshold.")
	page.subpages["money"].add_section("ifar","Rate vs. IFAR Threshold")
	imgtable = cbcwebpage.image_glob(base_name+'5_count_vs_ifar_*.png')
	page.subpages["money"].sections["ifar"].add_table(imgtable, "Rate vs. IFAR Threshold", "Comparison of observed zero-lag event rate to event rate expected from background as a function of inverse false-alarm rate (IFAR) threshold.")
	page.subpages["money"].add_section("table","Loudest Table")
	tab,name = cbcwebpage.wiki_table_parse(base_name+'summary_table.txt')
	page.subpages["money"].sections["table"].add_table(tab[0], "Summary Table", "Loudest Events")

	### UPPER LIMIT PLOTS ###
	page.add_subpage("ul","Upper Limit Plots", "Upper Limit Plots")
	page.subpages["ul"].div("""
<big><b>OVERVIEW:</b></big><br><br>
This section describes the upperlimit calculation which is a 90% confidence upper limit on the rate of mergers with units mergers/Mpc^3/year as a function of mass.  Various 
quantities go into this calculation.  They are shown here. 
""")

	range_summs = glob.glob(base_name+'-*_range_summary.txt')
	for rs in range_summs:
		tag = rs.replace('_',' ').replace('.txt','')
		page.subpages["ul"].add_section(tag,rs)
		tab,name = cbcwebpage.wiki_table_parse(rs)
		page.subpages["ul"].sections[tag].add_table(tab[0], "Range Summary", "Range summary")

	page.subpages["ul"].add_section("vt","Volume x time")
	imgtable = cbcwebpage.image_glob(base_name+'-*_volume_time.png')
	page.subpages["ul"].sections["vt"].add_table(imgtable, "Volume x time", "mass1 mass2 volume x time")

	page.subpages["ul"].add_section("evt","Error on Volume x time")
	imgtable = cbcwebpage.image_glob(base_name+'-*_fractional_error.png')
	page.subpages["ul"].sections["evt"].add_table(imgtable, "Error on Volume x time", "Error on mass1 mass2 volume x time")

	page.subpages["ul"].add_section("l","Lambda")
	imgtable = cbcwebpage.image_glob(base_name+'-*_lambda.png')
	page.subpages["ul"].sections["l"].add_table(imgtable, "Lambda", "likelihood fg/bg @ loudest event")

	page.subpages["ul"].add_section("p","Posterior")
	imgtable = cbcwebpage.image_glob(base_name+'-*_posterior.png')
	page.subpages["ul"].sections["p"].add_table(imgtable, "Posterior", "Poseterior on the rate")

	page.subpages["ul"].add_section("ul","90% Upper limit")
	imgtable = cbcwebpage.image_glob(base_name+'-*_upper_limit.png')
	page.subpages["ul"].sections["ul"].add_table(imgtable, "90% Upper limit", "90% upper limit")

	page.subpages["ul"].add_section("cul","Combined 90% Upper limit")
	imgtable = [[cbcwebpage._imagelinkcpy(base_name+'upper_limit.png'), cbcwebpage._imagelinkcpy(base_name+'posterior.png')]]
	page.subpages["ul"].sections["cul"].add_table(imgtable, "Combined 90% Upper limit", "Combined 90% upper limit")

# PAGE FOR DATABASE SUMMARY
page.add_subpage("databasesummary","Database Summary", "Database Summary")
tabs, names = cbcwebpage.wiki_table_parse(base_name+"plotsummary.txt")
print len(tabs), len(names)
for i, name in enumerate(names):
	tag = name.strip().replace(' ','').replace('/','').replace(':','').replace('.','')
	page.subpages["databasesummary"].add_section(tag,name)
	page.subpages["databasesummary"].sections[tag].add_table(tabs[i], "Database Overview", "Database Overview")
	
### ALL DONE WITH PLAYGROUND ###
if opts.open_box: page.write(base_name+"open_box")
else: page.write(base_name+"playground")

# copy the output
if opts.webserver_dir:
	try: os.makedirs(opts.webserver_dir)
	except: pass
	for f in page.fnames: 
		shutil.copy(f,opts.webserver_dir)
	#FIXME not the best way to do this, I should explicitely save file names
	try: os.mkdir(opts.webserver_dir+'/Images')
	except: pass
	for f in glob.glob('Images/*.png'):
		shutil.copy(f,opts.webserver_dir+'/Images')
