#!/usr/bin/env python
#
# Copyright (C) 2011  Chad Hanna
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import sys
import cgi
import cgitb
import os
os.environ["MPLCONFIGDIR"] = "/tmp"
import matplotlib
matplotlib.use('Agg')
import numpy
# FIXME don't import this when it is "real"
from numpy import random
import matplotlib.pyplot as plt
import time
cgitb.enable()
form = cgi.FieldStorage()

def now():
	#FIXME use pylal when available
	return time.time() - 315964785

def read_registry(dir, dataurl, ids):
	nodedict = {}
	ifos = set()
	for id in ids:
		url = '%s/%s%s' % (dir, id, dataurl)
		try:
			tmp = open(url,"r")
			firstline = tmp.readline().replace("#","").split()
			tag, node = firstline[0], firstline[1]
			for ifo in firstline[2:]:
				ifos.add(ifo)
			nodedict[id] = node
			tmp.close()
		except IOError:
			nodedict[id] = ""
	return nodedict, ifos

	
def load_data(directory, idrange, type):
	found = {}
	missed = {}
	for i, id in enumerate(idrange):
		fname = "%s/%s_%s.txt" % (directory, id, type)
		try:
			found[i] = numpy.loadtxt(fname)
			if len(found[i].shape) == 1:
				found[i] = numpy.array([found[i],])
		except IOError:
			missed[i] = numpy.array([])
		except ValueError:
			missed[i] = numpy.array([])
	return found, missed
			
def setup_plot():
	fig = plt.figure(figsize=(20,5),)
	fig.patch.set_alpha(0.0)
	h = fig.add_subplot(111, axisbg = 'k')
	plt.subplots_adjust(left = .062, right = 0.98, bottom = 0.3)
	return fig, h

def finish_plot(ids, registry, ylim, title=''):
	ticks = ["%s : %s " % (id, registry[id]) for id in ids]
	plt.xticks(numpy.arange(len(ids))+.3, ticks, rotation=90, fontsize = 10)
	plt.xlim([0, len(ids)])
	plt.ylim(ylim)
	tickpoints = numpy.linspace(ylim[0], ylim[1], 8)
	ticks = ["%.1e" % (10.**t,) for t in tickpoints]
	plt.yticks(tickpoints, ticks, fontsize = 20)
	plt.title(title, fontsize = 30)
	plt.savefig(sys.stdout, format = "svg")

def plot_latency(found, missed, ids, registry):
	fig, h = setup_plot()
	
	found_x = found.keys()
	latency_y = numpy.log10(numpy.array([found[k][-1,1] for k in found_x]))
	time_y = numpy.log10(now() - numpy.array([found[k][-1,0] for k in found_x]))
	try:
		max_y = max(time_y.max(), latency_y.max())
	except ValueError:
		max_y = 1
	missed_x = missed.keys()
	missed_y = numpy.ones(len(missed_x)) * max_y
	
	h.bar(missed_x, missed_y, color='r', alpha=0.9, linewidth=2)
	h.bar(found_x, latency_y, color='w', alpha=0.9, linewidth=2)
	h.bar(found_x, time_y, color='w', alpha=0.7, linewidth=2)
	finish_plot(ids, registry, [0, max_y], 'Time (s) since last event (gray) and latency (white)')

def plot_snr(found, missed, ids, registry):
	fig, h = setup_plot()
	
	found_x = found.keys()
	maxsnr_y = numpy.log10(numpy.array([found[k][:,1].max() for k in found_x]))
	mediansnr_y = numpy.log10(numpy.array([numpy.median(found[k][:,1]) for k in found_x]))

	try:	
		max_y = max(maxsnr_y)
	except ValueError:
		max_y = 1
	missed_x = missed.keys()
	missed_y = numpy.ones(len(missed_x)) * max_y
	
	h.bar(missed_x, missed_y, color='r', alpha=0.9, linewidth=2)
	h.bar(found_x, mediansnr_y, color='w', alpha=0.9, linewidth=2)
	h.bar(found_x, maxsnr_y, color='w', alpha=0.7, linewidth=2)
	finish_plot(ids, registry, [numpy.log10(5.5), max_y], 'SNR of last 1000 events: max (gray) and median (white)')

def plot_livetime(found, missed, ids, registry, ifo):
	fig, h = setup_plot()
	
	found_x = found.keys()
	# Handle log of 0 by setting it to max of (actual value, 1)
	on_y = numpy.log10(numpy.array([max(found[k][0][1],1) for k in found_x]))
	off_y = numpy.log10(numpy.array([max(found[k][0][2],1) for k in found_x]))
	gap_y = numpy.log10(numpy.array([max(found[k][0][3],1) for k in found_x]))

	if len(found_x) > 0:
		max_y = max(on_y.max(), off_y.max(), gap_y.max())
		min_y = min(on_y.min(), off_y.min(), gap_y.min())
	else:
		max_y = 1
		min_y = 0

	missed_x = missed.keys()
	missed_y = numpy.ones(len(missed_x)) * max_y
	
	h.bar(missed_x, missed_y, color='r', alpha=0.9, linewidth=2)
	h.bar(found_x, off_y, color='w', alpha=0.7, linewidth=2)
	h.bar(found_x, gap_y, color='b', alpha=0.5, linewidth=2)
	h.bar(found_x, on_y, color='w', alpha=0.5, linewidth=2)
	finish_plot(ids, registry, [min_y*.9, max_y], '%s Up time (gray) Down time (white) Dropped time (blue)' % (ifo,))

