// file: $isip_ifc/class/algo/Generator/gen_00.cc
// version: $Id: gen_00.cc 10391 2006-01-25 03:32:38Z prasad $
//

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

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

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

  // assign protected data from argument
  //
  algorithm_d = arg_a.algorithm_d;
  implementation_d = arg_a.implementation_d;
  cmode_d = arg_a.cmode_d;
  channels_d = arg_a.channels_d;
  accum_frame_d.assign(arg_a.accum_frame_d);
  seed_d = arg_a.seed_d;
  
  // assign the frequency and amplitude if the signal type
  //  is a sine, pulse, triangle or square
  //
  if ((arg_a.algorithm_d == SINE) || (arg_a.algorithm_d == PULSE) ||
      (arg_a.algorithm_d == TRIANGLE) || (arg_a.algorithm_d == SQUARE)) {
    frequency_d = arg_a.frequency_d;
    amplitude_d = arg_a.amplitude_d;
    phase_d = arg_a.phase_d;
    bias_d = arg_a.bias_d;
    phmode_d = arg_a.phmode_d;    
  }

  // assign the duty cycle if the signal type is pulse, square or triangle
  //
  if ((arg_a.algorithm_d == PULSE) || (arg_a.algorithm_d == TRIANGLE) ||
      (arg_a.algorithm_d == SQUARE)) {
    duty_cycle_d = arg_a.duty_cycle_d;
  }

  // assign the mean and variance if the signal type is gaussian noise
  //
  if (arg_a.algorithm_d == GAUSSIAN) {
    mean_d = arg_a.mean_d;
    variance_d = arg_a.variance_d;
  }

  // assign the system parameters if the signal type is Lorentz or Rossler
  //
  if (arg_a.algorithm_d == LORENTZ || arg_a.algorithm_d == ROSSLER) {
    chaos_a_d = arg_a.chaos_a_d;
    chaos_b_d = arg_a.chaos_b_d;
    chaos_c_d = arg_a.chaos_c_d;
    chaos_x0_d = arg_a.chaos_x0_d;
    chaos_y0_d = arg_a.chaos_y0_d;
    chaos_z0_d = arg_a.chaos_z0_d;
    chaos_integrate_upsample_d = arg_a.chaos_integrate_upsample_d;
   }
 

  // assign the gen sample freq
  //
  gen_sample_freq_d = arg_a.gen_sample_freq_d;
   
  // set initialization flag
  //
  is_valid_d = arg_a.is_valid_d;

  // exit gracefully
  //
  return AlgorithmBase::assign(arg_a);
}

