#include "common.h"
#include "ppm.h"

bool sameColor(Pixel_t t_pixel, Zone_t t_zone) {
  return t_pixel->r == t_zone->r && t_pixel->g == t_zone->g &&
         t_pixel->b == t_zone->b;
}

/* Adds a pixel to a zone, since the pixel isn't in a zone, then it isn't
   part of a segment either, hence we can confidently add pixels next to the
   original as parts of the segment and add the segment itself to the zone */
void addPixelToSelectedZone(Image_t t_img, int t_idx, Zone_t t_zone) {
  Pixel_t current_pixel;
  int xd, xg, y = t_idx / (int)t_img->x;
  current_pixel = darrayGet(t_img->pixels, t_idx);
  if (current_pixel->visited || t_idx >= (int)darraySize(t_img->pixels) ||
      t_idx < 0 || !sameColor(current_pixel, t_zone)) {
    return;
  }
  (*current_pixel).visited = true;
  for(xd = t_idx; xd % (int)t_img->x != 0; ++xd) { /* fetch right limit of segment */
    current_pixel = darrayGet(t_img->pixels, xd);
    if(!sameColor(current_pixel, t_zone)) {
      break;
    }
    (*current_pixel).visited = true;
  }
  for(xg = t_idx; xg - y >= 0; --xg) { /* fetch right limit of segment */
    current_pixel = darrayGet(t_img->pixels, xd);
    if(!sameColor(current_pixel, t_zone)) {
      break;
    }
    (*current_pixel).visited = true;
  }
  /* Add segment to its zone */
  darrayPushBack(t_zone->segments, newSegment(y, xd, xg));
  for(; xg <= xd; ++xg) { /* process every pixel up and down the segment */
    addPixelToSelectedZone(t_img, t_idx + t_img->x, t_zone);
  }
}

/* Selects the zone related to the pixel, skip tests if pixel has
 already been visited */
void chooseZoneForPixel(Image_t t_img, int t_idx, darray_t zones) {
  Zone_t current_zone;
  Pixel_t pixel;
  size_t i;
  pixel = darrayGet(t_img->pixels, t_idx);
  if (pixel->visited)
    return;
  for (i = 0; i < darraySize(zones); ++i) {
    current_zone = darrayGet(zones, i);
    if (sameColor(pixel, current_zone)) {
      addPixelToSelectedZone(t_img, t_idx, current_zone);
      break;
    }
  }
}

/* converts an image to zones */
darray_t imgToZones(Image_t t_img) {
  darray_t zones;
  const size_t nb_pixels = darraySize(t_img->pixels);
  size_t i;
  zones = darrayNew(sizeof(Zone));

  for (i = 0; i < nb_pixels; ++i) {
    chooseZoneForPixel(t_img, i, zones);
  }
  return zones;
}

void compress(const char *input_file) {
  Image_t img;
  darray_t zones;
  img = newImage();
  imageLoadPPM(input_file, img);
  zones = imgToZones(img);
  darrayDelete(zones);

  printf("Detected %zu zones\n", darraySize(zones));

  deleteImage(img);
}
