/**
 * @file lcd_api.h
 * @brief API for LCD functionality
 * @author Tim S.
 * @author Lorenz C.
 */

#ifndef INC_LCD_API_H_
#define INC_LCD_API_H_
#include <stdbool.h>
#include <string.h>
#include <ctype.h>

#define LOGGER_LEVEL_ALL
#include "log.h"
#include "../../Drivers/BSP/STM32746G-Discovery/stm32746g_discovery_lcd.h"
#include "llfs.h"
#include "gifdec.h"

/**
 * @brief The maximum amount of GIFs that can be displayed at the same time
 * @note This can't be higher than 255 (uint8_t)
 */
#define LCD_MAX_GIFS 5

#define LCD_BLUE          LCD_COLOR_BLUE
#define LCD_GREEN         LCD_COLOR_GREEN
#define LCD_RED           LCD_COLOR_RED
#define LCD_CYAN          LCD_COLOR_CYAN
#define LCD_MAGENTA       LCD_COLOR_MAGENTA
#define LCD_YELLOW        LCD_COLOR_YELLOW
#define LCD_LIGHTBLUE     LCD_COLOR_LIGHTBLUE
#define LCD_LIGHTGREEN    LCD_COLOR_LIGHTGREEN
#define LCD_LIGHTRED      LCD_COLOR_LIGHTRED
#define LCD_LIGHTCYAN     LCD_COLOR_LIGHTCYAN
#define LCD_LIGHTMAGENTA  LCD_COLOR_LIGHTMAGENTA
#define LCD_LIGHTYELLOW   LCD_COLOR_LIGHTYELLOW
#define LCD_DARKBLUE      LCD_COLOR_DARKBLUE
#define LCD_DARKGREEN     LCD_COLOR_DARKGREEN
#define LCD_DARKRED       LCD_COLOR_DARKRED
#define LCD_DARKCYAN      LCD_COLOR_DARKCYAN
#define LCD_DARKMAGENTA   LCD_COLOR_DARKMAGENTA
#define LCD_DARKYELLOW    LCD_COLOR_DARKYELLOW
#define LCD_WHITE         LCD_COLOR_WHITE
#define LCD_LIGHTGRAY     LCD_COLOR_LIGHTGRAY
#define LCD_GRAY          LCD_COLOR_GRAY
#define LCD_DARKGRAY      LCD_COLOR_DARKGRAY
#define LCD_BLACK         LCD_COLOR_BLACK
#define LCD_BROWN         LCD_COLOR_BROWN
#define LCD_ORANGE        LCD_COLOR_ORANGE
#define LCD_TRANSPARENT   LCD_COLOR_TRANSPARENT

#define LCD_ARGB8888  0x00000000U
#define LCD_RGB888    0x00000001U
#define LCD_RGB565    0x00000002U
#define LCD_ARGB1555  0x00000003U

#define LCD_FONT8     (&Font8)
#define LCD_FONT12    (&Font12)
#define LCD_FONT16    (&Font16)
#define LCD_FONT20    (&Font20)
#define LCD_FONT24    (&Font24)


extern LTDC_HandleTypeDef  hLtdcHandler;

typedef struct {
    GIFIMAGE gif;
    uint8_t* src;
    uint32_t x_pos;
    uint32_t y_pos;
    uint32_t last_frame_time;
    int loop_count;
    int cur_loop;
    int frame_delay;
} lcd_gif_t;

/**
 * @brief Initialise LCD
 * Initialise the LCD screen with BackLight on or not
 *
 * @param[in] bl_on Bool to enable or disable the LCD backlight
 *
 */
void lcd_init(bool bl_on);

/**
 * @brief LCD task
 * Task to be called in the main loop to update the LCD screen
 */
void lcd_task(void);

/**
 * @brief Display text
 * Display text on the LCD screen in a certain color. When text width exceeds BSP_LCD_GetXSize(),
 * a text wrap will be performed. If the text wrap is between two letters in a word, the '-' character
 * will be injected.
 *
 * @note When bg_color 0 is passed as a parameter, the background for the text will be transparent
 *
 * @param[in] text     C-style text string to display on the LCD screen
 * @param[in] x_pos    X-position
 * @param[in] y_pos    Y-position
 * @param[in] color    Color in which the text will be displayed, see preset colors in defines above
 * @param[in] bg_color Text background color
 * @param[in] font     Font size, see defines above in file
 */
void lcd_display_text(const char* text, uint16_t x_pos, uint16_t y_pos, uint32_t color, uint32_t bg_color, sFONT *font);

