#ifndef ka_stream_h
#define ka_stream_h

#include "inttypes.h"

#include "audio.h"
#include "audiosaver.h"
#include "ka_error.h"
#include "ka_input.h"
#include "ka_buffer.h"
#include "ka_demux.h"
#include "ka_acodec.h"
#include "ka_vcodec.h"
#include "ka_stack.h"
#include "ka_vinfo.h"
#include "ka_vstream.h"
#include "ka_subtitles.h"

/*
 * Events returned.
 */
typedef enum
{ ka_stream_event_inerror        = -1 // Error, replay should stop.
, ka_stream_event_wait           = 0  // No processing, waiting for some output to be freed.
, ka_stream_event_buffering      = 1  // Processing but nothing special is happening
, ka_stream_event_ready_for_play = 2  // Audio/Video ready, we may start playing
, ka_stream_event_decode_frame   = 3  // Starting to decode a new frame
                                      // the player may want to skip it
                                      // to speed up processing.
, ka_stream_event_end            = 4  // All done, we should stop the replay
, ka_stream_event_discontinuity  = 5  // All done, restart from new position (discontinuity)
} ka_stream_event;

#define ka_state_load_done      0x00000001 // end of input stream is reached
#define ka_state_push_done      0x00000002 // all input data in buffer is stacked
#define ka_state_decode_done    0x00000004 // all input stream processed
#define ka_state_all_done       0x00000008 // all input stream processed, all output done
#define ka_state_inerror        0x00000010 // in error, unrecoverable
#define ka_state_waittime       0x00000020 // possible wait time at end of section
#define ka_state_future_load    0x00000040 // possibly more input from a next section
#define ka_state_inputstarted   0x00002000 // set after first input
#define ka_state_playable       0x00004000 // found at least a program with some supported video/audio
#define ka_state_replaying      0x00008000 // ready_for_play event was sent
#define ka_state_playing_video  0x00010000 // playing video
#define ka_state_playing_audio  0x00020000 // playing audio

#define ka_state_input_done     0x00000003 // no more input data to stack
#define ka_state_clear_mask     0x0003e06f // flags to clean after a clear

typedef struct
{
  const char*     inputname;
  ka_error_t*     pErrorBlock;
  ka_input_t*     input;
  ka_buffer_t*    buf;
  ka_stack_t*     stack;
  uint32_t        state;
  uint32_t        program;
  uint32_t        hardware;
  uint32_t        decodeSection;
  uint32_t        displaySection;
  struct
  {
    const ka_demux_selector* pSelector;
    ka_demux_t*              demuxer;
    ka_vars_t*               vars;
  } demux;
  struct
  {
    ka_vstream_t*       vstream;
    const kav_vcodec_t* pcodec;
    const ka_vparams_t* params;
    uint32_t            channel;
    uint32_t            typ;
    int32_t             waitTime;
    uint32_t            waitTimeStart;
  } video;
  struct
  {
    audio_t*            astream;
    const ka_aparams_t* params;
    uint32_t            channel;
    uint32_t            typ;
    // saver
    audiosaver_t*       saver;
    uint32_t            savertyp;
  } audio;
  struct
  {
    ka_subtitles_t*     sstream;
    uint32_t            channel;
    uint32_t            typ;
  } subtitle;
  struct
  {
    uint32_t    synced_start;
    uint32_t    video_start;
    uint32_t    video_last;
    uint32_t    audio_start;
    uint32_t    audio_last;
    uint32_t    subtitle_start;
    uint32_t    subtitle_last;
    uint32_t    video_last_log;
    uint32_t    audio_last_log;
    uint32_t    subtitle_last_log;
    uint32_t    demux_last_log;
    uint32_t    work_last_log;
    uint32_t    start;
    uint32_t    replay_start;
    uint32_t    restart;
    uint32_t    end;
  } time;
  struct
  {
    uint32_t    io;
    uint32_t    demux;
    uint32_t    video;
    uint32_t    audio;
    uint32_t    subtitles;
  } cputime;
  char format[256];
  char msg[256];
} ka_stream_t;

ka_stream_t* ka_new_stream(ka_error_t* pErrorBlock, const char* inputname, uint32_t hardware, uint32_t program, uint32_t vchannel, uint32_t achannel, uint32_t schannel);
void ka_delete_stream(ka_stream_t**);

int ka_stream_programHasValidStreams(const ka_stream_t*, uint32_t program);

void ka_stream_reset(ka_stream_t*);
int ka_stream_restart(ka_stream_t*);

void ka_stream_getPosInfo(const ka_stream_t*, ka_demux_pos_t* pos);
void ka_stream_getAudioInfo(const ka_stream_t*, int32_t streamId, ka_demux_audio_info_t* pInfo);
void ka_stream_getSubtitleInfo(const ka_stream_t*, int32_t streamId, ka_demux_subtitle_info_t* pInfo);
void ka_stream_getAngleInfo(const ka_stream_t*, ka_demux_angle_info_t* pInfo);

int ka_stream_seek(ka_stream_t*, int64_t jump);
int ka_stream_setChapter(ka_stream_t*, uint32_t title, int32_t chapter);
uint32_t ka_stream_selectProgram(ka_stream_t*, uint32_t program, uint32_t vchannel, uint32_t achannel, uint32_t schannel);
uint32_t ka_stream_selectVideoStream(ka_stream_t*, uint32_t index);
uint32_t ka_stream_selectAudioStream(ka_stream_t*, int32_t index);
uint32_t ka_stream_selectSubtitleStream(ka_stream_t*, int32_t index);
int  ka_stream_setAngle(ka_stream_t*, uint32_t angle);

ka_stream_event ka_stream_process(ka_stream_t*, uint32_t exit_time);
const ka_vinfo_t* ka_stream_getVideoInfo(const ka_stream_t*);
ka_vframe_t* ka_stream_getDecodeFrame(const ka_stream_t*);
void ka_stream_skipDecodeFrame(ka_stream_t*);
void ka_stream_setMonochromeDecode(ka_stream_t* stream, int32_t mono);
ka_vframe_t* ka_stream_getFrame(const ka_stream_t*, uint32_t index);
void ka_stream_releaseFrame(ka_stream_t*, uint32_t index);
uint32_t ka_stream_getRTCStart(const ka_stream_t*);
void ka_stream_logStats(const ka_stream_t*);

const char* ka_stream_getTitleName(ka_stream_t*, uint32_t program, uint32_t title);
const char* ka_stream_getChapterName(ka_stream_t*, uint32_t program, uint32_t title, uint32_t chapter);
ka_stream_event ka_stream_checkSectionChange(ka_stream_t* stream, ka_stream_event event, ka_vframe_t* nextFrame);
int ka_stream_navigate(ka_stream_t*, int key);

#endif
