/***************************************************************************
 *   Copyright (C) 2005 by Roland Weigert   *
 *   roweigert@t-online.de   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

using namespace std;
#include <iostream>

#include "libid3tag-interface.h"

class ID3_Tag;

using namespace dami;

/*Set new MP3-File, and read the tags in the file if existing
 *put the read ID3V1 in the mediatag v1tag and ID3V2 in v2tag
 *attachedfile is the filename to be read*/
id3libfile::id3libfile(QString attachedfile)
{
  //Init all boolean variables, to make sure they have defined values
  containsV1Tag=FALSE;
  containsV2Tag=FALSE;
  readsuccess=FALSE;
  filename=attachedfile.local8Bit();
  /* Check for the file first, before any further actions, to avoid opening not existing files
   * Calling routine will recognize this over the boolean readsuccess */
  QFileInfo filecheck(filename);
  if (filecheck.exists()&&filecheck.isFile())
    {
      readsuccess=TRUE;
      workingfile.Link(filename.utf8());
    }
  else
    readsuccess=FALSE;
}

void id3libfile::readTags()
{
  if (workingfile.HasV1Tag())
    {
      ID3_Tag bufferfile;
      bufferfile.Link(filename.utf8(),ID3TT_ID3V1);
      getTagContent(bufferfile,&v1tag);
      //Check if the tags are empty before setting them as existing
      if (!v1tag.album.isEmpty()||!v1tag.artist.isEmpty()||!v1tag.title.isEmpty()||!v1tag.genre.isEmpty())
        containsV1Tag=TRUE;
    }
  if (workingfile.HasV2Tag())
    {
      ID3_Tag bufferfile;
      bufferfile.Link(filename.utf8(),ID3TT_ID3V2);
      getTagContent(bufferfile,&v2tag);
      //Check if the tags are empty before setting them as existing
      if (!v2tag.album.isEmpty()||!v2tag.artist.isEmpty()||!v2tag.title.isEmpty()||!v2tag.genre.isEmpty())
        containsV2Tag=TRUE;
    }
}

void id3libfile::readPicture()
{
  ID3_Tag bufferfile;
  bufferfile.Link(filename.local8Bit(),ID3TT_ID3V2);
  v2tag.cdcover=stripPicture(bufferfile);
}

/*save this fileobject, and write tags depending on parameter tagversion
 *tagversion=1 ->write only id3v1tag
 *tagversion=2 ->write only id3v2tag
 *tagversion=3 ->write id3v1tag and id3v2tag
 *return successvalue to see if operation was successfull*/
bool id3libfile::saveFile(int tagversion)
{
  bool success=FALSE;
  //First of all,check if fie still exists
  QFileInfo filecheck(filename);
  if (filecheck.exists()&&filecheck.isFile()&&filecheck.isWritable())
    {
      success=TRUE;
      if (tagversion==1||tagversion==3)
        {
          ID3_Tag bufferfile;
          bufferfile.Link(filename.local8Bit(),ID3TT_ID3V1);
          setTagContentv1(&bufferfile,&v1tag);
          bufferfile.Update(ID3TT_ID3V1);
          bufferfile.Clear();
          if (tagversion==1&&workingfile.HasV2Tag())
            {
              //strip unwanted id3v2-tag
              bufferfile.Link(filename.local8Bit(),ID3TT_ID3V2);
              bufferfile.Strip(ID3TT_ID3V2);
            }
        }
      if (tagversion==2||tagversion==3)
        {
          ID3_Tag bufferfile;
          bufferfile.Link(filename.local8Bit(),ID3TT_ID3V2);
          setTagContentv2(&bufferfile,&v2tag);
          //if we have a picture, write it to file
          if (!v2tag.cdcover.isNull())
            setPicture(&bufferfile,v2tag.cdcover);
          else
            removePicture(&bufferfile);
          bufferfile.Update(ID3TT_ID3V2);
          bufferfile.Clear();
          if (tagversion==2&&workingfile.HasV1Tag())
            {
              //strip unwanted id3v1-tag
              bufferfile.Link(filename.local8Bit(),ID3TT_ID3V1);
              bufferfile.Strip(ID3TT_ID3V1);
            }
        }
    }
  return success;
}

/*set ID3V1tags and ID3V2tags
 *use the values that come in the mediatag song*/
void id3libfile::setTags(mediatag song)
{
  /*write the tags from song into id3v1tag and id3v2tag
   *the entering into the tagid3lib-structure is done when file is saved only*/
  v1tag=song;
  v2tag=song;
}


/************************************************************************
*									*
*		Helperfunctions for libid3tag-usage                     *
*									*
*************************************************************************/

/*Read out the tags from given bufferfile.
 *store the tags into the given mediatag (Id3v1 or Id3v2).*/
void id3libfile::getTagContent(ID3_Tag bufferfile,mediatag *tagtofill)
{
  tagtofill->number=stripText(bufferfile,ID3FID_TRACKNUM).toInt();
  tagtofill->title=stripText(bufferfile,ID3FID_TITLE);
  tagtofill->album=stripText(bufferfile,ID3FID_ALBUM);
  tagtofill->artist=stripText(bufferfile,ID3FID_LEADARTIST);
  tagtofill->year=stripText(bufferfile,ID3FID_YEAR).toInt();
  int genrenumber=-1;//no genre
  QString genrebuffer;
  genrebuffer=stripText(bufferfile,ID3FID_CONTENTTYPE).remove("(");
  genrebuffer=genrebuffer.left(genrebuffer.find(")"));
  bool containsnumbers=TRUE;
  genrenumber=genrebuffer.toInt(&containsnumbers);
  if (containsnumbers)
    tagtofill->genre=genrehelper(genrenumber);
  else
    {
      //try to read genrecomment
      tagtofill->genre=stripText(bufferfile,ID3FID_CONTENTGROUP);
    }

}

