#include <stdio.h>
#include "parser_filter.h"




ParserFilter::ParserFilter()
:NullFilter(-1)
{
  parser = 0;
  errors = 0;

  out_spk = spk_unknown;
  state = state_trans;
  new_stream = false;
}

ParserFilter::ParserFilter(FrameParser *_parser)
:NullFilter(-1)
{
  parser = 0;
  errors = 0;

  out_spk = spk_unknown;
  state = state_trans;
  new_stream = false;

  set_parser(_parser);
}

ParserFilter::~ParserFilter()
{
}

bool
ParserFilter::set_parser(FrameParser *_parser)
{
  reset();
  parser = 0;

  if (!_parser)
    return true;

  const HeaderParser *header_parser = _parser->header_parser();
  if (!stream.set_parser(header_parser))
    return false;

  parser = _parser;
  return true;
}

const FrameParser *
ParserFilter::get_parser() const
{
  return parser;
}

size_t
ParserFilter::get_info(char *buf, size_t size) const
{
  char info[2048];
  size_t len = 0;
  
  len += stream.stream_info(info + len, sizeof(info) - len); 
  if (parser)
    len += parser->stream_info(info + len, sizeof(info) - len); 

  if (len + 1 > size) len = size - 1;
  memcpy(buf, info, len + 1);
  buf[len] = 0;
  return len;
}



void
ParserFilter::reset()
{
  NullFilter::reset();

  out_spk = spk_unknown;
  state = state_trans;

  if (parser)
    parser->reset();
  stream.reset();
  sync_helper.reset();
  new_stream = false;
}

bool
ParserFilter::is_ofdd() const
{
  return true;
}

bool
ParserFilter::query_input(Speakers spk) const
{
  if (!parser) 
    return false;
  else if (spk.format == FORMAT_RAWDATA) 
    return true;
  else
    return parser->header_parser()->can_parse(spk.format);
}

bool
ParserFilter::process(const Chunk *_chunk)
{
  assert(is_empty());

  if (!parser)
    return false;

  
  if (_chunk->is_dummy())
    return true;

  
  FILTER_SAFE(receive_chunk(_chunk));
  sync_helper.receive_sync(_chunk, stream.get_buffer_size());
  sync = false;

  switch (state)
  {
  case state_trans:
    if (load_parse_frame())
    {
      out_spk = parser->get_spk();
      state = state_full;
      new_stream = false;
    }
    else if (flushing)
    {
      
      

      
      
      
      
      reset();
    }
    return true;

  case state_empty:
    if (load_parse_frame())
    {
      if (new_stream)
      {
        state = state_format_change;
        new_stream = false;
      }
      else
        state = state_full;
    }
    else if (flushing)
    {
      
      
      state = state_no_frame;
    }
    return true;
  }

  
  assert(false);
  return false;
}

Speakers
ParserFilter::get_output() const
{
  return out_spk;
}

bool
ParserFilter::is_empty() const
{
  return state == state_empty || state == state_trans;
}

bool
ParserFilter::get_chunk(Chunk *_chunk)
{
  assert(!is_empty());

  if (!parser) 
    return false;

  switch (state)
  {
    case state_full:
      send_frame(_chunk);
      state = state_no_frame;
      return true;

    case state_no_frame:
      
      
      
      
      

      if (load_parse_frame())
      {
        if (new_stream)
        {
          
          send_eos(_chunk);
          out_spk = parser->get_spk();
          state = state_full;
          new_stream = false;
        }
        else
        {
          
          send_frame(_chunk);
          state = state_no_frame;
        }
      }
      else 
      {
        if (flushing)
        {
          
          send_eos(_chunk);

          
          
          
          
          reset();
        }
        else
        {
          
          _chunk->set_dummy();
          state = state_empty;
        }
      }

      return true;

    case state_format_change:
      
      _chunk->set_empty(out_spk);
      _chunk->set_eos();

      out_spk = parser->get_spk();
      state = state_full;
      return true;

    default:
      return false;
  }
}

bool
ParserFilter::load_parse_frame()
{
  uint8_t *end = rawdata + size;
  size_t old_data_size = size + stream.get_buffer_size();

  while (stream.load_frame(&rawdata, end))
  {
    new_stream |= stream.is_new_stream();
    Speakers old_parser_spk = parser->get_spk();
    if (parser->parse_frame(stream.get_frame(), stream.get_frame_size()))
    {
      if (old_parser_spk != parser->get_spk())
        new_stream = true;
      size = end - rawdata; 
      sync_helper.drop(old_data_size - size - stream.get_buffer_size());
      return true;
    }
    else
      errors++;
  }

  sync_helper.drop(old_data_size - stream.get_buffer_size());
  size = 0;
  return false;
}

void
ParserFilter::send_frame(Chunk *_chunk)
{
  if (out_spk.is_linear())
    _chunk->set_linear(out_spk, parser->get_samples(), parser->get_nsamples());
  else
    _chunk->set_rawdata(out_spk, parser->get_rawdata(), parser->get_rawsize());

  sync_helper.send_frame_sync(_chunk);
}

void
ParserFilter::send_eos(Chunk *_chunk)
{
  _chunk->set_empty(out_spk);
  _chunk->set_eos(true);

  
  sync_helper.reset(); 
}
