#include <noatun/playlistsaver.h>
#include <qdom.h>
#include <netaccess.h>
#include <qfile.h>
#include <qtextstream.h>
#include <noatun/app.h>
#include "ksaver.h"
#include <ksimpleconfig.h>
#include <kmimetype.h>
#include <klocale.h>
#include <qregexp.h>
#include <qxml.h>

PlaylistSaver::PlaylistSaver()
{

}

PlaylistSaver::~PlaylistSaver()
{

}

bool PlaylistSaver::save(const KURL &file, int opt)
{
	switch (opt)
	{
	default:
	case 0: case XMLPlaylist:
		return saveXML(file, opt);
	case M3U:
		return saveM3U(file, opt);
	case PLS:
		return savePLS(file, opt);
	}
}

bool PlaylistSaver::load(const KURL &file, int opt)
{
	switch (opt)
	{
	default:
	case 0: case XMLPlaylist:
		return loadXML(file, opt);
	case M3U:
		return loadM3U(file, opt);
	case PLS:
		return loadPLS(file, opt);
	}
}

bool PlaylistSaver::metalist(const KURL &url)
{
	{
		QString end=url.filename().right(3).lower();
		if (end=="mp3") // we want to download streams only
			return false;
		
		
		
		// it's actually a stream!
		if (end!="pls" && end!="m3u" && url.protocol().lower()=="http")
		{
			KMimeType::Ptr mimetype = KMimeType::findByURL(url);
			QString type=mimetype->name();
			if (type!="application/octet-stream")
				return false;
			QMap<QString,QString> map;
			map["playObject"]="Arts::StreamPlayObject";
			map["title"] = i18n("Stream from %1").arg(url.host());
			
			KURL u(url);
			if (!u.hasPath())
				u.setPath("/");
			
			map["stream_"] = map["url"] = u.url();
			
			reset();
			readItem(map);
			return true;
		}
	}
	
	// it is a pls or m3u file by now
	return loadXML(url) || loadPLS(url) || loadM3U(url);
}

bool PlaylistSaver::saveXML(const KURL &file, int )
{
	QString local;
	if (file.isLocalFile())
		local=QFile::encodeName(file.path());
	else
		local=napp->tempSaveName(file.path());

	// QDom is a pain :)
	
	QDomDocument doc("playlist");
	doc.setContent(QString("<!DOCTYPE XMLPlaylist><playlist version=\"1.0\" client=\"noatun\"/>"));
	
	QDomElement docElem=doc.documentElement();
	
	reset();
	PlaylistItem i;
	QStringList props;
	while ((i=writeItem()))
	{
		// write all properties
		props=i.properties();
		QDomElement elem=doc.createElement("item");
		for (QStringList::Iterator pi(props.begin()); pi!=props.end(); ++pi)
		{
			QString val=i.property(*pi);
			elem.setAttribute(*pi, val);
			
			if ((*pi)=="url")
			{
				KURL u(val);
				if (u.isLocalFile())
				{
					elem.setAttribute("local", u.path());
				}
			}
		}
		
		docElem.appendChild(elem);
		props.clear();
	}
	Noatun::KSaver saver(local);
	if (!saver.open())
		return false;
	saver.textStream().setEncoding(QTextStream::UnicodeUTF8);
	saver.textStream() << doc.toString();
	saver.close();

	return true;
}

class Structure : public QXmlDefaultHandler
{
public:
	PlaylistSaver *saver;
	bool fresh;
	
	Structure(PlaylistSaver *s)
		: saver(s), fresh(true)
	{

	}

	bool startElement(
			const QString&, const QString &,
			const QString &name, const QXmlAttributes &a
					 )
	{
		if (fresh)
		{
			if (name=="playlist")
			{
				fresh=false;
				return true;
			}
			else
			{
				return false;
			}
		}

		if (name != "item")
			return true;
		
		QMap<QString,QString> propMap;
	
		for (int i=0; i<a.count(); i++)
		{
			propMap[a.qName(i)] = a.value(i);
		}
		saver->readItem(propMap);

		return true;
	}
};


bool PlaylistSaver::loadXML(const KURL &file, int)
{
	QString dest;
	if(KIO::NetAccess::download(file, dest))
	{
		QFile file(dest);
		if (!file.open(IO_ReadOnly))
			return false;

		reset();

		// QXml is horribly documented
		QXmlInputSource source(&file);
		QXmlSimpleReader reader;
		
		Structure parser(this);
		reader.setContentHandler(&parser);
		reader.parse(source);
		
		return !parser.fresh;
	}
	return false;
}

