// file: $isip/class/mmedia/AlgorithmData/algd_02.cc
// version: $Id: algd_02.cc 10596 2006-08-08 21:09:12Z ss754 $
//

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

// method: diagnose
//
// arguments:
//  Integral::DEBUG level: (input) debug level for diagnostics
//
// return: a boolean value indicating status
//
boolean AlgorithmData::diagnose(Integral::DEBUG level_a) {

  //---------------------------------------------------------------------
  //
  // 0. preliminaries
  //
  //---------------------------------------------------------------------

  // output the class name
  //
  if (level_a > Integral::NONE) {
    SysString output(L"diagnosing class ");
    output.concat(CLASS_NAME);
    output.concat(L": ");
    Console::put(output);
    Console::increaseIndention();
  }

  //--------------------------------------------------------------------
  //
  // 1. required public methods
  //     class constructors
  //
  //--------------------------------------------------------------------

  // set indentation
  //  
  if (level_a > Integral::NONE) {
    Console::put(L"testing required public methods: class constructors...\n");
    Console::increaseIndention();
  }
  
  AlgorithmData algd_1;
  AlgorithmData algd_2(algd_1);
  
  if (!algd_2.eq(algd_1)) {
    return Error::handle(name(), L"copy constructor/eq", Error::TEST,
			 __FILE__, __LINE__);
  }

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  //--------------------------------------------------------------------
  //
  // 2. required public methods
  //     memory management methods
  //
  //--------------------------------------------------------------------

  // set indentation
  //  
  if (level_a > Integral::NONE) {
    Console::put(L"testing required public methods: memory management methods...\n");
    Console::increaseIndention();
  }
  
  AlgorithmData::setGrowSize((long)500);

  for (long j = 1; j <= 10; j++) {
    AlgorithmData** dyn_algd = new AlgorithmData*[j * 100];
    
    // create the objects
    //
    for (long i = 0; i < j * 100; i++) {
      dyn_algd[i] = new AlgorithmData();
    }
    
    // delete objects
    //
    for (long i = (j * 100) - 1; i >= 0; i--) {
      delete dyn_algd[i];
    }
      
    delete [] dyn_algd;
  } 

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  //---------------------------------------------------------------------
  //
  // 3. required public methods
  //     i/o methods 
  //
  //---------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing required public methods: io methods...\n");
    Console::increaseIndention();
  }

  // we need binary and text sof files
  //
  String tmp_filename0(L"test.sof");
  //  Integral::makeTemp(tmp_filename0);
  String tmp_filename1;
  Integral::makeTemp(tmp_filename1);  

  // open files in write mode
  //
  Sof tmp_file0;
  Sof tmp_file1;
  
  // set the data to be used in the object
  //
  MatrixFloat tmp_mat(2,2,L"1,2,3,4");
  VectorFloat tmp_vec(L"1,2,3,4");
  
  AlgorithmData algd_3, algd_4;

  // test with VectorFloat objects
  //
  algd_3.setCoefType(PREDICTION);
  algd_3.makeVectorFloat().assign(tmp_vec);

  tmp_file0.open(tmp_filename0, File::WRITE_ONLY, File::TEXT);
  tmp_file1.open(tmp_filename1, File::WRITE_ONLY, File::BINARY);
  
  algd_3.write(tmp_file0, (long)0);
  algd_3.write(tmp_file1, (long)0);

  tmp_file0.close();
  tmp_file1.close();

  // open the files in read mode
  //
  tmp_file0.open(tmp_filename0);
  tmp_file1.open(tmp_filename1);

  // read the value back
  //
  if (!algd_4.read(tmp_file0, (long)0) || !algd_4.eq(algd_3)) {
    algd_3.debug(L"algd_3");
    algd_4.debug(L"algd_4");    
    return Error::handle(name(), L"read", Error::TEST, __FILE__, __LINE__);
  }

  if (!algd_4.read(tmp_file1, (long)0) || !algd_4.eq(algd_3)) {
    return Error::handle(name(), L"read", Error::TEST, __FILE__, __LINE__);
  }
  
  tmp_file0.close();
  tmp_file1.close();

  // test with MatrixFloat objects
  //
  algd_3.clear();
  algd_3.setCoefType(COVARIANCE);
  algd_3.makeMatrixFloat().assign(tmp_mat);

  tmp_file0.open(tmp_filename0, File::WRITE_ONLY, File::TEXT);
  tmp_file1.open(tmp_filename1, File::WRITE_ONLY, File::BINARY);
  
  algd_3.write(tmp_file0, (long)0);
  algd_3.write(tmp_file1, (long)0);

  tmp_file0.close();
  tmp_file1.close();

  // open the files in read mode
  //
  tmp_file0.open(tmp_filename0);
  tmp_file1.open(tmp_filename1);

  // read the value back
  //
  if (!algd_4.read(tmp_file0, (long)0) || !algd_4.eq(algd_3)) {
    algd_3.debug(L"algd_3");
    algd_4.debug(L"algd_4");
    
    return Error::handle(name(), L"read", Error::TEST, __FILE__, __LINE__);
  }

  if (!algd_4.read(tmp_file1, (long)0) || !algd_4.eq(algd_3)) {
    return Error::handle(name(), L"read", Error::TEST, __FILE__, __LINE__);
  }
  
  tmp_file0.close();
  tmp_file1.close();

  // delete the temporary files
  //
  File::remove(tmp_filename0);
  File::remove(tmp_filename1);
 
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  } 
  
  
  //---------------------------------------------------------------------
  //
  // 4. class-specific public methods
  //     set and get methods
  //
  //---------------------------------------------------------------------

  // set indentation
  //  
  if (level_a > Integral::NONE) {
    Console::put(L"testing class-specific public methods: set and get methods...\n");
    Console::increaseIndention();
  }

  // set and get type
  //
  algd_1.setDataType(VECTOR_FLOAT);
  DATA_TYPE dt_val = algd_1.getDataType();

  if (dt_val != VECTOR_FLOAT) {
    return Error::handle(name(), L"setDataType", Error::TEST,
			 __FILE__, __LINE__);
  }

  algd_1.setCoefType(SIGNAL);
  COEF_TYPE ct_val = algd_1.getCoefType();

  if (ct_val != SIGNAL) {
    return Error::handle(name(), L"setCoefType", Error::TEST,
			 __FILE__, __LINE__);
  }

  // test makeVectorFloat and getVectorFloat
  //
  VectorFloat ref(L"1, 2, 3");
  VectorFloat ans;
  algd_1.makeVectorFloat().assign(ref);
  ans = algd_1.getVectorFloat();

  if (!ans.eq(ref)) {
    return Error::handle(name(), L"makeVectorFloat", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // set and get type
  //
  algd_1.setDataType(VECTOR_DOUBLE);
  dt_val = algd_1.getDataType();

  if (dt_val != VECTOR_DOUBLE) {
    return Error::handle(name(), L"setDataType", Error::TEST,
			 __FILE__, __LINE__);
  }

  // test makeVectorDouble and getVectorDouble
  //
  VectorDouble ref_1(L"1, 2, 3");
  VectorDouble ans_1;
  algd_1.makeVectorDouble().assign(ref_1);
  ans_1 = algd_1.getVectorDouble();

  if (!ans_1.eq(ref_1)) {
    return Error::handle(name(), L"makeVectorDouble", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // test makeVectorComplexFloat and getVectorComplexFloat
  //
  VectorComplexFloat ref_2(L"1, 2.0j, -3, -4.0, 0, 1j, 1, 1, 1+1j");
  VectorComplexFloat ans_2;

  // set and get type
  //
  algd_1.setDataType(VECTOR_COMPLEX_FLOAT);
  dt_val = algd_1.getDataType();

  if (dt_val != VECTOR_COMPLEX_FLOAT) {
    return Error::handle(name(), L"setDataType", Error::TEST,
			 __FILE__, __LINE__);
  }

  algd_1.makeVectorComplexFloat().assign(ref_2);
  ans_2 = algd_1.getVectorComplexFloat();

  if (!ans_2.eq(ref_2)) {
    return Error::handle(name(), L"makeVectorFloat", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // test makeVectorComplexDouble and getVectorComplexDouble
  //
  VectorComplexDouble ref_3(L"1, 2.0j, -3, -4.0, 0, 1j, 1, 1, 1+1j");  
  VectorComplexDouble ans_3;

  // set and get type
  //
  algd_1.setDataType(VECTOR_COMPLEX_DOUBLE);
  dt_val = algd_1.getDataType();

  if (dt_val != VECTOR_COMPLEX_DOUBLE) {
    return Error::handle(name(), L"setDataType", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  algd_1.makeVectorComplexDouble().assign(ref_3);
  ans_3 = algd_1.getVectorComplexDouble();

  if (!ans_3.eq(ref_3)) {
    return Error::handle(name(), L"makeVectorDouble", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // test makeMatrixFloat and getMatrixFloat
  //  
  MatrixFloat ref_4(2, 3, L"5.0, 5.0, 5.0, 5.0, 5.0, 5.0");
  MatrixFloat ans_4;

  // set and get type
  //
  algd_1.setDataType(MATRIX_FLOAT);
  dt_val = algd_1.getDataType();

  if (dt_val != MATRIX_FLOAT) {
    return Error::handle(name(), L"setDataType", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  algd_1.makeMatrixFloat().assign(ref_4);
  ans_4 = algd_1.getMatrixFloat();

  if (!ans_4.eq(ref_4)) {
    return Error::handle(name(), L"makeMatrixFloat", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // test makeMatrixDouble and getMatrixDouble
  //  
  MatrixDouble ref_5(2, 3, L"5.0, 5.0, 5.0, 5.0, 5.0, 5.0");
  MatrixDouble ans_5;

  // set and get type
  //
  algd_1.setDataType(MATRIX_DOUBLE);
  dt_val = algd_1.getDataType();

  if (dt_val != MATRIX_DOUBLE) {
    return Error::handle(name(), L"setDataType", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  algd_1.makeMatrixDouble().assign(ref_5);
  ans_5 = algd_1.getMatrixDouble();

  if (!ans_5.eq(ref_5)) {
    return Error::handle(name(), L"makeMatrixDouble", Error::TEST,
			 __FILE__, __LINE__);
  }

  // test makeComplexFloat and getComplexFloat
  //  
  MatrixComplexFloat ref_6(3, 3, L"1, 2.0j, -3, -4.0, 0, 1j, 1, 1, 1+1j", Integral::FULL);
  MatrixComplexFloat ans_6;

  // set and get type
  //
  algd_1.setDataType(MATRIX_COMPLEX_FLOAT);
  dt_val = algd_1.getDataType();

  if (dt_val != MATRIX_COMPLEX_FLOAT) {
    return Error::handle(name(), L"setDataType", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  algd_1.makeMatrixComplexFloat().assign(ref_6);
  ans_6 = algd_1.getMatrixComplexFloat();

  if (!ans_6.eq(ref_6)) {
    return Error::handle(name(), L"makeMatrixDouble", Error::TEST,
			 __FILE__, __LINE__);
  }

  // test makeComplexDouble and getComplexDouble
  //  
  MatrixComplexDouble ref_7(3, 3, L"1, 2.0j, -3, -4.0, 0, 1j, 1, 1, 1+1j", Integral::FULL);
  MatrixComplexDouble ans_7;

  // set and get type
  //
  algd_1.setDataType(MATRIX_COMPLEX_DOUBLE);
  dt_val = algd_1.getDataType();

  if (dt_val != MATRIX_COMPLEX_DOUBLE) {
    return Error::handle(name(), L"setDataType", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  algd_1.makeMatrixComplexDouble().assign(ref_7);
  ans_7 = algd_1.getMatrixComplexDouble();

  if (!ans_7.eq(ref_7)) {
    return Error::handle(name(), L"makeMatrixDouble", Error::TEST,
			 __FILE__, __LINE__);
  }

  // test makeCombination and getCombination---Float
  //
  VectorFloat ref_05(L"1, 2, 3");
  VectorFloat ref_06(L"11, 12, 13");  

  Vector<AlgorithmData> ref_8(2);
  Vector<AlgorithmData> ans_8(2);
  
  ref_8(0).makeVectorFloat().assign(ref_05);
  ref_8(1).makeVectorFloat().assign(ref_06);
    
  algd_1.makeCombination().assign(ref_8);
  ans_8 = algd_1.getCombination();

  if (!ans_8.eq(ref_8)) {
    return Error::handle(name(), L"makeVectorDouble", Error::TEST,
			 __FILE__, __LINE__);
  }
         
  // test makeCombination and getCombination---Double
  //
  ref_8(0).makeVectorDouble().assign(ref_05);
  ref_8(1).makeVectorDouble().assign(ref_06);
    
  algd_1.makeCombination().assign(ref_8);
  ans_8 = algd_1.getCombination();

  if (!ans_8.eq(ref_8)) {
    return Error::handle(name(), L"makeVectorDouble", Error::TEST,
			 __FILE__, __LINE__);
  }
         
  // test makeCombination--ComplexFloat and getCombination--ComplexFloat
  //
  VectorComplexFloat ref_02(L"1, 2.0j, -3, -4.0, 0, 1j, 1, 1, 1+1j");
  VectorComplexFloat ref_03(L"11, 12.0j, -13, -14.0, 10, 11j, 11, 11, 11+11j");
  
  ref_8(0).makeVectorComplexFloat().assign(ref_02);
  ref_8(1).makeVectorComplexFloat().assign(ref_03);
    
  algd_1.makeCombination().assign(ref_8);
  ans_8 = algd_1.getCombination();

  if (!ans_8.eq(ref_8)) {
    return Error::handle(name(), L"makeVectorDouble", Error::TEST,
			 __FILE__, __LINE__);
  }
         
  // test makeCombination---ComplexDouble and getCombination---ComplexDouble
  //
  ref_8(0).makeVectorComplexDouble().assign(ref_02);
  ref_8(1).makeVectorComplexDouble().assign(ref_03);
    
  algd_1.makeCombination().assign(ref_8);
  ans_8 = algd_1.getCombination();

  if (!ans_8.eq(ref_8)) {
    return Error::handle(name(), L"makeVectorDouble", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  //---------------------------------------------------------------------
  //
  // 5. class-specific public methods
  //     swap
  //
  //---------------------------------------------------------------------

  // set indentation
  //
  if (level_a > Integral::NONE) {
    Console::put(L"testing class-specific public methods: swap methods...\n");
    Console::increaseIndention();
  }

  // set variables for testing
  //
  AlgorithmData tmp;
  algd_1.assign(algd_2);
  tmp.swap(algd_2);

  if (!algd_1.eq(tmp)) {
    return Error::handle(name(), L"diagnose", Error::TEST,
			 __FILE__, __LINE__);
  }
  
  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }
  
  //--------------------------------------------------------------------
  //
  // 6. print completion message
  //
  //--------------------------------------------------------------------

  // reset indentation
  //
  if (level_a > Integral::NONE) {
    Console::decreaseIndention();
  }

  // possibly print completion message
  //  
  if (level_a > Integral::NONE) {
    String output(L"diagnostics completed successfully for class ");
    output.concat(name());
    output.concat(L"\n");
    Console::put(output);
  }

  // exit gracefully
  //  
  return true;
}
