#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>

// TFT display pins (using digital pins)
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8

// Initialize the TFT display
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

// Define colors
#define BACKGROUND_COLOR ILI9341_BLACK
#define ORBIT_COLOR ILI9341_WHITE

// Define colors for light emission
#define RED ILI9341_RED
#define YELLOW ILI9341_YELLOW
#define VIOLET ILI9341_MAGENTA
#define BLUE ILI9341_BLUE
#define GREEN ILI9341_GREEN
#define AMBER 0xFFBF00

// Speed of light in vacuum (in meters per second)
const float SPEED_OF_LIGHT = 3e8;

// Define constants for the orbits and electron
const int CENTER_X = 160;
const int CENTER_Y = 120;
const int OUTER_ORBIT_RADIUS = 60;
const int INNER_ORBIT_RADIUS = 30;
const int ELECTRON_RADIUS = 5;

// Variables for electron animation
float electronAngle = 0;
float electronSpeed = 0.05;

// Variables for light emission
const int wavelengths[] = {650, 590, 410, 450, 550, 590};
const uint16_t colors[] = {RED, YELLOW, VIOLET, BLUE, GREEN, AMBER};
const char* colorNames[] = {"Red", "Yellow", "Violet", "Blue", "Green", "Amber"};
int currentColorIndex = 0;
unsigned long lastChangeTime = 0;
const unsigned long delayTime = 5000;

// Planck's constant (in joule-seconds)
const double PLANCK_CONSTANT = 6.626e-34;

// Function to draw orbits
void drawOrbits() {
  tft.drawCircle(CENTER_X, CENTER_Y, OUTER_ORBIT_RADIUS, ORBIT_COLOR);
  tft.drawCircle(CENTER_X, CENTER_Y, INNER_ORBIT_RADIUS, ORBIT_COLOR);
}

// Function to draw an electron at a given position with the current color
void drawElectron(int x, int y, uint16_t color) {
  tft.fillCircle(x, y, ELECTRON_RADIUS, color);
}

// Function to draw emitted waves (photon emission)
void drawWaves(int startX, int startY, int amplitude, int wavelength, int length, uint16_t color) {
  for (int i = 0; i < length; i++) {
    int x = startX + i;
    int y = startY + amplitude * sin((float)i / wavelength * 2 * PI);
    tft.drawPixel(x, y, color);
  }
}

// Function to display the frequency, photon energy, total energy, and calculated Planck's constant
void displayData(float frequency, double photonEnergy, double totalEnergy, double calculatedPlanckConstant) {
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.setCursor(10, 10);
  tft.print("Freq: ");
  tft.print(frequency, 2);
  tft.print(" THz");
  tft.setCursor(10, 30);
  tft.print("Photon Energy: ");
  tft.print(photonEnergy, 2);
  tft.print(" J"); // Display photon energy in joules
  tft.setCursor(10, 50);
  tft.print("Total Energy: ");
  tft.print(totalEnergy, 2);
  tft.print(" J"); // Display total energy in joules
  tft.setCursor(10, 70);
  tft.print("Calculated Planck's Constant: ");
  tft.print(calculatedPlanckConstant, 2);
  tft.print(" J.s");
}

void setup() {
  Serial.begin(9600);
  Serial.println("TFT Display Initialized");

  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(BACKGROUND_COLOR);

  drawOrbits();
}

void loop() {
  unsigned long currentTime = millis();

  if (currentTime - lastChangeTime > delayTime) {
    tft.fillRect(0, 30, tft.width(), tft.height() - 30, BACKGROUND_COLOR);

    currentColorIndex = (currentColorIndex + 1) % 6;
    lastChangeTime = currentTime;

    float wavelengthInMeters = wavelengths[currentColorIndex] * 1e-9;
    float frequencyInHz = SPEED_OF_LIGHT / wavelengthInMeters;
    float frequencyInTHz = frequencyInHz * 1e-12;
    double photonEnergyJoules = frequencyInHz * PLANCK_CONSTANT;
    double totalEnergyJoules = photonEnergyJoules * 100000;
    double calculatedPlanckConstant = photonEnergyJoules / frequencyInHz;

    Serial.print("Current Color: ");
    Serial.print(colorNames[currentColorIndex]);
    Serial.print(" | Frequency: ");
    Serial.print(frequencyInTHz);
    Serial.print(" THz | Photon Energy: ");
    Serial.print(photonEnergyJoules, 2);
    Serial.print(" J | Total Energy: ");
    Serial.print(totalEnergyJoules, 2);
    Serial.print(" J | Calculated Planck's Constant: ");
    Serial.print(calculatedPlanckConstant, 2);
    Serial.println(" J.s");

    tft.setTextColor(ILI9341_WHITE);
    tft.setTextSize(2);
    tft.setCursor(10, 10);
    tft.print("Color: ");
    tft.print(colorNames[currentColorIndex]);

    drawWaves(CENTER_X + INNER_ORBIT_RADIUS, CENTER_Y, 10, wavelengths[currentColorIndex], 100, colors[currentColorIndex]);
    displayData(frequencyInTHz, photonEnergyJoules, totalEnergyJoules, calculatedPlanckConstant);

    electronAngle = 0;
  }

  tft.fillCircle(CENTER_X + OUTER_ORBIT_RADIUS * cos(electronAngle), CENTER_Y + OUTER_ORBIT_RADIUS * sin(electronAngle), ELECTRON_RADIUS, BACKGROUND_COLOR);

  electronAngle += electronSpeed;
  if (electronAngle >= 2 * PI) {
    electronAngle -= 2 * PI;
  }

  int electronX = CENTER_X + OUTER_ORBIT_RADIUS * cos(electronAngle);
  int electronY = CENTER_Y + OUTER_ORBIT_RADIUS * sin(electronAngle);

  drawElectron(electronX, electronY, colors[currentColorIndex]);

  if (electronAngle >= PI / 2 && electronAngle <= PI) {
    tft.fillCircle(electronX, electronY, ELECTRON_RADIUS, BACKGROUND_COLOR);
    electronX = CENTER_X + INNER_ORBIT_RADIUS * cos(electronAngle);
    electronY = CENTER_Y + INNER_ORBIT_RADIUS * sin(electronAngle);
    drawElectron(electronX, electronY, colors[currentColorIndex]);
  }

  delay(30);
}