/*
 * Copyright (C) 2007 Andre Beckedorf <evilJazz _AT_ katastrophos _DOT_ net>
 * 
 * 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 <qapplication.h>
#include <qimage.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qregexp.h>

#include "coverartprovider.h"
#include "qprogressdialog.h"
#include "debug.h"

#include <id3/tag.h>
#include <id3/utils.h>
#include <id3/misc_support.h>
#include <id3/readers.h>
#include <id3/io_helpers.h>

CoverArtProvider::CoverArtProvider(QWidget *owner, const char *name)
	:	QObject(owner, name),
		owner_(owner),
		coverArt_(NULL),
		sourceDirectory_(""),
		currentArtist_(""),
		currentAlbum_(""),
		currentFilename_("")
{
	validExtensionsList_ = QStringList() << "jpeg" << "jpg" << "png" << "bmp" << "tif" << "tiff";
	coverArt_ = new QImage();
}

CoverArtProvider::~CoverArtProvider()
{
	delete coverArt_;
}

void CoverArtProvider::setCoverArtDirectory(const QString &directory)
{
	if (directory != sourceDirectory_)
	{
		sourceDirectory_ = directory;	
		rescan();		
	}
}

void CoverArtProvider::rescan()
{
	coverArtImageFilenames_.clear();
	
	if (!sourceDirectory_.isEmpty() && QDir(sourceDirectory_).exists())
	{	
		QProgressDialog progress(tr("Please wait..."), tr("Cancel"), 0, owner_, "progress", true);
		
		progress.setCaption(tr("Scanning for cover art images..."));
		
		progress.setMinimumDuration(0);
		progress.setFixedWidth(QMIN(qApp->desktop()->width() * 0.9, 640));
		progress.setAutoClose(false);
		progress.setAutoReset(false);
		progress.show();
		qApp->processEvents();
			
		fillFileList(coverArtImageFilenames_, QFileInfo(sourceDirectory_).absFilePath(), true);
		
		progress.hide();
		qApp->processEvents();
	}
}

void CoverArtProvider::fillFileList(QStringList &filelist, const QString &path, const bool subdir)
{
	QDir dir(path);
	if (!dir.exists()) return;
	
	dir.setFilter(QDir::Files | (subdir ? QDir::Dirs : 0));
	dir.setSorting(QDir::Unsorted);

	const QFileInfoList *list = dir.entryInfoList();
	QString fileName;
	QFileInfoListIterator it(*list);
	QFileInfo *info;

	for (; (info = it.current()); ++it)
	{
		if (info->isFile())
		{
			// only add the file, if its extension is known...
			if (validExtension(info->extension(false)))
				filelist.append(info->absFilePath());
		}
		else 
		{
			fileName = info->fileName();
			if (fileName != "." && fileName != "..")
				fillFileList(filelist, info->absFilePath(), subdir);
		}
	}
}

bool CoverArtProvider::loadCover(const QString &artist, const QString &album, const QString &filename)
{
	bool result = true;
	
	/*
	DPRINTF("artist: %s", (const char*)artist.utf8());
	DPRINTF("album: %s", (const char*)album.utf8());
	
	DPRINTF("currentArtist_: %s", (const char*)currentArtist_.utf8());
	DPRINTF("currentAlbum_: %s", (const char*)currentAlbum_.utf8());
	*/
	
	if (artist.isEmpty() || album.isEmpty())
		result = false;
	else if (artist != currentArtist_ || album != currentAlbum_)
	{
		result = false;
		
		// Check if the file is a local MP3 file and try to detect if an image file is attached as ID3 tag
		if (QFileInfo(filename).extension(false).find("mp3", 0, false) != -1)
		{
			ID3_Tag tag(filename.utf8());
			const ID3_Frame* frame = tag.Find(ID3FID_PICTURE);
			
			if (frame && frame->Contains(ID3FN_DATA))
				result = coverArt_->loadFromData(frame->Field(ID3FN_DATA).GetRawBinary(), frame->Field(ID3FN_DATA).Size());
		}
		
		// Check for cover files in the same directory the media file is in...
		if (!result)
		{
			QStringList imageFilenames;
			fillFileList(imageFilenames, QFileInfo(filename).absFilePath(), false);
			
			if (imageFilenames.count() > 0)
			{
				int i = 0;
				while (i < imageFilenames.count() && !result)
				{
					 result = coverArt_->load(imageFilenames[i]);
					 ++i;
				}
			}
		}
		
		//Check for cover files in a separate tree...
		if (!result)
		{
			QString artistMatch = artist.lower();
			QString albumMatch = album.lower();
			
			artistMatch.replace(QRegExp("\\/"), " "); // AC/DC -> AC DC
			albumMatch.replace(QRegExp("\\/"), " ");			

			artistMatch.replace(QRegExp("\\-"), " "); // AC-DC -> AC DC
			albumMatch.replace(QRegExp("\\-"), " ");			
			
			artistMatch.replace(QRegExp("\\_"), " "); // AC_DC -> AC DC
			albumMatch.replace(QRegExp("\\_"), " ");			

			albumMatch.replace(QRegExp("\\(.*\\)"), ""); // remove (Reissue)
			artistMatch.replace(QRegExp("\\(.*\\)"), ""); 
						
			albumMatch.replace(QRegExp("\\[.*\\]"), ""); // remove [Reissue]
			artistMatch.replace(QRegExp("\\[.*\\]"), ""); 
			
			albumMatch.replace(QRegExp("[,.+&/=:#!']"), "");
			artistMatch.replace(QRegExp("[,.+&/=:#!']"), "");
			
			albumMatch = albumMatch.simplifyWhiteSpace();
			artistMatch = artistMatch.simplifyWhiteSpace();
			
			DPRINTF("artist: %s", (const char*)artist.utf8());
			DPRINTF("album: %s", (const char*)album.utf8());
			
			DPRINTF("artistMatch: %s", (const char*)artistMatch.utf8());
			DPRINTF("albumMatch: %s", (const char*)albumMatch.utf8());
						
			QStringList matchedFilenames;
			
			for (QStringList::Iterator it = coverArtImageFilenames_.begin(); it != coverArtImageFilenames_.end(); ++it )
			{
				QString temp = (*it);
				
				temp.replace(QRegExp("\\/"), " ");
				temp.replace(QRegExp("\\-"), " ");
				temp.replace(QRegExp("\\_"), " ");
				temp.replace(QRegExp("[,.+&/=:#!']"), "");
				temp = temp.simplifyWhiteSpace();
								
				//DPRINTF("temp: %s", (const char*)temp.utf8());
				
				if (temp.find(artistMatch, 0, false) > -1 && temp.find(albumMatch, 0, false) > -1)
				{
					DPRINTF("found match: %s", (const char*)(*it).utf8());
					matchedFilenames.append((*it));
				}
			}
			
			int i = 0;
			while (i < matchedFilenames.count() && !result)
			{
				 result = coverArt_->load(matchedFilenames[i]);
				 ++i;
			}
		}
		
		if (result)
		{
			currentArtist_ = artist;
			currentAlbum_ = album;
			currentFilename_ = filename;
		}
		else
		{
			currentArtist_ = "";
			currentAlbum_ = "";
			currentFilename_ = "";
			coverArt_->reset();
		}
	}
	
	return result;
}