// Note: Run menuconfig to set the WiFi Credentials -> CALE Configuration
// Requirements: Needs to have an EPD Class defined. Needs PSRAM.
// This example does not use a decoded buffer hence leaves more external RAM free
// At the same time it looses the JPG_DITHER functionality in favour of render speed.
// As default only configured for parallel epapers
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_types.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_sleep.h"
// WiFi related
#include "esp_event.h"
#include "esp_log.h"
#include "esp_timer.h"
// HTTP Client
#include "esp_http_client.h"

#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>


#define EXAMPLE_MAX_CHAR_SIZE    64


#include "esp_task_wdt.h"
#include <stdio.h>
#include <string.h>
#include <math.h> // round + pow
#include "image_downloader.h"

#define MOUNT_POINT "/sdcard"
static const char *TAG = "ImgDwn";

// Image URL and jpg settings. Make sure to update EPD_WIDTH/HEIGHT if using loremflickr
// Note: Only HTTP protocol supported (Check README to use SSL secure URLs) loremflickr
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define IMGDWN_WIDTH_STR  "800"
#define IMGDWN_WIDTH  620
#define IMGDWN_HEIGHT_STR "500"
#define IMGDWN_HEIGHT 460
#define IMGDWN_URL2 ("http://vps-edf71efa.vps.ovh.net:3000/render/d-solo/7BtRMrv4k/temperatures?orgId=1&var-emplacement=entree_ECS&var-emplacement=entree_reseauSol&panelId=4&width=650&height=460&scale=1&tz=Europe%2FParis/")
#define IMGDWN_URL ("http://vps-edf71efa.vps.ovh.net:3000/render/d-solo/bOcPeysGz/hauteur-cuve?orgId=1&from=now-2d&refresh=1m&panelId=4&width=" IMGDWN_WIDTH_STR "&height=" IMGDWN_HEIGHT_STR "&scale=1&tz=Europe%2FParis") // 650 460
// As default is 512 without setting buffer_size property in esp_http_client_config_t
#define HTTP_RECEIVE_BUFFER_SIZE 1938

#define DEBUG_VERBOSE false

// Buffers
uint8_t *fb;            // EPD 2bpp buffer
uint8_t *source_buf;    // JPG download buffer
uint8_t *decoded_image; // RAW decoded image

uint32_t buffer_pos = 0;
uint32_t time_download = 0;
uint32_t time_decomp = 0;
uint32_t time_render = 0;

uint16_t countDataEventCalls = 0;
uint32_t countDataBytes = 0;
uint32_t img_buf_pos = 0;
uint32_t dataLenTotal = 0;
uint64_t startTime = 0;

    void create_file_app(uint8_t *buffer, uint32_t size)
    {
        ESP_LOGI(TAG, "Opening file");
        //ESP_LOGI(TAG, "output buffer to spiffs: %s \n", buffer);
        FILE* f = fopen(MOUNT_POINT"/hello2.png", "wb+");
        if (f == NULL) {
            ESP_LOGE(TAG, "Failed to open file for writing");
            return;
        }
        for(int i=0; i<size;i++){
          fprintf(f, "%c", buffer[i]);        
        }
          fclose(f);
        ESP_LOGI(TAG, "File written");
    }
    
// Handles Htpp events and is in charge of buffering source_buf (jpg compressed image)
esp_err_t _http_event_handler_id(esp_http_client_event_t *evt)
{
    switch (evt->event_id)
    {
    case HTTP_EVENT_ERROR:
        ESP_LOGE(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        #if DEBUG_VERBOSE
          ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        #endif
        break;
    case HTTP_EVENT_ON_DATA:
        ++countDataEventCalls;
        #if DEBUG_VERBOSE
          if (countDataEventCalls%10==0) {
            ESP_LOGI(TAG, "%d len:%d\n", countDataEventCalls, evt->data_len);
          }
        #endif
        dataLenTotal += evt->data_len;

        if (countDataEventCalls == 1) startTime = esp_timer_get_time();
        // Append received data into source_buf
        memcpy(&source_buf[img_buf_pos], evt->data, evt->data_len);
        img_buf_pos += evt->data_len;

        // Optional hexa dump
        //ESP_LOG_BUFFER_HEX(TAG, source_buf, 100);
        break;

    case HTTP_EVENT_REDIRECT:
        break;
    case HTTP_EVENT_ON_FINISH:
        // Do not draw if it's a redirect (302)
        if (esp_http_client_get_status_code(evt->client) == 200) {
          printf("%"PRIu32" bytes read from %s\nIMG_BUF size: %"PRIu32"\n", img_buf_pos, IMGDWN_URL, img_buf_pos);
          //drawBufJpeg(source_buf, 0, 0);
          create_file_app(source_buf,img_buf_pos); //function which opens and records data to spiffs file
          time_download = (esp_timer_get_time()-startTime)/1000;
          ESP_LOGI("www-dw", "%"PRIu32" ms - download", time_download);
          // Refresh display
          //display.update();

          ESP_LOGI("total", "%"PRIu32" ms - total time spent\n", time_download+time_decomp+time_render);
        } else {
          printf("HTTP on finish got status code: %d\n", esp_http_client_get_status_code(evt->client));
        }
        break;

    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED\n");
        break;
    }
    return ESP_OK;
}

// Handles http request
static void download(void)
{    
    esp_http_client_config_t config = {
        .url = IMGDWN_URL,
        .disable_auto_redirect = false,
        .event_handler = _http_event_handler_id,
        .buffer_size = HTTP_RECEIVE_BUFFER_SIZE,
        .timeout_ms = 50000
        };

    esp_http_client_handle_t client = esp_http_client_init(&config);

    #if DEBUG_VERBOSE
      printf("Free heap before HTTP download: %d\n", xPortGetFreeHeapSize());
    #endif
    
    esp_err_t err = esp_http_client_perform(client);
    if (err == ESP_OK)
    {
        ESP_LOGI(TAG, "\nIMAGE URL: %s\n\nHTTP GET Status = %d, content_length = %"PRIi64"\n",
                 IMGDWN_URL,
                 esp_http_client_get_status_code(client),
                 esp_http_client_get_content_length(client));
    }
    else
    {
        ESP_LOGE(TAG, "\nHTTP GET request failed: %s", esp_err_to_name(err));
    }

    //printf("Go to sleep %d minutes\n", CONFIG_DEEPSLEEP_MINUTES_AFTER_RENDER);
    esp_http_client_cleanup(client);
    //deepsleep();
}

void imgdwn(void *domotic_event_group) {

        while(1){
        // Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
        // number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above)
        EventBits_t bits = xEventGroupWaitBits(domotic_event_group,
                                           BIT0,
                                           pdFALSE,
                                           pdFALSE,
                                           portMAX_DELAY);
        if (bits & BIT0)
        {
          ESP_LOGE(TAG, "beginning");

          // Should be big enough to allocate the JPEG file size, width * height should suffice
          source_buf = (uint8_t *)heap_caps_malloc(IMGDWN_HEIGHT * IMGDWN_WIDTH, MALLOC_CAP_SPIRAM);
          if (source_buf == NULL) {
              ESP_LOGE(TAG, "Initial alloc source_buf failed!");
          }
          printf("Free heap after buffers allocation: %zu\n", xPortGetFreeHeapSize());

          download();
          
          heap_caps_free(source_buf);
          printf("Free heap after buffers allocation: %zu\n", xPortGetFreeHeapSize());
          vTaskDelay(3600000 / portTICK_PERIOD_MS);

        }else{
          vTaskDelay(5000 / portTICK_PERIOD_MS);
        } 
        }


}