#!/usr/bin/env perl
package PS::MOPS::DET::dbclient;

use strict;
use warnings;
use FileHandle;
use Astro::SLA;
use Astro::Time;
use PS::MOPS::Constants qw(:all);
use PS::MOPS::Lib qw(:all);
use PS::MOPS::DC::Instance;
use PS::MOPS::DC::Field;
use PS::MOPS::DC::Detection;

use PS::MOPS::DET::table;


use subs qw(
    do_field
);

# Options.
my $debug;
my $help;

# Field status management.
my $START_FIELD_STATUS = $FIELD_STATUS_NEW;

#
# WARNING: $inst is used in a way that makes insert non-reentrant!
#

#
# $instance_name - Simulation instance
# $input_filename - FITS file.  The file is read, and the detections
#      are inserted into the specified simulation instance.
#

sub insert {
	my ($instance_name, $input_filename) = @_;

	my $inst = PS::MOPS::DC::Instance->new(DBNAME => $instance_name);
	my $mops_config = $inst->getConfig;
	my $mops_logger = $inst->getLogger;

	# Start.

	#
	# Read input data file
	#

	my $table = new PS::MOPS::DET::table;
	$table->openfile($input_filename);

    # Get exposure time in MJD.
    my $exptime_mjd = $table->keyval('EXPTIME') / 86400;

	# Get list of fieldIds.
	my $field = PS::MOPS::DC::Field->new($inst,
		epoch => $table->keyval('MJD-OBS'),
		ra => Astro::Time::str2deg($table->keyval('RA'), 'H'),
		dec => Astro::Time::str2deg($table->keyval('DEC'), 'D'),
		surveyMode => 0.0,
		timeStart => $table->keyval('MJD-OBS') - $exptime_mjd / 2.0,
		timeStop => $table->keyval('MJD-OBS') + $exptime_mjd / 2.0,
		status => $START_FIELD_STATUS,
		filter => substr($table->keyval('FILTER'), 0, 1),
		limitingMag => $table->keyval('LIMITMAG'),
		raSigma => 0.0,
		decSigma => 0.0,
		obscode => $table->keyval('OBSCODE'),
		de => [ $table->keyval('DE1'), $table->keyval('DE2'), $table->keyval('DE3'),
			$table->keyval('DE4'), $table->keyval('DE5'), $table->keyval('DE6'),
			$table->keyval('DE7'), $table->keyval('DE8'), $table->keyval('DE9'),
			$table->keyval('DE10') ],
		ocnum => 0.0,
	);

    my $num_added;
    my $dbh = $inst->dbh();
    $inst->atomic($dbh, sub {
        $field->insert();
        $num_added = do_field($field, $table, $inst); 
    });

	if ($num_added > 0 and !$debug)  {
		$mops_logger->info(sprintf "Added %d detections to field %d.",
			$num_added, $field->fieldId);
	}
}

sub do_field {
	my ($field, $table, $inst) = @_;
	my $i = 0;          # count inserted fields
	my $det_num = 0;    # night-unique false det ID
	my $num = 0;		# Placeholder

	# For the fieldId provided, generate $num uniformly-distributed
	# false detections in the field.
	eval {
		my ($tpra_rad, $tpdecl_rad);  # tangent plane RA/DEC in RAD
		my ($fra_rad, $fdecl_rad);  # false RA, DEC in RAD
		my ($fra_deg, $fdecl_deg);  # false RA, DEC in DEG
		my ($field_dra_rad, $field_ddecl_rad);
		my $det;
        my $flux;
        my $flux_sigma;
		my $mag;
		my $mag_sigma;
		my $S2N;
		my $ra_sigma_deg;
		my $dec_sigma_deg;
		my $obscode;
		my $orient_deg;
		my $length_deg;

		$field_dra_rad = 0.0;
		$field_ddecl_rad = 0.0;
		my @all_dets;

		while (my @data = $table->readrecord()) {
			$fra_deg = $data[0];
			$fdecl_deg = $data[1];
			$ra_sigma_deg = $data[2];
			$dec_sigma_deg = $data[3];
            $flux = $data[4];
            $flux_sigma = $data[5];
			$obscode = $table->keyval('OBSCODE');
			$orient_deg = $data[6];
			$length_deg = $data[8];

			my $det_id = sprintf('F%.07d', $i);

            # Convert IPP flux and flux_sigma to mag and S/N.
            ($mag, $mag_sigma, $S2N) = PS::MOPS::Lib::mopslib_flux2hsn($flux, $flux_sigma, $field->filter);

			$det = PS::MOPS::DC::Detection->new(
				$inst,
#				detId => $det_id,
				ra => $fra_deg,
				dec => $fdecl_deg,
				epoch => $field->epoch,
				mag => $mag,
				refMag => $mag,
				filter => $field->filter,
				s2n => $S2N,
				isSynthetic => 0,
				orient_deg => $orient_deg,
				length_deg => $length_deg,
				raSigma => $ra_sigma_deg,
				decSigma => $dec_sigma_deg,
				magSigma => $mag_sigma,
				obscode => $obscode,
				objectName => $MOPS_NONSYNTHETIC_OBJECT_NAME,
#				status => 'F',  # not necessary
			);
			push @all_dets, $det;
			$i++;
		}   # for

		# Write all to database.
        $field->addDetections(@all_dets);
	};

	warn $@ if $@;
	return $i;      # return num dets added
}

1;

=head1 NAME

PS::MOPS::DET::dbclient - Manipulate database tables.

=head1 SYNOPSIS

use PS::MOPS::DET::dbclient

=head1 DESCRIPTION

This module contains routines for accessing the database tables.

=head1 PUBLIC FUNCTIONS

=head2 insert

Read a FITS table containing a list of detections, and insert the detections
into the simulation database.

=cut
