// NeoPixel Ring simple sketch (c) 2013 Shae Erisson
// Released under the GPLv3 license to match the rest of the
// Adafruit NeoPixel library

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

// Which pin on the Arduino is connected to the NeoPixels?
#define PIN        6 // On Trinket or Gemma, suggest changing this to 1

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 3 // Popular NeoPixel ring size

// When setting up the NeoPixel library, we tell it how many pixels,
// and which pin to use to send signals. Note that for older NeoPixel
// strips you might need to change the third parameter -- see the
// strandtest example for more information on possible values.
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

#define DELAYVAL 500 // Time (in milliseconds) to pause between pixels


/*
 * ephemeris_full.ino
 *
 * Copyright (c) 2017 by Sebastien MARCHAND (Web:www.marscaper.com, Email:[email protected])
 */
/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
    
#include <Ephemeris.h>


static const SolarSystemObjectIndex SSO[2] = {Sun, EarthsMoon };   //Object to track
//uint32_t EarthsMoonColour = (255, 0, 0);
static const uint32_t M_C   = 0x99ffff;
static const uint32_t S_C   = 0xffff66;

void printDateAndTime(int day, int month, int year, int hour, int minute, int second )
{
  Serial.print(day);
  Serial.print("/");
  Serial.print(month);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.print(second);
}

void equatorialCoordinatesToString(EquatorialCoordinates coord, char raCoord[14] , char decCoord[14])
{
  int raHour,raMinute;
  float raSecond;
  Ephemeris::floatingHoursToHoursMinutesSeconds(coord.ra, &raHour, &raMinute, &raSecond);
    
  sprintf(raCoord," %02dh%02dm%02ds.%02d",raHour,raMinute,(int)raSecond,(int)round(((float)(raSecond-(int)raSecond)*pow(10,2))));
    
  int decDegree,decMinute;
  float decSecond;
  Ephemeris::floatingDegreesToDegreesMinutesSeconds(coord.dec, &decDegree, &decMinute, &decSecond);
    
  if(decDegree<0)
  {
    sprintf(decCoord,"%02dd%02d'%02d\".%02d",(int)decDegree,decMinute,(int)decSecond,(int)round(((float)(decSecond-(int)decSecond)*pow(10,2))));
  }
  else
  {
    sprintf(decCoord," %02dd%02d'%02d\".%02d",(int)decDegree,decMinute,(int)decSecond,(int)round(((float)(decSecond-(int)decSecond)*pow(10,2))));
  }
}

void printEquatorialCoordinates(EquatorialCoordinates coord)
{
  if( isnan(coord.ra) ||  isnan(coord.dec))
  {
    // Do not work for Earth of course...
    Serial.println("R.A: -");
    Serial.println("Dec: -");
        
    return;
  }
    
  char raCoord[14];
  char decCoord[14];
  equatorialCoordinatesToString(coord,raCoord,decCoord);

  Serial.print("R.A: ");
  Serial.println(raCoord);

  Serial.print("Dec: ");
  Serial.println(decCoord);

  return;
}

void printHorizontalCoordinates(HorizontalCoordinates coord)
{
  if( isnan(coord.azi) ||  isnan(coord.alt))
  {
    // Do not work for Earth of course...
    Serial.println("Azi: -");
    Serial.println("Alt: -");
        
    return;
  }

  Serial.print("Azi: ");
  Serial.print(coord.azi,2);
  Serial.println("d");

  Serial.print("Alt: ");
  Serial.print(coord.alt,2);
  Serial.println("d");
}

void printSolarSystemObjects(int day, int month, int year, int hour, int minute, int second)
{
  Serial.println("_____________________________________");
  printPlanet("Sun",          Sun,     day, month, year, hour, minute, second);
  Serial.println("_____________________________________");
  printPlanet("Earth's Moon", EarthsMoon,   day, month, year, hour, minute, second);
  Serial.println("_____________________________________");
}

