/*
    Inkplate6COLOR_Daily_Weather_Station example for Soldered Inkplate 6COLOR
    For this example you will need only USB cable and Inkplate 6COLOR.
    Select "Soldered Inkplate 6COLOR" from Tools -> Board menu.
    Don't have "Soldered Inkplate 6COLOR" option? Follow our tutorial and add it:
    https://soldered.com/learn/add-inkplate-6-board-definition-to-arduino-ide/

    This example will show you how you can use Inkplate 6 to display API data,
    e.g. Openweather public weather API

    IMPORTANT:
    Make sure to change your desired city, timezone and wifi credentials below
    Also have ArduinoJSON installed in your Arduino libraries
    Want to learn more about Inkplate? Visit www.inkplate.io
    Looking to get support? Write on our forums: https://forum.soldered.com/
    28 July 2020 by Soldered

    In order to convert your images into a format compatible with Inkplate
    use the Soldered Image Converter available at:
    https://github.com/SolderedElectronics/Soldered-Image-Converter/releases
*/

// Next 3 lines are a precaution, you can ignore those, and the example would also work without them
#ifndef ARDUINO_INKPLATECOLOR
#error "Wrong board selection for this example, please select Soldered Inkplate 6COLOR in the boards menu."
#endif

// ---------- CHANGE HERE  -------------:

// City search query
char city[128] = "OSIJEK";

// Coordinates sent to the api
char lat[] = "45.5510548";
char lon[] = "18.695463";

// Change to your wifi ssid and password
char ssid[] = "";
char pass[] = "";

// Change to your api key, if you don't have one, head over to:
// https://openweathermap.org/guide , register and copy the key provided
char apiKey[] = "";

// ----------------------------------

// Include Inkplate library to the sketch
#include "Inkplate.h"

// Header file for easier code readability
#include "Network.h"

// Including fonts used
#include "Fonts/Inter12pt7b.h"
#include "Fonts/Inter16pt7b.h"
#include "Fonts/Inter20pt7b.h"
#include "Fonts/Inter48pt7b.h"

// Including icons generated by the py file
#include "icons.h"

// Delay between API calls
#define DELAY_MS (uint32_t)10 * 60 * 1000 // 10 minute time
#define DELAY_WIFI_RETRY_SECONDS 5

// Inkplate object
Inkplate display;

// All our network functions are in this object, see Network.h
Network network;

// Contants used for drawing icons
char abbrs[32][16] = {"01d", "02d", "03d", "04d", "09d", "10d", "11d", "13d", "50d"};

const uint8_t *logos[18] = {
    icon_01d, icon_02d, icon_03d, icon_04d, icon_09d, icon_10d, icon_11d, icon_13d, icon_50d,
    icon_01n, icon_02n, icon_03n, icon_04n, icon_09n, icon_10n, icon_11n, icon_13n, icon_50n,
};

const uint8_t *s_logos[18] = {
    icon_s_01d, icon_s_02d, icon_s_03d, icon_s_04d, icon_s_09d, icon_s_10d, icon_s_11d, icon_s_13d, icon_s_50d,
    icon_s_01n, icon_s_02n, icon_s_03n, icon_s_04n, icon_s_09n, icon_s_10n, icon_s_11n, icon_s_13n, icon_s_50n,
};

RTC_DATA_ATTR char abbr1[16];
RTC_DATA_ATTR char abbr2[16];
RTC_DATA_ATTR char abbr3[16];
RTC_DATA_ATTR char abbr4[16];

// Variables for storing temperature
RTC_DATA_ATTR char temps[8][4] = {
    "-",
    "-",
    "-",
    "-",
};

RTC_DATA_ATTR uint8_t hours = 0;

// Variables for storing current time and weather info
RTC_DATA_ATTR char currentTemp[16] = "-";
RTC_DATA_ATTR char currentWind[16] = "-";

RTC_DATA_ATTR char currentTime[16] = "--:--";

RTC_DATA_ATTR char currentWeather[32] = "-";
RTC_DATA_ATTR char currentWeatherAbbr[8] = "01d";

// functions defined below
void drawWeather();
void drawCurrent();
void drawTemps();
void drawCity();
void drawTime();
void setTime();