bool PlaylistSaver::loadM3U(const KURL &file, int)
{
	QString local;
	if(KIO::NetAccess::download(file, local))
	{
		// if it's a PLS, transfer control, again (KIO bug?)
		{
			KSimpleConfig list(local, true);
			list.setGroup("playlist");

			// some stupid Windows lusers like to be case insensitive
			QStringList groups=list.groupList().grep(QRegExp("^playlist$", false));
			if (groups.count())
			{
				KURL l;
				l.setPath(local);
				return loadPLS(l);
			}
		}
		
		QFile saver(local);
		saver.open(IO_ReadOnly);
		QTextStream t(&saver);
		QString filename;
		QMap<QString,QString> prop;
		reset();
		while (!t.eof())
		{
			filename=t.readLine();
			if (filename.length())
			{
				if (filename.find(QRegExp("^[a-zA-Z0-9]+:/"))==0)
				{
					KURL url(filename);
					KMimeType::Ptr mimetype = KMimeType::findByURL(url);
					QString type=mimetype->name();
					if (type != "application/octet-stream")
					{
						prop["url"]=filename;
					}
					else
					{

						QMap<QString,QString> map;
						map["playObject"]="SplayPlayObject";
						map["title"] = i18n("Stream from %1").arg(url.host());

						if (!url.hasPath())
							url.setPath("/");

						map["url"] = url.url();
						map["stream_"]=map["url"];

						readItem(map);
						continue;
					}
				}
				else
				{
					KURL u1;
					// we have to deal with a relative path
					if (filename.find('/'))
					{
						u1.setPath(file.path(0));
						u1.setFileName(filename);
					}
					else
					{
						u1.setPath(filename);
					}
					prop["url"]=u1.url();
				}
				readItem(prop);
			}
		}

		KIO::NetAccess::removeTempFile(local);
	}
	return false;
}

bool PlaylistSaver::saveM3U(const KURL &file, int )
{
	QString local(napp->tempSaveName(file.path()));
	QFile saver(local);
	saver.open(IO_ReadWrite | IO_Truncate);
	QTextStream t(&saver);

	reset();
	PlaylistItem i;
	QStringList props;
	while ((i=writeItem()))
	{
		KURL u(i.property("url"));
		if (u.isLocalFile())
			t<< u.path() << '\n';
		else
			t << u.url() << '\n';
	}

	saver.close();
	KIO::NetAccess::upload(local, file);
	saver.remove();
	return true;
}

static QString findNoCase(const QMap<QString,QString> &map, const QString &key)
{
	for (QMap<QString,QString>::ConstIterator i=map.begin(); i!=map.end(); ++i)
	{
		if (i.key().lower() == key.lower())
			return i.data();
	}

	return 0;
}

bool PlaylistSaver::loadPLS(const KURL &file, int )
{
	QString local;
	if(KIO::NetAccess::download(file, local))
	{
		KSimpleConfig list(local, true);
		list.setGroup("playlist");

		// some stupid Windows lusers like to be case insensitive
		QStringList groups=list.groupList().grep(QRegExp("^playlist$", false));
		if (!groups.count()) return false;

		QMap<QString,QString> group=list.entryMap(groups[0]);

		QString numOfEntries = findNoCase(group, "numberofentries");
		if ( numOfEntries.isEmpty() )
			return false;
		
		reset();

		int nEntries = numOfEntries.toInt();
		for( int entry = 1; entry <= nEntries; ++entry )
		{
			QString str;
			str.sprintf("file%d", entry);
			QString cast=findNoCase(group,str.utf8());
			str.sprintf("title%d", entry);
			QString title=findNoCase(group,str.utf8());

			// assume that everything in a pls is a streamable file
			QMap<QString,QString> map;

			KURL url(cast);
			if (!url.hasPath())
				url.setPath("/");

			map["playObject"]="SplayPlayObject";
			if ( title.isEmpty() )
				map["title"] = i18n("Stream from %1 (port: %2)").arg( url.host() ).arg( url.port() );
			else
				map["title"] = i18n("Stream from %1, (ip: %2, port: %3)").arg( title ).arg( url.host() ).arg(url.port() );

			map["url"] = map["stream_"]= url.url();

			readItem(map);
		}
		return true;
	}
	return false;
}

bool PlaylistSaver::savePLS(const KURL &, int )
{
	return false;
}

void PlaylistSaver::setGroup(const QString &) 
{
}

	
