// file: $isip/class/algo/Math/math_00.cc
// version: $Id: math_00.cc 8283 2002-07-03 21:08:37Z picone $
//

// system include files
//
#include <typeinfo>

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

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

// method: default constructor
//
// arguments:
//  ALGORITHM algorithm: (input) algorithm name
//  IMPLEMENTATION implementation: (input) implementation name
//  long num_operands: (input) number of operands
//
// return: none
//
Math::Math(ALGORITHM algorithm_a, 
	   IMPLEMENTATION implementation_a, 
	   long num_operands_a) {

  // clean up memory and reset
  //
  algorithm_d = algorithm_a;
  implementation_d = implementation_a;
  num_operands_d = num_operands_a;
  function_d.assign(num_operands_d, (long)DEF_FUNCTION);
  operation_d.assign(num_operands_d, (long)DEF_OPERATION);
  operation_d(0).assign((long)ASSIGN);
  weight_d.assign(num_operands_d, (float)1.0);
  const_d.assign(DEF_CONST);
  
  // exit gracefully
  //
}

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

  // assign all the data
  //
  algorithm_d = arg_a.algorithm_d;
  implementation_d = arg_a.implementation_d;
  num_operands_d = arg_a.num_operands_d;
  function_d.assign(arg_a.function_d);
  operation_d.assign(arg_a.operation_d);
  weight_d.assign(arg_a.weight_d);
  const_d.assign(arg_a.const_d);

  // copy the base class
  //
  return AlgorithmBase::assign(arg_a);
}

// method: eq
//
// arguments:
//  const Math& arg: (input) input object to assign
//
// return: a boolean value indicating status
//
// this method checks if two Math objects are the same
//
boolean Math::eq(const Math& arg_a) const {

  // check algorithm
  //
  if (algorithm_d != arg_a.algorithm_d) {
    return false;
  }

  // check implementation
  //
  if (implementation_d != arg_a.implementation_d) {
    return false;
  }

  // check number of operands
  //
  if (num_operands_d != arg_a.num_operands_d) {
    return false;
  }
  
  // check equality of function
  //
  if (!function_d.eq(arg_a.function_d)) {
    function_d.debug(L"function_d");
    arg_a.function_d.debug(L"arg_a.function_d");
    return false;
  }

  // check equality of operation
  //
  if (!operation_d.eq(arg_a.operation_d)) {
    return false;
  }
  
  // check equality of weights
  //
  if (!weight_d.eq(arg_a.weight_d)) {
    return false;
  }

  // check equality of constant
  //
  if (const_d != arg_a.const_d) {
    return false;
  }

  // exit gracefully by checking the base class
  //
  return AlgorithmBase::eq(arg_a);
}

// method: clear
//
// arguments:
//  Integral::CMODE ctype: (input) clear mode
//
// return: a boolean value indicating status
//
// this method resets the data members to the default values
//
boolean Math::clear(Integral::CMODE ctype_a) {

  // clean up memory and reset
  //
  // reset the data members unless the mode is RETAIN
  //
  if (ctype_a != Integral::RETAIN) {
    num_operands_d = DEF_NUM_OPERANDS;
    algorithm_d = DEF_ALGORITHM;
    implementation_d = DEF_IMPLEMENTATION;
    function_d.clear(ctype_a);
    operation_d.clear(ctype_a);
    weight_d.clear(ctype_a);
    const_d.clear(ctype_a);
  }

  // call the base clear method
  //
  return AlgorithmBase::clear(ctype_a);
}

//---------------------------------------------------------------------------
//
// class-specific public methods:  
//  AlgorithmBase interface contract methods
//
//---------------------------------------------------------------------------

// method: assign
//
// arguments:
//  const AlgorithmBase& arg: (input) object to assign
//
// return: a boolean value indicating status
//
// this method assigns input object to the current object
//
boolean Math::assign(const AlgorithmBase& arg_a) {

  // case: input is a Math object
  //  
  if (typeid(arg_a) == typeid(Math)) {
    return assign((Math&)arg_a);
  }

  // case: other
  //  if the input algorithm object is not a Math object, return
  //  an error.
  //  
  else {
    return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__);
  }

  // exit gracefully
  //
  return true;
}

// method: eq
//
// arguments:
//  const AlgorithmBase& arg: (input) object to assign
//
// return: a boolean value indicating status
//
// this method checks whether two Math objects are equal or not
//
boolean Math::eq(const AlgorithmBase& arg_a) const {

  // case: input is a Math object
  //  
  if (typeid(arg_a) == typeid(Math)) {
    return eq((Math&)arg_a);
  }

  // case: other
  //  if the input algorithm object is not a Math object, return an
  //  error.
  //  
  else {
    return Error::handle(name(), L"eq", Error::ARG, __FILE__, __LINE__);
  }
  
  // exit gracefully
  //
  return true;
}

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

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

// constants: i/o related constants
//
const String Math::PARAM_NUMBER(L"num_operands");
const String Math::PARAM_ALGORITHM(L"algorithm");
const String Math::PARAM_IMPLEMENTATION(L"implementation");
const String Math::PARAM_CONST(L"constant");
const String Math::PARAM_FUNCTION(L"function");
const String Math::PARAM_OPERATION(L"operation");
const String Math::PARAM_WEIGHT(L"weight");
const String Math::DELIM(L",");

// constants: NameMap(s) for the enumerated values
//
const NameMap Math::ALGO_MAP(L"FUNCTION_CALCULATOR");
const NameMap Math::IMPL_MAP(L"ENUMERATE");
const NameMap Math::OPER_MAP(L"ASSIGN, ADD, SUBTRACT, MULTIPLY, DIVIDE");
const NameMap Math::FUNC_MAP(L"IDENTITY, ABS, ACOS, ASIN, ATAN, CEIL, COS, EXP, EXP2, EXP10, FACTORIAL, FLOOR, IMAG, INVERSE, LOG, LOG2, LOG10, LOG1P, MAG, NEG, REAL, RFLOOR, ROUND, SIN, SQRT, SQUARE, TAN, TRANSPOSE");

// static instantiations: memory manager
//
MemoryManager Math::mgr_d(sizeof(Math), Math::name());
