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

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

//------------------------------------------------------------------------
//
// required public methods
//
//-----------------------------------------------------------------------

// method: clear
//
// arguments:
//  Integral::CMODE ctype: (input) clear mode
//
// return: a boolean value indicating status
//
boolean AlgorithmData::clear(Integral::CMODE ctype_a) {

  // for RETAIN or FREE, we need to call the sub-clear methods.
  //
  if ((ctype_a == Integral::RETAIN) || (ctype_a == Integral::FREE)) {
  
    if (data_type_d == VECTOR_FLOAT) {
      return reinterpret_cast < VectorFloat* > (data_d)->clear(ctype_a);
    }
    else if (data_type_d == VECTOR_COMPLEX_FLOAT) {
      return reinterpret_cast<VectorComplexFloat*>(data_d)->clear(ctype_a);
    }
    else if (data_type_d == MATRIX_FLOAT) {
      return reinterpret_cast <MatrixFloat* > (data_d)->clear(ctype_a);
    }
    else if (data_type_d == MATRIX_COMPLEX_FLOAT) {
      return reinterpret_cast<MatrixComplexFloat*>(data_d)->clear(ctype_a);
    }
    else if (data_type_d == COMBINATION) {
      return reinterpret_cast<Vector<AlgorithmData>*>(data_d)->clear(ctype_a);
    }
    else if (data_type_d == VECTOR_DOUBLE) {
      return reinterpret_cast <VectorDouble*> (data_d)->clear(ctype_a);
    }
    else if (data_type_d == VECTOR_COMPLEX_DOUBLE) {
      return reinterpret_cast<VectorComplexDouble*>(data_d)->clear(ctype_a);
    }
    else if (data_type_d == MATRIX_DOUBLE) {
      return reinterpret_cast <MatrixDouble*> (data_d)->clear(ctype_a);
    }
    else if (data_type_d == MATRIX_COMPLEX_DOUBLE) {
      return reinterpret_cast<MatrixComplexDouble*>(data_d)->clear(ctype_a);
    }
  }

  // unless RETAIN, reinitialize the object
  //
  if (ctype_a != Integral::RETAIN) {
    setDataType(NONE);
    coef_type_d = DEF_CTYPE;
  }

  return true;
}

// method: eq
//
// arguments:
//  const AlgorithmData& arg: (input) input object
//
// return: a boolean value indicating status
//
// this method checks if two objects are the same
//
// note that the is_valid flag is not checked as part of
// the equality condition.
//
boolean AlgorithmData::eq(const AlgorithmData& arg_a) const {

  // check all internal data
  //
  if (data_type_d != arg_a.data_type_d) {
    return false;
  }

  // branch on type before comparing the data
  // float type
  //
  else if (data_type_d == VECTOR_FLOAT) {
    return getVectorFloat().eq(arg_a.getVectorFloat());
  }
  else if (data_type_d == VECTOR_COMPLEX_FLOAT) {
    return getVectorComplexFloat().eq(arg_a.getVectorComplexFloat());
  }
  else if (data_type_d == MATRIX_FLOAT) {
    return getMatrixFloat().eq(arg_a.getMatrixFloat());
  }

  else if (data_type_d == MATRIX_COMPLEX_FLOAT) {
    return getMatrixComplexFloat().eq(arg_a.getMatrixComplexFloat());
  }

  else if (data_type_d == COMBINATION) {
    return getCombination().eq(arg_a.getCombination());
  }


  // double type
  //
  else if (data_type_d == VECTOR_DOUBLE) {
    return getVectorDouble().eq(arg_a.getVectorDouble());
  }
  else if (data_type_d == VECTOR_COMPLEX_DOUBLE) {
    return getVectorComplexDouble().eq(arg_a.getVectorComplexDouble());
  }
  else if (data_type_d == MATRIX_DOUBLE) {
    return getMatrixDouble().eq(arg_a.getMatrixDouble());
  }

  else if (data_type_d == MATRIX_COMPLEX_DOUBLE) {
    return getMatrixComplexDouble().eq(arg_a.getMatrixComplexDouble());
  }

  if (coef_type_d != arg_a.coef_type_d) {
    return false;
  }
  
  // exit gracefully
  //
  return true;
}

