#ifndef DE265_NAL_PARSER_H
#define DE265_NAL_PARSER_H
#include "libde265/sps.h"
#include "libde265/pps.h"
#include "libde265/nal.h"
#include "libde265/util.h"
#include <vector>
#include <queue>
#define DE265_NAL_FREE_LIST_SIZE 16
#define DE265_SKIPPED_BYTES_INITIAL_SIZE 16
class NAL_unit {
 public:
  NAL_unit();
  ~NAL_unit();
  nal_header header;
  de265_PTS  pts;
  void*      user_data;
  void clear();
  
  LIBDE265_CHECK_RESULT bool resize(int new_size);
  LIBDE265_CHECK_RESULT bool append(const unsigned char* data, int n);
  LIBDE265_CHECK_RESULT bool set_data(const unsigned char* data, int n);
  int size() const { return data_size; }
  void set_size(int s) { data_size=s; }
  unsigned char* data() { return nal_data; }
  const unsigned char* data() const { return nal_data; }
  
  int num_skipped_bytes_before(int byte_position, int headerLength) const;
  int  num_skipped_bytes() const { return skipped_bytes.size(); }
  
  
  void insert_skipped_byte(int pos);
  
  void remove_stuffing_bytes();
 private:
  unsigned char* nal_data;
  int data_size;
  int capacity;
  std::vector<int> skipped_bytes; 
};
class NAL_Parser
{
 public:
  NAL_Parser();
  ~NAL_Parser();
  de265_error push_data(const unsigned char* data, int len,
                        de265_PTS pts, void* user_data = NULL);
  de265_error push_NAL(const unsigned char* data, int len,
                       de265_PTS pts, void* user_data = NULL);
  NAL_unit*   pop_from_NAL_queue();
  de265_error flush_data();
  void        mark_end_of_stream() { end_of_stream=true; }
  void        mark_end_of_frame() { end_of_frame=true; }
  void  remove_pending_input_data();
  int bytes_in_input_queue() const {
    int size = nBytes_in_NAL_queue;
    if (pending_input_NAL) { size += pending_input_NAL->size(); }
    return size;
  }
  int number_of_NAL_units_pending() const {
    int size = NAL_queue.size();
    if (pending_input_NAL) { size++; }
    return size;
  }
  int number_of_complete_NAL_units_pending() const {
    return NAL_queue.size();
  }
  void free_NAL_unit(NAL_unit*);
  int get_NAL_queue_length() const { return NAL_queue.size(); }
  bool is_end_of_stream() const { return end_of_stream; }
  bool is_end_of_frame() const { return end_of_frame; }
 private:
  
  bool end_of_stream; 
  bool end_of_frame;  
  int  input_push_state;
  NAL_unit* pending_input_NAL;
  
  std::queue<NAL_unit*> NAL_queue;  
  int nBytes_in_NAL_queue; 
  void push_to_NAL_queue(NAL_unit*);
  
  std::vector<NAL_unit*> NAL_free_list;  
  LIBDE265_CHECK_RESULT NAL_unit* alloc_NAL_unit(int size);
};
#endif