#!/usr/bin/env perl

=head1 NAME

export_known - Export MOPS data in DES format for KNOWN_SERVER processing

=head1 SYNOPSIS

export_known [--nn=NIGHT_NUM] [--name=NAME] [-ssm] [--help]

  --nn NIGHT_NUM : night number to process, or all data if unspecified
  --field_status=X : only use tracklets from fields with specified status (for --nn only)
  --name NAME : name (prefix really) to use for processing, default 'MOPS'
  --ssm : include Solar System model in DES manifest
  --help : display man page

=head1 DESCRIPTION

export_known retrieves all detection and tracklet data for the night(s)
specified and packages them in DES format for processing by KNOWN_SERVER.

This program started life as exportSim, so there are some options in the
code that are obsolete or vestigial.

=cut

use strict;
use warnings;

use FileHandle;
use Getopt::Long;
use Pod::Usage;
use Math::Trig;
use Astro::SLA;

use PS::MOPS::Constants qw(:all);
use PS::MOPS::DC::Instance;
use PS::MOPS::DC::Tracklet;

my $nn;
my $field_status;
my $ssm;
my $name;       # job name to write, default MOPS instance name

# Vestigial options.
my $known;      # export specifically for KNOWN_SERVER processing
my $worry;
my $min_prob = 0;
my $raw_tracks;
GetOptions(
    'nn=i' => \$nn,
    'field_status=s' => \$field_status,
    'name=s' => \$name,
    'min_prob=f' => \$min_prob,
    ssm => \$ssm,
) or pod2usage(2);


my $inst = PS::MOPS::DC::Instance->new(DBNAME => undef);
my $mops_config = $inst->getConfig('backend');
my $DB_HOST = $mops_config->{backend}->{hostname} || die "can't get DB hostname";
my $dbh = $inst->dbh;
my $sql;
my $line;
my $cmd;
my $tid;
my $det_id;
my $dbname = $inst->dbname;
my $where = '';         # set to select results from certain fields.
my $tracklet_fh;
my @manifest_files;
my $field_status_str = $field_status ? "f.status='$field_status' and " : '';

$name ||= 'MOPS';



# Load existing PS1 catalog from KNOWN files.
my $known_tbl = load_known();     # tracklets already in KNOWN catalog


# All tracklets.
if ($nn) {
    print STDERR "Exporting detections and tracklets for night $nn from DB $dbname...\n";
}
else {
    print STDERR "Exporting all detections and tracklets for DB $dbname...\n";
}
my %seen_dets;          # detections already written to file for this run
my $tref;

push @manifest_files, "$name.in.tracklet_pointer";
$tracklet_fh = new FileHandle ">$name.in.tracklet_pointer";
print $tracklet_fh <<"HEADER";
!!TRACKLET_ID DET_ID
HEADER

push @manifest_files, "$name.in.detection";
my $det_fh = new FileHandle ">$name.in.detection";
print $det_fh <<"HEADER";
!!OID TIME_MJD OBS_TYPE RA_DEG DEC_DEG APPMAG FILTER OBSERVATORY RA_RMS DEC_RMS MAG_RMS S2N SECRET
HEADER


if (defined($nn)) {
    $tref = $dbh->selectcol_arrayref("select tracklet_id from tracklets t join fields f using (field_id) where $field_status_str f.nn=$nn and t.classification='N' and probability > $min_prob");
}
else {
    $tref = $dbh->selectcol_arrayref("select tracklet_id from tracklets t where t.classification='N' and probability > $min_prob");
}
foreach my $tid (@{$tref}) {
    my $trk = modct_retrieve($inst, trackletId => $tid) or die "can't retrieve tracklet $tid: " . $dbh->errstr;

    if (!already_known($known_tbl, $trk)) {
        # Write detections.
        foreach my $det (@{$trk->detections}) {
            print $tracklet_fh $tid, ' ', $det->detId, "\n";

            if (!$seen_dets{$det->detId}) {
                print $det_fh join(' ', 
                    $det->detId, 
                    $det->epoch, 
                    'O', 
                    $det->ra, 
                    $det->dec, 
                    sprintf("%.6f", $det->mag), 
                    $det->filter, 
                    $det->obscode, 
                    $det->raSigma * 3600, 
                    $det->decSigma * 3600, 
                    $det->magSigma, 
                    $det->s2n, 
                    ($det->objectName || 'FALSE')
                ), "\n";
                $seen_dets{$det->detId} = 1;        # don't write this det again
            }
        }
    }
}