// method: eq
//
// arguments:
//  const Generator& arg: (input) object to be compared
//
// return: a boolean value indicating status
//
// this method checks whether the current Generator object is identical to the
// input object
//
boolean Generator::eq(const Generator& arg_a) const {

  if (algorithm_d != arg_a.algorithm_d) {
    return false;
  }
  
  if (implementation_d != arg_a.implementation_d) {
    return false;
  }  
  
  if (cmode_d != arg_a.cmode_d) {
    return false;
  }
    
  if (!accum_frame_d.eq(arg_a.accum_frame_d)) {
    return false;
  }

  if (channels_d != arg_a.channels_d) {
    return false;
  }
  
  if ((arg_a.algorithm_d == SINE) || (arg_a.algorithm_d == PULSE) ||
      (arg_a.algorithm_d == TRIANGLE) || (arg_a.algorithm_d == SQUARE)) {
    if ((frequency_d != arg_a.frequency_d) ||
	(amplitude_d != arg_a.amplitude_d) ||
	(phase_d != arg_a.phase_d) || (bias_d != arg_a.bias_d) ||
	(phmode_d != arg_a.phmode_d)) {
      return false;
    }
  }

  if ((arg_a.algorithm_d == SQUARE) || (arg_a.algorithm_d == TRIANGLE) ||
      (arg_a.algorithm_d == PULSE)) {
    if (duty_cycle_d != arg_a.duty_cycle_d) {
      return false;
    }
  }

  if (arg_a.algorithm_d == GAUSSIAN) {
    if ((mean_d != arg_a.mean_d) ||
	(variance_d != arg_a.variance_d)) {
      return false;
    }
  } 

  if (arg_a.algorithm_d == LORENTZ || arg_a.algorithm_d == ROSSLER ) {
    if ((chaos_a_d != arg_a.chaos_a_d) || (chaos_b_d != arg_a.chaos_b_d) ||
	(chaos_c_d != arg_a.chaos_c_d) || (chaos_x0_d != arg_a.chaos_x0_d) ||
	(chaos_y0_d != arg_a.chaos_y0_d) || (chaos_z0_d != arg_a.chaos_z0_d) ||
	(chaos_integrate_upsample_d != arg_a.chaos_integrate_upsample_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
//
// this method resets the data members to the default values
//
boolean Generator::clear(Integral::CMODE ctype_a) {

  // reset the data members unless the mode is RETAIN
  //
  if (ctype_a != Integral::RETAIN) {

    // clear the the design parameters
    //
    algorithm_d = DEF_ALGORITHM;
    implementation_d = DEF_IMPLEMENTATION;
    cmode_d = AlgorithmBase::ACCUMULATE;
    accum_frame_d.clear();
    channels_d = DEF_CHANNELS;
    amplitude_d = DEF_AMPLITUDE;
    mean_d = DEF_MEAN;
    variance_d = DEF_VARIANCE;
    duty_cycle_d = DEF_DUTY_CYCLE;
    phase_d = DEF_PHASE;
    phmode_d = DEF_PHMODE;
    frequency_d = DEF_FREQUENCY;
    bias_d = DEF_BIAS;
    seed_d = DEF_SEED;
    chaos_a_d = DEF_CHAOS_A;
    chaos_b_d = DEF_CHAOS_B;
    chaos_c_d = DEF_CHAOS_C;
    chaos_x0_d = DEF_CHAOS_X0;
    chaos_z0_d = DEF_CHAOS_Y0;
    chaos_y0_d = DEF_CHAOS_Z0;
    chaos_integrate_upsample_d = DEF_CHAOS_INTEGRATE_UPSAMPLE;

  }
  
  // set the initialization flag
  //
  is_valid_d = false;

  // call the base clear method
  //
  return AlgorithmBase::clear();   
}
  
//---------------------------------------------------------------------------
//
// class-specific public methods:
//  public methods required by the AlgorithmBase interface contract
//
//---------------------------------------------------------------------------

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

  if (typeid(arg_a) == typeid(Generator)) {
    return assign((Generator&)arg_a);
  }
  
  // case: other
  //  if the input algorithm object is not a Generator object, error
  //
  else {
    return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__);
  }
}
 
// method: eq
//
// arguments:
//  const AlgorithmBase& arg: (input) object to be compared
//
// return: a boolean value indicating status
//
// this method checks whether the current Generator object is identical
// to the input algorithm object
//
boolean Generator::eq(const AlgorithmBase& arg_a) const {

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

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

// method: init
//
// arguments: none
//
// return: a boolean value indicating status
//
// to initialize this object, either the
// or the duration and sample frequency must be set,
// or the length.
//
// see the header file for references for the algorithms.
//
boolean Generator::init() {

  // initialize vector of accum_frame
  //
  accum_frame_d.setLength(channels_d);

  // seed the random variable if the algorithm type is guassian
  //
  if (algorithm_d == GAUSSIAN) {
    Random::GLOBAL_GAUSSIAN.seed((long)seed_d);
  }
  
  // set the initialization flag
  //
  is_valid_d = true;

  // exit gracefully
  //
  return true;
}

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

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

// constants: i/o related constants
//
const String Generator::DEF_PARAM(L"");
const String Generator::PARAM_ALGORITHM(L"algorithm");
const String Generator::PARAM_IMPLEMENTATION(L"implementation");
const String Generator::PARAM_PHMODE(L"phase_mode");
const String Generator::PARAM_ACCUM_FRAME(L"accum_frame");
const String Generator::PARAM_CHANNELS(L"channels");
const String Generator::PARAM_FREQUENCY(L"frequency");
const String Generator::PARAM_AMPLITUDE(L"amplitude");
const String Generator::PARAM_MEAN(L"mean");
const String Generator::PARAM_VARIANCE(L"variance");
const String Generator::PARAM_DUTY_CYCLE(L"duty_cycle");
const String Generator::PARAM_PHASE(L"phase");
const String Generator::PARAM_BIAS(L"DC");
const String Generator::PARAM_SEED(L"seed");
const String Generator::PARAM_GEN_SAMPLE_FREQUENCY(L"gen_sample_frequency");
const String Generator::PARAM_CHAOS_A(L"chaos_a");
const String Generator::PARAM_CHAOS_B(L"chaos_b");
const String Generator::PARAM_CHAOS_C(L"chaos_c");
const String Generator::PARAM_CHAOS_X0(L"chaos_x0");
const String Generator::PARAM_CHAOS_Y0(L"chaos_y0");
const String Generator::PARAM_CHAOS_Z0(L"chaos_z0");
const String Generator::PARAM_CHAOS_INTEGRATE_UPSAMPLE(L"chaos_integrate_upsample");

// constants: NameMap(s) for the enumerated values
//
const NameMap Generator::ALGO_MAP(L"SINE, SQUARE, TRIANGLE, PULSE, GAUSSIAN, LORENTZ, ROSSLER");
const NameMap Generator::IMPL_MAP(L"FUNCTION");
const NameMap Generator::PHMODE_MAP(L"DETERMINISTIC, RANDOM");

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