// file: $isip/class/algo/Connection/conn_05.cc
// version: $Id: conn_05.cc 8269 2002-07-02 19:14:33Z gao $
//

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

// method: apply
//
// arguments:
//  Vector<AlgorithmData>& output: (output) processed output
//  const Vector< CircularBuffer<AlgorithmData> >& input: (input) input data
//
// return: a boolean value indicating status
//
boolean Connection::apply(Vector<AlgorithmData>& output_a,
			  const Vector< CircularBuffer<AlgorithmData> >& input_a) {

  // declare local variables
  //
  boolean res = true;
  long nsignal = input_a.length();

  // start the debugging output
  //
  displayStart(this);
    
  // branch on algorithm: CHANNEL
  //  for CHANNEL algorithm, we convert multichannel data
  //  to single channel data for all input signals
  //
  if (algorithm_d == CHANNEL) {

    // branch on the implementation: CONCATENATE
    //

    if (implementation_d == CONCATENATE) {

      // set the output length
      //
      output_a.setLength(nsignal);

      // loop over all signals
      //
      for (long s = 0; s < nsignal; s++) {
	// display the channel number
	//
	displayChannel(s);
	
	// process a channel
	//
	const Vector<AlgorithmData>* comb = &(input_a(s)(0).getCombination());
	
	if ((*comb)(0).getDataType() == AlgorithmData::VECTOR_FLOAT) {
	  res &= computeChannelConcatenate(output_a(s).makeVectorFloat(), *comb);
	}
	else {
	  return Error::handle(name(), L"apply",
			       Error::NOT_IMPLEM, __FILE__, __LINE__);
	}
      }
    }

    // implementation: INTERLEAVE
    //  loop across channels first, thereby interleaving samples
    //  from each channel into the output signal.
    //
    else if (implementation_d == INTERLEAVE) {
      // single signal
      //
      if (nsignal == 1) {
	// set the output length
	//
	output_a.setLength(nsignal);
	
	// process a channel
	//
	const Vector<AlgorithmData>* comb = &(input_a(0)(0).getCombination());
	  
	res &= computeChannelInterleave(output_a(0).makeVectorFloat(), *comb);
      }

      // multiple signal
      //
      else {
	
	Vector<AlgorithmData> temp_comb;
	temp_comb.setLength(nsignal);
	
	long nchan  = input_a(0)(0).getCombination().length();
	output_a.setLength(nchan);
      
	// loop over all channels
	//
	for (long c = 0; c < nchan; c++) {
	  
	  // loop over all signals
	  //
	  for (long s = 0; s < nsignal; s++) {
	    
	    // display the channel number
	    //
	    displayChannel(s);
	    
	    const Vector<AlgorithmData>* comb =
	      &(input_a(s)(0).getCombination());	  
	    temp_comb(s).assign((*comb)(c));
	    
	  } //end of signal for loop
	  
	  // process a channel
	  //
	  res &= computeChannelInterleave(output_a(c).makeVectorFloat(), temp_comb);
	  
	} // end of channel for loop
      }
    }
    
    // else: error
    //
    else {
      return Error::handle(name(), L"apply",
			   Error::NOT_IMPLEM, __FILE__, __LINE__);
    } 
  }
  
  // algorithm: STREAM
  //  for this mode, we build one multichannel signal out of multiple
  //  multichannel signals.
  //
  else if (algorithm_d == STREAM) {

    // implementation: CONCATENATE
    //  build a new output signal which includes all channels of all inputs
    //
    if (implementation_d == CONCATENATE) {

      // initialize some counters
      //
      long j = 0;
      long output_length = 0;
      
      for (long c = 0; c < nsignal; c++) {
	 
	output_length += input_a(c)(0).getCombination().length();

      }
      output_a.setLength(output_length);

      
      for (long s = 0; s < nsignal; s++) {
	 
	long nchan  = input_a(s)(0).getCombination().length();
	const Vector<AlgorithmData>* comb = &(input_a(s)(0).getCombination());
	
	for (long c = 0; c < nchan; c++) {	
	  res &= computeStreamConcatenate(output_a(j++), (*comb)(c));	
	}
      }				  

      // possibly display the data
      //
      display(output_a, input_a(0)(0).getCombination(), name());
    }

    // implementation: SELECT    
    //  build a new output signal which includes the specified channel
    //  from each input.
    //
    else if (implementation_d == SELECT) {

      // set the output length, and transfer the data to the output
      //
      output_a.setLength(nsignal);

      for (long s = 0; s < nsignal; s++) {
	const Vector<AlgorithmData>* comb = &(input_a(s)(0).getCombination());
	res &= computeStreamSelect(output_a(s), *comb);
      }
      
      // possibly display the data
      //
      display(output_a, input_a, name());
    }
  }

  else {
    return Error::handle(name(), L"apply",
			 Error::NOT_IMPLEM, __FILE__, __LINE__);
  }

  // finish the debugging output
  //
  displayFinish(this);
  
  // exit gracefully
  //
  return res;
}

