#!/usr/bin/perl

=head1 NAME

lookup_sub - find detections in MPC obs format in MOPS submission table

=head1 SYNOPSIS

lookup_sub [OPTIONS] < OBSFILE

  OBSFILE : MPC-formatted observations
  --multi : show all matches, not just first
  --debug : dump data, don't insert anything
  --help : show this manpage

=head1 DESCRIPTION

=cut


use strict;
use warnings;
use Data::Dumper;
use Getopt::Long;
use Pod::Usage;
use Mail::Send;
use Astro::Time;

# Just a stub for quick debugging.
use PS::MOPS::Lib qw(:all);
use PS::MOPS::MPC;
use PS::MOPS::DC::Instance;
use PS::MOPS::DC::Detection;
use PS::MOPS::DC::Tracklet;


# Detection statuses.
our $SUBMISSION_PENDING_NEO = 'P';
our $SUBMISSION_PENDING_STD = 'Q';
our $SUBMISSION_NEO = 'S';
our $SUBMISSION_STD = 'T';
our $SUBMISSION_OUTREACH = 'O';

# Start program here.
my $instance_name;
my $multi = 1;
my $debug;
my $help;
GetOptions(
    'instance=s' => \$instance_name,
    multi => \$multi,
    debug => \$debug,
    help => \$help,
) or pod2usage(2);
pod2usage(-verbose => 3) if $help;


my $inst = PS::MOPS::DC::Instance->new(DBNAME => $instance_name);
my $dbname = $inst->dbname;
my $logger = $inst->getLogger();
my $dbh = $inst->dbh;
my $lookup_sth = $dbh->prepare(<<"SQL") or die $dbh->errstr;
/* args are MJD1, MJD2, P1.dec, P2.dec, P1.dec, P2.dec, P1.ra, P2.ra */
select desig 
from export.mpc_sub m
where (m.epoch_mjd between ? and ?)
and abs(
    degrees(
        /* spherical distance from tracklet to target field center */
        acos(least(1.0, /* handle slight roundoff error causing arg > 1.0 */
            sin(radians(m.dec_deg)) * sin(radians(?))
            + cos(radians(m.dec_deg)) * cos(radians(?)) * cos(radians(m.ra_deg - ?))
        ))
    )
) < 0.000555 /* 2 arcsec */
SQL


# First read all the MPC-formatted detections and arrange into 
# designations (tracklets).
my $tracklets;
my %seen;

if (@ARGV) {
    $tracklets = read_argv();       # read MOPS IDs from command line
}
else {
    $tracklets = read_mpc();        # read all from STDIN
}

while (my ($desig, $detref) = each %{$tracklets}) {
    # 1. Check that none of the tracklet's detections have been submitted.
    # 2. Set up insert data.
    # 3. Insert into table & retrieve designation.
    # 4. Submit via email.

    # This is a tracklet; fetch it and add the detections.
    foreach my $det (@{$detref}) {
        # Look up det in DB.
        my $found_desig;
        my $det_id;
        if ($det_id = lookup_det($det)) {
#            emit(sprintf "Found %s as %s/%s.\n", $desig, $dbname, $det_id);
            emit("$det_id ($desig)\n") unless $seen{$det_id}++;
            last unless $multi;
        }
    }
}
$lookup_sth->finish;
exit;


sub emit {
    print @_;
}


sub read_mpc {
    my $line;
    my %desigs;
    while ($line = <STDIN>) {
        chomp $line;
        next if !$line or $line =~ /^\s*$/ or $line =~ /^[A-Z]/;

        # We're gonna do a little magic here to handle cases where the 
        # MPC observations were pasted from a program that fusses with the
        # leading spaces.
        if (substr($line, 0, 1) eq ' ') {
            $line =~ s/^\s+/     /;     # enforce exactly five spaces to start string if first char is string

            # Addl magic to undo to handle comets, where there are four leading spaces.
            $line =~ s/^     ([CP][IJK]\d\d[A-Z]\w\w\w)/    $1/;
        }


        my $foo = PS::MOPS::MPC::mpc_split($line);
        my $desig = $foo->{DESIGNATION} or die "didn't get designation from $line";
        next unless $foo->{OBSERVATORY} eq 'F51';

        my $det = {
            desig => $foo->{DESIGNATION},
            epoch_mjd => date2mjd($foo->{DATE}),
            ra => str2deg($foo->{RA}, 'H'),
            dec => str2deg($foo->{DEC}, 'D'),
            mag => $foo->{MAG},
            filter_id => $foo->{BAND},
            obscode => $foo->{OBSERVATORY},
        };
        push @{$desigs{$desig}}, $det;
    }

    return \%desigs;
}


sub read_argv {
    my %desigs;
    for my $id (@ARGV) {
        my $det;
        if ($id =~ /^T/) {
            my $trk_id = $id;
            $trk_id =~ s/^T//;
            my $trk = modct_retrieve($inst, trackletId => $trk_id);
            $id = $inst->dbname . "/$id";
            for $det (@{$trk->detections}) {
                push @{$desigs{$id}}, {
                    desig => $id,
                    epoch_mjd => $det->epoch,
                    ra => $det->ra,
                    dec => $det->dec,
                    mag => $det->mag,
                    filter_id => $det->filter,
                    obscode => $det->obscode,
                };
            }
        }
        elsif ($id =~ /^D/) {
            my $det_id = $id;
            $det_id =~ s/^D//;
            $det = modcd_retrieve($inst, detId => $det_id);
            $id = $inst->dbname . "/$id";
            push @{$desigs{$id}}, {
                desig => $id,
                epoch_mjd => $det->epoch,
                ra => $det->ra,
                dec => $det->dec,
                mag => $det->mag,
                filter_id => $det->filter,
                obscode => $det->obscode,
            };
        }
    }

    return \%desigs;
}


sub lookup_det {
    my ($det) = @_;
    $lookup_sth->execute(
        $det->{epoch_mjd} - 5 / 100_000, 
        $det->{epoch_mjd} + 5 / 100_000, 
        $det->{dec}, $det->{dec}, $det->{ra}
    ) or die $lookup_sth->errstr;
    my ($near) = $lookup_sth->fetchrow_array();
    return $near;
}


sub date2mjd {
    # Given an MPC date string, return an FPA id for the nearest PS1 
    # exposure within +/- 1 sec.  Date format is
    # 2011 01 23.23452
    my ($date) = @_;
    $date =~ s/^\s+|\s+$//g;    # strip
    my ($y, $m, $d) = split /\s+/, $date;
    my $df = ($d - int($d));
    $d = int($d);
    my $mjd = cal2mjd($d, $m, $y, $df);
    return $mjd;
}

