

#ifndef VALIB_SYNC_H
#define VALIB_SYNC_H

#include "filter.h"






class Sync
{
protected:
  bool    syncing; 
  bool    sync[2]; 
  vtime_t time[2]; 

public:
  Sync()
  {
    reset();
  }

  inline void receive_sync(bool _sync, vtime_t _time)
  {
    if (_sync)
      if (syncing)
      {
        sync[0] = true;
        time[0] = _time;
        sync[1] = false;
        time[1] = _time;
      }
      else
      {
        sync[1] = true;
        time[1] = _time;
      }
  }
  inline void receive_sync(const Chunk *chunk)
  {
    receive_sync(chunk->sync, chunk->time);
  }

  inline void send_sync(Chunk *_chunk)
  {
    _chunk->sync = sync[0];
    _chunk->time = time[0];
    sync[0] = sync[1];
    time[0] = time[1];
    sync[1] = false;
  }

  inline bool is_syncing()
  {
    return syncing;
  }

  inline void set_syncing(bool _syncing)
  {
    syncing = _syncing;
  }

  inline void reset()
  {
    syncing = true;
    sync[0] = false;
    sync[1] = false;
  }
};
























































class SyncHelper
{
protected:
  bool    sync[2]; 
  vtime_t time[2]; 
  int     pos[2];  

  inline void shift();

public:
  SyncHelper()
  { reset(); }

  inline void receive_sync(const Chunk *chunk, int pos);
  inline void send_frame_sync(Chunk *chunk);
  inline void send_sync(Chunk *chunk, double size_to_time);
  inline void drop(int size);
  inline void reset();
};



inline void
SyncHelper::shift()
{
  sync[0] = sync[1];
  time[0] = time[1];
  pos[0]  = pos[1];
  sync[1] = false;
  time[1] = 0;
  pos[1]  = 0;
}

inline void
SyncHelper::receive_sync(const Chunk *chunk, int _pos)
{
  if (chunk->sync)
  {
    if (sync[0] && pos[0] != _pos)
    {
      assert(pos[0] < _pos);
      sync[1] = true;
      time[1] = chunk->time;
      pos[1]  = _pos;
    }
    else
    {
      sync[0] = true;
      time[0] = chunk->time;
      pos[0]  = _pos;
    }
  }
}

inline void
SyncHelper::send_frame_sync(Chunk *chunk)
{
  if (pos[0] <= 0)
  {
    chunk->sync = sync[0];
    chunk->time = time[0];
    shift();
  }
}

inline void
SyncHelper::send_sync(Chunk *chunk, double size_to_time)
{
  if (pos[0] <= 0)
  {
    chunk->sync = sync[0];
    chunk->time = time[0] - pos[0] * size_to_time;
    shift();
  }
}

inline void
SyncHelper::drop(int size)
{
  if (sync[0])
    pos[0] -= size;

  if (sync[1])
  {
    pos[1] -= size;
    if (pos[1] <= 0)
      shift();
  }
}

inline void
SyncHelper::reset()
{
  sync[0] = false;
  time[0] = 0;
  pos[0]  = 0;
  sync[1] = false;
  time[1] = 0;
  pos[1]  = 0;
}

#endif
