#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>

#include "def.h"
#include "filter.h"
#include "bitmap_24bitRGB.h"
#include "bitmap_8bit.h"
#include "bitmap_2bit.h"
#include "threshold.h"
#include "color_components.h"


#define THRESHOLD_VALUE (3)

void printTimes(time_t start, time_t end) {
  printf(" start %f , end %f -> length %f \n",
	 (double) start, (double) end, (double) (end-start));
}

void testAFilter(Filter *filter) {

  Bitmap_24bitRGB *rgbBmp = NULL;
  Bitmap_8bit *grayBmp  = NULL;
  Bitmap_8bit *filterBmp = NULL;
  time_t startTime, endTime;

  rgbBmp = readFromFile_bmp24bitRGB("test_source.ppm");
  assert(rgbBmp != NULL);

  grayBmp = intensityComponent_bmp24bit(rgbBmp);
  assert(grayBmp != NULL);

  writeToFile_bmp8bit(grayBmp, "test_intensity.pgm");

  startTime = time(NULL);
  filterBmp = applyFilter(grayBmp, filter);
  assert(filterBmp != NULL);
  endTime = time(NULL);

  writeToFile_bmp8bit(filterBmp, "test_lowpass.pgm");

  printTimes(startTime, endTime);

}

void testFilterCreation() {
  Filter *f;
  Point2D origin;
  int isAverage;

  double mask[] = {
     1.0,  2.0,  1.0,
     0.0,  0.0,  0.0,
    -1.0, -2.0, -1.0};
  
  printf("Testing filter creation:\n");
  origin.x = 1;
  origin.y = 1;

  isAverage = TRUE;
  f = createFilter(origin, 3, 3, isAverage, mask);

  printFilter(f);
}


static Bitmap_8bit * prewitt1(Bitmap_8bit *source) {
  Bitmap_8bit *filterBmp = NULL;
  Filter *filter;
  int isAverage; 

  double mask[] = {
    -1.0,-1.0,-1.0,
     0.0, 0.0, 0.0,
     1.0, 1.0, 1.0 };
  Point2D filterOrigin;
  filterOrigin.x = 1;
  filterOrigin.y = 1;
  
  isAverage = TRUE;
  filter = createFilter(filterOrigin, 3, 3, isAverage, mask); 
  printFilter(filter);

  filterBmp = applyFilter(source, filter);
  
  return filterBmp;
}


void testMedian() {
  Bitmap_24bitRGB *rgbBmp = NULL;
  Bitmap_8bit *grayBmp  = NULL;
  Bitmap_8bit *filterBmp = NULL;
  Bitmap_8bit *edgeBmp = NULL;
  Bitmap_2bit *binaryBmp = NULL;

  time_t startTime, endTime;

  rgbBmp = readFromFile_bmp24bitRGB("test_source.ppm");
  if(rgbBmp == NULL) {
    perror("readFromFile_bmp24bitRGB");
    exit(1);
  }

  grayBmp = intensityComponent_bmp24bit(rgbBmp);
  if(rgbBmp == NULL) {
    perror("convert_24bitRGB_to_8bit(rgbBmp)");
    exit(1);
  }
 
  startTime = time(NULL); printf("start\n");
  filterBmp = applyMedianFilter(grayBmp);
  endTime = time(NULL); printf("end\n");
  printTimes(startTime, endTime);

  if(filterBmp == NULL) {
    perror("medianFilter");
    exit(1);
  }
  writeToFile_bmp8bit(filterBmp, "test_medianfiltered.pgm");



  edgeBmp = prewitt1(filterBmp);
  writeToFile_bmp8bit(edgeBmp, "test_edgefiltered.pgm");  
  binaryBmp = threshold_8bit(edgeBmp, (unsigned char) THRESHOLD_VALUE);
  writeToFile_bmp2bit(binaryBmp, "test_edgesthresholded.pgm");  
  
}

