""" Code to compute target visibility

Context : SRP
Module  : SRPVisibility.py
Version : 2.2.1
Author  : Stefano Covino
Date    : 25/02/2018
E-mail  : stefano.covino@brera.inaf.it
URL:    : http://www.merate.mi.astro.it/~covino
Purpose : Compute target visibility, Moon and Sun separation.

Usage   : SRPVisibility  -a arg1 arg2 / -o arg3 arg4 [-d arg5 arg6 arg7] [-h] [-l arg8 arg9 / -s arg10] [-t arg11] [-v]
            -a Altazimuthal coordinates (dd.dddd dd.dddd)
            -d Altitude (m), prssure (mBar) and temperature (C) of the observing site
            -l Coordinate location of observing site (dd:mm:ss or dd.dddd)
            -s Observing site
            -o Object coordinates (hh:mm:ss dd:mm:ss or hh.ddd dd.ddd)
            -t Computation time ('yyy/mm/dd hh:mm:ss')


History : (20/12/2003) First version.
        : (01/09/2004) Better coordinate management.
        : (03/02/2005) Optparse.
        : (21/05/2005) Sun altitude.
        : (01/08/2009) Coordinated in degrees in output.
        : (17/03/2010) Astrometric coordinates.
        : (12/09/2011) Better cosmetics.
        : (14/09/2011) Input of various format for object coordinates.
        : (12/01/2012) Minor bug.
        : (09/02/2012) Sidereal time computation added.
        : (26/08/2012) Air refraction added.
        : (27/08/2012) Altazimuthal input allowed.
        : (27/01/2016) Ecliptic coordinates added.
        : (13/07/2016) Better checks on input.
        : (05/12/2016) Galactic coordinates added.
        : (25/02/2018) Dates from 2000/1/1 0:0:0.
"""


import math, sys
import ephem
from optparse import OptionParser
import SRP.SRPConstants as SRPConstants
import SRP.TimeAstro_algs as TimeAstro_algs
from SRP.SRPMath.AstroAngleInput import AstroAngleInput
from SRP.SRPMath.AstroCoordInput import AstroCoordInput
from SRP.SRPSky.HourAngle import HourAngle
from SRP.SRPSky.ParallacticAngle import ParallacticAngle
from SRP.SRPSky.SiderealTime import SiderealTime



parser = OptionParser(usage="usage: %prog -a arg1 arg2 / -o arg3 arg4 [-d arg5 arg6 arg7] [-h] [-l arg8 arg9 / -s arg10] [-t arg11] [-v]", version="%prog 2.2.0")
parser.add_option("-a", "--altaz", action="store", nargs=2, type="string", dest="altaz", help="Altazimuthal coordinates (dd.dddd dd.dddd)")
parser.add_option("-d", "--data", action="store", nargs=3, type="float", dest="data", default=(0,0,0), help="Altitude (m), pressure (mBar) and temperature (C) of the observing site")
parser.add_option("-l", "--location", action="store", nargs=2, type="string", dest="locat", help="Coordinate location of observing site (dd:mm:ss or dd.dddd).")
parser.add_option("-o", "--object", action="store", nargs=2, type="string", dest="object", help="Object coordinates (hh:mm:ss dd:mm:ss or hh.ddd dd.ddd)")
parser.add_option("-s", "--site", action="store", nargs=1, type="string", dest="site", help="Name of observing site.")
parser.add_option("-t", "--time", action="store", nargs=1, type="string", dest="time", help="Computation time ('yyy/mm/dd hh:mm:ss')")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="Fully describe operations.")
(options, args) = parser.parse_args()


Site = ephem.Observer()
if options.locat:
    Site.lat = str(options.locat[0])
    Site.long = str(options.locat[1])
#
elif options.site:
    if options.site in list(SRPConstants.SiteDict.keys()):
        Site.lat = str(SRPConstants.SiteDict[options.site].Lat)
        Site.long = str(SRPConstants.SiteDict[options.site].Long)
    else:
        print("Available sites: ")
        for entr in list(SRPConstants.SiteDict.keys()):
            print(SRPConstants.SRPTab+entr)
        parser.error("Site %s is not recognized." % options.site)
