#include "thalia_wavpack/wavpack_tag.h"
#include "thalia_wavpack/wavpack_entry_point.h"

#include "WDL/win32_utf8.h"

THA_WavPackTag::THA_WavPackTag()
  : m_file(NULL)
  , m_metadata(false, WDL_StringKeyedArray<char *>::freecharptr)
{}

THA_WavPackTag::~THA_WavPackTag()
{
  if (m_wvctx) WavpackCloseFile(m_wvctx);
  if (m_file) delete m_file;
  m_metadata.DeleteAll();
}

bool THA_WavPackTag::Open(const char *filename)
{
  m_fn.Set(filename);

  int rmode, rbufsize, rnbufs;
  THA_GetDiskReadMode(&rmode, &rbufsize, &rnbufs);
  m_file = new WDL_NEW WDL_FileRead(filename, rmode, rbufsize, rnbufs);

  if (!m_file || !m_file->IsOpen())
  {
    return false;
  }

  char error[2048];
  int flags = OPEN_TAGS;
#if _WIN32
  flags |= OPEN_FILE_UTF8;
#endif

  m_sr.can_seek = tha_can_seek;
  m_sr.close = tha_close;
  m_sr.get_length = tha_get_length;
  m_sr.get_pos = tha_get_pos;
  m_sr.push_back_byte = tha_push_back_byte;
  m_sr.read_bytes = tha_read_bytes;
  m_sr.set_pos_abs = tha_set_pos_abs;
  m_sr.set_pos_rel = tha_set_pos_rel;
  m_sr.truncate_here = tha_truncate_here;
  m_sr.write_bytes = tha_write_bytes;

  m_wvctx = WavpackOpenFileInput(m_fn.Get(), error, flags, 0);
  //m_wvctx = WavpackOpenFileInputEx64(&m_sr, m_file, NULL, error, flags, 0);

  if (!m_wvctx) return false;

  int it = WavpackGetNumTagItems(m_wvctx);

  char text[2048];
  int l = WavpackGetTagItem(m_wvctx, "Title", text, sizeof(text));
  if (l) m_metadata.Insert("Title", strdup(text));
  l = WavpackGetTagItem(m_wvctx, "Artist", text, sizeof(text));
  if (l) m_metadata.Insert("Artist", strdup(text));
  l = WavpackGetTagItem(m_wvctx, "Album", text, sizeof(text));
  if (l) m_metadata.Insert("Album", strdup(text));
  l = WavpackGetTagItem(m_wvctx, "Year", text, sizeof(text));
  if (l) m_metadata.Insert("Year", strdup(text));
  l = WavpackGetTagItem(m_wvctx, "Genre", text, sizeof(text));
  if (l) m_metadata.Insert("Genre", strdup(text));
  l = WavpackGetTagItem(m_wvctx, "Comment", text, sizeof(text));
  if (l) m_metadata.Insert("Comment", strdup(text));
  l = WavpackGetTagItem(m_wvctx, "Track", text, sizeof(text));
  if (l) m_metadata.Insert("Track", strdup(text));

  return true;
}

const char *THA_WavPackTag::GetType() const
{
  return "WV";
}

const char *THA_WavPackTag::GetTitle() const
{
  return m_metadata.Get("Title", "");
}

const char *THA_WavPackTag::GetArtist() const
{
  return m_metadata.Get("Artist", "");
}

const char *THA_WavPackTag::GetAlbum() const
{
  return m_metadata.Get("Album", "");
}

const char *THA_WavPackTag::GetGenre() const
{
  return m_metadata.Get("Genre", "");
}

const char *THA_WavPackTag::GetTrack() const
{
  return m_metadata.Get("Track", "");
}

const char *THA_WavPackTag::GetYear() const
{
  return m_metadata.Get("Year", "");
}

const char *THA_WavPackTag::GetComment() const
{
  return m_metadata.Get("Comment", "");
}

WDL_INT64 THA_WavPackTag::GetFileSize() const
{
  return m_file->GetSize();
}

const char *THA_WavPackTag::GetFileName() const
{
  return m_fn.get_filepart();
}

const char *THA_WavPackTag::GetFilePath() const
{
  return m_fn.Get();
}

const char *THA_WavPackTag::GetFileExtension() const
{
  return m_fn.get_fileext();
}

void THA_WavPackTag::SetTitle(const char *val)
{
  m_metadata.Insert("Title", strdup(val));
}

void THA_WavPackTag::SetArtist(const char *val)
{
  m_metadata.Insert("Artist", strdup(val));
}

void THA_WavPackTag::SetAlbum(const char *val)
{
  m_metadata.Insert("Album", strdup(val));
}

void THA_WavPackTag::SetGenre(const char *val)
{
  m_metadata.Insert("Genre", strdup(val));
}

void THA_WavPackTag::SetTrack(const char *val)
{
  m_metadata.Insert("Track", strdup(val));
}

void THA_WavPackTag::SetYear(const char *val)
{
  m_metadata.Insert("Year", strdup(val));
}

void THA_WavPackTag::SetComment(const char *val)
{
  m_metadata.Insert("Comment", strdup(val));
}

bool THA_WavPackTag::Save()
{
  if (m_wvctx)
  {
    if (m_wvctx) { WavpackCloseFile(m_wvctx); m_wvctx = NULL; }
    if (m_file) { delete m_file; m_file = NULL; }

    char error[2048];
    int flags = OPEN_TAGS | OPEN_EDIT_TAGS;
#if _WIN32
    flags |= OPEN_FILE_UTF8;
#endif

    //WDL_FileWrite fw(m_fn.Get());
    //if (!fw.IsOpen())
    //{
    //  return false;
    //}

    //WavpackStreamReader64 sr;
    //sr.can_seek = tha_can_seek;
    //sr.close = tha_close;
    //sr.get_length = tha_get_length;
    //sr.get_pos = tha_get_pos;
    //sr.push_back_byte = tha_push_back_byte;
    //sr.read_bytes = tha_read_bytes;
    //sr.set_pos_abs = tha_set_pos_abs;
    //sr.set_pos_rel = tha_set_pos_rel;
    //sr.truncate_here = tha_truncate_here;
    //sr.write_bytes = tha_write_bytes;

    WavpackContext *wvctx = WavpackOpenFileInput(m_fn.Get(), error, flags, 0);
    //WavpackContext *wvctx = WavpackOpenFileInputEx64(&sr, &fw, NULL, error, flags, 0);
    if (!wvctx) return false;

    for (int i = 0; i < m_metadata.GetSize(); i++)
    {
      const char *key;
      char *val = m_metadata.Enumerate(i, &key);
      if (val)
      {
        WavpackAppendTagItem(wvctx, key, val, (int)strlen(val));
      }
    }

    WavpackWriteTag(wvctx);
    WavpackCloseFile(wvctx);
    return true;
  }

  return false;
}