void testFilteringNearPictureEdges() {
  Bitmap_8bit *grayBmp = NULL;
  Bitmap_8bit *filteredBmp = NULL;
  Point2D filterOrigin;
  Filter *filter;
  int isAverage;

  unsigned char bmpValues[] = {
    10,  0, 0, 0, 
    0,   0, 0, 0,
    0,   0, 0, 0,
    0,   0, 0, 5
  };
  double mask[] = {
    1, 1, 1, 
    1, 1, 1,
    1, 1, 1
  };
  
  printf("Testing filtering near edges with small 4x4 image\n");
  filterOrigin.x = 1;
  filterOrigin.y = 1;
  

  isAverage = TRUE;
  filter = createFilter(filterOrigin, 3, 3, isAverage, mask);
  printFilter(filter);

  grayBmp = create_bmp8bit(4,4);
  setPixel_bmp8bit(grayBmp, 0, 0, bmpValues[0]);
  setPixel_bmp8bit(grayBmp, 1, 0, bmpValues[1]);
  setPixel_bmp8bit(grayBmp, 2, 0, bmpValues[2]);
  setPixel_bmp8bit(grayBmp, 3, 0, bmpValues[3]);
  setPixel_bmp8bit(grayBmp, 0, 1, bmpValues[4]);
  setPixel_bmp8bit(grayBmp, 1, 1, bmpValues[5]);
  setPixel_bmp8bit(grayBmp, 2, 1, bmpValues[6]);
  setPixel_bmp8bit(grayBmp, 3, 1, bmpValues[7]);
  setPixel_bmp8bit(grayBmp, 0, 2, bmpValues[8]);
  setPixel_bmp8bit(grayBmp, 1, 2, bmpValues[9]);
  setPixel_bmp8bit(grayBmp, 2, 2, bmpValues[10]);
  setPixel_bmp8bit(grayBmp, 3, 2, bmpValues[11]);
  setPixel_bmp8bit(grayBmp, 0, 3, bmpValues[12]);
  setPixel_bmp8bit(grayBmp, 1, 3, bmpValues[13]);
  setPixel_bmp8bit(grayBmp, 2, 3, bmpValues[14]);
  setPixel_bmp8bit(grayBmp, 3, 3, bmpValues[15]);
  
  printf("Gray Picture:\n");
  printf("%3d %3d %3d %3d\n", 
	 getPixel_bmp8bit(grayBmp, 0, 0), 
	 getPixel_bmp8bit(grayBmp, 1, 0), 
	 getPixel_bmp8bit(grayBmp, 2, 0), 
	 getPixel_bmp8bit(grayBmp, 3, 0));
  printf("%3d %3d %3d %3d\n", 
	 getPixel_bmp8bit(grayBmp, 0, 1), 
	 getPixel_bmp8bit(grayBmp, 1, 1), 
	 getPixel_bmp8bit(grayBmp, 2, 1), 
	 getPixel_bmp8bit(grayBmp, 3, 1));
  printf("%3d %3d %3d %3d\n", 
	 getPixel_bmp8bit(grayBmp, 0, 2), 
	 getPixel_bmp8bit(grayBmp, 1, 2), 
	 getPixel_bmp8bit(grayBmp, 2, 2), 
	 getPixel_bmp8bit(grayBmp, 3, 2));
  printf("%3d %3d %3d %3d\n", 
	 getPixel_bmp8bit(grayBmp, 0, 3), 
	 getPixel_bmp8bit(grayBmp, 1, 3), 
	 getPixel_bmp8bit(grayBmp, 2, 3), 
	 getPixel_bmp8bit(grayBmp, 3, 3));

  filteredBmp = applyFilter(grayBmp, filter);
  
  printf("Filtered picture:\n");
  printf("%3d %3d %3d %3d\n", 
	 getPixel_bmp8bit(filteredBmp, 0, 0), 
	 getPixel_bmp8bit(filteredBmp, 1, 0), 
	 getPixel_bmp8bit(filteredBmp, 2, 0), 
	 getPixel_bmp8bit(filteredBmp, 3, 0));
  printf("%3d %3d %3d %3d\n", 
	 getPixel_bmp8bit(filteredBmp, 0, 1), 
	 getPixel_bmp8bit(filteredBmp, 1, 1), 
	 getPixel_bmp8bit(filteredBmp, 2, 1), 
	 getPixel_bmp8bit(filteredBmp, 3, 1));
  printf("%3d %3d %3d %3d\n", 
	 getPixel_bmp8bit(filteredBmp, 0, 2), 
	 getPixel_bmp8bit(filteredBmp, 1, 2), 
	 getPixel_bmp8bit(filteredBmp, 2, 2), 
	 getPixel_bmp8bit(filteredBmp, 3, 2));
  printf("%3d %3d %3d %3d\n", 
	 getPixel_bmp8bit(filteredBmp, 0, 3), 
	 getPixel_bmp8bit(filteredBmp, 1, 3), 
	 getPixel_bmp8bit(filteredBmp, 2, 3), 
	 getPixel_bmp8bit(filteredBmp, 3, 3));
}


