#ifndef ka_stack_h
#define ka_stack_h

#include "ka_block.h"
#include "ka_error.h"

#define KA_STACK_FIFO_NUM 16*1024
#define KA_PROGRAM_MAX_VIDEOS    16
#define KA_PROGRAM_MAX_AUDIOS    16
#define KA_PROGRAM_MAX_SUBTITLES 32
#define KA_PROGRAM_MAX_TITLES 100
#define KA_PROGRAM_MAX_CHAPTERS 64 // Note: already found DVD with 0x0158 chapters
#define KA_MAX_PROGRAMS  64
#define KA_MAX_TYP_INFOS 256

#define ps_stack_prop_allowvideo      0x00000001
#define ps_stack_prop_allowaudio      0x00000002
#define ps_stack_prop_notimestamp     0x00000004
#define ps_stack_prop_noseek          0x00000008

#define ka_fifo_status_used           0x00000001
#define ka_fifo_status_pull           0x00000002
#define ka_fifo_status_pulldone       0x00000004
#define ka_fifo_status_codecready     0x00000010
#define ka_fifo_status_outputdone     0x00000020
#define ka_fifo_status_codecdone      0x00000040
#define ka_fifo_status_codecerror     0x00000080

typedef struct
{
  ka_block_id  kid;
  uint32_t     pid;
  uint32_t     count;
  void*        data;
} ka_idinfo_t;

typedef struct
{
  uint32_t     status;
  ka_block_t*  fstart;
  ka_block_t*  fread;
  ka_block_t*  fwrite;
  ka_block_t*  fend;
  uint32_t     size;
  ka_block_t   fifo[];
} ka_fifo_t;

uint32_t ka_fifo_count(const ka_fifo_t*);

typedef struct
{
  char*        name;
  ka_block_id  blockid;
  int          inactive;
} ka_block_info_t;

typedef struct
{
  uint32_t         nr_chapters;
  ka_block_info_t  info;
  ka_block_info_t  chapters[KA_PROGRAM_MAX_CHAPTERS];
} ka_title_t;

typedef struct
{
  ka_idinfo_t  info;
  uint32_t     nr_videos;
  uint32_t     nr_audios;
  uint32_t     nr_subtitles;
  uint32_t     nr_titles;
  ka_block_id  videos[KA_PROGRAM_MAX_VIDEOS];
  ka_block_id  audios[KA_PROGRAM_MAX_AUDIOS];
  ka_block_id  subtitles[KA_PROGRAM_MAX_SUBTITLES];
  ka_title_t   titles[KA_PROGRAM_MAX_TITLES];
} ka_program_t;

typedef struct
{
  uint32_t     properties;
  uint32_t     nr_programs;
  uint32_t     nr_infos;
  uint32_t     nr_vars;
  ka_program_t programs[KA_MAX_PROGRAMS];
  ka_idinfo_t  infos[KA_MAX_TYP_INFOS];
  ka_fifo_t    video;
  ka_block_t   video_blocks[KA_STACK_FIFO_NUM];
  ka_fifo_t    audio;
  ka_block_t   audio_blocks[KA_STACK_FIFO_NUM];
  ka_fifo_t    subtitle;
  ka_block_t   subtitle_blocks[256];
  ka_fifo_t    navigation;
  ka_block_t   navigation_blocks[256];
} ka_stack_t;

ka_stack_t* ka_new_stack(ka_error_t* error_block);
void ka_delete_stack(ka_stack_t**);

void ka_stack_clear(ka_stack_t*);
void ka_stack_reset(ka_stack_t*);
void ka_stack_setProperties(ka_stack_t*, uint32_t datatype);
int ka_stack_isFull(const ka_stack_t*);
int ka_stack_push(ka_stack_t*
                , uint32_t typ  // block type
                , uint32_t section // section id
                , uint32_t scr  // time stamp, source
                , uint32_t dts  // time stamp, decode
                , uint32_t pts  // time stamp, presentation
                , const uint8_t* sod   // start of packet data
                , const uint8_t* eod); // end of packet data

ka_idinfo_t* ka_stack_programInfo(ka_stack_t*, uint32_t prog_id);
ka_idinfo_t* ka_stack_idInfo(ka_stack_t*, uint32_t pid, ka_block_id kid);

#ifdef __CC_NORCROFT
#pragma -v1 // hint to the compiler to check f/s/printf format
#endif
int ka_stack_addTitle(ka_stack_t*, uint32_t pg,  uint32_t id, const char* pformat, ...);
int ka_stack_addChapter(ka_stack_t*, uint32_t pg, uint32_t t, uint32_t id, const char* pformat, ...);
#ifdef __CC_NORCROFT
#pragma -v0 // return to default
#endif
uint32_t ka_stack_getCountForKid(ka_stack_t*, ka_block_id kid);
void ka_stack_programMapId(ka_stack_t*, uint32_t prog_id, ka_block_id id);
void ka_stack_createFallbackProgram(ka_stack_t*);
int ka_stack_idBelongsToProgram(const ka_program_t* pprogram, ka_block_id kid);

#endif
