//
//  MoonTopocentric.js
//  
//
//  Created by SOL on 5/3/25.
//

// MARK: - Jean Meeus & Peter Duffett-Smith.

var PARALLAX = {
    
    width:null,
    height:null,
    //Define framerate variables
    fps:20, //Set desired framerate
    now:null,
    then:Date.now(),
    interval:null,
    delta:null,
    
    julianCenturyInJulianDays:36525,
    julianEpochJ1990:2447891.5, //PAGE 86 - USED FOR MOON CALCULATIONS
    julianDate:null,
    current:null,
    newDate:null,
    MINUTE:null,
    HOUR:null,
    DAY:null,
    MONTH:null,
    YEAR:null,
    increase:-4, //by default increase time by 4 hours per frame

    sunEc:null,
    
    moonMeanLongitude:null,
    moonMeanElongation:null,
    moonArgumentLatitude:null,
    moonMeanLongitudeAscendingNode:null,
    
    A1:null,
    A2:null,
    A3:null,
    E:null,
    sumL:null,
    sumB:null,
    sumR:null,
    
    moonRA:null, //Array with R.A. H, M & S values
    moonDECL:null, //Array with DECLINATION H, M & S values
    
    moonRATopocentric:null,
    moonDECLTopocentric:null,
    
    moonRADeg:null, //Degree value of R.A.
    moonDECLDeg:null, //Degree value of DECLINATION
    
    topoLocRA:null,
    topoLocDECL:null,
    
    daysSinceEpoch:null,
    sunMeanAnomaly:null,
    sunEclipticLongitude:null,
    
    moonDistanceKM:null,
    moonHorizontalParallax:null,
    
    GSTDecimal:null,
    LST:null,
    LongitudeObserver:null,
    LongitudeObserverDirection:null,
    AltitudeObserver:null,
    LatitudeObserver:null,
    
    //TABLE 47.A
    //MEEUS PAGES 339 & 340
    sumLArray: [
        [0,0,1,0,6288774,-20905355], //1
        [2,0,-1,0,1274027,-3699111], //2
        [2,0,0,0,658314,-2955968], //3
        [0,0,2,0,213618,-569925], //4
        [0,1,0,0,-185116,48888], //5
        [0,0,0,2,-114332,-3149], //6
        [2,0,-2,0,58793,246158], //7
        [2,-1,-1,0,57066,-152138], //8
        [2,0,1,0,53322,-170733], //9
        [2,-1,0,0,45758,-204586], //10
        [0,1,-1,0,-40923,-129620], //11
        [1,0,0,0,-34720,108743], //12
        [0,1,1,0,-30383,104755], //13
        [2,0,0,-2,15327,10321], //14
        [0,0,1,2,-12528,null], //15
        [0,0,1,-2,10980,79661], //16
        [4,0,-1,0,10675,-34782], //17
        [0,0,3,0,10034,-23210], //18
        [4,0,-2,0,8548,-21636], //19
        [2,1,-1,0,-7888,24208], //20
        [2,1,0,0,-6766,30824], //21
        [1,0,-1,0,-5163,-8379], //22
        [1,1,0,0,4987,-16675], //23
        [2,-1,1,0,4036,-12831], //24
        [2,0,2,0,3994,-10445], //25
        [4,0,0,0,3861,-11650], //26
        [2,0,-3,0,3665,14403], //27
        [0,1,-2,0,-2689,-7003], //28
        [2,0,-1,2,-2602,null], //29
        [2,-1,-2,0,2390,10056], //30
        [1,0,1,0,-2348,6322], //31
        [2,-2,0,0,2236,-9884], //32
        [0,1,2,0,-2120,5751], //33
        [0,2,0,0,-2069,null], //34
        [2,-2,-1,0,2048,-4950], //35
        [2,0,1,-2,-1773,4130], //36
        [2,0,0,2,-1595,null], //37
        [4,-1,-1,0,1215,-3958], //38
        [0,0,2,2,-1110,null], //39
        [3,0,-1,0,-892,3258], //40
        [2,1,1,0,-810,2616], //41
        [4,-1,-2,0,759,-1897], //42
        [0,2,-1,0,-713,-2117], //43
        [2,2,-1,0,-700,2354], //44
        [2,1,-2,0,691,null], //45
        [2,-1,0,-2,596,null], //46
        [4,0,1,0,549,-1423], //47
        [0,0,4,0,537,-1117], //48
        [4,-1,0,0,520,-1571], //49
        [1,0,-2,0,-487,-1739], //50
        [2,1,0,-2,-399,null], //51
        [0,0,2,-2,-381,-4421], //52
        [1,1,1,0,351,null], //53
        [3,0,-2,0,-340,null], //54
        [4,0,-3,0,330,null], //55
        [2,-1,2,0,327,null], //56
        [0,2,1,0,-323,1165], //57
        [1,1,-1,0,299,null], //58
        [2,0,3,0,294,null], //59
        [2,0,-1,-2,0,8752] //60
    ],

    //TABLE 47.B
    //MEEUS PAGES 341
    sumBArray: [
        [0,0,0,1,5128122], //1
        [0,0,1,1,280602], //2
        [0,0,1,-1,277693], //3
        [2,0,0,-1,173237], //4
        [2,0,-1,1,55413], //5
        [2,0,-1,-1,46271], //6
        [2,0,0,1,32573], //7
        [0,0,2,1,17198], //8
        [2,0,1,-1,9266], //9
        [0,0,2,-1,8822], //10
        [2,-1,0,-1,8216], //11
        [2,0,-2,-1,4324], //12
        [2,0,1,1,4200], //13
        [2,1,0,-1,-3359], //14
        [2,-1,-1,1,2463], //15
        [2,-1,0,1,2211], //16
        [2,-1,-1,-1,2065], //17
        [0,1,-1,-1,-1870], //18
        [4,0,-1,-1,1828], //19
        [0,1,0,1,-1794], //20
        [0,0,0,3,-1749], //21
        [0,1,-1,1,-1565], //22
        [1,0,0,1,-1491], //23
        [0,1,1,1,-1475], //24
        [0,1,1,-1,-1410], //25
        [0,1,0,-1,-1344], //26
        [1,0,0,-1,-1335], //27
        [0,0,3,1,1107], //28
        [4,0,0,-1,1021], //29
        [4,0,-1,1,833], //30
        [0,0,1,-3,777], //31
        [4,0,-2,1,671], //32
        [2,0,0,-3,607], //33
        [2,0,2,-1,596], //34
        [2,-1,1,-1,491], //35
        [2,0,-2,1,-451], //36
        [0,0,3,-1,439], //37
        [2,0,2,1,422], //38
        [2,0,-3,-1,421], //39
        [2,1,-1,1,-366], //40
        [2,1,0,1,-351], //41
        [4,0,0,1,331], //42
        [2,-1,1,1,315], //43
        [2,-2,0,-1,302], //44
        [0,0,1,3,-283], //45
        [2,1,1,-1,-229], //46
        [1,1,0,-1,223], //47
        [1,1,0,1,223], //48
        [0,1,-2,-1,-220], //49
        [2,1,-1,-1,-220], //50
        [1,0,1,1,-185], //51
        [2,-1,-2,-1,181], //52
        [0,1,2,1,-177], //53
        [4,0,-2,-1,176], //54
        [4,-1,-1,-1,166], //55
        [1,0,1,-1,-164], //56
        [4,0,1,-1,132], //57
        [1,0,-1,-1,-119], //58
        [4,-1,0,-1,115], //59
        [2,-2,0,1,107] //60
    ],
    
    //TABLE 22.A
    //MEEUS PAGES 144
    //Periodic terms for the nutation in longitude
    sumNutationLongitudeArray: [
        [0,0,0,0,1,-171996,-174.2,92025,8.9], //1
        [-2,0,0,2,2,-13187,-1.6,5736,-3.1], //2
        [0,0,0,2,2,-2274,-0.2,977,-0.5], //3
        [0,0,0,0,2,2062,0.2,-895,0.5], //4
        [0,1,0,0,0,1426,-3.4,54,-0.1], //5
        [0,0,1,0,0,712,0.1,-7,null], //6
        [-2,1,0,2,2,-517,1.2,224,-0.6], //7
        [0,0,0,2,1,-386,-0.4,200,null], //8
        [0,0,1,2,2,-301,null,129,-0.1], //9
        [-2,-1,0,2,2,217,-0.5,-95,0.3], //10
        
        [-2,0,1,0,0,-158,null,null,null], //11
        [-2,0,0,2,1,129,0.1,-70,null], //12
        [0,0,-1,2,2,123,null,-53,null], //13
        [2,0,0,0,0,63,null,null,null], //14
        [0,0,1,0,1,63,0.1,-33,null], //15
        [2,0,-1,2,2,-59,null,26,null], //16
        [0,0,-1,0,1,-58,-0.1,32,null], //17
        [0,0,1,2,1,-51,null,27], //18
        [-2,0,2,0,0,48,null,null,null], //19
        [0,0,-2,2,1,46,null,-24,null], //20
        
        [2,0,0,2,2,-38,null,16,null], //21
        [0,0,2,2,2,-31,null,13,null], //22
        [0,0,2,0,0,29,null,null,null], //23
        [-2,0,1,2,2,29,null,-12,null], //24
        [0,0,0,2,0,26,null,null,null], //25
        [-2,0,0,2,0,-22,null,null,null], //26
        [0,0,-1,2,1,21,null,-10,null], //27
        [0,2,0,0,0,17,-0.1,null,null], //28
        [2,0,-1,0,1,16,null,-8,null], //29
        [-2,2,0,2,2,-16,0.1,7,null], //30
        [0,1,0,0,1,-15,null,9,null], //31
        
        [-2,0,1,0,1,-13,null,7,null], //32
        [0,-1,0,0,1,-12,null,6,null], //33
        [0,0,2,-2,0,11,null,null,null], //34
        [2,0,-1,2,1,-10,null,5,null], //35
        [2,0,1,2,2,-8,null,3,null], //36
        [0,1,0,2,2,7,null,-3,null], //37
        [-2,1,1,0,0,-7,null,null,null], //38
        [0,-1,0,2,2,-7,null,3,null], //39
        [2,0,0,2,1,-7,null,3,null], //40
        
        [2,0,1,0,0,6,null,null,null], //41
        [-2,0,2,2,2,6,null,-3,null], //42
        [-2,0,1,2,1,6,null,-3,null], //43
        [2,0,-2,0,1,-6,null,3,null], //44
        [2,0,0,0,1,-6,null,3,null], //45
        [0,-1,1,0,0,5,null,null,null], //46
        [-2,-1,0,2,1,-5,null,3,null], //47
        [-2,0,0,0,1,-5,null,3,null], //48
        [0,0,2,2,1,-5,null,3,null], //49
        [-2,0,2,0,1,4,null,null,null], //50
        
        [-2,1,0,2,1,4,null,null,null], //51
        [0,0,1,-2,0,4,null,null,null], //52
        [-1,0,1,0,0,-4,null,null,null], //53
        [-2,1,0,0,0,-4,null,null,null], //54
        [1,0,0,0,0,-4,null,null,null], //55
        [0,0,1,2,0,3,null,null,null], //56
        [0,0,-2,2,2,-3,null,null,null], //57
        [-1,-1,1,0,0,-3,null,null,null], //58
        [0,1,1,0,0,-3,null,null,null], //59
        [0,-1,1,2,2,-3,null,null,null], //60
        
        [2,-1,-1,2,2,-3,null,null,null], //61
        [0,0,3,2,2,-3,null,null,null], //62
        [2,-1,0,2,2,-3,null,null,null] //63
        
    ],
    
    earthObliquity:null
    
} // PARALLAX

