#ifndef PROBE_H
#define PROBE_H

#include "language.h"

#define PROBE_STREAM_LIMIT 64
#define PROBE_CHAPTER_LIMIT 256
#define PROBE_ATTACHMENT_LIMIT 64
#define PROBE_TAG_LIMIT 64

typedef enum {
  SUBTITLE_TEXT,
  SUBTITLE_ASS,
  SUBTITLE_BITMAP,
} SubtitleKind;

enum {
  DISPOSITION_DEFAULT = 1u << 0,
  DISPOSITION_FORCED = 1u << 1,
  DISPOSITION_HEARING_IMPAIRED = 1u << 2,
  DISPOSITION_VISUAL_IMPAIRED = 1u << 3,
  DISPOSITION_COMMENT = 1u << 4,
  DISPOSITION_ORIGINAL = 1u << 5,
  DISPOSITION_DUB = 1u << 6,
  DISPOSITION_LYRICS = 1u << 7,
  DISPOSITION_KARAOKE = 1u << 8,
  DISPOSITION_CLEAN_EFFECTS = 1u << 9,
  DISPOSITION_ATTACHED_PIC = 1u << 10,
  DISPOSITION_TIMED_THUMBNAILS = 1u << 11,
  DISPOSITION_NON_DIEGETIC = 1u << 12,
  DISPOSITION_CAPTIONS = 1u << 13,
  DISPOSITION_DESCRIPTIONS = 1u << 14,
  DISPOSITION_METADATA = 1u << 15,
  DISPOSITION_DEPENDENT = 1u << 16,
  DISPOSITION_STILL_IMAGE = 1u << 17,
  DISPOSITION_MULTILAYER = 1u << 18,
};

typedef struct {
  ValueType type;
  size_t stream_index;
  bool duration_known;
  double duration;
  char codec_name[32];
  SubtitleKind subtitle_kind;
  char language[32];
  char title[128];
  unsigned dispositions;
} ProbeStream;

typedef struct {
  double start;
  double end;
  char title[128];
} ProbeChapter;

typedef struct {
  size_t stream_index;
  char filename[128];
  char mimetype[64];
} ProbeAttachment;

typedef struct {
  char key[64];
  char value[256];
} ProbeTag;

typedef struct {
  bool has_video;
  bool has_audio;
  bool has_subtitles;
  bool video_duration_known;
  bool audio_duration_known;
  double video_duration;
  double audio_duration;
  bool subtitle_duration_known;
  double subtitle_duration;
  ProbeStream streams[PROBE_STREAM_LIMIT];
  size_t stream_count;
  ProbeChapter chapters[PROBE_CHAPTER_LIMIT];
  size_t chapter_count;
  ProbeAttachment attachments[PROBE_ATTACHMENT_LIMIT];
  size_t attachment_count;
  ProbeTag tags[PROBE_TAG_LIMIT];
  size_t tag_count;
} ProbeResult;

typedef bool (*ProbeRunner)(const char* path, ProbeResult* result, void* context, Error* error);

typedef struct ProbeCacheEntry ProbeCacheEntry;

typedef struct {
  Arena arena;
  ProbeCacheEntry* entries;
  ProbeRunner runner;
  void* runner_context;
  size_t invocation_count;
} ProbeCache;

void probe_cache_init(ProbeCache* cache, ProbeRunner runner, void* context);
bool probe_cache_get(ProbeCache* cache, const char* path, ProbeResult* result, Error* error);
void probe_cache_destroy(ProbeCache* cache);
bool probe_run_ffprobe(const char* path, ProbeResult* result, void* context, Error* error);

#endif