#ifndef _INTERPOLATION_UPSAMPLER_HPP_
#define _INTERPOLATION_UPSAMPLER_HPP_

#pragma once

#include <cpp/radio/Vector.hpp>
#include <cpp/radio/FirComplex.hpp>

namespace Radio
{
namespace Interpolation
{

// --------------------------------------------------------------
// Complex FIR-based UpSampler
// --------------------------------------------------------------

class UpSampler
{
public:
	UpSampler()
	: m_pFir(nullptr)
	, m_pCoeff(nullptr)
	, m_L(0)
	{
		
	}
	~UpSampler()
	{
		if (m_pFir)
			delete [] m_pFir;
			
		if (m_pCoeff)
			delete [] m_pCoeff;
		
	}
	void init(uint32_t L, RealScalar const *coeff, uint32_t N)
	{
		uint32_t i, j;
		uint32_t stage_N;
		uint32_t stage;
	
		if (m_pFir)
			delete [] m_pFir;

		if (m_pCoeff)
			delete [] m_pCoeff;

		m_pFir = new FirComplex[L];
		m_pCoeff = new RVec[L];
		
		for (stage=0; stage < L; stage++)
		{
			stage_N = 0;
			for (i=L-stage-1; i < N; i += L)
			{
				stage_N++;
			}
			m_pFir[stage].setNumTaps(stage_N);
			m_pCoeff[stage].resize(stage_N);
			
			j=0;
			for (i=L-stage-1; i < N; i += L)
			{
				if (coeff)
				{
					m_pCoeff[stage][j++] = coeff[i];
				}
			}
		}
		m_L = L;
	}

	uint32_t process(CVec &dst, CVec const &src, uint32_t len)
	{
		uint32_t i;
		uint32_t j;
		uint32_t currStage;
		
		j = 0;
		for (i=0; i < len; i++)
		{
			for (currStage=0; currStage < m_L; currStage++)
			{
				m_pFir[currStage].feed(src[i]);
				dst[m_L-1-currStage+j] = m_pFir[currStage].processReal(m_pCoeff[currStage]);
			}
			j += m_L;
		}
		return j;
	}

private:
	FirComplex *m_pFir;
	RVec *m_pCoeff;
	uint32_t m_L;
	
};

} // Radio::Interpolation
} // ::Radio

#endif // _INTERPOLATION_UPSAMPLER_HPP_