/*strip out the text into a qstring from given frame
* return QString::null if the searched frame does not exist*/
QString id3libfile::stripText(ID3_Tag bufferfile,ID3_FrameID frameindex)
{
  QString tagtext;
  ID3_Frame *searchedframe=bufferfile.Find(frameindex);
  if (searchedframe)
    {
      ID3_Field *searchedfield=searchedframe->GetField(ID3FN_TEXT);
      tagtext=QString(searchedfield->GetRawText());
    }
  else
    tagtext=QString::null;
  return tagtext;
}

/*Get the first picture out of tag*/
QPixmap id3libfile::stripPicture(ID3_Tag bufferfile)
{
  const unsigned char *tagdata;
  QPixmap encodedpicture;
  ID3_Frame *searchedframe=bufferfile.Find(ID3FID_PICTURE);
  if (searchedframe)
    {
      ID3_Field *searchedfield=searchedframe->GetField(ID3FN_DATA);
      tagdata=searchedfield->GetRawBinary();
      encodedpicture.loadFromData(tagdata,searchedfield->Size());
    }
  return encodedpicture;
}

/*put text into the given frame
 *Use the text and frame given from the calling function
 *create the frame if it isn't existing already*/
void id3libfile::putText(ID3_Tag *bufferfile,ID3_FrameID frameindex, QString filltext)
{
  ID3_Frame *searchedframe=NULL;
  searchedframe=bufferfile->Find(frameindex);
  if (searchedframe)
    {    //always delete the original frame
      bufferfile->RemoveFrame(searchedframe);
    }
  searchedframe=new ID3_Frame(frameindex);
  bufferfile->AttachFrame(searchedframe);
  ID3_Field *searchedfield=searchedframe->GetField(ID3FN_TEXT);
  if (!filltext.isEmpty())
    searchedfield->Set(filltext);
}

/*Write tags stored in the class into the tags from the opened file
 *
 */
void id3libfile::setTagContentv1(ID3_Tag *bufferfile,mediatag *tagtoput)
{
  putText(bufferfile,ID3FID_TRACKNUM,QString::number(tagtoput->number));
  putText(bufferfile,ID3FID_TITLE,tagtoput->title);
  putText(bufferfile,ID3FID_ALBUM,tagtoput->album);
  putText(bufferfile,ID3FID_LEADARTIST,tagtoput->artist);
  putText(bufferfile,ID3FID_YEAR,QString::number(tagtoput->year));
  //get right genrevalue from our genre-QString
  int genreint=genrehelper(tagtoput->genre);
  if (genreint!=-1)
    {
      QString genre=QString("(%1)").arg(QString::number(genreint));
      putText(bufferfile,ID3FID_CONTENTTYPE,genre);
    }
  else
    {
      //Put an empty genre-frame into file
      putText(bufferfile,ID3FID_CONTENTTYPE,QString::null);
    }
}

void id3libfile::setTagContentv2(ID3_Tag *bufferfile,mediatag *tagtoput)
{
  putText(bufferfile,ID3FID_TRACKNUM,QString::number(tagtoput->number));
  putText(bufferfile,ID3FID_TITLE,tagtoput->title);
  putText(bufferfile,ID3FID_ALBUM,tagtoput->album);
  putText(bufferfile,ID3FID_LEADARTIST,tagtoput->artist);
  putText(bufferfile,ID3FID_YEAR,QString::number(tagtoput->year));
  //get right genrevalue from our genre-QString
  int genreint=genrehelper(tagtoput->genre);
  if (genreint!=-1)
    {
      QString genre=QString("(%1)").arg(QString::number(genreint));
      putText(bufferfile,ID3FID_CONTENTTYPE,genre);
    }
  else
    {
      //Put an empty genre-frame into file
      putText(bufferfile,ID3FID_CONTENTTYPE,QString::null);
      //and write genrecomment instead
      putText(bufferfile,ID3FID_CONTENTGROUP,tagtoput->genre.ascii());
    }
}

/*write picture in Pixmap to the tag as front-cover*/
void id3libfile::setPicture(ID3_Tag *bufferfile,QPixmap cdcover)
{
  bool newframe=FALSE;
  QPixmap encodedpicture;
  ID3_Frame *searchedframe=bufferfile->Find(ID3FID_PICTURE);
  if (!searchedframe)
    {
      newframe=TRUE;
      searchedframe=new ID3_Frame(ID3FID_PICTURE);
    }
  ID3_Field *coverfield=searchedframe->GetField(ID3FN_PICTURETYPE);
  coverfield->Set(FRONT_COVER);
  coverfield=searchedframe->GetField(ID3FN_MIMETYPE);
  coverfield->Set("image/jpeg");
  ID3_Field *picturefield=searchedframe->GetField(ID3FN_DATA);
  QByteArray picturedata;
  QBuffer picturebuffer(picturedata);
  picturebuffer.open( IO_WriteOnly );
  cdcover.save( &picturebuffer,"JPEG" );
  picturebuffer.close();
  size_t picturesize=picturedata.size();
  picturefield->Set((const uchar *)picturedata.data(),picturesize);
  if(newframe)
    bufferfile->AttachFrame(searchedframe);
}

/*write picture in Pixmap to the tag as front-cover*/
void id3libfile::removePicture(ID3_Tag *bufferfile)
{
  ID3_Frame *searchedframe=bufferfile->Find(ID3FID_PICTURE);
  if (searchedframe)
    {
      searchedframe=bufferfile->RemoveFrame(searchedframe);
    }
}