function getMoonTopocentricCoords( now, simEvent ){
    
    let latitude = simEvent.locLat
    let longitude = simEvent.locLon
    let altitude = simEvent.locAlt

    PARALLAX.interval = 1000/PARALLAX.fps;

    PARALLAX.current = now; //Set simulation minute of the day

    //Set location to here

    PARALLAX.LatitudeObserver = latitude
    //PARALLAX.LatitudeObserver = convertHMSToDecimalHours_PARALLAX(6,21,22); //Taken from Meeus (page 82) --> Defines lines along earth from north to south (Greek letter "Phi")

    PARALLAX.LongitudeObserverDirection = 'E'
    PARALLAX.LongitudeObserver = longitude
    if ( longitude < 0.0 ) {
        PARALLAX.LongitudeObserverDirection = 'W'
        PARALLAX.LongitudeObserver = -longitude
    }
    let t = Math.trunc( PARALLAX.LongitudeObserver )
    let f = PARALLAX.LongitudeObserver - t
    PARALLAX.LongitudeObserver =  Math.trunc(t / 15.0) + f
    //PARALLAX.LongitudeObserver = convertHMSToDecimalHours_PARALLAX(7,47,27); //L = 7h 47m 27s (taken from Meeus)
    
    PARALLAX.AltitudeObserver = altitude
    //console.log(PARALLAX.LatitudeObserver,PARALLAX.LongitudeObserver, PARALLAX.LongitudeObserverDirection, PARALLAX.AltitudeObserver)

    PARALLAX.MINUTE = PARALLAX.current.getUTCMinutes();
    PARALLAX.HOUR = PARALLAX.current.getUTCHours();
    PARALLAX.DAY = PARALLAX.current.getUTCDate();
    PARALLAX.MONTH = PARALLAX.current.getUTCMonth()+1; //January is 0!
    PARALLAX.YEAR = PARALLAX.current.getUTCFullYear();
    //Get Julian Date of input date
    PARALLAX.julianDate = getJulianDate_PARALLAX(PARALLAX.YEAR,PARALLAX.MONTH,PARALLAX.DAY,PARALLAX.HOUR,PARALLAX.MINUTE);

    //MAIN FUNCTION: Calculate geocentric R.A. & DECLINATION of Moon
    calculateMoonGeocentric_PARALLAX();
    
    //MAIN FUNCTION: Calculate topocentric R.A. & DECLINATION of Moon (location = Solar Coaster location)
    return calculateMoonTopocentric_PARALLAX();

} // getMoonTopocentricCoords

