/***************************************************************************
 *   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.             *
 ***************************************************************************/

#include <iostream>

using namespace std;
#define QStringToTString(s) TagLib::String(s.utf8().data(),TagLib::String::UTF8)
#include "taglib-interface.h"

taglibfile::taglibfile(QString attachedfile)
{
    containsV1Tag=FALSE;
    containsV2Tag=FALSE;
    readsuccess=FALSE;
    bitrate=0;
    workingfile=NULL;
    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=new TagLib::MPEG::File(QFile::encodeName(filename));
        bitrate=workingfile->audioProperties()->bitrate();
        v1tag.songlength=workingfile->audioProperties()->length();
        v2tag.songlength=workingfile->audioProperties()->length();
    }
    else
        readsuccess=FALSE;
}

taglibfile::~taglibfile()
{
    //if workingfile points to valid file, delete it
    if (workingfile)
    {
        delete workingfile;
    }
}

bool taglibfile::saveFile(int tagversion)
{
    bool success=FALSE;
    //First of all,check if file still exists
    QFileInfo filecheck(filename);
    if (filecheck.exists()&&filecheck.isFile()&&filecheck.isWritable())
    {
        success=TRUE;
        if (tagversion==1||tagversion==3)
        {
            setTagContentv1();
            workingfile->save(TagLib::MPEG::File::ID3v1);
            if (tagversion==1&&workingfile->ID3v2Tag())
            {
                //Get rid off the v2-tag, if we don't want to write one
                workingfile->strip(TagLib::MPEG::File::ID3v2,TRUE);
            }
        }
        if (tagversion==2||tagversion==3)
        {
            setTagContentv2();
            //if we have a picture, write it to file
            if (!v2tag.cdcover.isNull())
                setPicture(v2tag.cdcover);
            else
                removePicture();
            workingfile->save(TagLib::MPEG::File::ID3v2);
            if (tagversion==2&&workingfile->ID3v1Tag())
            {
                //Get rid off the v1-tag, if we don't want to write one
                workingfile->strip(TagLib::MPEG::File::ID3v1,TRUE);
            }
        }
    }
    return success;
}

void taglibfile::readTags()
{
    if (workingfile->ID3v1Tag())
    {
        getTagContentv1();
        if (!v1tag.album.isEmpty()||!v1tag.artist.isEmpty()||!v1tag.title.isEmpty()||!v1tag.genre.isEmpty())
            containsV1Tag=TRUE;
    }
    if (workingfile->ID3v2Tag())
    {
        getTagContentv2();
        if (!v2tag.album.isEmpty()||!v2tag.artist.isEmpty()||!v2tag.title.isEmpty()||!v2tag.genre.isEmpty())
            containsV2Tag=TRUE;
    }
    if (containsV1Tag||containsV2Tag)
    {
        //Check if we have something in the genrestrings
        if (v1tag.genre.isEmpty()&&v1tag.genre.isEmpty())
        {
            //read out over a fileref, to keep the old stuff working, we tagged with old k-yamo-version
            TagLib::FileRef genrecheck(QFile::encodeName(filename));
            QString oldgenrevalue=TStringToQString(genrecheck.tag()->genre());
            //set our got value, if we have one
            if (!oldgenrevalue.isEmpty())
            {
                v1tag.genre=oldgenrevalue;
                v2tag.genre=oldgenrevalue;
            }
        }
    }
}

void taglibfile::readPicture()
{
    if (containsV2Tag)
        v2tag.cdcover=stripPicture();
}

void taglibfile::setTags(mediatag song)
{
    /*write the tags from song into id3v1tag and id3v2tag
     *the entering into the taglib-structure is done when file is saved only*/
    v1tag=song;
    v2tag=song;
}

/************************************************************************
*									*
*		Helperfunctions for taglib-usage                     *
*									*
*************************************************************************/

