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

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

#include <fileref.h>
#include <glibmm.h>

// Plugin-specific include
#include <taglib.h>
#include <fileref.h>
#include <tfile.h>
#include <tag.h>

#include <id3v2tag.h>
#include <mpegfile.h>
#include <id3v2framefactory.h>
#include <textidentificationframe.h>
#include <uniquefileidentifierframe.h>

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

#include "id3v2/reader.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-id3",
    "audio/mpeg",
    NULL
  };

  return _types;
}

namespace
{
  // Based on SoundJuicer code, (C) Ross Burton <ross@burtonini.com> 
  void
  add_txxx_tag (TagLib::ID3v2::Tag    * id3v2tag,
                ustring const&    spec_id,
                ustring const&    idstring) 
  {
    using namespace Bmp;
    using namespace TagLib;

    ID3v2::UserTextIdentificationFrame * frame;

    if (idstring.empty())
      return;

    if (spec_id.empty())
      return;

    id3v2tag->removeFrames (spec_id.c_str());
    frame = new ID3v2::UserTextIdentificationFrame (String::UTF8);
    id3v2tag->addFrame (frame);
    frame->setDescription (String (spec_id.c_str(), String::UTF8));
    frame->setText (String (idstring.c_str(), String::UTF8));
  }
}

extern "C" bool _set (std::string const& filename, Track & track)
{
  ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance();
  factory->setDefaultTextEncoding (String::UTF8);

  MPEG::File opfile (filename.c_str(), factory);
  if (!metadata_check_file (&opfile))
    return false;

  opfile.strip ();

  ID3v2::Tag * tag = opfile.ID3v2Tag (true);
  if (!tag)
    return false;

  metadata_set_common (&opfile, track);
   
  ID3v2::TextIdentificationFrame *frame = 0;

  if (track.mb_album_artist)
  {
    frame = new ID3v2::TextIdentificationFrame ("TPE2", String::UTF8);
    frame->setText (String (track.mb_album_artist.get().c_str(), String::UTF8));
    tag->addFrame (frame);
  }

  if (track.mb_album_artist_id)
  {
    add_txxx_tag (tag,
                  "MusicBrainz Album Artist Id", 
                  track.mb_album_artist_id.get());
  }

  if (track.mb_album_id)
  {
    add_txxx_tag (tag,
                  "MusicBrainz Album Id", 
                  track.mb_album_id.get());
  }

  if (track.mb_artist_id)
  {
    add_txxx_tag (tag,
                  "MusicBrainz Artist Id", 
                  track.mb_artist_id.get());
  }

  if (track.mb_album_artist_sort_name)
  {
    add_txxx_tag (tag,
                  "ALBUMARTISTSORT", 
                  track.mb_album_artist_sort_name.get());
  }

  if (track.asin)
  {
    add_txxx_tag (tag,
                  "ASIN", 
                  track.asin.get());
  }

  if (track.puid)
  {
    add_txxx_tag (tag,
                  "MusicIP PUID", 
                  track.puid.get());
  }

  if (track.mb_track_id)
  {
    ID3v2::UniqueFileIdentifierFrame *frame = new ID3v2::UniqueFileIdentifierFrame ("http://musicbrainz.org", track.mb_track_id.get().c_str());
    tag->addFrame (frame);
  }

  if (track.mb_release_date)
  {
    frame = new ID3v2::TextIdentificationFrame ("TDRL", String::UTF8);
    frame->setText (String (track.mb_release_date.get().c_str(), String::UTF8));
    tag->addFrame (frame);

    frame = new ID3v2::TextIdentificationFrame ("TDRC", String::UTF8);
    frame->setText (String (track.mb_release_date.get().c_str(), String::UTF8));
    tag->addFrame (frame);
  }

  if (track.mb_artist_sort_name)
  {
    frame = new ID3v2::TextIdentificationFrame ("TSOP", String::UTF8);
    frame->setText (String (track.mb_artist_sort_name.get().c_str(), String::UTF8));
    tag->addFrame (frame);
  }

  opfile.save (TagLib::MPEG::File::ID3v2);
  return true;
}

extern "C" bool _get (std::string const& filename, DB::Row & row)  
{
  MPEG::File opfile (filename.c_str());
  if (!metadata_check_file (&opfile))
    return false;

  ID3v2::Tag * tag = opfile.ID3v2Tag (false);
  if (tag)
  {
    metadata_get_id3v2 (tag, row);
  }

  row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_TRACK ).id, guint64 (opfile.tag()->track())));
  row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_DATE ).id, guint64 (opfile.tag()->year())));

  std::string value; 

  value = opfile.tag()->artist().to8Bit(true);
  if (!value.empty())
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_ARTIST ).id, value));

  value = opfile.tag()->album().to8Bit(true);
  if (!value.empty())
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_ALBUM ).id, value));

  value = opfile.tag()->genre().to8Bit(true);
  if (!value.empty())
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_GENRE ).id, value));

  value = opfile.tag()->comment().to8Bit(true);
  if (!value.empty())
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_COMMENT ).id, value));

  if (opfile.audioProperties())
  {
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_BITRATE ).id, guint64 (opfile.audioProperties()->bitrate())));
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_SAMPLERATE ).id, guint64 (opfile.audioProperties()->sampleRate())));
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_TIME ).id, guint64 (opfile.audioProperties()->length())));
  }
  else
  {
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_BITRATE ).id, guint64 (0)));
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_SAMPLERATE ).id, guint64 (0)));
      row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_TIME ).id, guint64 (0)));
  }

  row.insert (std::make_pair (get_attribute_info( ATTRIBUTE_TITLE ).id, opfile.tag()->title().to8Bit(true)));

  return true;
}