function calculateMoonTopocentric_PARALLAX(){
    
    //Calculate Moon Parallax (Meeus)
    //-------------------------------
    PARALLAX.moonDistanceKM = 385000.56 + (PARALLAX.sumR / 1000); //Meeus page 342
    PARALLAX.moonHorizontalParallax = Math.asin(6378.14 / PARALLAX.moonDistanceKM); //Meeus page 337
    PARALLAX.moonHorizontalParallax = toDegrees_PARALLAX(PARALLAX.moonHorizontalParallax);
    
    //Get GST & LST (Duffett)
    //-------------------------------
    //Convert Universal Time to Greenwich Mean Sidereal Time (GST)
    PARALLAX.GSTDecimal = convertUT2GST(PARALLAX.YEAR,PARALLAX.MONTH,PARALLAX.DAY,PARALLAX.HOUR,PARALLAX.MINUTE,0);
    //Convert GST to LST using geographical location of observer
    PARALLAX.LST = convertGST2LST(PARALLAX.GSTDecimal,PARALLAX.LongitudeObserver,PARALLAX.LongitudeObserverDirection);
    
    //Get PsinO & PcosO
    //-----------------
    //Calculate "u"
    u = 0.996647 * Math.tan(toRadians_PARALLAX(PARALLAX.LatitudeObserver));
    u = Math.atan(u);
    u = toDegrees_PARALLAX(u);
    
    //Calculate h based on elevation (above sea level)
    h = PARALLAX.AltitudeObserver / 6378140; //6,378.14 km = equatorial radius (the distance from Earth's center to the equator)
    
    //calculate p cos o
    PsinO = 0.996647 * Math.sin(toRadians_PARALLAX(u)) + h * Math.sin(toRadians_PARALLAX(PARALLAX.LatitudeObserver));

    //calculate p sin o
    PcosO = Math.cos(toRadians_PARALLAX(u)) + h * Math.cos(toRadians_PARALLAX(PARALLAX.LatitudeObserver));
    
    moonRAHoursDecimal = PARALLAX.moonRADeg / 15; //convert from degrees to hours
    
    //LOCAL HOUR ANGLE, MEASURED WESTWARD FROM THE SOUTH
    H = PARALLAX.LST - moonRAHoursDecimal;
    H = H * 15; //convert to degrees
    while(H<0){H = H +360;} //get into a positive value

    //Calculate Topocentric R.A.
    //--------------------------
    form_402_numerator = -PcosO * Math.sin(toRadians_PARALLAX(PARALLAX.moonHorizontalParallax)) * Math.sin(toRadians_PARALLAX(H));
    form_402_divider = Math.cos(toRadians_PARALLAX(PARALLAX.moonDECLDeg)) - PcosO * Math.sin(toRadians_PARALLAX(PARALLAX.moonHorizontalParallax)) * Math.cos(toRadians_PARALLAX(H));
    form_402 = form_402_numerator / form_402_divider;
    form_402 = Math.atan(form_402);
    form_402 = toDegrees_PARALLAX(form_402);
    
    PARALLAX.topoLocRA = PARALLAX.moonRADeg + form_402; //Keep in degrees for celestial sphere
    
    form_402 = form_402 / 15; //Convert hours
    moonRATopo = moonRAHoursDecimal + form_402;
    
    PARALLAX.moonRATopocentric = convertDecimalHoursToHMS(moonRATopo);
    
    //Calculate Topocentric DECLINATION
    //---------------------------------
    form_403_numerator = (Math.sin(toRadians_PARALLAX(PARALLAX.moonDECLDeg)) - PsinO * Math.sin(toRadians_PARALLAX(PARALLAX.moonHorizontalParallax))) * Math.cos(toRadians_PARALLAX(form_402));
    form_403_divider = Math.cos(toRadians_PARALLAX(PARALLAX.moonDECLDeg)) - PcosO * Math.sin(toRadians_PARALLAX(PARALLAX.moonHorizontalParallax)) * Math.cos(toRadians_PARALLAX(H));
    form_403 = form_403_numerator / form_403_divider;
    form_403 = Math.atan(form_403);
    form_403 = toDegrees_PARALLAX(form_403);

    PARALLAX.topoLocDECL = form_403; //Keep in degrees for celestial sphere
    PARALLAX.moonDECLTopocentric = convertDecimalHoursToHMS(form_403);
    
    //DEBUG
    //console.log(PARALLAX.YEAR+"-"+PARALLAX.MONTH+"-"+PARALLAX.DAY+"|"+PARALLAX.HOUR+":"+PARALLAX.MINUTE+"|RA="+moonRATopo+"|DEC="+form_403);

    return {
        ra: moonRATopo,
        dec: form_403
    }
    
} // calculateMoonTopocentric_PARALLAX

