#!/usr/bin/env python
#
# Copyright (C) 2011 Chris Pankow
#
# 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.
"""Stream-based burst analysis tool"""

#
# =============================================================================
#
#                                   Preamble
#
# =============================================================================
#


import os
import sys
import signal
import math
import time

from optparse import OptionParser

import pygtk
pygtk.require("2.0")
import gobject
gobject.threads_init()
import pygst
pygst.require("0.10")

# This mess is to make gstreamer stop eating our help messages.
if "--help" in sys.argv or "-h" in sys.argv:
	try:
		del sys.argv[ sys.argv.index( "--help" ) ]
	except ValueError:	
		pass
	try:
		del sys.argv[ sys.argv.index( "-h" ) ]
	except ValueError:	
		pass
	
	import gst
	sys.argv.append( "--help" )
else:
	import gst

from gstlal import pipeparts
#from gstlal import epparts
from gstlal import datasource
import gstlal.excesspower as ep
from gstlal.excesspower import parts
from gstlal.excesspower.scan import EPScan

from glue import gpstime
from glue.lal import LIGOTimeGPS
from glue.segments import segment

__author__ = "Chris Pankow <chris.pankow@ligo.org>"
__version__ = "Defiant" # until we get proper versioning tags

#
# =============================================================================
#
#                             Options Handling
#
# =============================================================================
#

parser = OptionParser()
ep.append_options(parser)
datasource.append_options(parser)

(options, args) = parser.parse_args()
gw_data_source_opts = datasource.GWDataSourceInfo(options)

# Verbosity and diagnostics
verbose = options.verbose

#
# Handler / Pipeline options
#

# We need a pipeline and pipeline handler instance to configure
pipeline = gst.Pipeline("gstlal_excesspower")
mainloop = gobject.MainLoop()

handler = ep.process_options(options, gw_data_source_opts, pipeline, mainloop)
handler.initialize_handler_objects(options)

# Construct a scan object if requested
scan_obj = None
if options.scan_start and options.scan_end:
    trigger_segment = segment(map(LIGOTimeGPS, (options.scan_start, options.scan_end)))
    scan_obj = EPScan(trigger_segment, low_freq=handler.flow, high_freq=handler.fhigh, base_band=handler.base_band)
    handler.set_trigger_time_and_action(scan_obj.scan_segment, action="scan")

#
# =============================================================================
#
#                                     Main
#
# =============================================================================
#

if verbose:
	print "Assembling pipeline... this is gstlal_excesspower, version code name %s\n" % __version__,

# Construct the data acquisition and conditioning part of the pipeline
head = datasource.mkbasicsrc(pipeline, gw_data_source_opts, handler.inst, verbose)

# If we're running online, we need to set up a few things 
if gw_data_source_opts.data_source in ("lvshm", "framexmit"):
    # FIXME: This is a guess. Not a terrible one, but still inaccurate
    handler.time_since_dump = handler.stop = handler.start = gpstime.GpsSecondsFromPyUTC(time.time())

    # This enables EP to get the on and off signals to make a segment list
    gate = pipeline.get_by_name( "%s_state_vector_gate" % handler.inst )
    gate.set_property("emit-signals", True)
    gate.connect("start", handler.handle_segment, "on")
    gate.connect("stop", handler.handle_segment, "off")

elif gw_data_source_opts.seg is not None:
	handler.time_since_dump = handler.start = float(gw_data_source_opts.seg[0])

# Construct the analysis end of the pipeline
parts.construct_excesspower_pipeline(pipeline, head, handler, scan_obj, options.drop_time, options.peak_fraction, disable_triggers=options.disable_triggers, verbose=verbose)

# Spectrum notification processing
handler.whitener.connect_after("notify::mean-psd", parts.on_psd_change, handler, options.drop_time)
# Handle spectral correlation changes
handler.whitener.connect_after("notify::spectral-correlation", parts.on_spec_corr_change, handler)

# Check for empty frame segments list if handed frames 
for ifo, seglist in gw_data_source_opts.frame_segments.iteritems():
	if seglist is not None and abs(seglist) == 0:
		fname = ep.make_cache_parseable_name(inst = handler.inst, tag = handler.channel, start = float(gw_data_source_opts.seg[0]), stop = float(gw_data_source_opts.seg[1]), ext = "xml.gz", dir = handler.outdir)
		handler.write_triggers(filename = fname)
		if verbose:
			print "No analyzable livetime in requested segment."
		sys.exit(0)

# Handle shutdowns
signal.signal(signal.SIGINT, handler.shutdown)
signal.signal(signal.SIGTERM, handler.shutdown)

print "Startin' up."
if pipeline.set_state(gst.STATE_PLAYING) == gst.STATE_CHANGE_FAILURE:
	raise RuntimeError("pipeline failed to enter PLAYING state")
mainloop.run()

# All done, write out a scan if asked
if handler.trigger_segment:
    scan_obj.close()
    scan_obj.write_out("gstlal_excesspower_scan_%s_%s_%d_%d" % (handler.channel, handler.inst, math.floor(int(options.scan_start)), math.ceil(int(options.scan_end))))