void printPlanet(char *solarSystemObjectName, SolarSystemObjectIndex index, int day, int month, int year, int hour, int minute, int second )
{
  SolarSystemObject solarSystemObject = Ephemeris::solarSystemObjectAtDateAndTime(index, day, month, year, hour, minute, second);

  if( index == Earth )
  {
    Serial.println(solarSystemObjectName);
    Serial.println("Look under your feet... ;)");

    return;
  }
  
  Serial.println(solarSystemObjectName);
  printEquatorialCoordinates(solarSystemObject.equaCoordinates);
  printHorizontalCoordinates(solarSystemObject.horiCoordinates);

  if( solarSystemObject.riseAndSetState == RiseAndSetOk )
  {
    int hour,minute;
    float second;
    
    Ephemeris::floatingHoursToHoursMinutesSeconds(solarSystemObject.rise, &hour, &minute, &second);
    Serial.print("Rise: ");
    Serial.print(hour);
    Serial.print("h");
    Serial.print(minute);
    Serial.print("m");
    Serial.print(second);
    Serial.println("s");

    Ephemeris::floatingHoursToHoursMinutesSeconds(solarSystemObject.set, &hour, &minute, &second);
    Serial.print("Set:  ");
    Serial.print(hour);
    Serial.print("h");
    Serial.print(minute);
    Serial.print("m");
    Serial.print(second);
    Serial.println("s");
  }

  if( isnan(solarSystemObject.diameter) )
  {
    // Do not work for Earth of course...
    Serial.println("Dist: -");
    Serial.println("Diam: -");
  }
  else
  {
    Serial.print("Dist: ");
    if( index != EarthsMoon )
    {
      Serial.print(solarSystemObject.distance,3);
      Serial.println(" AU");
    }
    else
    {
      Serial.print(solarSystemObject.distance/6.68459e-9);
      Serial.println(" Km");
    }
    
    if( solarSystemObject.diameter <= 1 )
    {
      Serial.print("Diam: ");
      Serial.print(solarSystemObject.diameter*60,2);
      Serial.println("\"");
    }
    else
    {
      Serial.print("Diam: ");
      Serial.print(solarSystemObject.diameter,2);
      Serial.println("'");
    }
  }
}

void setup() 
{

    // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  // END of Trinket-specific code.

  pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)


  Serial.begin(9600);

  // Set location on earth for horizontal coordinates transformations
  Ephemeris::setLocationOnEarth(47,15,5,  // Lat: 48°50'11"
                                 8,31,47); // Lon: -2°20'14"

  // East is negative=>flip=true and West is positive=>flip = false
  Ephemeris::flipLongitude(false);
    
  // Set altitude to improve rise and set precision
  Ephemeris::setAltitude(645);
                                




  /* Serial.println("_____________________________________");
  Serial.println("Testing coordinates transformations:");
    
  EquatorialCoordinates polarStarEqCoord;
  polarStarEqCoord.ra  = Ephemeris::hoursMinutesSecondsToFloatingHours(2, 31, 49);      // 2h31m49s
  polarStarEqCoord.dec = Ephemeris::degreesMinutesSecondsToFloatingDegrees(89, 15, 51); // +89° 15′ 51″
  printEquatorialCoordinates(polarStarEqCoord);
  
  Serial.println("Convert RA/Dec to Alt/Az:");
  HorizontalCoordinates polarStarHCoord = Ephemeris::equatorialToHorizontalCoordinatesAtDateAndTime(polarStarEqCoord,
                                                                                                      day, month, year,
                                                                                                      hour, minute, second);
  printHorizontalCoordinates(polarStarHCoord);

  Serial.println("Convert Alt/Az back to RA/Dec:");
  polarStarEqCoord = Ephemeris::horizontalToEquatorialCoordinatesAtDateAndTime(polarStarHCoord,
                                                                               day, month, year,
                                                                               hour, minute, second);
  printEquatorialCoordinates(polarStarEqCoord);
  */

  return;
}




void loop() {


  Serial.println("Benchmarking Solar system...");
  float startTime = millis();
  
  // Choose a date and time
  int day=25,month=9,year=2022,hour=22,minute=25,second=0;

    // Compute and print solar system objects
  Serial.print("Data of Solar system objects (");
  printDateAndTime(day,month,year,hour,minute,second);
  Serial.println(")");
  printSolarSystemObjects(day, month, year, hour, minute, second);


  int ssoLenght = sizeof(SSO)/sizeof(*SSO);
  for (int i = 0; i < ssoLenght; i++) 
  {
    SolarSystemObject solarSystemObject = Ephemeris::solarSystemObjectAtDateAndTime((SolarSystemObjectIndex)SSO[i], day, month, year, hour, minute, second);
  
     Serial.println((solarSystemObject.horiCoordinates.alt,2)+90);


  }
  float elapsedTime = ((float)millis() - startTime) / (float)1000;

  Serial.print("Elapsed time: ");
  Serial.print(elapsedTime);
  Serial.println("s");


  

  // The first NeoPixel in a strand is #0, second is 1, all the way up
  // to the count of pixels minus one.
  for(int i=0; i<NUMPIXELS; i++) { // For each pixel...
  
  pixels.clear(); // Set all pixel colors to 'off'

    // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
    // Here we're using a moderately bright green color:
    pixels.setPixelColor(i, M_C);

    pixels.show();   // Send the updated pixel colors to the hardware.

    delay(DELAYVAL); // Pause before next pass through loop
  }









}