<?php

/*
   ###########################################################################
   TEST/DEMO FUNCTION:  App_Geocent_T_List_Ephem()

   This program requires an Internet connection to access the JPL Horizons API.

   AUTHOR   : Jay Tanner - 2025
   LANGUAGE : PHP v8.2.12

   This function returns a simple apparent geocentric ephemeris based on a
   list of Julian Dates.

   ---------------------------------------------------------------------
   Edit and run the source code to experiment with different parameters.
   More quantities can easily be added to the ephemeris and the order of
   the columns can be arranged in just about any way you wish.

   NO DEPENDENCIES
   ###########################################################################
*/


/* --------------------------------------------------
   Define random NASA/JPL body ID for this test/demo.
   A random solar system body will be selected.

   Refresh page for new randomized selection.
*/
   
$BodyID Random_Int(111);
   
$BodyID Str_Replace('1099''10',(($BodyID == 11)? '301':$BodyID.'99'));
   
$BodyID Str_Replace('399''301'$BodyID);
   
$BodyID .= (MT_Rand() % == 0)? ';' '';
   if (
MT_Rand() % == 0) {$BodyID Random_Int(150000).';';}

// ---------------------
// Define asteroid note.

   
$AsteroidNoteText = (StrPos($BodyID';') !== FALSE)? '(asteroid)' '';

// --------------------------------------------------------
// Define date span, time and zone variables for ephemeris.

// $BodyID     = '301'; // Un-comment for Moon to override random selection above.
   
$TimeZone   '-05:00'// +Positive = East
   
$TimeScale  'UT';     // 'UT|TT'

// -----------------------------------------------
// Define example list of JD (Julian Date) values
// for which to compute the ephemeris.

   
$TList =
"
'2433056.5'
'2437892.184365723'
'2441505.322565431'
'2442133.739790178'
'2449031.573128554'"
;



// ---------------------------------
// Use Daylight Saving/Summer Time ?

   
$DSSTYN 'No'// 'Yes|No'

/* -------------------------------------------------------------
   Define angular output mode.
   HMS = Return hour angles and declinations as HMS/DMS strings.
   DEG = Return hour angles and declinations in decimal hours/degrees.
*/
   
$DEGorHMS      'HMS'// 'DEG|HMS'

// ---------------------------------------------------------
// Call the custom function to generate the ephemeris table.

   
$AppGeoEphemListText App_Geocent_T_List_Ephem ($BodyID,$TList,$TimeZone,
                                                    
$TimeScale,$DSSTYN,
                                                    
$DEGorHMS);

// --------------------------------------------------------
// Generate a client web page to display the returned text.

   
print <<< _HTML

<!DOCTYPE HTML>

<br>

<!-- Top yellow source code view link. --->
<br>
<table width="800" align="bottom" cellspacing="1" cellpadding="3">
<tr>
<td colspan="1" style="font-size:10pt; color:black;
                       background:white;text-align:left;">
<b><a href='View-Source-Code.php' target='_blank'
style='font-family:Verdana; color:black; background:yellow;
       text-decoration:none; border:1px solid black; padding:4px;'>
       &nbsp;View Source Code&nbsp;</a></b>
</td></tr>
</table>

<b><pre style='font-size:11pt;'>
TEST/DEMO FUNCTION:  App_Geocent_T_List_Ephem()

App_Geocent_T_List_Ephem (BodyID,TList,TimeZone,TimeScale,DSSTYN,DEGorHMS)

This function returns an apparent geocentric ephemeris for a series of Julian
Dates.

Refresh page for a new random Body ID selection.
##############################################################################

NASA/JPL Body ID = 
$BodyID  $AsteroidNoteText

Time Scale             =  
$TimeScale
Time Zone              =  UT
$TimeZone (Ignored when using TT Scale)
Daylight/Summer Time ? =  
$DSSTYN
Output DEG or HMS    ? =  
$DEGorHMS

-------------------------------------
List of Julian Dates to be processed:
$TList

##############################################################################



$AppGeoEphemListText
</pre></b>

<!-- For extra scroll space at bottom of page --->
<br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br>

_HTML;


/* ###########################################################################
   This function sends a user-defined Internet query to the NASA/JPL Horizons
   API in Pasadena, California.

   In this function, the query is supposed to be the Body ID or record #.

   This function returns a simple apparent geocentric ephemeris for the
   specified BodyID and a given list of Julian dates to which the compu-
   tations apply.

   Internal to Horizons, the list is called the 'TLIST' as shown in the
   code below.

   ------------------------
   Example JD TLIST format:

   '2437892.184365723'
   '2441505.322565431'
   '2442133.739790178'
   '2449031.573128554'

   The ephemeris values returned are:

   COLUMN  CONTENTS
   ------  -----------------------------------------------------
     1     Date and Time UT/ZONE/TT
     2     Solar presence symbol
     3     Lunar presence symbol
     4     Right Ascension DEG/HMS
     5     Declination DEG/DMS
     6     Distance AU/KM
     7     Angular diameter in arc seconds
     8     Apparent visual magnitude
     9     Surface brightness of 1 square arc second of disc
   --------------------------------------------------------------
   These two columns are appended to the table ONLY for the moon.
   They can be used to determine the simple lunar phase angle.

   11 ... SOT = Sun-Observer-Target(Moon) angle in degrees.

   12 ... Moon relative to sun: /L = Leading;   /T = Trailing

   NOTE: For the simple lunar phase angle from 0 to 360 degrees:
         PhaseAng = (LorT == 'L')? 360-SOT : SOT

   When parsing the returned text, the type of text needs to be determined
   so we know whether it was an ephemeris, an error or some other message
   that came back.

   An ephemeris will be identified by special starting and endpoint markers
   and the table columns will be in linear CSV (spreadsheet) format for easy
   parsing and re-formatting. The ephemeris Start/End markers are:

   $$SOE = Start Of Ephemeris
           and
   $$EOE = End Of Ephemeris

   If there are no ephemeris markers, then whatever text was returned was not
   an ephemeris table and must be parsed differently.


   ###########################################################################
*/
   
