// Copyright (c) 2018 Giorgos Vougioukas
//
// The license can be found in the LICENSE file.

#ifndef _THA_FLAC_AUDIO_INPUT_H_
#define _THA_FLAC_AUDIO_INPUT_H_

#if defined(_WIN32)
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <process.h>
#else
#include "WDL/swell/swell.h"
#include "WDL/swell/swell-functions.h"
#endif

extern "C"
{
  #include <FLAC/all.h>
  #include <share/win_utf8_io.h>
  #include <share/windows_unicode_filenames.h>
}

#if defined(__linux__)
#define NO_POSIX_FILEREAD
#include <sys/types.h>
#include <unistd.h>
#endif

#include "thalia/sample_format.h"
#include "thalia/thalia_plugin_public.h"

#include "WDL/wdlstring.h"
#include "WDL/fileread.h"
#include "WDL/filewrite.h"
#include "WDL/queue.h"
#include "WDL/resample.h"
#include "WDL/mutex.h"

class THA_FlacInput : public THA_IFileInput
{
public:
  THA_FlacInput();
  ~THA_FlacInput();

  bool Open(const char *filename);

  const char *GetType() const;

  const char *GetFileName() const;

  int GetChannels() const;

  double GetSampleRate() const;

  double GetLength() const;

  int GetBitsPerSample() const;

  double GetPosition() const;

  void Seek(double time);

  int GetSamples(SAM *buffer, int length);

  bool IsStreaming() const;

  int Extended(int call, void *parm1, void *parm2, void *parm3);

private:
  static FLAC__StreamDecoderReadStatus read_callback(
    const FLAC__StreamDecoder *decoder,
    FLAC__byte buffer[],
    size_t *bytes,
    void *client_data);

  static FLAC__StreamDecoderSeekStatus seek_callback(
    const FLAC__StreamDecoder *decoder,
    FLAC__uint64 absolute_byte_offset,
    void *client_data);

  static FLAC__StreamDecoderTellStatus tell_callback(
    const FLAC__StreamDecoder *decoder,
    FLAC__uint64 *absolute_byte_offset,
    void *client_data);

  static FLAC__StreamDecoderLengthStatus length_callback(
    const FLAC__StreamDecoder *decoder,
    FLAC__uint64 *stream_length,
    void *client_data);

  static FLAC__bool eof_callback(
    const FLAC__StreamDecoder *decoder,
    void *client_data);

  static FLAC__StreamDecoderWriteStatus write_callback(
    const FLAC__StreamDecoder *decoder,
    const FLAC__Frame *frame,
    const FLAC__int32 * const buffer[],
    void *client_data);

  static void metadata_callback(
    const FLAC__StreamDecoder *decoder,
    const FLAC__StreamMetadata *metadata,
    void *client_data);

  static void error_callback(
    const FLAC__StreamDecoder *decoder,
    FLAC__StreamDecoderErrorStatus,
    void *client_data);

  FLAC__StreamDecoder *m_decoder;

  WDL_FileRead *m_file;
  WDL_FastString m_fn;

  int m_channels;
  int m_bitspersample;
  double m_samplerate;
  WDL_INT64 m_totallength;

  WDL_HeapBuf m_buffer;
  WDL_TypedQueue<SAM> m_samples;
  WDL_Resampler m_rs;

  double m_currentpos;

  double m_hwsamplerate;
};

#endif // _THA_FLAC_AUDIO_INPUT_H_