/**
 * @brief Draw BMP image on screen
 * Draw BMP image from C array to the LCD screen at position X, Y. In color mode ARGB8888, RGB888, RGB565 or ARGB1555
 * Supports ARGB8888, RGB565, RGB888
 *
 * @author Wim Dams
 *
 * @param[in] p_src      C array containing the image data
 * @param[in] x_pos      X-position
 * @param[in] y_pos      Y-position
 * @param[in] x_size     Width of image
 * @param[in] y_size     Height of image
 * @param[in] color_mode Color mode (see defined color modes above in file)
 */
void lcd_draw_raw_img(const void* p_src, uint32_t x_pos, uint32_t y_pos, uint32_t x_size, uint32_t y_size, uint32_t color_mode);

/**
 * @brief Draw BMP image on screen
 * Draw BMP image from C array to the LCD screen at position X, Y. In color mode ARGB8888, RGB888, RGB565 or ARGB1555
 * Supports ARGB8888, RGB565, RGB888
 *
 * @param[in] bmp_buff   BMP file data
 * @param[in] x_pos      X-position
 * @param[in] y_pos      Y-position
 */
void lcd_draw_bmp_img(uint8_t* bmp_buff, uint32_t x_pos, uint32_t y_pos);

/**
 * @brief Draw BMP image on screen by specifying the name, the BMP image has in the file system
 * Draw BMP image from C array to the LCD screen at position X, Y by specifying the BMP image name on the filesystem
 * Supports ARGB8888, RGB565, RGB888
 *
 * @param[in] name       Name of image on filesystem
 * @param[in] x_pos      X-position
 * @param[in] y_pos      Y-position
 */
void lcd_draw_img_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos);

/**
 * @brief Clear LCD text
 * Clears the text drawn on the LCD screen
 *
 */
void lcd_clear_text(void);

/**
 * @brief Clear images
 * Clears the images drawn on the LCD screen
 *
 */
void lcd_clear_images(void);

/**
 * @brief Set background color of layer 0
 * Sets the layer 0 color
 *
 * @param[in] color  Color of layer 0 (images layer)
 */
void lcd_set_bg_color_layer0(uint32_t color);

/**
 * @brief LCD stop all GIFs
 * Stops all playing GIFs on lcd screen
 *
 */
void lcd_stop_all_gifs(void);

/**
 * @brief Draw GIF image on screen from memory
 * Draw GIF image from memory to the LCD screen at position X, Y
 * @warning If the GIF has a loop count specified, it will stop after the specified amount of loops and the lcd_gif_t handle will be invalid for further use
 * @note Before drawing over a GIF, make sure to call lcd_stop_gif(), otherwise the GIF will keep overwriting the screen
 *
 * @param src  Pointer to the GIF image data
 * @param size The size of the GIF image data
 * @param x_pos The X position on the screen
 * @param y_pos The Y position on the screen
 * @return A handle to the GIF image, NULL if the GIF could not be opened @ref lcd_gif_t
 */
lcd_gif_t* lcd_draw_gif(uint8_t* src, size_t size, uint32_t x_pos, uint32_t y_pos);

/**
 * @brief Draw GIF image on screen from filesystem
 * Draw GIF image from filesystem to the LCD screen at position X, Y
 * @warning If the GIF has a loop count specified, it will stop after the specified amount of loops and the lcd_git_t handle will be invalidated
 * @note Before drawing over a GIF, make sure to call lcd_stop_gif(), otherwise the GIF will keep overwriting the screen
 *
 * @param name The filename of the GIF image
 * @param x_pos The X position on the screen
 * @param y_pos The Y position on the screen
 * @return A handle to the GIF image, NULL if the GIF could not be opened @ref lcd_gif_t
 */
lcd_gif_t* lcd_draw_gif_from_fs(const char* name, uint32_t x_pos, uint32_t y_pos);

/**
 * @brief Stop a GIF from playing
 * Frees the GIF slot and stops the GIF from playing
 * Call this function before trying to draw over a GIF
 * @warning Make sure the GIF is still playing, otherwise it might stop another GIF
 *
 * @param gif The handle to the GIF image @ref lcd_gif_t
 */
void lcd_stop_gif(lcd_gif_t* gif);

/**
 * @brief Check if a GIF is still playing
 * @note It is possible that the GIF has stopped playing, but another GIF has taken its slot and is still playing
 *
 * @param gif The handle to the GIF image @ref lcd_gif_t
 * @return True if the GIF is still playing, false if not
 */
bool lcd_gif_is_playing(lcd_gif_t* gif);

#endif /* INC_LCD_API_H_ */