void setup()
{
    // Begin serial and display
    Serial.begin(115200);
    display.begin();

    // Try connecting to a WiFi network.
    // Parameters are network SSID, password, timeout in seconds and whether to print to serial.
    // If the Inkplate isn't able to connect to a network stop further code execution and print an error message.
    if (!display.connectWiFi(ssid, pass, WIFI_TIMEOUT, true))
    {
        //Can't connect to netowrk
        // Clear display for the error message
        display.clearDisplay();
        // Set the font size;
        display.setTextSize(3);
        // Set the cursor positions and print the text.
        display.setCursor((display.width() / 2) - 200, display.height() / 2);
        display.print(F("Unable to connect to "));
        display.println(F(ssid));
        display.setCursor((display.width() / 2) - 200, (display.height() / 2) + 30);
        display.println(F("Please check ssid and pass!"));
        // Display the error message on the Inkplate and go to deep sleep
        display.display();
        esp_sleep_enable_timer_wakeup(100L * DELAY_WIFI_RETRY_SECONDS);
        (void)esp_deep_sleep_start();
    }

    setTime();

    // Get all relevant data, see Network.cpp for info
    Serial.print("Retrying fetching data");
    while (!network.getData(lat, lon, apiKey, city, temps[0], temps[1], temps[2], temps[3], currentTemp, currentWind,
                            currentTime, currentWeather, currentWeatherAbbr, abbr1, abbr2, abbr3, abbr4, &hours))
    {
        Serial.print('.');
        delay(500);
    }
    network.getTime(currentTime);

    // Draw data, see functions below for info
    drawWeather();
    drawCurrent();
    drawTemps();
    drawCity();
    drawTime();

    // Refresh full screen every fullRefresh times, defined above
    display.display();

    // Activate wakeup timer
    esp_sleep_enable_timer_wakeup(1000L * DELAY_MS);

    // Start deep sleep (this function does not return). Program stops here.
    esp_deep_sleep_start();
}

void loop()
{
    // Never here! If you are using deep sleep, the whole program should be in setup() because the board restarts each
    // time. loop() must be empty!
}

// Function for getting time from NTP server
void setTime()
{
    // Structure used to hold time information
    struct tm timeInfo;
    display.getNTPDateTime(&timeInfo);
    time_t nowSec;
    // Fetch current time in epoch format and store it
    display.getNTPEpoch(&nowSec);
    // This loop ensures that the NTP time fetched is valid and beyond a certain threshold
    while (nowSec < 8 * 3600 * 2)
    {
        delay(500);
        yield();
        display.getNTPEpoch(&nowSec);
    }
    gmtime_r(&nowSec, &timeInfo);
    Serial.print(F("Current time: "));
    Serial.print(asctime(&timeInfo));
}

// Function for drawing weather info
void drawWeather()
{
    // Searching for weather state abbreviation
    for (int i = 0; i < 10; ++i)
    {
        // If found draw specified icon
        if (strcmp(abbrs[i], currentWeatherAbbr) == 0)
            display.drawBitmap(10, 10, logos[i], 152, 152, INKPLATE_ORANGE);
    }

    // Draw weather state
    display.setTextColor(INKPLATE_BLUE);
    display.setFont(&Inter16pt7b);
    display.setTextSize(1);
    display.setCursor(40, 170);
    display.println(currentWeather);
}

// Function for drawing current time
void drawTime()
{
    // Drawing current time
    display.setTextColor(INKPLATE_BLUE);
    display.setFont(&Inter16pt7b);
    display.setTextSize(1);

    display.setCursor(600 - 20 * strlen(currentTime), 35);
    display.println(currentTime);
}

// Function for drawing city name
void drawCity()
{
    // Drawing city name
    display.setTextColor(INKPLATE_BLUE);
    display.setFont(&Inter16pt7b);
    display.setTextSize(1);

    display.setCursor(300 - 9 * strlen(city), 435);
    display.println(city);
}