//Read in files v2tag into the internal variable v2tag
void taglibfile::getTagContentv1()
{
    v1tag.number=workingfile->ID3v1Tag()->track();
    v1tag.title=TStringToQString(workingfile->ID3v1Tag()->title());
    v1tag.album=TStringToQString(workingfile->ID3v1Tag()->album());
    v1tag.artist=TStringToQString(workingfile->ID3v1Tag()->artist());
    v1tag.year=workingfile->ID3v1Tag()->year();
    v1tag.genre=TStringToQString(workingfile->ID3v1Tag()->genre());
}

//Read in files v2tag into the internal variable v2tag
void taglibfile::getTagContentv2()
{
    v2tag.number=workingfile->ID3v2Tag()->track();
    v2tag.title=TStringToQString(workingfile->ID3v2Tag()->title());
    v2tag.album=TStringToQString(workingfile->ID3v2Tag()->album());
    v2tag.artist=TStringToQString(workingfile->ID3v2Tag()->artist());
    v2tag.year=workingfile->ID3v2Tag()->year();
    //treat genre special, to get special categories working, that where set using th sam code in id3lib-class
    int genrenumber=-1;//no genre
    QString genrebuffer;
    genrebuffer=stripTextv2("TCON").remove("(");
    genrebuffer=genrebuffer.left(genrebuffer.find(")"));
    bool containsnumbers=TRUE;
    genrenumber=genrebuffer.toInt(&containsnumbers);
    if (genrebuffer.isEmpty())
        containsnumbers=FALSE;
    if (containsnumbers)
        v2tag.genre=genrehelper(genrenumber);
    else
    {
        //try to read genrecomment
        v2tag.genre=stripTextv2("TIT1").local8Bit();
    }
}

//For reading of special strings in id3v2tags
QString taglibfile::stripTextv2(QString frameindex)
{
    QString tagtext;
    TagLib::ID3v2::FrameList searchedframe=workingfile->ID3v2Tag()->frameListMap()[frameindex.ascii()];
    if (!searchedframe.isEmpty())
    {
        tagtext=QString::fromUtf8(TStringToQString(searchedframe.front()->toString()));
    }
    return tagtext;
}

using namespace TagLib;
QPixmap taglibfile::stripPicture()
{
    QPixmap encodedpicture=NULL;
    TagLib::ID3v2::AttachedPictureFrame *pictureframe=NULL;
    TagLib::ID3v2::FrameList searchedframe=workingfile->ID3v2Tag()->frameListMap()["APIC"];
    bool foundpicture=FALSE;
    if (!searchedframe.isEmpty())
    {
        //we are only interested in media-picture. Ignore all others
        TagLib::ID3v2::FrameList::ConstIterator frameindex=searchedframe.begin();
        while(frameindex!=searchedframe.end()&&!foundpicture)
        {
            pictureframe=static_cast<TagLib::ID3v2::AttachedPictureFrame *>(searchedframe.front());
            if(pictureframe->type()==TagLib::ID3v2::AttachedPictureFrame::FrontCover)
            {
                foundpicture=TRUE;
            }
            ++frameindex;
        }
    }
    if (foundpicture)
    {
        //We have a picture,so use it
        ByteVector datavector=pictureframe->picture();
        //copy data into our QPixmap
        encodedpicture.loadFromData((const unsigned char*)pictureframe->picture().data(),pictureframe->size());
    }
    return encodedpicture;
}

void taglibfile::setPicture(QPixmap picturetoencode)
{
    bool newframe=FALSE;
    TagLib::ID3v2::AttachedPictureFrame *pictureframe=NULL;
    TagLib::ID3v2::FrameList searchedframe=workingfile->ID3v2Tag()->frameListMap()["APIC"];
    if (!searchedframe.isEmpty())
    {
        TagLib::ID3v2::FrameList::ConstIterator frameindex=searchedframe.begin();
        while(frameindex!=searchedframe.end())
        {
            pictureframe=static_cast<TagLib::ID3v2::AttachedPictureFrame *>(searchedframe.front());
            if(pictureframe->type()==TagLib::ID3v2::AttachedPictureFrame::FrontCover)
                break;
            ++frameindex;
        }
    }
    else
    {
        newframe=TRUE;
        pictureframe=new TagLib::ID3v2::AttachedPictureFrame;
    }
    QByteArray picturedata;
    QBuffer buffer(picturedata);
    buffer.open(IO_WriteOnly);
    picturetoencode.save(&buffer,"JPEG");
    buffer.close();
    pictureframe->setMimeType("image/jpeg");
    pictureframe->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
    pictureframe->setPicture(TagLib::ByteVector(picturedata,picturedata.size()));
    if (newframe)
        workingfile->ID3v2Tag()->addFrame(pictureframe);
}

