/// QasTools: Desktop toolset for the Linux sound system ALSA.
/// \copyright See COPYING file.

#include "is_buffer.hpp"
#include "image_set.hpp"
#include "image_set_meta.hpp"
#include <algorithm>
#include <cassert>
#include <iostream>

namespace dpe
{

IS_Buffer::IS_Buffer ()
: _storage_limit ( 8 * 1024 * 1024 )
{
  _remove_poll_timer.setInterval ( 1000 / 3 );
  connect (
      &_remove_poll_timer, &QTimer::timeout, this, &IS_Buffer::remove_poll );
}

IS_Buffer::~IS_Buffer ()
{
  clear ();
}

std::size_t
IS_Buffer::byte_count () const
{
  std::size_t res = 0;
  for ( const auto & handle : _handles ) {
    res += handle->img_set->byte_count ();
  }
  return res;
}

void
IS_Buffer::clear ()
{
  // std::cout << "IS_Buffer::clear byte count " << byte_count() << "\n";
  if ( !_handles.empty () ) {
    _handles.clear ();
  }
}

dpe::IS_Buffer_Handle *
IS_Buffer::acquire_return_handle ( const dpe::Image_Set_Meta * meta_n,
                                   dpe::Image_Set * cur_set_n )
{
  dpe::IS_Buffer_Handle * res = nullptr;

  // Try to find an image set with matching meta information
  for ( auto & handle : _handles ) {
    if ( meta_n->matches ( handle->meta.get () ) ) {
      res = handle.get ();
      break;
    }
  }

  bool no_match = true;
  if ( res != nullptr ) {
    // Increment user count of the set found
    // if the argument set is not the found set
    no_match = ( res->img_set.get () != cur_set_n );
    if ( no_match ) {
      ++res->num_users;
    }
  }

  if ( ( cur_set_n != nullptr ) && no_match ) {
    return_img_set ( cur_set_n );
  }

  return res;
}

void
IS_Buffer::append_handle ( std::unique_ptr< dpe::IS_Buffer_Handle > handle_n )
{
  ++handle_n->num_users;
  _handles.push_back ( std::move ( handle_n ) );
}

void
IS_Buffer::return_img_set ( dpe::Image_Set * img_set_n )
{
  if ( img_set_n == nullptr ) {
    return;
  }

  std::size_t list_idx = _handles.size ();

  for ( std::size_t ii = 0; ii < _handles.size (); ++ii ) {
    dpe::Image_Set * img_set = _handles[ ii ]->img_set.get ();
    if ( img_set == img_set_n ) {
      list_idx = ii;
      break;
    }
  }

  if ( list_idx < _handles.size () ) {
    // Image set found in list
    auto & handle = _handles[ list_idx ];

    // std::cout << "IS_Buffer::return_img_set users " << handle->num_users <<
    //"\n";
    if ( handle->num_users > 0 ) {
      --handle->num_users;
    }

    if ( handle->num_users == 0 ) {
      // std::cout << "IS_Buffer::return_img_set bytes " << byte_count() <<
      //"\n";
      if ( byte_count () <= _storage_limit ) {
        // Delete later
        handle->remove_time.start ();
        if ( !_remove_poll_timer.isActive () ) {
          _remove_poll_timer.start ();
        }
      } else {
        _handles.erase ( _handles.cbegin () + list_idx );
      }
    }
  }

  // std::cout << "dpe::IS_Buffer::return_img_set: ";
  // std::cout << "List size " << _handles.size() << "\n";
}

void
IS_Buffer::remove_poll ()
{
  std::size_t pending = 0;

  std::size_t idx = 0;
  while ( idx < _handles.size () ) {
    auto & handle = _handles[ idx ];
    bool do_remove = false;

    if ( handle->num_users == 0 ) {
      if ( handle->remove_time.isValid () ) {
        if ( handle->remove_time.hasExpired ( 1000 ) ) {
          do_remove = true;
        } else {
          ++pending;
        }
      }
    }

    if ( do_remove ) {
      _handles.erase ( _handles.cbegin () + idx );
    } else {
      ++idx;
    }
  }

  if ( pending == 0 ) {
    _remove_poll_timer.stop ();
  }

  // std::cout << "dpe::IS_Buffer::remove_poll: ";
  // std::cout << "List size " << _handles.size() << "\n";
}

} // namespace dpe
