#include <string.h>
#include "parallel_fir.h"

ParallelFIR::ParallelFIR()
:list(0), count(0), ver(0), list_ver(0)
{}

ParallelFIR::ParallelFIR(const FIRGen *const *list_, size_t count_)
:list(0), count(0), ver(0), list_ver(0)
{
  set(list_, count_);
}

ParallelFIR::~ParallelFIR()
{
  release();
}


void
ParallelFIR::set(const FIRGen *const *list_, size_t count_)
{
  release();

  list = new const FIRGen *[count_];
  if (!list) return;

  count = count_;
  for (size_t i = 0; i < count_; i++)
    list[i] = list_[i];
}

void
ParallelFIR::release()
{
  safe_delete(list);
  count = 0;
  ver++;
}

int
ParallelFIR::version() const
{
  int sum = 0;
  for (size_t i = 0; i < count; i++)
    sum += list[i]->version();

  if (sum != list_ver)
    list_ver = sum, ver++;

  return ver;
}

const FIRInstance *
ParallelFIR::make(int sample_rate) const
{
  size_t i;
  size_t fir_count = 0;
  int length = 1;
  int center = 0;
  int min_point = 0;
  int max_point = 1;

  if (count == 0) return 0;
  const FIRInstance *result = 0;
  const FIRInstance **fir = new const FIRInstance *[count];
  if (!fir) return 0;

  
  

  fir_count = 0;
  for (i = 0; i < count; i++)
  {
    if (list[i] == 0) continue;
    fir[fir_count] = list[i]->make(sample_rate);
    if (fir[fir_count])
    {
      if (min_point > - fir[fir_count]->center)
        min_point = -fir[fir_count]->center;
      if (max_point < fir[fir_count]->length - fir[fir_count]->center)
        max_point = fir[fir_count]->length - fir[fir_count]->center;
      fir_count++;
    }
  }

  length = max_point - min_point;
  center = -min_point;

  
  

  if (fir_count == 0)
    result = 0;
  else if (fir_count == 1)
    result = fir[0];
  else
  {
    double *data = new double[length];
    if (data)
    {
      int current_length = fir[0]->length;
      memset(data, 0, length * sizeof(double));

      for (i = 0; i < fir_count; i++)
        for (int j = 0; j < fir[i]->length; j++)
          data[j + center - fir[i]->center] += fir[i]->data[j];

      result = new DynamicFIRInstance(sample_rate, firt_custom, length, center, data);
    }
  }

  
  

  if (fir_count > 1)
    for (i = 0; i < fir_count; i++)
      safe_delete(fir[i]);
  safe_delete(fir);

  return result;
}
