#ifndef player_h
#define player_h

typedef struct osd_s osd_t;

#include "inttypes.h"
#include "colorspace/ka_colconv.h"
#include "colorspace/ka_drawer.h"
#include "colorspace/ka_screen.h"
#include "scalers/ka_scaleconv.h"
#include "ka_stream.h"
#include "wimp.h"
#include "inteldma.h"
#include "videooverlay.h"

// misc
#define FRAC 16 // number of fractional bits in x_mag, y_mag

// Player status flags
#define player_status_new          0x001
#define player_status_restart      0x002
#define player_status_seek         0x004
#define player_status_act          0x007 // regroup the above ones
#define player_status_readyforplay 0x008 // when display has been setup
#define player_status_redrawframe  0x010 // when frame should be redrawn
#define player_status_plot_isbanner  0x100

// Plotting acceleration modes
typedef enum
{ ACCEL_MODE_NONE
, ACCEL_MODE_INTELDMA
, ACCEL_MODE_GEMINUS
, ACCEL_MODE_VIDEOOVERLAY
} ACCEL_MODE;

// Player play status
typedef enum
{ play_status_play
, play_status_pause
, play_status_advance
, play_status_stop
} play_status;

typedef struct
{
    sprite_header_t* frame;// rgb frame buffer
    int buf_size;          // size of above
    int byte_width;
    int height;
} rgb_savearea;

typedef enum
{ SAVEAREA_PLOTTER = 0 // image rgb version
, SAVEAREA_DESKTOP     // desktop area copy
, SAVEAREA_BANNER      // are where banner is converted to sprite
, SAVEAREA_SPRITE      // sprite save
, SAVEAREA_COUNT
} SAVEAREA;

typedef struct
{
  int x;
  int y;
  int width;
  int height;
} scr_pos_t;

typedef struct
{
  // display frame info
  ka_vframe_t* curr_frame;   // may be null if skipped/corrupted
  ka_vframe_t* prev_frame;   // may be null if skipped/corrupted
  ka_paint_t   paint;        // parameters for colour space conversion, whole picture
  ka_paint_t  paint_sprite;  // parameters for colour space conversion, sprite saving
  ka_drawer_f drawer;        // pointer to colour space conversion function
  ka_drawer_f drawer_sprite; // same for sprite (cf drawer for overlays cannot be used here)
  ka_scale_t  plot;          // parameters for scaler
  scr_pos_t   pos;
  // final picture aspect (after aspect ration and pan & scan)
  struct
  {
    int width;
    int height;
    int x_mag; // zoom to apply to correct picture width aspect
    int y_mag; // zoom to apply to correct picture height aspect
  } aspect;
  // scaling for mouse to frame pixel
  struct
  {
    int x;
    int y;
  } osd_mag;
  rgb_savearea rgb_area[SAVEAREA_COUNT];

  // draw decision
  uint32_t I_pts;
  uint32_t P_pts;
  uint32_t B_pts;
  int I_delta;
  int P_delta;
  int B_delta;
  int frames_late;         // how much behind schedule are we?
  int I_skip;              // bool, wait till next I_frame
  int F_valid;             // bool, forward reference frame decoded
  int B_valid;             // bool, backward reference frame decoded
  struct
  {
    uint32_t section;      // section to which the frame belongs
    uint32_t pts;          // given or calculated frame time stamp
    uint32_t sequence_ref; // index of displayed sequence
    int      picturenr;    // index of displayed frame
    int      frametype;    // frametype displayed: I, P, B
    int      fieldnr;      // field nr to display
    int      fieldtype;    // fieldtype to display
    int      deinterlace;  // deinterlace option
    uint32_t duration;     // duration till next field/frame
    ka_vframe_t frame;     // used when deinterlacin and to retain displayed frame info
    uint32_t    timetonext;// expected remaining time till next draw, i.e. free decoding time
    ka_vinfo_t  vinfo;     // current copy of vinfo
  } draw;

  // stats
  int frame_count;         // nr of frames decoded so far
  int drawn_count;         // minus dropped frames
  int drawn_field_count;
  int I_count;
  int P_count;
  int B_count;
  int I_drawn;
  int P_drawn;
  int B_drawn;
  struct
  {
    uint32_t wait;
    uint32_t sync;
    uint32_t draw;
    uint32_t scale;
  } cputime;
  struct
  {
    uint32_t fps_delta;
    uint32_t fps_last;
    uint32_t wait_last;
  } time;

  // screen info
  ka_screen_t      screen_paint;
  ka_screen_t      screen_plot;
  ka_screen_t      screen_sprite;
  ka_colourspace_t colourspace;
  ka_scaleconv_t   scaleconv;
  int x_mag;
  int y_mag;
  int zoom;
  uint32_t  trans[256];    // Translation table
  uint32_t* ptrans;        // Null if unsused, &trans[0] otherwise
  struct
  {
    uint32_t width;
    uint32_t height;
    uint32_t cols;
  } full_screen;

  // status
  int             status_flags;
  play_status     play;
  int             mode;

  ka_stream_t*    stream;
  osd_t*          osd;
  uint32_t        lastrtc;

  int acceleration_mode;     // 0 No acceleration, 1 IntelDMA, 2 Gemnius. The generell ability
  int acceleration_mode_used;     // 0 No acceleration, 1 IntelDMA, 2 Gemnius. Really used.
  // TM, Iyonix DMA redraw
  intel_dma_t*    idma;
  // VideoOverlay
  int             vo_overlay;
  gvoverlaydesc_t vo_desc;
  uint32_t        vo_aspect;
  uint32_t        vo_mode_index;
  uint32_t        hardware;
  ka_error_t      error_block;
} player_t;

player_t* new_player(uint32_t hardware);
void delete_player(player_t**);

void player_reset(player_t*);
void player_clear(player_t*);
void player_plotFrame(player_t*, const wimp_redraw_t*);
void player_redrawLastFrame(player_t*);

void player_setupDisplay(player_t*);
void player_adaptDisplay(player_t*, int newmode, int reason);
void player_toggleFullScreen(player_t* player);

void player_onNewFrameStarted(player_t*);

typedef enum
{ play_draw_noframe // there was nothing to draw
, play_draw_drawn   // frame/field was drawn
, play_draw_early   // too early to plot frame, you may work some more
, play_draw_early_suspicious // very early, better multi-task once (and possibly resync)
} play_draw;

play_draw player_onFrameToDraw(player_t*, ka_vframe_t* frame);

play_status player_getPlayStatus(const player_t*);
void player_setPlayStatus(player_t*, play_status status);
void player_restartPlay(player_t*, uint32_t state);
void player_seek(player_t*, int val, int range, int relative);

typedef struct
{
  char s[10][256];
} player_infostats_t;

const player_infostats_t* player_buildInfoStats(const player_t* player);

#endif