// method: assign
//
// arguments:
//  const AlgorithmData& arg: (input) object to assign
//
// return: a boolean value indicating status
//
// this method assigns the input argument to "this".
//
boolean AlgorithmData::assign(const AlgorithmData& arg_a) {

  // if the types are not equal, we must make them so
  //
  if (data_type_d != arg_a.data_type_d) {
    setDataType(arg_a.data_type_d);
  }

  // branch on mode before making assignment
  // float type
  //
  if (arg_a.data_type_d == VECTOR_FLOAT) {
    reinterpret_cast<VectorFloat*>(data_d)->assign(*(reinterpret_cast<VectorFloat*>(arg_a.data_d)));
  }

  else if (arg_a.data_type_d == VECTOR_COMPLEX_FLOAT) {
    reinterpret_cast<VectorComplexFloat*>(data_d)->assign(*(reinterpret_cast<VectorComplexFloat*>(arg_a.data_d)));
  }

  else if (arg_a.data_type_d == MATRIX_FLOAT) {
    reinterpret_cast<MatrixFloat*>(data_d)->assign(*(reinterpret_cast<MatrixFloat*>(arg_a.data_d)));
  }

  else if (arg_a.data_type_d == MATRIX_COMPLEX_FLOAT) {
    reinterpret_cast<MatrixComplexFloat*>(data_d)->assign(*(reinterpret_cast<MatrixComplexFloat*>(arg_a.data_d)));
  }

  else if (arg_a.data_type_d == COMBINATION) {
    reinterpret_cast<Vector<AlgorithmData>*>(data_d)->assign(*(reinterpret_cast<Vector<AlgorithmData>*>(arg_a.data_d)));
  }


  // double type
  //
  else if (arg_a.data_type_d == VECTOR_DOUBLE) {
    reinterpret_cast<VectorDouble*>(data_d)->assign(*(reinterpret_cast<VectorDouble*>(arg_a.data_d)));
  }

  else if (arg_a.data_type_d == VECTOR_COMPLEX_DOUBLE) {
    reinterpret_cast<VectorComplexDouble*>(data_d)->assign(*(reinterpret_cast<VectorComplexDouble*>(arg_a.data_d)));
  }

  else if (arg_a.data_type_d == MATRIX_DOUBLE) {
    reinterpret_cast<MatrixDouble*>(data_d)->assign(*(reinterpret_cast<MatrixDouble*>(arg_a.data_d)));
  }

  else if (arg_a.data_type_d == MATRIX_COMPLEX_DOUBLE) {
    return Error::handle(name(), L"assign", Error::NOT_IMPLEM, __FILE__,
			 __LINE__);
  }

  // copy the coef descriptor
  //
  coef_type_d = arg_a.coef_type_d;
  
  // exit gracefully
  //
  return true;
}

//---------------------------------------------------------------------------
//
// class-specific public methods
//
//---------------------------------------------------------------------------

