/**
 *   \file utilities.c
 *   \brief Implémentation des fonctions utilitaires
 *
 *  Dans ce fichier sont implémentées les fonctions utilitaires pour la
 *  manipulation des structures de données déclarées dans le fichier header
 *  correspondant.
 */

#include "utilities.h"

/**
 *  Créé un nouveau pixel initialisé avec les arguments `r`, `g` et `b` et
 *  renvoie un pointeur vers ce pixel créé.
 *
 *  \param[in] r Valeur rouge du pixel
 *  \param[in] g Valeur verte du pixel
 *  \param[in] b Valeur bleue du pixel
 *  \return Pointeur sur une structure de type \ref Pixel
 */
Pixel_t newPixel(uint8_t t_r, uint8_t t_g, uint8_t t_b) {
  Pixel_t res;
  res = (Pixel_t)malloc(sizeof(Pixel));
  res->r = t_r;
  res->g = t_g;
  res->b = t_b;
  res->visited = false;
  return res;
}

/**
 *  Destructeur d’un pixel. Étant donné qu’un pixel ne contient aucune donnée
 *  pointée par un pointeur, la seule action de la fonction sera de libérer la
 *  mémoire pointée par le pointeur de pixel en lui-même et donc le pixel passé
 *  en argument.
 *
 *  \param[in] self Pointeur vers le pixel à détruire
 */
void deletePixel(Pixel_t t_self) {
  free(t_self);
}

/**
 *  Constructeur d’un conteneur d’image. Les dimensions sont initialisées à zéro
 *  (0) et son tableau de pixels a été créé et initialisé en tableau vide. Le
 *  constructeur renvoie un pointeur vers la nouvelle structure \ref Image.
 *
 *  \return Pointeur vers une structure \ref Image initialisée.
 */
Image_t newImage() {
  Image_t res;
  res = (Image_t)malloc(sizeof(Image));
  res->x = 0;
  res->y = 0;
  res->pixels = darrayNew(sizeof(Pixel));
  return res;
}

/**
 *  Destructeur d’un conteneur d’image. Le destructeur appellera le destructeur
 *  du vecteur de pixels qui sera libéré de la mémoire, puis ultimement le
 *  destructeur libérera la structure \ref Image pointée par le pointeur passé
 *  en argument.
 *
 *  \param[in] self Conteneur d’image à détruire
 */
void deleteImage(Image_t t_self) {
  unsigned long i;
  for(i = 0; i < darraySize(t_self->pixels); ++i) {
    deletePixel(darrayGet(t_self->pixels, i));
  }
  darrayDelete(t_self->pixels);
  free(t_self);
}

/**
 *  Constructeur d’un conteneur de segment. Le constructeur va initialiser les
 *  valeurs qu’il contiendra avec les arguments qui lui seront passés lors de
 *  l’appel de la fonction.
 *
 *  \param[in] y Ordonnée à laquelle le segment réside
 *  \param[in] xd Abscisse extrême droite du segment
 *  \param[in] xg Abscisse extrême gauche du segment
 *  \return Pointeur sur un conteneur de segment
 */
Segment_t newSegment(uint16_t t_y, uint16_t t_xd, uint16_t t_xg) {
  Segment_t res;
  res = (Segment_t)malloc(sizeof(Segment));
  res->y = t_y;
  res->xd = t_xd;
  res->xg = t_xg;
  return res;
}

/**
 *  Destructeur de conteneur de segment. Les conteneurs de segments ne contenant
 *  pas de pointeur propriétaire de données, le destructeur libérera simplement
 *  de la mémoire le conteneur pointé par le pointeur passé en argument.
 *
 *  \param[in] self Conteneur de segment à détruire
 */
void deleteSegment(Segment_t t_self) {
  free(t_self);
}

/**
 *  \brief function description
 *
 *  Constructeur de conteneur de zone, initialise grâce aux arguments la couleur
 *  de la zone et initialise un tableau dynamique vide de \ref Segment. Renvoie
 *  un pointeur vers la structure nouvellement créée.
 *
 *  \param[in] r Valeur rouge de la couleur de la zone
 *  \param[in] g Valeur verte de la couleur de la zone
 *  \param[in] b Valeur bleue de la couleur de la zone
 *  \return Pointeur vers la structure créée
 */
Zone_t newZone(uint8_t t_r, uint8_t t_g, uint8_t t_b) {
  Zone_t res;
  res = (Zone_t)malloc(sizeof(Zone));
  res->r = t_r;
  res->g = t_g;
  res->b = t_b;
  res->segments = darrayNew(sizeof(Segment));
  return res;
}

/**
 *  Destructeur de zone, libère de la mémoire les segments contenus dans le
 *  tableau de segments, puis le tableau en lui-même pour ultimement libérer
 *  de la mémoire le conteneur de zone en lui-même pointé par le pointeur passé
 *  en argument du destructeur.
 *
 *  \param[in] self Conteneur de zone à détruire
 */
void deleteZone(Zone_t t_self) {
  unsigned long i;
  for(i = 0; i < darraySize(t_self->segments); ++i) {
    deleteSegment(darrayGet(t_self->segments, i));
  }
  darrayDelete(t_self->segments);
  free(t_self);
}

Pixel_t imgAt(Image_t t_img, int t_x, int t_y) {
  return (Pixel_t)darrayGet(t_img->pixels, t_x + t_y * t_img->x);
}
