/* --------------------------------------------------*/
/*   Filtrage Moyen				     */
/*   Fichier: LibMoyen.c			     */
/*   Auteur: Patrick Bonnin			     */
/*   Date de Creation:                               */
/*   Livree : Le TI a l'IUT                          */
/* --------------------------------------------------*/
#include "Structures.h"

#define MIN_BOX_SIZE 2
#define SEUIL_ECART_TYPE 160
#define SEUIL_MAXMOINSMIN 10
#define METHODE 1 // 0 pour MaxMoinsMin | 1 pour Ecart Type

/* ---- Code de l'operateur Moyen ---- */

int etiqcpt = 1;

void Pavlidis(IMAGE *image, IMAGE *imres)
{
  POINT	*point = NULL; /* point courant et point voisin */
  int	i,j; /* variables indices ligne et colonne du voisinage */
  int	moy; /* variable temporaire de type short */
  BOX *firstBox;

  if(crea_POINT(point) == NULL) // creation des points
  {
     fprintf(stderr,"Erreur d'Allocation Memoire du Point : Moyen \n");
     exit (0);
  }

    if(NLIG(image) !=  NCOL(image) || NCOL(image) % 2 != 0) {
        fprintf(stderr,"L'image n'est pas adaptée \n");
         exit (0);
    }

    crea_BOX(firstBox);

    BOX_XMIN(firstBox) = 0;
    BOX_YMIN(firstBox) = 0;
    BOX_XMAX(firstBox) = NCOL(image);
    BOX_YMAX(firstBox) = NLIG(image);

    split(firstBox, image, point, imres);

  free((void *)point);
} // --- fin de l'operateur ---

int maxMoinsMin(POINT *point, BOX *box, IMAGE *image, IMAGE *imres) {
    int min = (int) PIXEL(image, point);
    int max = (int) PIXEL(image, point);

    for(POINT_Y(point) = BOX_YMIN(box); POINT_Y(point) <= BOX_YMAX(box); POINT_Y(point)++) {
        for(POINT_X(point) = BOX_XMIN(box); POINT_X(point) <= BOX_XMAX(box); POINT_X(point)++) {
            if((int) PIXEL(image, point) < min)
                min = (int) PIXEL(image, point);
            else if((int) PIXEL(image, point) > max)
                max = (int) PIXEL(image, point);
        }
    }

    int difference = max - min;

    if(difference < SEUIL_MAXMOINSMIN && (BOX_XMAX(box) - BOX_XMIN(box)) > MIN_BOX_SIZE &&
       (BOX_YMAX(box) - BOX_YMIN(box)) > MIN_BOX_SIZE) {
        // Box homogène
        for(POINT_Y(point) = BOX_YMIN(box); POINT_Y(point) <= BOX_YMAX(box); POINT_Y(point)++) {
            for(POINT_X(point) = BOX_XMIN(box); POINT_X(point) <= BOX_XMAX(box); POINT_X(point)++) {
                ETIQ(imres, point) = etiqcpt;
            }
        }
        etiqcpt++;
        return 1;
    }
    else if((BOX_XMAX(box) - BOX_XMIN(box)) <= MIN_BOX_SIZE &&
       (BOX_YMAX(box) - BOX_YMIN(box)) <= MIN_BOX_SIZE){
        for(POINT_Y(point) = BOX_YMIN(box); POINT_Y(point) <= BOX_YMAX(box); POINT_Y(point)++) {
            for(POINT_X(point) = BOX_XMIN(box); POINT_X(point) <= BOX_XMAX(box); POINT_X(point)++) {
                ETIQ(imres, point) = 0;
            }
        }
        return 1;
    }
}