// method: setDataType
//
// arguments:
//  DATA_TYPE type: (input) new type
//
// return: a boolean value indicating status
//
// this method sets the class to hold data in the specified mode
//
boolean AlgorithmData::setDataType(DATA_TYPE type_a) {

  // if the mode is none, data should be null
  //
  if (!((data_type_d == NONE) ^ (data_d != (void*)NULL))) {
    return Error::handle(name(), L"setDataType",
			 Error::MEM, __FILE__, __LINE__);
  }

  // if the mode is different, delete the old and allocate the new
  //
  if (data_type_d != type_a) {

    // delete the old instance for all modes but NONE
    // float type
    //
    if (data_type_d == VECTOR_FLOAT) {
      delete reinterpret_cast < VectorFloat*> (data_d);
    }
    else if (data_type_d == VECTOR_COMPLEX_FLOAT) {
      delete reinterpret_cast < VectorComplexFloat*> (data_d);
    }
    else if (data_type_d == MATRIX_FLOAT) {
      delete reinterpret_cast < MatrixFloat* > (data_d);
    }
    else if (data_type_d == MATRIX_COMPLEX_FLOAT) {
      delete reinterpret_cast < MatrixComplexFloat* > (data_d);
    }
    else if (data_type_d == COMBINATION) {
      delete reinterpret_cast < Vector < AlgorithmData >*> (data_d);
    }
    
    // double type
    //
    if (data_type_d == VECTOR_DOUBLE) {
      delete reinterpret_cast < VectorDouble* > (data_d);
    }
    else if (data_type_d == VECTOR_COMPLEX_DOUBLE) {
      delete reinterpret_cast < VectorComplexDouble* > (data_d);
    }
    else if (data_type_d == MATRIX_DOUBLE) {
      delete reinterpret_cast < MatrixDouble* > (data_d);
    }
    else if (data_type_d == MATRIX_COMPLEX_DOUBLE) {
      delete reinterpret_cast < MatrixComplexDouble* > (data_d);
    }

    
    // create the new instance for all modes but NONE
    //
    if (type_a == VECTOR_FLOAT) {
      data_d = reinterpret_cast < void* > (new VectorFloat);
    }
    else if (type_a == VECTOR_COMPLEX_FLOAT) {
      data_d = reinterpret_cast < void* > (new VectorComplexFloat);
    }
    else if (type_a == MATRIX_FLOAT) {
      data_d = reinterpret_cast < void* > (new MatrixFloat);
    }
    else if (type_a == MATRIX_COMPLEX_FLOAT) {
      data_d = reinterpret_cast < void* > (new MatrixComplexFloat);
    }

    // double type
    //
    else if (type_a == VECTOR_DOUBLE) {
      data_d = reinterpret_cast < void* > (new VectorDouble);
    }
    else if (type_a == VECTOR_COMPLEX_DOUBLE) {
      data_d = reinterpret_cast < void* > (new VectorComplexDouble);
    }
    else if (type_a == MATRIX_DOUBLE) {
      data_d = reinterpret_cast < void* > (new MatrixDouble);
    }
    else if (type_a == MATRIX_COMPLEX_DOUBLE) {
      data_d = reinterpret_cast < void* > (new MatrixComplexDouble);
    }
    else if (type_a == COMBINATION) {
      data_d = reinterpret_cast < void* > (new Vector<AlgorithmData>);
    }    
    else if (type_a == NONE) {
      data_d = (void*)NULL;
    }

    // set the mode
    //
    data_type_d = type_a;
  }

  // or just clear the current data
  //
  else {
    clear(Integral::RETAIN);
  }

  // exit gracefully
  //
  return true;
}

// method: swap
//
// arguments:
//  AlgorithmData& arg: (input/output) object to swap with
//
// return: a boolean value indicating status
//
boolean AlgorithmData::swap(AlgorithmData& arg_a) {

  // first copy the current object into temporary memory
  //
  DATA_TYPE tmp_dtype = data_type_d;
  COEF_TYPE tmp_ctype = coef_type_d;
  void* tmp_data = data_d;

  // now copy the argument into the current object
  //
  data_type_d = arg_a.data_type_d;
  coef_type_d = arg_a.coef_type_d;
  data_d = arg_a.data_d;

  // copy the temporary memory into the argument
  //
  arg_a.data_type_d = tmp_dtype;
  arg_a.coef_type_d = tmp_ctype;
  arg_a.data_d = tmp_data;

  // exit gracefully
  //
  return true;
}

//---------------------------------------------------------------------------
//
// we define non-integral constants in the default constructor
//      
//---------------------------------------------------------------------------

// constants: class name
//
const String AlgorithmData::CLASS_NAME(L"AlgorithmData");

// constants: i/o related constants
//
const String AlgorithmData::DEF_PARAM(L"");
const String AlgorithmData::PARAM_DATA_TYPE(L"data_type");
const String AlgorithmData::PARAM_COEF_TYPE(L"coef_type");
const String AlgorithmData::PARAM_DATA(L"values");

// constants: NameMap(s) for the enumerated values
//
const NameMap AlgorithmData::DTYPE_MAP(L"NONE, VECTOR_FLOAT, VECTOR_COMPLEX_FLOAT, MATRIX_FLOAT, MATRIX_COMPLEX_FLOAT, VECTOR_DOUBLE, VECTOR_COMPLEX_DOUBLE, MATRIX_DOUBLE, MATRIX_COMPLEX_DOUBLE, COMBINATION");

const NameMap AlgorithmData::CTYPE_MAP(L"GENERIC, PROPAGATE, SIGNAL, SPECTRUM, CORRELATION, COVARIANCE, ENERGY, FILTER, LOG_AREA_RATIO, PREDICTION, REFLECTION, RPS, LYAPUNOV, CORRELATION_INTEGRAL, MUTUAL_INFORMATION, CORRELATION_ENTROPY, CORRELATION_DIMENSION");

// static instantiations: memory manager and debug level
//
DebugLevel AlgorithmData::debug_level_d;
MemoryManager AlgorithmData::mgr_d(sizeof(AlgorithmData),
				   AlgorithmData::name(),
				   MemoryManager::TRACK);