function convertHMSToDecimalHours_PARALLAX(h,m,s){
    s = s / 60; //take number of seconds and divide by 60
    m = (s + m) / 60; //take number of minutes and divide by 60
    
    h = h + m;
    
    return h;
}

function toRadians_PARALLAX(deg){
    return deg * (Math.PI / 180);
}

function toDegrees_PARALLAX(radians){
  return radians * (180/Math.PI);
}

function round_PARALLAX(value, decimals) {
    return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}
//FUNCTION THAT CONVERTS UT TO GREENWICH MEAN SIDEREAL TIME (GST)
function convertUT2GST(year,month,day,hour,minute,second){
    //1. First get JD of date with 0h
    JD = getJulianDate_PARALLAX(PARALLAX.YEAR,PARALLAX.MONTH,PARALLAX.DAY,0,0,0);
    
    //2. Calculate S = JD - 2451545.0
    S = JD - 2451545.0
    //3. Calculate T = S / 36525.0
    T = S / 36525.0
    //4. Find T0
    T0 = 6.697374558 + (2400.051336 * T) + (0.000025862 * Math.pow(T,2));
    
    T0Range = Math.trunc(Math.abs(T0)/24)+1;
    T024 = T0Range * 24;
    
    if(T0<0){  //ADDED THIS TO MAKE IT WORK FOR BOTH EXAMPLES IN MEEUS
        T0 = T0 + T024;
    }
    else{
        T0 = T0 - T024;
    }
    
    //5. Convert UT to decimal hours
    decimalHours = convertHMSToDecimalHours_PARALLAX(hour,minute,second);
    //6. Multiply UT by 1.002737909
    decimalHoursMult = decimalHours * 1.002737909;
    //7. Get GST
    GST = T0 + decimalHoursMult;
    if(GST>24){GST = GST -24;}

    return GST;
}

