#include <pgm.h>
#include <math.h>

enum { N = 4, M = 4 };

typedef struct pgm_t {
  int cols, rows;
  gray maxval;
  gray **pgm;
} pgm;

struct pgm_t load_pgm( const char *filename ) {
  FILE *fp = fopen( filename, "w" );
  struct pgm_t pgm;
  pgm.pgm = pgm_readpgm( fp, &pgm.cols, &pgm.rows, &pgm.maxval );
  fclose( fp );
  return pgm;
}

void store_pgm( const char *filename, const struct pgm_t *pgm ) {
  FILE *fp = fopen( filename, "w" );
  pgm_writepgm( fp, pgm->pgm, pgm->cols, pgm->rows, pgm->maxval, 0 );
  fclose( fp );
}

struct pgm_t mesh( const struct pgm_t *src, int w, int h ) {
  struct pgm_t result;
  int x, y;
  double d = (double)(src->cols * src->rows)/w/h;

  result.maxval = src->maxval;
  result.cols = w;
  result.rows = h;
  result.pgm = pgm_allocarray( w, h );
  for( x = 0; x < src->cols; ++x ) {
    for( y = 0; y < src->rows; ++y ) {
      result.pgm[x/w][y/h] += src->pgm[x][y];
    }
  }
  
  for( x = 0; x < w; ++x ) {
    for( y = 0; y < h; ++y ) {
      result.pgm[x][y] /= d;
    }
  }

  return result;
}
double calc_similarness( const struct pgm_t *a, const struct pgm_t *b ) {
  double result = 0;
  int x, y;
#if 0
  assert( a->cols == b->cols );
  assert( a->rows == b->rows );
  assert( a->maxval == b->maxval );
#endif
  for( x = 0; x < a->cols; ++x ) {
    for( y = 0; y < a->rows; ++y ) {
      result += fabs( a->pgm[x][y] - b->pgm[x][y] );
    }
  }
  return result / a->cols / a->rows;
}

int main( int argc, const char *argv[]) {
  if( strcmp( argv[0], "(1)" ) == 0 ) {
    struct pgm_t g = load_pgm( argv[1] );
    struct pgm_t g2 = mesh( &g, N, M );
    store_pgm( "result-1.pgm", &g2 );
  }
  else if( strcmp( argv[0], "(2)" ) == 0 ) {
    struct pgm_t in = load_pgm( argv[1] );
    struct pgm_t meshed = mesh( &in, N, M );
    double max_similarness = 0.0;
    int most_similar_number = -1;
    int i;
    for( i = 0; i < 10; ++i ) {
      char buf[32];
      sprintf( buf, "std%i.pgm", i );
      struct pgm_t std_N = load_pgm( buf );
      struct pgm_t meshed_N = mesh( &std_N, N, M );
      double similarness = calc_similarness( &in, &std_N );
      if( similarness > max_similarness ) {
        max_similarness = similarness;
        most_similar_number = i;
      }
      printf( "SIMILARITY TO #%i IS %f\n", i, similarness );
    }
    printf( "MOST SIMILAR NUMBER IS: %d", most_similar_number );
  }
  else if( strcmp( argv[0], "(3)" ) == 0 ) {
  }
}
