package PS::MOPS::MPCLib;

# Routines useful in processing MPC observation and orbit data.

use strict;
use warnings;
use base qw(Exporter);

our @EXPORT = qw(get_perihelion
                 get_time_of_perihelion
                 get_epoch
                 convert_mpc_object_number_to_number
               );

use Astro::Time;

# Return perihelion given a and e.
# @param $a semimajor axis [AU]
# @param $e eccentricity
# @return Perihelion q [AU].
sub get_perihelion {
    my ($a, $e)=@_;
    my $f=$e*$a;
    my $q=$a-$f;
    return $q;
}

# Return time of perihelion given mean anomaly M and daily motion n and the epoch.
# @param $n daily motion [deg]
# @param $M mean anomaly
# @param $epoch MPC packed-form date.
# @return Time of perihelion [MJD].
sub get_time_of_perihelion {
    my ($M,$n,$epoch)=@_;
    my $epoch_mjd=get_epoch($epoch);
    my $perihelion=$epoch_mjd-($M/$n);
    return $perihelion;
}

# Return an MJD value given a packed-form MPC date.
# @param $pe packed epoch
# @todo Test that all fractions are recovered correctly.
# @return epoch [MJD]
sub get_epoch {
    my ($pe)=@_;
    my $base_packed_length=5;
    my $century=substr($pe,0,1) || die "unable to get substring";
    my $year=substr($pe,1,2) || die "unable to get substring";
    my $month=substr($pe,3,1) || die "unable to get substring";
    my $day=substr($pe,4,1) || die "unable to get substring";
    my $length=length($pe) || die "unable to get substring";;
    my $fraction;
    if($length-$base_packed_length>0){
        $fraction=substr($pe,5,$length-$base_packed_length) || die "unable to get substring";
        $fraction="0." . $fraction;
    }
    my $numeric_month={1=>1,2=>2,3=>3,4=>4,5=>5,6=>6,7=>7,8=>8,9=>9,A=>10,B=>11,C=>12}->{uc($month)} || die "bad month";
    my $numeric_day={1=>1,2=>2,3=>3,4=>4,5=>5,6=>6,7=>7,8=>8,9=>9,A=>10,B=>11,C=>12,D=>13,E=>14,F=>15,G=>16,H=>17,I=>18,J=>19,K=>20,L=>21,M=>22,N=>23,O=>24,P=>25,Q=>26,R=>27,S=>28,T=>29,U=>30,V=>31}->{uc($day)} || die "bad day";
    my $numeric_century={I=>18,J=>19,K=>20}->{uc($century)} || die "bad century";
    my $full_year=$numeric_century . $year;
    my $epoch_mjd=cal2mjd($numeric_day, $numeric_month, $full_year, $fraction);
    return $epoch_mjd;
}

# Given a five-character MPC object number. Convert it to a pure numeric value.
#
# Numeric equivalency examples
#
# 99999 = 99999
# A0000 = 100000
# A9999 = 109999
# B0000 = 110000
# B9999 = 119999
#
# @param MPC object number
# @return Numeric value
sub convert_mpc_object_number_to_number {
    my($mpc_num)=@_;

    my $first_char=substr($mpc_num,0,1);
    my $last_four_char=substr($mpc_num,1,4);
    my %assoc=(A=>10,B=>11,C=>12,D=>13,E=>14,F=>15,G=>16);

    if($first_char=~/\d/){ # Not a letter and no need for conversion.
        return $mpc_num;
    }
    else{
        return "$assoc{$first_char}$last_four_char";
    }
}

1;