//FUNCTION THAT CONVERTS DECIMAL GST INTO LST (LOCAL SIDEREAL TIME)
function convertGST2LST(GSTDecimalHours,geographicalLongitude,direction){
    //Apply corrections based on geographical location
    if(direction=="W"){
        geographicalLongitude = GSTDecimalHours - geographicalLongitude;
    }
    else if (direction=="E"){
        geographicalLongitude = GSTDecimalHours + geographicalLongitude;
    }

    if(geographicalLongitude>24){
        geographicalLongitude = geographicalLongitude - 24;
    }

    return geographicalLongitude;
}

function convertDecimalHoursToHMS(decimal){
    hours = Math.trunc(decimal);
    
    minutes = decimal%1;
    minutes = minutes * 60;
    
    seconds = minutes%1;
    seconds = seconds * 60;
    seconds = round_PARALLAX(seconds,2); //Added 2 decimal accuracy
    
    minutes = Math.trunc(minutes);
    
    //ADDED TO AVOID MINUTES & SECONDS ALSO SHOW NEGATIVE SIGN
    if(minutes<0){minutes = Math.abs(minutes);}
    if(seconds<0){seconds = Math.abs(seconds);}
    
    return [hours,minutes,seconds];
}

//DEGREES TO RIGHT ASCENSION
function DegreesToRA_PARALLAX(decimal){
    //360° = 24 hours (15° = 1 hour)
    fifteen = decimal / 15;
    
    //Degrees to hours
    hours = Math.floor(fifteen);
    //Degrees to minutes
    minfloat = (fifteen - hours) * 60;
    minutes = Math.floor(minfloat);
    //Degrees to seconds
    secfloat = (minfloat - minutes) * 60;
    seconds = round_PARALLAX(secfloat,0);
    
    return [hours, minutes, seconds];
}

//DEGREES TO DECLINATION
function DegreesToDECL_PARALLAX(decimal){
    //Make value positive for correct calculation
    negative = false;
    if(decimal<0){decimal = Math.abs(decimal);negative = true;}
        
    //Degrees to hours
    hours = Math.floor(decimal);
    //Degrees to minutes
    minfloat = (decimal - hours) * 60;

    minutes = Math.floor(minfloat);
    //Degrees to seconds
    secfloat = (minfloat - minutes) * 60;
    seconds = round_PARALLAX(secfloat,0);

    //Correct degrees back to negative/positive
    if(negative){
        hours = -hours;
        decimal = -decimal;
    }
    
    return [hours, minutes, seconds];
}


function getJulianDate_PARALLAX(Year,Month,Day,Hour,Minute){
    var inputDate = new Date(Date.UTC(Year,Month,Day,Minute));
    var switchDate = new Date(Date.UTC("1582","10","15"));

    var isGregorianDate = inputDate >= switchDate;

    //Adjust if B.C.
    if(Year<0){
        Year++;
    }

    //Adjust if JAN or FEB
    if(Month==1||Month==2){
        Year = Year - 1;
        Month = Month + 12;
    }

    //Calculate A & B; ONLY if date is equal or after 1582-Oct-15
    var A = Math.floor(Year/100); //A
    var B = 2-A+Math.floor(A/4); //B
    
    //Ignore B if date is before 1582-Oct-15
    if(!isGregorianDate){B=0;}
                
    //Added Minute Accuracy
    return ((Math.floor(365.25*Year)) + (Math.floor(30.6001*(Month+1))) + Day + (0.04166666666666666666666666666667*Hour) + (0.000694444444444444*Minute) + 1720994.5 + B);
}

