// file: $USFS/class/image_analysis/v3.0/imaga_rle_06.cc
//

// system include files
//
#include <string.h>

// isip include files
//
#include "image_analysis.h"

#include "image_analysis_constants.h"
#include <integral_constants.h>

// method: rle_dct_cc
//
// arguments: none
//
// return: a logical_1 value indicating status
//
// this method computes the DCT of the image block and replaces it with the
// pixels with the coefficient valus
//
logical_1 Image_analysis::rle_dct_cc() {
  
  // create temporary space for the DCT coefficients
  //
  float_4* dct_r = new float_4[IMAGA_RLE_BLK_SIZE * IMAGA_RLE_BLK_SIZE];
  float_4* dct_g = new float_4[IMAGA_RLE_BLK_SIZE * IMAGA_RLE_BLK_SIZE];
  float_4* dct_b = new float_4[IMAGA_RLE_BLK_SIZE * IMAGA_RLE_BLK_SIZE];
  
  if (dct_r == NULL) {
    error_handler_cc((char_1*)"rle_dct_cc",
		     (char_1*)"error allocating memory");
    return ISIP_FALSE;
  }

  if (dct_g == NULL) {
    error_handler_cc((char_1*)"rle_dct_cc",
		     (char_1*)"error allocating memory");
    return ISIP_FALSE;
  }
  
  if (dct_b == NULL) {
    error_handler_cc((char_1*)"rle_dct_cc",
		     (char_1*)"error allocating memory");
    return ISIP_FALSE;
  }

  memset(dct_r, 0, IMAGA_RLE_BLK_SIZE*IMAGA_RLE_BLK_SIZE*sizeof(float_4));
  memset(dct_g, 0, IMAGA_RLE_BLK_SIZE*IMAGA_RLE_BLK_SIZE*sizeof(float_4));
  memset(dct_b, 0, IMAGA_RLE_BLK_SIZE*IMAGA_RLE_BLK_SIZE*sizeof(float_4));
  
  // create intermediate storage for the DCT algorithm
  //
  float_4* intermed_r = new float_4[IMAGA_RLE_BLK_SIZE * IMAGA_RLE_BLK_SIZE];
  float_4* intermed_g = new float_4[IMAGA_RLE_BLK_SIZE * IMAGA_RLE_BLK_SIZE];
  float_4* intermed_b = new float_4[IMAGA_RLE_BLK_SIZE * IMAGA_RLE_BLK_SIZE];
  
  if (intermed_r == NULL) {
    error_handler_cc((char_1*)"rle_dct_cc",
		     (char_1*)"error allocating memory");
    return ISIP_FALSE;
  }

  if (intermed_g == NULL) {
    error_handler_cc((char_1*)"rle_dct_cc",
		     (char_1*)"error allocating memory");
    return ISIP_FALSE;
  }
  
  if (intermed_b == NULL) {
    error_handler_cc((char_1*)"rle_dct_cc",
		     (char_1*)"error allocating memory");
    return ISIP_FALSE;
  }

  memset(intermed_r, 0, IMAGA_RLE_BLK_SIZE*IMAGA_RLE_BLK_SIZE*sizeof(float_4));
  memset(intermed_g, 0, IMAGA_RLE_BLK_SIZE*IMAGA_RLE_BLK_SIZE*sizeof(float_4));
  memset(intermed_b, 0, IMAGA_RLE_BLK_SIZE*IMAGA_RLE_BLK_SIZE*sizeof(float_4));

  // computing the intermediate constants
  //
  for (int_4 i=0; i<IMAGA_RLE_BLK_SIZE; i++) {
    for (int_4 j=0; j<IMAGA_RLE_BLK_SIZE; j++) {
      intermed_r[i * IMAGA_RLE_BLK_SIZE + j] = 0;
      intermed_g[i * IMAGA_RLE_BLK_SIZE + j] = 0;
      intermed_b[i * IMAGA_RLE_BLK_SIZE + j] = 0;
      for (int_4 k=0; k<IMAGA_RLE_BLK_SIZE; k++) {
	intermed_r[i * IMAGA_RLE_BLK_SIZE + j] += rle_r_red_d[i * IMAGA_RLE_BLK_SIZE + k] * rle_r_cos_d[k][j];
	intermed_g[i * IMAGA_RLE_BLK_SIZE + j] += rle_r_grn_d[i * IMAGA_RLE_BLK_SIZE + k] * rle_r_cos_d[k][j];
	intermed_b[i * IMAGA_RLE_BLK_SIZE + j] += rle_r_blu_d[i * IMAGA_RLE_BLK_SIZE + k] * rle_r_cos_d[k][j];
      }
    }
  }

  // compute the DCT coefficients one by one
  //
  float_4 C1 = 1.0;
  float_4 C2 = 1.0;
  for (int_4 u=0; u < IMAGA_RLE_BLK_SIZE; u++) {
    for (int_4 v=0; v < IMAGA_RLE_BLK_SIZE; v++) {
      dct_r[u*IMAGA_RLE_BLK_SIZE + v] = 0;
      dct_g[u*IMAGA_RLE_BLK_SIZE + v] = 0;
      dct_b[u*IMAGA_RLE_BLK_SIZE + v] = 0;
      C1 = 1.0;
      C2 = 1.0;
      for (int_4 j=0; j < IMAGA_RLE_BLK_SIZE; j++) {
	dct_r[u*IMAGA_RLE_BLK_SIZE + v] += intermed_r[j*IMAGA_RLE_BLK_SIZE + v]
	  * rle_r_cos_d[j][u];
	dct_g[u*IMAGA_RLE_BLK_SIZE + v] += intermed_g[j*IMAGA_RLE_BLK_SIZE + v]
	  * rle_r_cos_d[j][u];
	dct_b[u*IMAGA_RLE_BLK_SIZE + v] += intermed_b[j*IMAGA_RLE_BLK_SIZE + v]
	  * rle_r_cos_d[j][u];
      }
      if (u == 0) { C1 = 0.707106781; }
      if (v == 0) { C2 = 0.707106781; }
      dct_r[u*IMAGA_RLE_BLK_SIZE + v] *= (C1 * C2 / 4.0);
      dct_g[u*IMAGA_RLE_BLK_SIZE + v] *= (C1 * C2 / 4.0);
      dct_b[u*IMAGA_RLE_BLK_SIZE + v] *= (C1 * C2 / 4.0);
    }
  }
  
  for (int_4 i=0; i < (IMAGA_RLE_BLK_SIZE*IMAGA_RLE_BLK_SIZE); i++) {
    rle_r_red_d[i] = dct_r[i];
    rle_r_grn_d[i] = dct_g[i];
    rle_r_blu_d[i] = dct_b[i];
  }

  // free memory
  //
  delete [] intermed_r;
  delete [] intermed_g;
  delete [] intermed_b;
  delete [] dct_r;
  delete [] dct_g;
  delete [] dct_b;

  // exit gracefully
  //
  return ISIP_TRUE;
}
