/* -*- c++ -*- */
/*
 * Copyright 2012,2014 Free Software Foundation, Inc.
 *
 * This file is part of GNU Radio
 *
 * GNU Radio is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * GNU Radio is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gnuradio/filter/filterbank.h>
#include <cstdio>
#include <iostream>
#include <stdexcept>

namespace gr {
  namespace filter {
    namespace kernel {

      filterbank::filterbank(const std::vector<std::vector<float> > &taps)
        : d_taps(taps)
      {
        d_nfilts = d_taps.size();
        d_fir_filters = std::vector<kernel::fir_filter_ccf*>(d_nfilts);
        if (d_nfilts == 0) {
          throw std::invalid_argument("The taps vector may not be empty.");
        }
        d_active.resize(d_nfilts);
        // Create an FIR filter for each channel and zero out the taps
        std::vector<float> vtaps(1, 0.0f);
        for(unsigned int i = 0; i < d_nfilts; i++) {
          d_fir_filters[i] = new kernel::fir_filter_ccf(1, vtaps);
        }
        // Now, actually set the filters' taps
        set_taps(d_taps);
      }

      filterbank::~filterbank()
      {
        for(unsigned int i = 0; i < d_nfilts; i++) {
          delete d_fir_filters[i];
        }
      }

      void
      filterbank::set_taps(const std::vector<std::vector<float> > &taps)
      {
        d_taps = taps;
        // Check that the number of filters is correct.
        if (d_nfilts != d_taps.size()) {
          throw std::runtime_error("The number of filters is incorrect.");
        }
        // Check that taps contains vectors of taps, where each vector
        // is the same length.
        d_ntaps = d_taps[0].size();
        for (unsigned int i = 1; i < d_nfilts; i++) {
          if (d_taps[i].size() != d_ntaps) {
            throw std::runtime_error("All sets of taps must be of the same length.");
          }
        }
        for(unsigned int i = 0; i < d_nfilts; i++) {
          // If filter taps are all zeros don't bother to crunch the numbers.
          d_active[i] = false;
          for (unsigned int j = 0; j < d_ntaps; j++) {
            if (d_taps[i][j] != 0) {
              d_active[i] = true;
              break;
            }
          }

          d_fir_filters[i]->set_taps(d_taps[i]);
        }
      }

      void
      filterbank::print_taps()
      {
        unsigned int i, j;
        for(i = 0; i < d_nfilts; i++) {
          printf("filter[%d]: [", i);
          for(j = 0; j < d_taps_per_filter; j++) {
            printf(" %.4e", d_taps[i][j]);
          }
          printf("]\n\n");
        }
      }

      std::vector< std::vector<float> >
      filterbank::taps() const
      {
        return d_taps;
      }

    } /* namespace kernel */
  } /* namespace filter */
} /* namespace gr */