void test5x5Lowpass() {
  Filter *filter;
  int isAverage;
  Point2D filterOrigin;
  double mask[] = {
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0,
    1.0, 1.0, 1.0, 1.0, 1.0
  };
  
  printf("Testing 5x5 lowpass filtering:\n");

  filterOrigin.x = 2;
  filterOrigin.y = 2;
  isAverage = TRUE;
  filter = createFilter(filterOrigin, 5, 5, isAverage, mask); 
  testAFilter(filter);
}

void test3x3Lowpass() {
  Filter *filter;
  int isAverage;
  Point2D filterOrigin;
  double mask[] = {
    1.0, 1.0, 1.0,
    1.0, 1.0, 1.0,
    1.0, 1.0, 1.0
  };

  printf("Testing 3x3 lowpass filtering:\n");

  filterOrigin.x = 1;
  filterOrigin.y = 1;
  isAverage = TRUE;
  filter = createFilter(filterOrigin, 3, 3, isAverage, mask); 
  testAFilter(filter);
}

  


void testFiltering() {
  Bitmap_24bitRGB *rgbBmp = NULL;
  Bitmap_8bit *grayBmp  = NULL;
  Bitmap_8bit *filterBmp = NULL;
  Bitmap_2bit *binaryBmp = NULL;
  Filter *filter;
  
  time_t startTime, endTime;
  /* HIGH PASS: 
   double mask[] = {
    -1.0,-1.0,-1.0,
   -1.0, 8.0,-1.0,
   -1.0,-1.0,-1.0 };
   */

  /* PREWITT 1 */
  double mask[] = {
    -1.0,-1.0,-1.0,
     0.0, 0.0, 0.0,
     1.0, 1.0, 1.0 };
  
  /* PREWITT 2 

  double mask[] = {
    -1.0, 0.0, 1.0,
    -1.0, 0.0, 1.0,
    -1.0, 0.0, 1.0 };
    */

  /* Sobel horiz 
  double mask[] = {
    -1.0,-2.0,-1.0,
     0.0, 0.0, 0.0,
     1.0, 2.0, 1.0 };
  */

  /* Sobel vertical 
   double mask[] = {
    -1.0, 0.0, 1.0,
    -2.0, 0.0, 2.0,
    -1.0, 0.0, 1.0 };
    */

  /* Roberts 1 
   double mask[] = {
     1.0, 0.0,     
     0.0,-1.0};
  */

  /* Edge subspace W1 
  double mask[] = {
    -1.0,-1.4142,-1.0,
     0.0,    0.0, 0.0,
     1.0, 1.4142, 1.0 };
  */


  int isAverage;
  Point2D filterOrigin;
  filterOrigin.x = 1;
  filterOrigin.y = 1;
  

  isAverage = TRUE;
  filter = createFilter(filterOrigin, 3, 3, isAverage, mask); 
  /*filter = createFilter(filterOrigin, 2, 2, 1.0/4.0, mask);*/

  printFilter(filter);

  rgbBmp = readFromFile_bmp24bitRGB("test_source.ppm");
  assert(rgbBmp != NULL);

  grayBmp = intensityComponent_bmp24bit(rgbBmp);
  assert(grayBmp != NULL);

  writeToFile_bmp8bit(grayBmp, "test_intensity.pgm");

  startTime = time(NULL);
  filterBmp = applyFilter(grayBmp, filter);
  assert(filterBmp != NULL);
  endTime = time(NULL);

  writeToFile_bmp8bit(filterBmp, "test_filtered.pgm");


  binaryBmp = threshold_8bit(filterBmp, (unsigned char) THRESHOLD_VALUE);
  assert(binaryBmp != NULL);

  writeToFile_bmp2bit(binaryBmp, "test_thresholded.pbm");
  
  printTimes(startTime, endTime);
  
}

  
int main() {
  //testFilterCreation();
  //testFiltering();
  testMedian();
  //testFilteringNearPictureEdges();
  //test5x5Lowpass();
  //test3x3Lowpass();
 
 return 0;
}
  