def plot_ram(found, missed, ids, registry):
	fig, h = setup_plot()
	
	found_x = found.keys()
	found_y = numpy.log10(numpy.array([found[k][0,1] for k in found_x]))

	try:	
		max_y, min_y = max(found_y), min(found_y)
	except ValueError:
		max_y, min_y = (1,0)
	missed_x = missed.keys()
	missed_y = numpy.ones(len(missed_x)) * max_y
	
	h.bar(missed_x, missed_y, color='r', alpha=0.9, linewidth=2)
	h.bar(found_x, found_y, color='w', alpha=0.9, linewidth=2)
	finish_plot(ids, registry, [0.9 * min_y, max_y], 'RAM usage GB')

def plot_single_col(found, missed, ids, registry, col = 0, title = ''):
	fig, h = setup_plot()
	
	found_x = found.keys()
	found_y = numpy.log10(numpy.array([found[k][0][col] for k in found_x]))

	try:	
		max_y, min_y = max(found_y), min(found_y)
	except ValueError:
		max_y, min_y = (1,0)
	missed_x = missed.keys()
	missed_y = numpy.ones(len(missed_x)) * max_y
	
	h.bar(missed_x, missed_y, color='r', alpha=0.9, linewidth=2)
	h.bar(found_x, found_y, color='w', alpha=0.9, linewidth=2)
	finish_plot(ids, registry, [0.9 * min_y, max_y], title)

def get_ids(form):
	idrange = [int(n) for n in form.getvalue("id").split(",")]
	#FIXME relies on 4 digit ids
	ids = ['%04d' % (job,) for job in range(idrange[0], idrange[1]+1)]
	return ids

if "dir" not in form:
	raise ValueError("must specify dir")
if "id" not in form:
	raise ValueError("must specify id")

ids = get_ids(form)
directory = form.getvalue("dir")
reg, ifos = read_registry(form.getvalue("dir"), "_registry.txt", ids)

# Header
print >>sys.stdout, 'Cache-Control: no-cache, must-revalidate'
print >>sys.stdout, 'Expires: Mon, 26 Jul 1997 05:00:00 GMT'
print >>sys.stdout, 'Content-type: text/html\r\n'

# HTML preamble
print """
<html>
<head>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
<meta http-equiv="CACHE-CONTROL" content="NO-CACHE">
<meta http-equiv="refresh" content="300">
</head>
<body bgcolor=#E0E0E0 face="Arial">
"""

# title
print """
<font size=10><img src="../lcbo.jpg"> Low-latency Compact Binary Online </font><font size=6 color=#707070><b><right>%s: %d - %s </right></b><br></font><hr><br>
""" % ("".join(sorted(ifos)), int(now()), time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime()))

# start a table
print "<table>"


#
# latency history
#

print "<tr><td><div id='canvaslatency'>"
found, missed = load_data(directory, ids, "latency_history")
plot_latency(found, missed, ids, reg)
print "</div></td></tr>"

#
# snr history
#

print "<tr><td><div id='canvassnr'>"
found, missed = load_data(directory, ids, "snr_history")
plot_snr(found, missed, ids, reg)
print "</div></td></tr>"
	
#
# live time by ifo
#

for ifo in ifos:
	print "<tr><td><div id='%scanvastime'>" % (ifo,)
	found, missed = load_data(directory, ids, "%sstate_vector_on_off_gap" % (ifo,))
	plot_livetime(found, missed, ids, reg, ifo)
	print "</div></td></tr>"

#
# Template Duration
#

print "<tr><td><div id='canvasdur'>"
found, missed = load_data(directory, ids, "bank")
plot_single_col(found, missed, ids, reg, 1, "Template Duration (s)")
print "</div></td></tr>"

#
# Chirp Mass
#

print "<tr><td><div id='canvasmchirp'>"
found, missed = load_data(directory, ids, "bank")
plot_single_col(found, missed, ids, reg, 2, "Chirp Mass")
print "</div></td></tr>"

#
# RAM
#

print "<tr><td><div id='canvasram'>"
found, missed = load_data(directory, ids, "ram_history")
plot_ram(found, missed, ids, reg)
print "</div></td></tr>"

#
# end a table
#

print "</table>"

# links at bottom
print "<h3>Node summary info:</h3><hr>"
for id in ids:
	print '<font size=5><a href="gstlal_llcbcnode?dir=%s&id=%s"> %s </a></font>' % (form.getvalue("dir"), id, id)

# likelihood links at bottom
print "<h3>Node likelihood info:</h3><hr>"
for id in ids:
	url = os.path.join(form.getvalue("dir"), "%s_likelihood.xml" % (id,))
	print '<font size=5><a href="gstlal_inspiral_plot_likelihoods?url=%s"> %s </a></font>' % (url, id)
print "</body>"

