// Based on:
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license.

#ifndef _EUTERPE_FFMPEG_GLUE_H_
#define _EUTERPE_FFMPEG_GLUE_H_

#include <stdint.h>
#include <stdlib.h>

#if defined(__linux__)
#include <unistd.h>
#endif

#include "euterpe_gen/ffmpeg_deleters.h"
#include "euterpe_gen/ffmpeg_common.h"
#include "WDL/fileread.h"

extern int (*GetDiskReadMode)();
extern int (*GetDiskReadBufferSize)();
extern int (*GetDiskReadBuffers)();

struct AVFormatContext;
struct AVIOContext;

class RSE_FFmpegURLProtocol
{
public:
  virtual ~RSE_FFmpegURLProtocol()
  {}

  // Read the given amount of bytes into data, returns the
  // number of bytes read if successful, error otherwise.
  virtual int Read(uint8_t *data, int size) = 0;

  // Returns true and the current file position for this file
  // false if the file position could not retrieved.
  virtual bool GetPosition(int64_t *position_out) = 0;

  // Returns true if the file position could be set, false
  // otherwise.
  virtual bool SetPosition(int64_t position) = 0;

  // Returns true and the file size, false if the file size
  // could not be retrieved.
  virtual bool GetSize(int64_t *size_out) = 0;

  // Return true if the protocol is a stream.
  virtual bool IsStreaming() = 0;
};

class RSE_FFmpegFileProtocol : public RSE_FFmpegURLProtocol
{
public:
  explicit RSE_FFmpegFileProtocol(const char *filename)
    : m_file(NULL)
  {
    int readmode = GetDiskReadMode();
    int readbuffer = GetDiskReadBufferSize();
    int readbuffers = GetDiskReadBuffers();
    m_file = new WDL_FileRead(filename, readmode, readbuffer, readbuffers, 0U, 0U);
  }

  ~RSE_FFmpegFileProtocol()
  {
    delete m_file;
  }

  int Read(uint8_t *data, int size)
  {
    return m_file->Read(data, size);
  }

  bool GetPosition(int64_t *position_out)
  {
    *position_out = (int64_t)m_file->GetPosition();

    if (*position_out < 0)
    {
      return false;
    }

    return true;
  }

  bool SetPosition(int64_t position)
  {
    bool zero_for_success = m_file->SetPosition((WDL_INT64)position);

    if (zero_for_success)
    {
      return false;
    }
    else
    {
      return true;
    }
  }

  bool GetSize(int64_t *size_out)
  {
    *size_out = (int64_t)m_file->GetSize();

    if (*size_out <= 0)
    {
      return false;
    }

    return true;
  }

  bool IsStreaming()
  {
    return false;
  }

private:
  WDL_FileRead *m_file;
};

class RSE_FFmpegGlue
{
public:
  explicit RSE_FFmpegGlue(RSE_FFmpegURLProtocol *protocol);
  ~RSE_FFmpegGlue();

  bool OpenContext();

  AVFormatContext *FormatContext()
  {
    return m_format_context;
  }

private:
  bool m_open_called;

  AVFormatContext *m_format_context;
  AVIOContext *m_avio_context;
};

#endif // _EUTERPE_FFMPEG_GLUE_H_