function App_Geocent_T_List_Ephem ($BodyID,$TList,$TimeZone,$TimeScale,$DSSTYN,
                               
$DEGorHMS)
{
// ---------------
// Read arguments.

   
$BodyID  StrToUpper(trim($BodyID));
              if (
$BodyID == 'Q' or $BodyID == 'X') {return '';}

   
$Command URLEncode(trim($BodyID));
   
$TList   URLEncode(trim($TList));

/* -----------------------------------------------------------
   Adjust for Daylight/Summer Time, if indicated. This assumes
   that the Time Zone string is given in the standard +-HH:mm
   format or an error may occur.
*/
   
$DSSTYN  substr(StrToUpper(trim($DSSTYN)),0,1);
   
$DSSTAdj = ($DSSTYN == 'N')? 0:1;
   list(
$TZHH$TZmm) = PReg_Split("[\:]"$TimeZone);
   
$TZSign substr($TZHH,0,1);
   
$TZHours = (($TZSign == '-')? -1:1)*(abs($TZHH) + $TZmm/60) + $DSSTAdj;
   
$i StrPos($TZHours'.');  if ($i == FALSE) {$TZHours .= '.00';}
   
$i StrPos($TZHours'.');
   
$TZHH $TZSign.SPrintF("%02d"abs(substr($TZHours,0,$i)));
   
$TimeZone "$TZHH:$TZmm";
   
$TimeScale = (StrToUpper(substr(trim($TimeScale),0,1)) == 'T')? 'TT':'UT';
   
$DEGorHMS  = (StrToUpper(substr(trim($DEGorHMS),0,1)) == 'D')? 'DEG':'HMS';

// ---------------------------------------------------------------------
// Handle special case of moon to include SOT,/r columns at end of line
// and to use km instead of AUs as the distance units.

   
$SOT '';  $DistUnits 'AU';

   if (
$BodyID == '301') {$SOT ',23';  $DistUnits 'KM';}

/* =======================================================================
   CONSTRUCT CALLING URL FOR JPL HORIZONS API.    IN THE CASE OF THE MOON,
   KILOMETERS (KM) ARE SET AS THE RANGE (DISTANCE) UNITS, RATHER THAN AUs.
   THIS IS A LUNAR CUSTOMIZATION, THE DEFAULT DISTANCE UNITS ARE AUs.

   For angles in Deg Min Sec format use:  &ANG_FORMAT='HMS'
   =======================================================================
*/
   
$From_Horizons_API =
   
"https://ssd.jpl.nasa.gov/api/horizons.api?format=text" .
   
"&COMMAND='$Command'"                     .
   
"&MAKE_EPHEM='YES'"                       .
   
"&OBJ_DATA='YES'"                         .
   
"&EPHEM_TYPE='OBSERVER'"                  .
   
"&REF_SYSTEM='ICRF'"                      .
   
"&CENTER='500@399'"                       .
   
"&CAL_FORMAT='BOTH'"                      .
   
"&TIME_TYPE='UT'"                         .
   
"&TIME_ZONE='$TimeZone'"                  .
   
"&TIME_DIGITS='SECONDS'"                  .
   
"&TLIST_TYPE='JD'"                        .
   
"&TLIST='$TList'"                         .
   
"&ANG_FORMAT='$DEGorHMS'"                 .
   
"&APPARENT='AIRLESS'"                     .
   
"&RANGE_UNITS='$DistUnits'"               .
   
"&SUPPRESS_RANGE_RATE='YES'"              .
   
"&EXTRA_PREC='YES'"                       .
   
"&QUANTITIES='2,20,13,9$SOT'"             .
   
"&CSV_FORMAT='YES'"                       ;
// ======================================================================


/* ------------------------------------------------------------------------
   Send query to JPL Horizons API to get raw ephemeris as large text block.
   This text can later be parsed and its contents selectively extracted.
   It is possible that an error message could be returned, so this should
   be taken into account.
*/
   
$W Str_Replace(",\n"" \n"trim(File_Get_Contents($From_Horizons_API)));

   return 
$W;

// End of  App_Geocent_T_List_Ephem (...)





?>