void taglibfile::removePicture()
{
    TagLib::ID3v2::AttachedPictureFrame *pictureframe=NULL;
    TagLib::ID3v2::FrameList searchedframe=workingfile->ID3v2Tag()->frameListMap()["APIC"];
    if (!searchedframe.isEmpty())
    {
        //walk through all pictures and delete the front-cover only
        workingfile->ID3v2Tag()->removeFrame(searchedframe.front());
    }
}

void taglibfile::putText(QString frameindex,QString text)
{
    TagLib::ID3v2::FrameList searchedframe=workingfile->ID3v2Tag()->frameListMap()[frameindex.ascii()];
    if (!searchedframe.isEmpty())
    {
        searchedframe.front()->setText(QStringToTString(text));
    }
    else
    {
        const TagLib::ByteVector test(frameindex);
        TagLib::ID3v2::TextIdentificationFrame *newframe=new TagLib::ID3v2::TextIdentificationFrame(test,TagLib::String::UTF8);
        newframe->setText(QStringToTString(text));
        workingfile->ID3v2Tag()->addFrame(newframe);
    }
}

void taglibfile::setTagContentv1()
{
    TagLib::ID3v1::Tag *tagtoset=NULL;
    //Do the genre first, cause we have to strip the flags maybe,to get rid of not wanted genre
    int genreint=genrehelper(v1tag.genre);
    if (genreint!=-1)
    {
        tagtoset=workingfile->ID3v1Tag(TRUE);
        tagtoset->setGenre((QStringToTString(v1tag.genre)));
    }
    else
    {
        //Strip all v1tags, to get rid of the genre, cause we want to use TIT1-Frame
        workingfile->strip(TagLib::MPEG::File::ID3v1);
        workingfile->save(TagLib::MPEG::File::ID3v1);
        delete workingfile;
        workingfile=new TagLib::MPEG::File(QFile::encodeName(filename).data());
        tagtoset=workingfile->ID3v1Tag(TRUE);
        tagtoset->setGenre((QStringToTString(v1tag.genre)));
    }
    tagtoset->setTrack(v1tag.number);
    tagtoset->setTitle((QStringToTString(v1tag.title)));
    tagtoset->setAlbum((QStringToTString(v1tag.album)));
    tagtoset->setArtist((QStringToTString(v1tag.artist)));
    tagtoset->setYear(v1tag.year);
}

void taglibfile::setTagContentv2()
{
    TagLib::ID3v2::FrameFactory::instance()->setDefaultTextEncoding(TagLib::String::UTF8);
    //Check if Textidentificationframe already exists, and create it, if not
    TagLib::ID3v2::Tag *tagtoset=workingfile->ID3v2Tag(TRUE);
    tagtoset->setTrack(v2tag.number);
    tagtoset->setTitle((QStringToTString(v2tag.title)));
    tagtoset->setAlbum((QStringToTString(v2tag.album)));
    tagtoset->setArtist((QStringToTString(v2tag.artist)));
    tagtoset->setYear(v2tag.year);
    int genreint=genrehelper(v2tag.genre);
    if (genreint!=-1)
    {
        tagtoset->setGenre((QStringToTString(v2tag.genre)));
    }
    else
    {
        //remove any category in normal genre-frame, and set our new genre into TIT1-frame
        putText("TCON","");
        putText("TIT1",v2tag.genre);
    }
}


