#include "euterpe/euterpe_plugin_public.h"
#include "euterpe_gen/ffmpeg_input.h"
#include "euterpe_gen/ffmpeg_tagger.h"
#include "euterpe_gen/ffmpeg_pic.h"

#if defined(_WIN32) && defined(_DEBUG)
#include <vld.h>
#endif

//#define ENABLE_EUTERPE_INPUT_CONSOLE

#include "WDL/wdlcstring.h"

static HINSTANCE ffmpeg_instance;
static HWND ffmpeg_main_hwnd;

double (*GetHardwareSampleRate)();
int (*GetResamplerSinc)();
int (*GetDiskReadMode)();
int (*GetDiskReadBufferSize)();
int (*GetDiskReadBuffers)();

RSE_IFileInput *CreateFromType(const char *type)
{
  if (!strcmp(type, "MP3"))
  {
    return new RSE_FFmpegInput;
  }

  return NULL;
}

RSE_IFileInput *CreateFromFile(const char *filename)
{
  if (!wdl_filename_cmp(WDL_get_fileext(filename), ".mp3") ||
    !wdl_filename_cmp(WDL_get_fileext(filename), ".flac"))
  //if (!wdl_filename_cmp(WDL_get_fileext(filename), ".mp3"))
  {
    RSE_FFmpegInput *p = new RSE_FFmpegInput;

    if (p->Open(filename))
    {
      return p;
    }

    delete p;
  }

  return NULL;
}

struct RSE_AudioInputRegister ffmpeg_reg_struct =
{
  CreateFromType,
  CreateFromFile,
};

RSE_IFileTagger *CreateFFmpegTagger(const char *filename)
{
  if (!wdl_filename_cmp(WDL_get_fileext(filename), ".mp3") ||
    !wdl_filename_cmp(WDL_get_fileext(filename), ".flac"))
  {
    RSE_FFmpegTagger *p = new RSE_FFmpegTagger;

    if (p && p->Open(filename))
    {
      return p;
    }
    else
    {
      delete p;
    }
  }

  return NULL;
}

RSE_FileTaggerRegister tagger_reg =
{
  &CreateFFmpegTagger
};

RSE_IFilePic *CreateFFmpegPic(const char *filename)
{
  if (!wdl_filename_cmp(WDL_get_fileext(filename), ".mp3") ||
    !wdl_filename_cmp(WDL_get_fileext(filename), ".flac"))
  {
    RSE_FFmpegPic *p = new RSE_FFmpegPic();

    if (p->Open(filename))
    {
      return p;
    }
    else
    {
      delete p;
    }
  }

  return NULL;
}

RSE_FilePicRegister apic_reg =
{
  &CreateFFmpegPic
};

void euterpe_ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vargs)
{
  vprintf(fmt, vargs);
}

extern "C"
{
  EUTERPE_PLUGIN_EXPORT int EUTERPE_PLUGIN_ENTRYPOINT(
    EUTERPE_PLUGIN_HINSTANCE instance, RSE_PluginInfo *rec)
  {
#if defined(_WIN32) && defined(_DEBUG) && defined(ENABLE_EUTERPE_INPUT_CONSOLE)
    // The first will use the console only if
    // the application is started by the command 
    // line. The second one will always enable
    // the console.
    //if (AttachConsole(ATTACH_PARENT_PROCESS))
    if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole())
    {
        freopen("CONOUT$", "w", stdout);
        freopen("CONOUT$", "w", stderr);
    }

    // AV_LOG_QUIET
    // AV_LOG_PANIC
    // AV_LOG_FATAL
    // AV_LOG_ERROR
    // AV_LOG_WARNING
    // AV_LOG_INFO
    // AV_LOG_VERBOSE
    // AV_LOG_DEBUG
    av_log_set_level(AV_LOG_ERROR);
    av_log_set_callback(euterpe_ffmpeg_log_callback);
#endif

    ffmpeg_instance = instance;

    if (rec)
    {
      if (rec->caller_version != EUTERPE_PLUGIN_VERSION || !rec->GetFunc)
      {
        return 0;
      }

      *((void **)&GetHardwareSampleRate) = rec->GetFunc("GetHardwareSampleRate");
      *((void **)&GetResamplerSinc) = rec->GetFunc("GetResamplerSinc");
      *((void **)&GetDiskReadMode) = rec->GetFunc("GetDiskReadMode");
      *((void **)&GetDiskReadBufferSize) = rec->GetFunc("GetDiskReadBufferSize");
      *((void **)&GetDiskReadBuffers) = rec->GetFunc("GetDiskReadBuffers");

      ffmpeg_main_hwnd = rec->hwnd_main;

      if (!GetHardwareSampleRate || !GetResamplerSinc || !rec->Register ||
        !GetDiskReadMode || !GetDiskReadBufferSize || !GetDiskReadBuffers)
      {
        return 0;
      }

      rec->Register("pcmsrc", &ffmpeg_reg_struct);
      rec->Register("tagger", &tagger_reg);
      rec->Register("apic", &apic_reg);

      return 1;
    }
    else
    {
      return 0;
    }
  }
}