// Function for drawing temperatures
void drawTemps()
{
    // Drawing 4 black rectangles in which temperatures will be written
    int rectWidth = 100;
    int rectSpacing = (600 - rectWidth * 4) / 5;
    int yRectangleOffset = 200;
    int rectHeight = 200;

    display.fillRect(1 * rectSpacing + 0 * rectWidth, yRectangleOffset, rectWidth, rectHeight, BLACK);
    display.fillRect(2 * rectSpacing + 1 * rectWidth, yRectangleOffset, rectWidth, rectHeight, BLACK);
    display.fillRect(3 * rectSpacing + 2 * rectWidth, yRectangleOffset, rectWidth, rectHeight, BLACK);
    display.fillRect(4 * rectSpacing + 3 * rectWidth, yRectangleOffset, rectWidth, rectHeight, BLACK);

    int textMargin = 6;

    display.setFont(&Inter16pt7b);
    display.setTextSize(1);
    display.setTextColor(INKPLATE_BLUE);

    int dayOffset = 40;

    display.setCursor(1 * rectSpacing + 0 * rectWidth + textMargin, yRectangleOffset + textMargin + dayOffset);
    display.println("Today");

    display.setCursor(2 * rectSpacing + 1 * rectWidth + textMargin, yRectangleOffset + textMargin + dayOffset);
    display.println(wDays[hours + 1 > 6 ? hours + 1 - 6 : hours + 1]);

    display.setCursor(3 * rectSpacing + 2 * rectWidth + textMargin, yRectangleOffset + textMargin + dayOffset);
    display.println(wDays[hours + 2 > 6 ? hours + 2 - 6 : hours + 2]);

    display.setCursor(4 * rectSpacing + 3 * rectWidth + textMargin, yRectangleOffset + textMargin + dayOffset);
    display.println(wDays[hours + 3 > 6 ? hours + 3 - 6 : hours + 3]);

    int tempOffset = 120;

    // Drawing temperature values into black rectangles
    display.setFont(&Inter16pt7b);
    display.setTextSize(1);
    display.setTextColor(INKPLATE_BLUE);

    display.setCursor(1 * rectSpacing + 0 * rectWidth + textMargin, yRectangleOffset + textMargin + tempOffset);
    display.print(temps[0]);
    display.println(F("C"));

    display.setCursor(2 * rectSpacing + 1 * rectWidth + textMargin, yRectangleOffset + textMargin + tempOffset);
    display.print(temps[1]);
    display.println(F("C"));

    display.setCursor(3 * rectSpacing + 2 * rectWidth + textMargin, yRectangleOffset + textMargin + tempOffset);
    display.print(temps[2]);
    display.println(F("C"));

    display.setCursor(4 * rectSpacing + 3 * rectWidth + textMargin, yRectangleOffset + textMargin + tempOffset);
    display.print(temps[3]);
    display.println(F("C"));

    int iconOffset = 130;

    for (int i = 0; i < 18; ++i)
    {
        // If found draw specified icon
        if (strcmp(abbr1, abbrs[i]) == 0)
            display.drawBitmap(1 * rectSpacing + 0 * rectWidth + textMargin, yRectangleOffset + textMargin + iconOffset,
                               s_logos[i], 48, 48, INKPLATE_WHITE, INKPLATE_BLACK);
    }

    for (int i = 0; i < 18; ++i)
    {
        // If found draw specified icon
        if (strcmp(abbr2, abbrs[i]) == 0)
            display.drawBitmap(2 * rectSpacing + 1 * rectWidth + textMargin, yRectangleOffset + textMargin + iconOffset,
                               s_logos[i], 48, 48, INKPLATE_WHITE, INKPLATE_BLACK);
    }

    for (int i = 0; i < 18; ++i)
    {
        // If found draw specified icon
        if (strcmp(abbr3, abbrs[i]) == 0)
            display.drawBitmap(3 * rectSpacing + 2 * rectWidth + textMargin, yRectangleOffset + textMargin + iconOffset,
                               s_logos[i], 48, 48, INKPLATE_WHITE, INKPLATE_BLACK);
    }

    for (int i = 0; i < 18; ++i)
    {
        // If found draw specified icon
        if (strcmp(abbr4, abbrs[i]) == 0)
            display.drawBitmap(4 * rectSpacing + 3 * rectWidth + textMargin, yRectangleOffset + textMargin + iconOffset,
                               s_logos[i], 48, 48, INKPLATE_WHITE, INKPLATE_BLACK);
    }
}

// Current weather drawing function
void drawCurrent()
{
    // Drawing current information

    // Temperature:
    display.setFont(&Inter48pt7b);
    display.setTextSize(1);
    display.setTextColor(INKPLATE_BLUE);

    display.setCursor(150, 130);
    display.print(currentTemp);

    int x = display.getCursorX();
    int y = display.getCursorY();

    display.setFont(&Inter20pt7b);
    display.setTextSize(1);

    display.setCursor(x, y);
    display.println(F("C"));

    // Wind:
    display.setFont(&Inter48pt7b);
    display.setTextSize(1);
    display.setTextColor(INKPLATE_BLUE);

    display.setCursor(350, 130);
    display.print(currentWind);

    x = display.getCursorX();
    y = display.getCursorY();

    display.setFont(&Inter20pt7b);
    display.setTextSize(1);

    display.setCursor(x, y);
    display.println(F("m/s"));

    // Labels underneath
    display.setFont(&Inter12pt7b);
    display.setTextSize(1);

    display.setCursor(165, 170);
    display.println(F("TEMPERATURE"));

    display.setCursor(390, 170);
    display.println(F("WIND SPEED"));
}
