#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif //HAVE_CONFIG_H

#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <glibmm.h>
#include <fileref.h>
#include <taglib.h>
#include <fileref.h>
#include <tfile.h>
#include <tag.h>
#include <mpcfile.h>
#include <apetag.h>
#include <apeitem.h>
#include <apefooter.h>

#include "bmp/types/types-basic.hh"
#include "bmp/types/types-library.hh"
#include "bmp/library-ops.hh"

#include "common/common.hh"

using namespace Bmp;
using namespace TagLib;
using namespace Glib;

extern "C" int  _plugin_has_accessors;
int  _plugin_has_accessors = 1;

extern "C" int  _plugin_version;
int _plugin_version = PLUGIN_VERSION;

extern "C" const char ** _mimetypes ()
{
  static const char * _types[] =
  {
    "application/x-apetag",
    NULL
  };
  return _types;
}

extern "C" bool _set (std::string const& filename, Track & track)
{
  MPC::File opfile (filename.c_str());
  if (!metadata_check_file (&opfile))
    return false;

  APE::Tag * tag = opfile.APETag(true);
  if (tag)
  {
      metadata_set_common (&opfile, track);

      if (track.mb_album_artist)
        tag->addValue ("Album Artist",
                        String (track.mb_album_artist.get(),            String::UTF8));

      if (track.mb_album_artist_id)
        tag->addValue ("MUSICBRAINZ_ALBUMARTISTID",
                        String (track.mb_album_artist_id.get(),         String::UTF8));

      if (track.mb_album_artist_sort_name)
        tag->addValue ("ALBUMARTISTSORT",
                        String (track.mb_album_artist_sort_name.get(),  String::UTF8));

      if (track.mb_track_id)
        tag->addValue ("MUSICBRAINZ_TRACKID",
                        String (track.mb_track_id.get(),                String::UTF8));

      if (track.mb_album_id)
        tag->addValue ("MUSICBRAINZ_ALBUMID",
                        String(track.mb_album_id.get(),                 String::UTF8));

      if (track.mb_artist_id)
        tag->addValue ("MUSICBRAINZ_ARTISTID",
                        String (track.mb_artist_id.get(),               String::UTF8));

      if (track.mb_artist_sort_name)
        tag->addValue ("ARTISTSORT",
                        String (track.mb_artist_sort_name.get(),        String::UTF8));

      if (track.mb_release_date)
        tag->addValue ("Year",
                        String (track.mb_release_date.get(),            String::UTF8));

      if (track.asin)
        tag->addValue ("ASIN",
                        String (track.asin.get(),                       String::UTF8));

      if (track.asin)
        tag->addValue ("MUSICIP_PUID",
                        String (track.asin.get(),                       String::UTF8));

      opfile.save();
      return true;
  }
  else
  {
      return false;
  }
}

extern "C" bool _get (std::string const& filename, DB::Row & row)
{
  struct {
      AttributeId     datum;
      char          * id;
  } mb_metadata_ape[] = {
    { ATTRIBUTE_MB_ALBUM_ARTIST,                "Album Artist"                },
    { ATTRIBUTE_MB_ALBUM_ARTIST_ID,             "MUSICBRAINZ_ALBUMARTISTID"   },
    { ATTRIBUTE_MB_ALBUM_ARTIST_SORTNAME,       "ALBUMARTISTSORT"             }, 
    { ATTRIBUTE_MB_TRACK_ID,                    "MUSICBRAINZ_TRACKID"         },
    { ATTRIBUTE_MB_ALBUM_ID,                    "MUSICBRAINZ_ALBUMID"         },
    { ATTRIBUTE_MB_ARTIST_ID,                   "MUSICBRAINZ_ARTISTID"        },
    { ATTRIBUTE_MB_ARTIST_SORTNAME,             "ARTISTSORT"                  },
    { ATTRIBUTE_MB_RELEASE_DATE,                "Year"                        },
    { ATTRIBUTE_ASIN,                           "ASIN"                        },
    { ATTRIBUTE_MUSICIP_PUID,                   "MUSICIP_PUID"                },
  };


  MPC::File opfile (filename.c_str());
  if (!metadata_check_file (&opfile))
    return false;

  APE::Tag * tag = opfile.APETag();
  if (tag)
  {
      metadata_get_common (&opfile, row);
      TagLib::APE::ItemListMap const& items (tag->itemListMap());
      for (unsigned int n = 0; n < G_N_ELEMENTS (mb_metadata_ape); ++n)
      {
        if (!items[mb_metadata_ape[n].id].isEmpty())
        {
          row.insert (std::make_pair (get_attribute_info(mb_metadata_ape[n].datum).id,
              ustring (items[mb_metadata_ape[n].id].toString().toCString (true))));
        }
      }
      return true;
  }
  else
  {
      return false;
  }
}