close $tracklet_fh;
close $det_fh;
print STDERR "Done.\n";


# SSM.
if ($ssm) {
    print STDERR "Writing SSM...";
    push @manifest_files, "ssm.orbit";
    system('catOrbits --ssm --format=COM > ssm.orbit');
    print STDERR "done.\n";
    warn $? if $?;
}
else {
    system('touch ssm.orbit');
}


my $fh = new FileHandle ">>$name.manifest";
push @manifest_files, "$name.manifest";
print $fh map { $_ . "\n" } @manifest_files;
close $fh;

exit;


sub load_known {
    # Build a table of 
    #   epoch_mjd => [
    #     [ra, dec, mag]
    #   ]
    my $catdir = $mops_config->{known}->{local_catalog_dir};
    if (!$catdir) {
        print STDERR "Could not find known->{local_catalog_dir} in config.\n";
        return;
    }
    die "not a directory: $catdir" unless -d $catdir;

    my $seen = {};
    my $nfn = "$catdir/fitcnumb/F51.tracklet";
    my $mfn = "$catdir/fitcmult/F51.tracklet";
    my $fh;
    my $ndet = 0;
    my ($id, $epoch_mjd, $obstype, $ra_deg, $dec_deg, $mag, $rest);
    my $epoch_str;

    $fh = new FileHandle $nfn or die "can't open numbered F51 tracklet file $nfn";
    print STDERR "Loading known detections from $nfn.\n";
    while (<$fh>) {
        next if /^!/;       # skip comment
        ($id, $epoch_mjd, $obstype, $ra_deg, $dec_deg, $mag, $rest) = split /\s+/, $_, 7;
        $epoch_str = sprintf "%.6f", $epoch_mjd;
        push @{$seen->{$epoch_str}}, [ $ra_deg, $dec_deg, $mag, $id ];
        $ndet++;
    }
    $fh->close;

    $fh = new FileHandle $mfn or die "can't open numbered F51 tracklet file $mfn";
    print STDERR "Loading known detections from $mfn.\n";
    while (<$fh>) {
        next if /^!/;       # skip comment
        ($id, $epoch_mjd, $obstype, $ra_deg, $dec_deg, $mag, $rest) = split /\s+/, $_, 7;
        $epoch_str = sprintf "%.6f", $epoch_mjd;
        push @{$seen->{$epoch_str}}, [ $ra_deg, $dec_deg, $mag, $id ];
        $ndet++;
    }
    $fh->close;

    printf STDERR "Loaded %d known F51 observations from %d exposures.\n", $ndet, scalar keys %{$seen};
    return $seen;
}


sub already_known {
    # Return 1 if any of this tracklet's detections match previously attributed detections from the KNOWN F51 catalog.
    my ($tbl, $trk) = @_;
    return unless $tbl;

    my $epoch_str;
    my ($epoch_mjd, $ra_deg, $dec_deg);
    my $found = 0;
    my $THRESH_ARCSEC = 1.0;    # ?
    my $THRESH_RAD = deg2rad($THRESH_ARCSEC / 3600);        # for SLALIB
    my $dist_arcsec;

    foreach my $det (@{$trk->detections}) {
        ($epoch_mjd, $ra_deg, $dec_deg) = ($det->epoch, $det->ra, $det->dec);
        $epoch_str = sprintf "%.6f", $epoch_mjd;
        if (exists($tbl->{$epoch_str})) {
            # Found matching exposure, look for matching det.
            foreach my $kdet (@{$tbl->{$epoch_str}}) {
                if (abs($dec_deg - $kdet->[1]) < $THRESH_ARCSEC) {
                    if (($dist_arcsec = slaDsep(deg2rad($ra_deg), deg2rad($dec_deg), deg2rad($kdet->[0]), deg2rad($kdet->[1]))) < $THRESH_RAD) {
                        $found = 1;
                        printf STDERR "Found T%s [K%s $kdet->[-1] %.2f\"].\n", $trk->trackletId, ($trk->knownId || 'NA'), $dist_arcsec;
                        last;
                    }
                }
            }
            last if $found;
        }
    }
    return $found;
}
