//
// (C) 2007 DEREZYNSKI Milosz
//

#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 <boost/format.hpp>
#include <boost/algorithm/string.hpp>
static boost::format fsizefmt ("%llu");

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

using namespace Glib;
using namespace TagLib;
using namespace Bmp::DB;
using namespace std;

namespace
{
      using namespace Bmp;

      TagLib::ID3v2::UserTextIdentificationFrame*
      find_utif (TagLib::ID3v2::Tag *tag, TagLib::String const& description)
      {
        TagLib::ID3v2::FrameList l = tag->frameList("TXXX");
        for(TagLib::ID3v2::FrameList::Iterator i = l.begin(); i != l.end(); ++i)
        {
          TagLib::ID3v2::UserTextIdentificationFrame * f (dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame *> (*i));
          if (f && f->description() == description)
            return f;
        }
        return 0;
      }
}

namespace Bmp
{
    void
    metadata_get_id3v2 (TagLib::ID3v2::Tag * tag, Row & row)
    {
      using boost::algorithm::split;
      using boost::algorithm::find_nth;
      using boost::iterator_range;
      using TagLib::ID3v2::FrameList;

      struct {
          AttributeId         datum;
          const std::string   id;
      } mb_metadata_id3v2[] = {
        { ATTRIBUTE_MB_ALBUM_ARTIST_ID,             "MusicBrainz Album Artist Id"   },
        { ATTRIBUTE_MB_ALBUM_ID,                    "MusicBrainz Album Id"          },
        { ATTRIBUTE_MB_ARTIST_ID,                   "MusicBrainz Artist Id"         },
        { ATTRIBUTE_ASIN,                           "ASIN"                          },
        { ATTRIBUTE_MB_ALBUM_ARTIST_SORTNAME,       "ALBUMARTISTSORT"               },
        { ATTRIBUTE_MUSICIP_PUID,                   "MusicIP PUID"                  },
      };

      ID3v2::UserTextIdentificationFrame * frame = 0;
      for (unsigned int n = 0; n < G_N_ELEMENTS (mb_metadata_id3v2); ++n)
      {
        frame = find_utif (tag, String (mb_metadata_id3v2[n].id, String::UTF8));
        if (frame)
        {
          std::string str = frame->toString().toCString (true);
          iterator_range <std::string::iterator> match = find_nth (str, "] ", 0);
          if (!match.empty())
          {
            ustring substr (match.end(), str.end());
            if (!substr.empty())
            {
              g_print("%s=%s\n", mb_metadata_id3v2[n].id.c_str(), substr.c_str());
              row.insert (std::make_pair (get_attribute_info (mb_metadata_id3v2[n].datum).id, substr));
            }
          }
        }
      }


      // MB UFID
      FrameList const& map = tag->frameListMap()["UFID"];
      if (!map.isEmpty())
      {
        for (FrameList::ConstIterator iter = map.begin(); iter != map.end(); ++iter)
        {
          ID3v2::UniqueFileIdentifierFrame *ufid = reinterpret_cast<ID3v2::UniqueFileIdentifierFrame*> (*iter);
          if (ufid->owner() == "http://musicbrainz.org")
          {
            ByteVector vec (ufid->identifier());
            vec.append ('\0');
            g_print("UFID=%s\n", string(vec.data()).c_str()); 
            row.insert (std::make_pair (get_attribute_info (ATTRIBUTE_MB_TRACK_ID).id, string (vec.data())));
            break;
          }
        }
      }

      // TDRC 
      {
        FrameList const& map = tag->frameListMap()["TDRC"];
        if (!map.isEmpty())
        {
          g_print("TDRC=%s", map.front()->toString().toCString (true));
          row.insert (std::make_pair (get_attribute_info (ATTRIBUTE_MB_RELEASE_DATE).id, string (map.front()->toString().toCString (true))));
        }
      }

      // TPE2 (Album Artist) 
      {
        FrameList const& map = tag->frameListMap()["TPE2"];
        if (!map.isEmpty())
        {
          g_print("TPE2=%s", (map.front()->toString().toCString (true)));
          row.insert (std::make_pair (get_attribute_info (ATTRIBUTE_MB_ALBUM_ARTIST).id, string (map.front()->toString().toCString (true))));
        }
      }


      // TSOP/XSOP (Artist Sort Name)
      {
        const char *id3v2frame = 0;

        if (!tag->frameListMap()["XSOP"].isEmpty())
          id3v2frame = "XSOP";
        else if (!tag->frameListMap()["TSOP"].isEmpty())
          id3v2frame = "TSOP";

        if (id3v2frame)
        {
          FrameList const& map = tag->frameListMap()[id3v2frame];
          if (!map.isEmpty())
          {
            g_print("XSOP/TSOP=%s", (map.front()->toString().toCString (true)));
            row.insert (std::make_pair (get_attribute_info (ATTRIBUTE_MB_ARTIST_SORTNAME).id, string (map.front()->toString().toCString (true))));
          }
        }
      }
    }

} // end namespace Bmp