else:
    Site.lat = str(SRPConstants.SiteDict['LaSilla'].Lat)
    Site.long = str(SRPConstants.SiteDict['LaSilla'].Long)
#
if options.data:
    if options.data[1] < 0:
        parser.error("Pressure must be positive.")
    if options.data[2] < -273:
        parser.error("Temperature must be within acceptable ranges.")
Site.elev = options.data[0]
Site.pressure = options.data[1]
Site.temp = options.data[2]
#
if options.time:
    Site.date = options.time

sun = ephem.Sun(Site)
moon = ephem.Moon(Site)

#
nb = ephem.FixedBody()
#
if options.object and options.altaz:
    parser.error("Either equatorial or altazimuthal coordinates.")
elif not (options.object or options.altaz):
    parser.print_help()
    sys.exit(1)
#
if options.altaz:
    AZ = AstroAngleInput(options.altaz[0])
    ALT = AstroAngleInput(options.altaz[1],period=(0.,90.))
    RA, DEC = Site.radec_of(math.radians(AZ.Angle), math.radians(ALT.Angle))
    nb._ra = str(RA)
    nb._dec = str(DEC)
elif options.object:
    coords = AstroCoordInput(options.object[0], options.object[1])
    if coords.Valid:
        nb._ra = str(coords.EphemCoord.ra)
        nb._dec = str(coords.EphemCoord.dec)
    else:
        parser.error("Coordinates are not properly written.")
#
nb._epoch = ephem.date(ephem.J2000)
nb.compute(Site)
#
if options.verbose:
    print("Site coordinates        : Latitude %s, Longitude %s" % (Site.lat, Site.long))
    print("Target astrometric coordinates: RA %s, DEC %s" % (nb.a_ra, nb.a_dec))
    print("Target coordinates (deg)      : RA %.5f, DEC %.5f" % (math.degrees(float(nb.a_ra)), math.degrees(float(nb.a_dec))))
if options.verbose:
    print("Computation time: %s" % Site.date)
    print("Target Althazimuthal coordinates      : AZ %s, ALT %s" % (nb.az, nb.alt))
    print("Target Althazimuthal coordinates (deg): AZ %.5f, ALT %.5f" % (math.degrees(float(nb.az)), math.degrees(float(nb.alt))))

    print("Moon separation: %s" % ephem.separation((moon.az,moon.alt), (nb.az,nb.alt)))
    print("Sun separation: %s" % ephem.separation((sun.az,sun.alt), (nb.az,nb.alt)))
    print("Sun altitude: %s" % sun.alt)
    print("Ecliptic long: %s, lat: %s" % (ephem.Ecliptic(nb).long,ephem.Ecliptic(nb).lat))
    print("Galactic long: %s, lat: %s" % (ephem.Galactic(nb).long, ephem.Galactic(nb).lat))
    print("Sidereal time: %s" % ephem.hours(str(SiderealTime(Site))))
    print("Hour angle: %s" % ephem.hours(ephem.degrees(str(HourAngle(math.degrees(float(nb.a_ra)),Site)))))
    print("Parallactic angle: %.5f" % ParallacticAngle(nb,Site))
else:
    print("%.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f" % (Site.date-ephem.date('2000/1/1 0:0:0'),
        math.degrees(float(nb.az)), math.degrees(float(nb.alt)),
        math.degrees(ephem.separation((moon.az,moon.alt), (nb.az,nb.alt))),
        math.degrees(ephem.separation((sun.az,sun.alt), (nb.az,nb.alt))),
        math.degrees(float(sun.alt)), math.degrees(float(ephem.Ecliptic(nb).long)),
        math.degrees(float(ephem.Ecliptic(nb).lat)), math.degrees(float(ephem.Galactic(nb).long)),
        math.degrees(float(ephem.Galactic(nb).lat)), math.degrees(float(nb.a_ra)),
        math.degrees(float(nb.a_dec)), math.degrees(SiderealTime(Site)),
        HourAngle(math.degrees(float(nb.a_ra)),Site),ParallacticAngle(nb,Site)))
#
