#!/usr/bin/env python
# -*- coding: utf-8 -*-

import glob, os.path, re, traceback, unittest
from datetime import datetime
from time import strptime
import ephem

# Since users might be in another locale, we have to translate the
# month into an integer on our own.
month_ints = {
    'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
    'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12,
    }

# Read an ephemeris from the JPL, and confirm that PyEphem returns the
# same measurements to within one arcsecond of accuracy.

angle_error = ephem.degrees('0:00:10.8') # Hyperion is seriously misbehaving
size_error = 0.1

def cleanup(s):
    return s.strip().replace(' ', ':')

class JPLDatum(object):
    pass

class JPLTest(unittest.TestCase):

    def runTest(self):
        in_data = False

        f = open(self.path)
        try:
            lines = f.readlines()
        finally:
            f.close()

        for line in lines:

            if line.startswith('Target body name:'):
                name = line.split()[3]
                if not hasattr(ephem, name):
                    raise ValueError('ephem lacks a body named %r' % name)
                body_class = getattr(ephem, name)
                body = body_class()

            elif line.startswith('$$SOE'):
                in_data = True

            elif line.startswith('$$EOE'):
                in_data = False

            elif in_data:
                datestr = line[1:6] + str(month_ints[line[6:9]]) + line[9:18]
                date = datetime.strptime(datestr, '%Y-%m-%d %H:%M')
                body.compute(date)

                jpl = JPLDatum()
                jpl.a_ra = ephem.hours(cleanup(line[23:34]))
                jpl.a_dec = ephem.degrees(cleanup(line[35:46]))
                jpl.size = float(line[71:])

                for attr, error in (('a_ra', angle_error),
                                    ('a_dec', angle_error),
                                    ('size', size_error)):
                    try:
                        body_value = getattr(body, attr)
                    except AttributeError: # moons lack "size"
                        continue
                    jpl_value = getattr(jpl, attr)
                    difference = abs(body_value - jpl_value)
                    if difference > error:
                        raise ValueError('at %s, %s returns %s=%s'
                                         ' but JPL insists that %s=%s'
                                         ' which is %s degrees away' %
                                         (date, body.name, attr, body_value,
                                          attr, jpl_value,
                                          ephem.degrees(difference)))

re, traceback, datetime, strptime, ephem

def load_tests(loader, tests, pattern):
    suite = unittest.TestSuite()
    for path in glob.glob(os.path.dirname(__file__) + '/jpl/*.txt'):
        case = JPLTest()
        case.path = path
        suite.addTest(case)
    return suite
