#pragma once

#include "utils/workers/result.hpp"
#include "utils/workers/setup.hpp"
#include "utils/fft/fft.hpp"
#include "utils/fvec/fvec.hpp"
#include "utils/windows/hann/hann.hpp"

namespace hr
{
  template<typename Plugin>
  class adapter 
  {
    public:
      adapter(Plugin& p) : m_plugin { p } 
      { 
        m_end = m_plugin.m_setup.m_block_size - m_plugin.m_setup.m_step_size;
        m_data.resize(m_plugin.m_setup.m_block_size, 0.0);
        m_data_old.resize(m_end, 0.0);
        m_fft.init(m_plugin.m_setup.m_block_size);
        m_hann.creaate(m_plugin.m_setup.m_block_size);
      }

      virtual ~adapter() { }

    protected:
      Plugin& m_plugin;
      real_time m_timestamp;
      fft m_fft;
      math::hann m_hann;
      fvec_t m_data;
      fvec_t m_data_old;
      size_t m_end;

    public:
      void process(fvec_t& in, real_time timestamp)
      {
        m_timestamp = timestamp;

        switch(m_plugin.m_setup.m_domain)
        {
          case DOMAIN_PLUGIN::TIME:
          {
            m_plugin.process(in, m_timestamp);
            break;
          }
          case DOMAIN_PLUGIN::FREQUENSY:
          {
            frequensy(in);
            break;
          }
        }
      }

      result get_result() { return m_plugin.get_result(); }

    private:
      void swap_buffer(fvec_t& in)
      {
        size_t i = 0;
        for (i = 0; i < m_end; ++i) m_data[i] = m_data_old[i];
        for (i = 0; i < m_plugin.m_setup.m_step_size; ++i) m_data[m_end + i] = in[i];
        for (i = 0; i < m_end; ++i) m_data_old[i] = m_data[i + m_plugin.m_setup.m_step_size];
      }

      void frequensy(fvec_t& in)
      {
        swap_buffer(in);
        m_hann.apply(m_data);
        m_data.shift();
        auto r = m_fft.process(m_data);
        m_plugin.process(r, in, m_timestamp);
      }
  };
}