int ecartType(POINT *point, BOX *box, IMAGE *image, IMAGE *imres) {
    int moyenne = 0;
    int nbPoints = 0;
    int moyenneCarre = 0;

    for(POINT_Y(point) = BOX_YMIN(box); POINT_Y(point) <= BOX_YMAX(box); POINT_Y(point)++) {
        for(POINT_X(point) = BOX_XMIN(box); POINT_X(point) <= BOX_XMAX(box); POINT_X(point)++) {
            moyenne += (int) PIXEL(image, point);
            moyenneCarre += (int) PIXEL(image, point) * (int) PIXEL(image, point);
            nbPoints++;
        }
    }

    moyenne /= nbPoints;
    moyenneCarre /= nbPoints;

    int ecartType = moyenneCarre - (moyenne * moyenne);

    if(ecartType < SEUIL_ECART_TYPE && (BOX_XMAX(box) - BOX_XMIN(box)) > MIN_BOX_SIZE &&
       (BOX_YMAX(box) - BOX_YMIN(box)) > MIN_BOX_SIZE)
    {
        // Box homogène
        for(POINT_Y(point) = BOX_YMIN(box); POINT_Y(point) <= BOX_YMAX(box); POINT_Y(point)++) {
            for(POINT_X(point) = BOX_XMIN(box); POINT_X(point) <= BOX_XMAX(box); POINT_X(point)++) {
                ETIQ(imres, point) = etiqcpt;
            }
        }
        etiqcpt++;
        return 1;
    }
    else if((BOX_XMAX(box) - BOX_XMIN(box)) <= MIN_BOX_SIZE &&
       (BOX_YMAX(box) - BOX_YMIN(box)) <= MIN_BOX_SIZE){
        for(POINT_Y(point) = BOX_YMIN(box); POINT_Y(point) <= BOX_YMAX(box); POINT_Y(point)++) {
            for(POINT_X(point) = BOX_XMIN(box); POINT_X(point) <= BOX_XMAX(box); POINT_X(point)++) {
                ETIQ(imres, point) = 0;
            }
        }
        return 1;
    }
}

void split(BOX *box, IMAGE *image, POINT *point, IMAGE *imres) {
    POINT* tmpPoint;
    if(crea_POINT(tmpPoint) == NULL) // creation des points
    {
        fprintf(stderr,"Erreur d'Allocation Memoire du Point : Moyen \n");
        exit (0);
    }

    BOX *hautGauche, *hautDroite, *basGauche, *basDroite;
    crea_BOX(hautGauche);
    crea_BOX(hautDroite);
    crea_BOX(basGauche);
    crea_BOX(basDroite);

    BOX_XMIN(hautGauche) = BOX_XMIN(box);
    BOX_XMAX(hautGauche) = (BOX_XMIN(box) + BOX_XMAX(box)) / 2;
    BOX_YMIN(hautGauche) = BOX_YMIN(box);
    BOX_YMAX(hautGauche) = (BOX_YMIN(box) + BOX_YMAX(box)) / 2;

    BOX_XMIN(hautDroite) = (BOX_XMIN(box) + BOX_XMAX(box)) / 2 + 1;
    BOX_XMAX(hautDroite) = BOX_XMAX(box);
    BOX_YMIN(hautDroite) = BOX_YMIN(box);
    BOX_YMAX(hautDroite) = (BOX_YMIN(box) + BOX_YMAX(box)) / 2;

    BOX_XMIN(basGauche) = BOX_XMIN(box);
    BOX_XMAX(basGauche) = (BOX_XMIN(box) + BOX_XMAX(box)) / 2;
    BOX_YMIN(basGauche) = (BOX_YMIN(box) + BOX_YMAX(box)) / 2 + 1;
    BOX_YMAX(basGauche) = BOX_YMAX(box);

    BOX_XMIN(basDroite) = (BOX_XMIN(box) + BOX_XMAX(box)) / 2 + 1;
    BOX_XMAX(basDroite) = BOX_XMAX(box);
    BOX_YMIN(basDroite) = (BOX_YMIN(box) + BOX_YMAX(box)) / 2 + 1;
    BOX_YMAX(basDroite) = BOX_YMAX(box);

    POINT_X(tmpPoint) = BOX_XMIN(box);
    POINT_Y(tmpPoint) = BOX_YMIN(box);

    if(METHODE == 0) {
        if(maxMoinsMin(tmpPoint, box, image, imres) == 1)
            return;
    }
    else {
        if(ecartType(tmpPoint, box, image, imres) == 1)
            return;
    }

    split(hautGauche, image, tmpPoint, imres);
    split(hautDroite, image, tmpPoint, imres);
    split(basGauche, image, tmpPoint, imres);
    split(basDroite, image, tmpPoint, imres);
}