function calculateMoonGeocentric_PARALLAX(){
    //Calculate T
    //PAGE 143
    // T = JDE - 2451545 / 36525
    PARALLAX.T = (PARALLAX.julianDate - 2451545) / 36525;
    
    //Calculate "L'" (Mean Longitude of Moon)
    //PAGE 338
    //FORMULA 47.1
    PARALLAX.moonMeanLongitude = 218.3164477 + (481267.88123421 * PARALLAX.T) - (0.0015786 * Math.pow(PARALLAX.T,2)) + (Math.pow(PARALLAX.T,3) / 538841) - (Math.pow(PARALLAX.T,4) / 65194000);
    PARALLAX.moonMeanLongitude = PARALLAX.moonMeanLongitude - 360 * (Math.floor(PARALLAX.moonMeanLongitude/360)); //Reduce to less than 360 degrees (recommended Meeus method)

    //Calculate "D" (Mean Elongation of the Moon)
    //FORMULA 47.2
    PARALLAX.moonMeanElongation = 297.8501921 + (445267.1114034 * PARALLAX.T) - (0.0018819 * Math.pow(PARALLAX.T,2)) + (Math.pow(PARALLAX.T,3) / 545868) - (Math.pow(PARALLAX.T,4) / 113065000);
    PARALLAX.moonMeanElongation = PARALLAX.moonMeanElongation - 360 * (Math.floor(PARALLAX.moonMeanElongation/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    //Calculate "M" (Mean Anomaly of the Sun)
    //FORMULA 47.3
    PARALLAX.sunMeanAnomaly = 357.5291092 + (35999.0502909 * PARALLAX.T) - (0.0001536 * Math.pow(PARALLAX.T,2)) + (Math.pow(PARALLAX.T,3) / 24490000);
    PARALLAX.sunMeanAnomaly = PARALLAX.sunMeanAnomaly - 360 * (Math.floor(PARALLAX.sunMeanAnomaly/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    //Calculate "M'" (Mean Anomaly of the Moon)
    //FORMULA 47.4
    PARALLAX.moonMeanAnomaly = 134.9633964 + (477198.8675055 * PARALLAX.T) + (0.0087414 * Math.pow(PARALLAX.T,2)) + (Math.pow(PARALLAX.T,3) / 69699) - (Math.pow(PARALLAX.T,4) / 14712000);
    PARALLAX.moonMeanAnomaly = PARALLAX.moonMeanAnomaly - 360 * (Math.floor(PARALLAX.moonMeanAnomaly/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    //Calculate "F" (Argument of Latitude of the Moon)
    //FORMULA 47.5
    PARALLAX.moonArgumentLatitude = 93.2720950 + (483202.0175233 * PARALLAX.T) - (0.0036539 * Math.pow(PARALLAX.T,2)) - (Math.pow(PARALLAX.T,3) / 3526000) + (Math.pow(PARALLAX.T,4) / 863310000);
    PARALLAX.moonArgumentLatitude = PARALLAX.moonArgumentLatitude - 360 * (Math.floor(PARALLAX.moonArgumentLatitude/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    
    //Calculate "A1" (due to the action of Venus)
    //PAGE 338
    PARALLAX.A1 = 119.75 + (131.849 * PARALLAX.T);
    PARALLAX.A1 = PARALLAX.A1 - 360 * (Math.floor(PARALLAX.A1/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    //Calculate "A2" (due to the action of Jupiter)
    PARALLAX.A2 = 53.09 + (479264.290 * PARALLAX.T);
    PARALLAX.A2 = PARALLAX.A2 - 360 * (Math.floor(PARALLAX.A2/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    //Calculate "A3"
    PARALLAX.A3 = 313.45 + (481266.484 * PARALLAX.T);
    PARALLAX.A3 = PARALLAX.A3 - 360 * (Math.floor(PARALLAX.A3/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    
    //Calculate "E"
    //FORMULA 47.6
    PARALLAX.E = 1 - (0.002516 * PARALLAX.T) - (0.0000074 * Math.pow(PARALLAX.T,2));
    PARALLAX.E = PARALLAX.E - 360 * (Math.floor(PARALLAX.E/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    
    //Calculate sum of ∑l & ∑r
    PARALLAX.sumL = 0;
    PARALLAX.sumR = 0;
    //Loop through the linear combination array
    for(i=0;i<60;i++){
        terms = PARALLAX.sumLArray[i];
        //[0] = D (Moon Mean Elongation)
        //[1] = M (Sun Mean Anomaly)
        //[2] = M' (Moon Mean Anomaly)
        //[3] = F (Moon Argument of latitude)
        //[4] = Coefficient l
        //[5] = Coefficient r
        
        termD         = terms[0] * PARALLAX.moonMeanElongation;
        termMSun     = terms[1] * PARALLAX.sunMeanAnomaly;
        termMMoon    = terms[2] * PARALLAX.moonMeanAnomaly;
        termF        = terms[3] * PARALLAX.moonArgumentLatitude;
        
        term = termD + termMSun + termMMoon + termF; //Add up the four fundamental arguments D, M, M' and F.
        
        term_cos = Math.cos(toRadians_PARALLAX(term)); //For ∑r
        term = Math.sin(toRadians_PARALLAX(term));
         
        
        if(terms[1]!=0){ //Term M depends on eccentricity of the Earth's orbit around the Sun
            term = PARALLAX.E * term; //Multiply sum of fundamental arguments by coefficient (include "E")
            term_cos = PARALLAX.E * term_cos;
        }

        
        //For Coefficient l
        if(terms[4]!=0){ //It has a value (>0)
            PARALLAX.sumL = PARALLAX.sumL + (terms[4] * term); //Add subtotal to total
        }
        else{ //Coefficient l = 0
            PARALLAX.sumL = PARALLAX.sumL + term; //Add subtotal to total
        }
        
        //For Coefficient r
        if(terms[5]!=null){ //It has a value
            PARALLAX.sumR = PARALLAX.sumR + (terms[5] * term_cos); //Add subtotal to total
        }
        else{ //Coefficient r = null
            PARALLAX.sumR = PARALLAX.sumR + term_cos; //Add subtotal to total
        }
    }
    //Additives to ∑l
    PARALLAX.sumL = PARALLAX.sumL + (3958 * Math.sin(toRadians_PARALLAX(PARALLAX.A1))); //A1
    PARALLAX.sumL = PARALLAX.sumL + (1962 * Math.sin(toRadians_PARALLAX(PARALLAX.moonMeanLongitude - PARALLAX.moonArgumentLatitude))); //L' - F
    PARALLAX.sumL = PARALLAX.sumL + (318 * Math.sin(toRadians_PARALLAX(PARALLAX.A2))); //A2
    
    //Calculate sum of ∑b
    PARALLAX.sumB = 0;
    //Loop through the linear combination array
    for(i=0;i<60;i++){
        terms = PARALLAX.sumBArray[i];
        //[0] = D (Moon Mean Elongation)
        //[1] = M (Sun Mean Anomaly)
        //[2] = M' (Moon Mean Anomaly)
        //[3] = F (Moon Argument of latitude)
        //[4] = Coefficient
        
        termD         = terms[0] * PARALLAX.moonMeanElongation;
        termMSun     = terms[1] * PARALLAX.sunMeanAnomaly;
        termMMoon    = terms[2] * PARALLAX.moonMeanAnomaly;
        termF        = terms[3] * PARALLAX.moonArgumentLatitude;
        
        term = termD + termMSun + termMMoon + termF; //Add up the four fundamental arguments D, M, M' and F.
        
        term = Math.sin(toRadians_PARALLAX(term));
        
        if(terms[1]!=0){ //Term M depends on eccentricity of the Earth's orbit around the Sun
            if(terms[4]!=0){ //In case of last term, the coefficient does not exist, so exclude it
                term = terms[4] * PARALLAX.E * term; //Multiply sum of fundamental arguments by coefficient (include "E")
            }
            else{
                term = PARALLAX.E * term; //Multiply sum of fundamental arguments by coefficient (include "E")
            }
        }
        else{
            if(terms[4]!=0){
                term = terms[4] * term; //Multiply sum of fundamental arguments by coefficient (exclude "E")
            }
        }
        
        PARALLAX.sumB = PARALLAX.sumB + term; //Add subtotal to total
    }
    //Additives to ∑b
    PARALLAX.sumB = PARALLAX.sumB - (2235 * Math.sin(toRadians_PARALLAX(PARALLAX.moonMeanLongitude))); //L'
    PARALLAX.sumB = PARALLAX.sumB + (382 * Math.sin(toRadians_PARALLAX(PARALLAX.A3))); //A3
    PARALLAX.sumB = PARALLAX.sumB + (175 * Math.sin(toRadians_PARALLAX(PARALLAX.A1 - PARALLAX.moonArgumentLatitude))); //A1 - F
    PARALLAX.sumB = PARALLAX.sumB + (175 * Math.sin(toRadians_PARALLAX(PARALLAX.A1 + PARALLAX.moonArgumentLatitude))); //A1 + F
    PARALLAX.sumB = PARALLAX.sumB + (127 * Math.sin(toRadians_PARALLAX(PARALLAX.moonMeanLongitude - PARALLAX.moonMeanAnomaly))); //L' - M'
    PARALLAX.sumB = PARALLAX.sumB - (115 * Math.sin(toRadians_PARALLAX(PARALLAX.moonMeanLongitude + PARALLAX.moonMeanAnomaly))); //L' + M'
    
    
    PARALLAX.moonRADeg = PARALLAX.moonMeanLongitude + (PARALLAX.sumL / 1000000);
    
    PARALLAX.moonDECLDeg = PARALLAX.sumB / 1000000;
    
    //Calculate Longitude of the ascending node of the Moon's mean orbit on the ecliptic
    PARALLAX.moonMeanLongitudeAscendingNode = 125.04452 - (1934.136261 * PARALLAX.T) + (0.0020708 * Math.pow(PARALLAX.T,2)) + (Math.pow(PARALLAX.T,3) / 450000);
    PARALLAX.moonMeanLongitudeAscendingNode = PARALLAX.moonMeanLongitudeAscendingNode - 360 * (Math.floor(PARALLAX.moonMeanLongitudeAscendingNode/360)); //Reduce to less than 360 degrees (recommended Meeus method)
    
    
    //Calculate sum of ∑ψ & ∑ε
    PARALLAX.sumNutation = 0;
    PARALLAX.sumObliquity = 0;
    //Loop through the linear combination array
    for(i=0;i<63;i++){
        terms = PARALLAX.sumNutationLongitudeArray[i];
        //[0] = D (Moon Mean Elongation)
        //[1] = M (Sun Mean Anomaly)
        //[2] = M' (Moon Mean Anomaly)
        //[3] = F (Moon Argument of latitude)
        //[4] = Ω (Moon Mean Longitude of the ascending node)
        //[5] = Coefficient I
        //[6] = Coefficient II
        
        //[7] = e coefficient I
        //[8] = e coefficient II
        
        termD         = terms[0] * PARALLAX.moonMeanElongation;
        termMSun     = terms[1] * PARALLAX.sunMeanAnomaly;
        termMMoon    = terms[2] * PARALLAX.moonMeanAnomaly;
        termF        = terms[3] * PARALLAX.moonArgumentLatitude;
        termPhi        = terms[4] * PARALLAX.moonMeanLongitudeAscendingNode;
        
        term = termD + termMSun + termMMoon + termF + termPhi; //Add up the five fundamental arguments D, M, M', F & Ω.
        
        termSin = Math.sin(toRadians_PARALLAX(term));
        termCos = Math.cos(toRadians_PARALLAX(term));
        
        if(terms[6]!=null){
            termSin = (terms[5] + (terms[6]*PARALLAX.T)) * termSin; //Multiply sum of fundamental arguments by coefficient
        }
        else{
            termSin = terms[5] * termSin; //Multiply sum of fundamental arguments by coefficient (missing cofficient II)
        }
        
        if(terms[7]!=null){
            if(terms[8]!=null){
                termCos = (terms[7] + (terms[8]*PARALLAX.T)) * termCos;
            }
            else{
                termCos = terms[7] * termCos;
            }
        }
        
        
        PARALLAX.sumNutation = PARALLAX.sumNutation + termSin; //Add subtotal to total
        PARALLAX.sumObliquity = PARALLAX.sumObliquity + termCos;
    }
    
    PARALLAX.sumNutation = PARALLAX.sumNutation * 0.0001 / 3600; //Unit = 0".0001
    PARALLAX.sumObliquity = PARALLAX.sumObliquity * 0.0001 / 3600;
    
    PARALLAX.apparentMoonRADeg = PARALLAX.moonRADeg + PARALLAX.sumNutation;

    //CALCULATE MEAN OBLIQUITY OF THE ECLIPTIC & TRUE OBLIQUITY OF THE ECLIPTIC
    //-------------------------------------------------------------------------
    PARALLAX.earthObliquity0 = 23.43929 - (0.01300417 * PARALLAX.T) - (0.0000001638889 * Math.pow(PARALLAX.T,2)) - (0.0000005036111 * Math.pow(PARALLAX.T,3)); //E0
    PARALLAX.earthObliquity = PARALLAX.earthObliquity0 + PARALLAX.sumObliquity; //True Obliquity of the ecliptic
    PARALLAX.earthObliquity0 = convertDecimalHoursToHMS(PARALLAX.earthObliquity0); //Convert from decimal to H, M & S

    
    //USING FORMULA FROM SECTION 27 TO CONVERT TO RIGHT ASCENSION
    //--------------------------------
    findY = (Math.sin(toRadians_PARALLAX(PARALLAX.apparentMoonRADeg)) * Math.cos(toRadians_PARALLAX(PARALLAX.earthObliquity))) - (Math.tan(toRadians_PARALLAX(PARALLAX.moonDECLDeg)) * Math.sin(toRadians_PARALLAX(PARALLAX.earthObliquity)))
    findX = Math.cos(toRadians_PARALLAX(PARALLAX.apparentMoonRADeg));
    findAtan = Math.atan(findY/findX);
    findAtan = toDegrees_PARALLAX(findAtan);
    //REMOVE INVERSE TAN AMBIGUITY
    if(findX<0){findAtan += 180;}
    else if(findX>0 && findY<0){findAtan += 360;}
    //--------------------------------
    //Calculate Right Ascension (R.A) --> Horizontal location in sky
    //Convert Moon Ecliptic Longitude from degrees to HOURS, MINUTES, SECONDS
    PARALLAX.moonRADeg = findAtan;
    PARALLAX.moonRA = DegreesToRA_PARALLAX(findAtan);
    
    
    //CONVERT DECLINATION FROM DEGREES TO DEGREES, MINUTES & SECONDS
    //==============================================================
    //USING FORMULA FROM SECTION 27 TO CONVERT TO DECLINATION
    PARALLAX.moonDECL = Math.asin(((Math.sin(toRadians_PARALLAX(PARALLAX.moonDECLDeg))) * (Math.cos(toRadians_PARALLAX(PARALLAX.earthObliquity)))) + ((Math.cos(toRadians_PARALLAX(PARALLAX.moonDECLDeg))) * (Math.sin(toRadians_PARALLAX(PARALLAX.earthObliquity))) * (Math.sin(toRadians_PARALLAX(PARALLAX.apparentMoonRADeg)))));
    PARALLAX.moonDECL = toDegrees_PARALLAX(PARALLAX.moonDECL);
    //Now convert from DEGREES TO HOURS, MINUTES, SECONDS:
    PARALLAX.moonDECLDeg = PARALLAX.moonDECL;
    PARALLAX.moonDECL = DegreesToDECL_PARALLAX(PARALLAX.moonDECL);
}

