#include <FastLED.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

// RTC module at address 0x68
#define DS1307_ADDRESS 0x68

// LCD module at address 0x27
LiquidCrystal_I2C lcd(0x27, 20, 4);

uint8_t clear = 0x00;

#define WIDTH 32
#define HEIGHT 32
#define NUM_LEDS ((WIDTH) * (HEIGHT))

CRGB leds[NUM_LEDS + 1];

uint16_t XY(uint8_t x, uint8_t y) {
  if (x >= WIDTH) return NUM_LEDS;
  if (y >= HEIGHT) return NUM_LEDS;
  // if (y & 1)
  //   return (y + 1) * WIDTH - 1 - x;
  // else
    return y * WIDTH + x;
}

#include "wuLineAA.h"

// struct 

void setup()
{
  FastLED.addLeds<NEOPIXEL, 2>(leds, NUM_LEDS);
  Wire.begin();
  Serial.begin(9600);
  lcd.begin (16,2);
  lcd.backlight();
  // Use a line below to customize a date and time
  // sec, min, hour, month, day, day of week, year % 100
  // setDateTime(40, 59, 23, 1, 4, 1, 21);
}

void loop()
{
  // Read the values ​​(date and time) of the DS1307 module
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(clear);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 0x07);

  uint8_t seconds = bcdToDec(Wire.read());
  uint8_t minutes = bcdToDec(Wire.read());
  uint8_t hours = bcdToDec(Wire.read() & 0xff);
  uint8_t wday = bcdToDec(Wire.read());
  uint8_t mday = bcdToDec(Wire.read());
  uint8_t month = bcdToDec(Wire.read());
  uint8_t year = bcdToDec(Wire.read());

  // Shows the data on the display
  lcd.setCursor(0,0);
  lcd.print("    ");

  // Adds 0 (clear) if the time is less than 10
  if (hours < 10)
    lcd.print("0");

  lcd.print(hours);
  if (seconds & 1)
    lcd.print(":");
  else
    lcd.print(" ");

  // Adds 0 (clear) if minutes are less than 10
  if (minutes < 10)
     lcd.print("0");

  lcd.print(minutes);

  if (seconds & 1)
    lcd.print(":");
  else
    lcd.print(" ");

  if (seconds < 10)
     lcd.print("0");

  lcd.print(seconds);

  lcd.setCursor(2,1);

  // Show the day of the week
  switch(wday)
    {
      case 0:lcd.print("Sun");
      break;
      case 1:lcd.print("Mon");
      break;
      case 2:lcd.print("Tue");
      break;
      case 3:lcd.print("Wed");
      break;
      case 4:lcd.print("Thu");
      break;
      case 5:lcd.print("Fri");
      break;
      case 6:lcd.print("Sat");
    }

    lcd.setCursor(6,1);

    // Adds 0 (clear) if day of the month is less than 10
    if (mday < 10)
      lcd.print("0");

    lcd.print(mday);
    lcd.print("/");

    // Add 0 (clear) if month is less than 10
    if (month < 10)
      lcd.print("0");

    lcd.print(month);
    lcd.print("/");
    lcd.print(year);

    ledclock(hours, minutes, seconds);
    while (0) {
      if (++seconds >= 60) ++minutes, seconds -= 60;
      if (minutes >= 60) ++hours, minutes -= 60;
      if (hours >= 24) hours -= 24;
      ledclock(hours, minutes, seconds);
    }
}

// Set the date and time of the DS1307
void setDateTime(uint8_t seconds, uint8_t minutes, uint8_t hours,
  uint8_t wday, uint8_t mday, uint8_t month, uint8_t year)
{
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(clear); // Write clear, so that it can receive data

  // The lines below write in the CI the date and time values ​​
  // that were placed in the variables above
  Wire.write(decToBcd(seconds));
  Wire.write(decToBcd(minutes));
  Wire.write(decToBcd(hours));
  Wire.write(decToBcd(wday));
  Wire.write(decToBcd(mday));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.write(clear);
  Wire.endTransmission();
}

uint8_t decToBcd(uint8_t value)
{
  // Converts the decimal number to BCD
  return ((value / 10 * 16) + (value % 10));
}

uint8_t bcdToDec(uint8_t value)
{
  // Converts from BCD to decimal
  return ((value / 16 * 10) + (value % 16));
}


void ledclock(const uint8_t &hours, const uint8_t &minutes, const uint8_t &seconds) {
  fadeToBlackBy(leds, NUM_LEDS, 64);
  CRGB c = 0xffffff;
  // everything is fixed-point, with 8-bits of fraction
  uint16_t centrex = WIDTH * 128;
  uint16_t centrey = HEIGHT * 128;
  uint16_t length = WIDTH * 128;
  uint16_t base_theta = 65536 * 3 / 4;
  uint16_t theta;
  int16_t dx, dy;

  // second hand
  theta = seconds * 65536 / 60;
  dx = ((int32_t)cos16(theta + base_theta) * length) / 32768;
  dy = ((int32_t)sin16(theta + base_theta) * length) / 32768;
  wuLineAA(centrex, centrey, centrex + dx, centrey + dy, &c);

  // minute hand
  length = length * 7 / 8;
  theta = (theta + minutes * 65536) / 60;
  dx = ((int32_t)cos16(theta + base_theta) * length) / 32768;
  dy = ((int32_t)sin16(theta + base_theta) * length) / 32768;
  wuLineAA(centrex, centrey, centrex + dx, centrey + dy, &c);

  // hour hand
  length = length * 3 / 4;
  theta = (theta + (hours % 12) * 65536) / 12;
  // theta = (theta / 5 + (hours % 12) * 65536) / 12;
  dx = ((int32_t)cos16(theta + base_theta) * length) / 32768;
  dy = ((int32_t)sin16(theta + base_theta) * length) / 32768;
  wuLineAA(centrex, centrey, centrex + dx, centrey + dy, &c);

  FastLED.show();
}
GND5VSDASCLSQWRTCDS1307+