#!/usr/bin/python

# Copyright (C) 2012 Duncan M. Macleod, Kipp Cannon
#
# 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.


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


"""Command-line interface to CBC coherent injection identification code.

Accepts as input one or more LIGO Light Weight XML files, each
containing CBC candidates and a list of injections, and adds entries
to the coincidence tables indicating which events match which injections.

"""

import sys
import optparse

from glue.ligolw import lsctables
from glue.ligolw import utils
from glue.ligolw.utils import process as ligolw_process

from pylal import git_version
from pylal import ligolw_miinjfind

__author__ = "Duncan M. Macleod <duncan.macleod@ligo.org>"
__credits__ = "Kipp Cannon <kipp.cannon@ligo.org>"
__version__ = git_version.id
__date__ = git_version.date


#
# =============================================================================
#
#                                 Command Line
#
# =============================================================================
#


def parse_command_line():
    """Parse command line arguments and options.
    """
    parser = optparse.OptionParser(description=__doc__,\
                                   usage="%prog [options] [file ...]",
                                   formatter=optparse.IndentedHelpFormatter(4))
    parser.add_option("-f", "--force", action="store_true",
                      help="process even if file has already been processed.")
    parser.add_option("--comment", metavar="text",
                      help=("set the comment string to be written to the "
                            "process table, (default=%default)."))
    parser.add_option("-w", "--time-window", type='float', default=9.,
                      help=("set the time window, in seconds, used by "
                            "the inspiral match-algorithm. Default is 9.0s."))
    parser.add_option("-l", "--loudest-by", type="string", default=None,
                      metavar="COLUMN",
                      help=("return only the loudest MultiInspiral event "
                            "for each injection, as ranked by COLUMN."))
    parser.add_option("-v", "--verbose", action="store_true",
                      help="be verbose.")
    parser.add_option("-V", "--version", action="version",
                      help="show program's version number and exit.")
    parser.version = __version__
    options, filenames=parser.parse_args()
    return options, (filenames or [None])


#
# =============================================================================
#
#                                    Input
#
# =============================================================================
#


#
# Use interning row builder to save memory.
#

ligolw_miinjfind.table.RowBuilder = ligolw_miinjfind.table\
                                          .InterningRowBuilder

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

if __name__ == "__main__":
    #
    # command line
    #

    options, filenames = parse_command_line()

    # must match columns in sngl_inspiral table
    search = "inspiral"

    #
    # loop over files
    #

    for n, filename in enumerate(filenames):
        # load the document
        if options.verbose:
            sys.stderr.write("%d/%d:" % (n + 1, len(filenames)))
        xmldoc = utils.load_filename(filename, verbose = options.verbose)
        ligolw_miinjfind.table.InterningRowBuilder.strings.clear()

        # have we already processed it?
        if ligolw_process.doc_includes_process(
               xmldoc,
               ligolw_miinjfind.process_program_name):
            if options.verbose:
                sys.stderr.write("warning: %s already processed, "
                                 % (filename or "stdin"))
            if not options.force:
                if options.verbose:
                    sys.stderr.write("skipping (use --force to force)\n")
                continue
            if options.verbose:
                sys.stderr.write("continuing by --force\n")

        # add process metadata to document
        process = ligolw_miinjfind.append_process(
                      xmldoc, "inspiral", options.time_window,
                      options.loudest_by, comment=options.comment)

        # run miinjfind algorithm
        ligolw_miinjfind.ligolw_miinjfind(xmldoc, process, search,
                                          options.time_window,
                                          options.loudest_by,
                                          verbose=options.verbose)

        # close out the process metadata
        ligolw_process.set_process_end_time(process)

        # done
        utils.write_filename(xmldoc, filename, verbose = options.verbose,
                             gz=(filename or "stdout").endswith(".gz"))
        xmldoc.unlink()
        lsctables.table.reset_next_ids(lsctables.TableByName.values())
