/*
 * vcardfactory.cpp - class for caching vCards
 * Copyright (C) 2003  Michail Pishchagin
 *
 * 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include "vcardfactory.h"

#include <qobject.h>
#include <qapplication.h>

#include <qdict.h>
#include <qmap.h>

#include <qdom.h>
#include <qfile.h>
#include <qtextstream.h>

#include "common.h" // jidEncode
#include "profiles.h"

//----------------------------------------------------------------------------
// VCardFactory
//----------------------------------------------------------------------------

class VCardFactoryPrivate : public QObject
{
	Q_OBJECT

private:
	static const uint dictSize;
	static QStringList vcardList;
	static QDict<VCard> *vcardDict;

public slots:
	void taskFinished();

signals:
	void vcardChanged(const Jid&);

public:
	VCardFactoryPrivate();
	~VCardFactoryPrivate();

	static QDict<VCard> *vcards();
	static void checkLimit(QString jid, VCard *vcard);
};

const uint VCardFactoryPrivate::dictSize = 5; // don't cache too many vCards at a time
QDict<VCard> *VCardFactoryPrivate::vcardDict = 0;
QStringList VCardFactoryPrivate::vcardList;

VCardFactoryPrivate::VCardFactoryPrivate()
: QObject(qApp, "VCardFactoryPrivate")
{
	vcardDict = new QDict<VCard>;
	vcardDict->setAutoDelete(true);
}

VCardFactoryPrivate::~VCardFactoryPrivate()
{
	delete vcardDict;
}

QDict<VCard> *VCardFactoryPrivate::vcards()
{
	return vcardDict;
}

void VCardFactoryPrivate::checkLimit(QString jid, VCard *vcard)
{
	if ( vcardList.find(jid) != vcardList.end() ) {
		vcardDict->remove(jid);
		vcardList.remove(jid);
	}
	else if ( vcardList.size() > dictSize ) {
		vcardDict->remove( vcardList.back() );
		vcardList.pop_back();
	}

	vcardDict->insert(jid, vcard);
	vcardList.push_front(jid);
}

void VCardFactoryPrivate::taskFinished()
{
	JT_VCard *task = (JT_VCard *)sender();
	if ( task->success() ) {
		Jid j = task->jid();

		VCard *vcard = new VCard;
		*vcard = task->vcard();
		checkLimit(j.userHost(), vcard);

		// save vCard to disk

		// ensure that there's a vcard directory to save into
		QDir p(pathToProfile(activeProfile));
		QDir v(pathToProfile(activeProfile) + "/vcard");
		if(!v.exists())
			p.mkdir("vcard");

		QFile file ( getVCardDir() + "/" + jidEncode(j.userHost()).lower() + ".xml" );
		file.open ( IO_WriteOnly );
		QTextStream out ( &file );
		out.setEncoding ( QTextStream::UnicodeUTF8 );
		QDomDocument doc;
		doc.appendChild( vcard->toXml ( &doc ) );
		out << doc.toString(4);

		emit vcardChanged(j);
	}
}

static VCardFactoryPrivate *vcardFactoryPrivate = 0;

const VCard *VCardFactory::vcard(const Jid &j)
{
	if ( !vcardFactoryPrivate )
		vcardFactoryPrivate = new VCardFactoryPrivate;

	// first, try to get vCard from runtime cache
	QDict<VCard> *vcards = VCardFactoryPrivate::vcards();
	if ( vcards->find( j.userHost() ) )
		return vcards->find( j.userHost() );

	// then try to load from cache on disk
	QFile file ( getVCardDir() + "/" + jidEncode(j.userHost()).lower() + ".xml" );
	file.open (IO_ReadOnly);
	QDomDocument doc;
	VCard *vcard = new VCard;
	if ( doc.setContent(&file, false) ) {
		vcard->fromXml( doc.documentElement() );
		VCardFactoryPrivate::checkLimit(j.userHost(), vcard);

		return vcard;
	}

	delete vcard;
	return 0;
}

void VCardFactory::setVCard(const Jid &j, const VCard &v)
{
	if ( !vcardFactoryPrivate )
		vcardFactoryPrivate = new VCardFactoryPrivate;

	VCard *vcard = new VCard;
	*vcard = v;
	VCardFactoryPrivate::checkLimit(j.userHost(), vcard);
}

JT_VCard *VCardFactory::getVCard(const Jid &jid, Task *rootTask, const QObject *obj, const char *slot, bool cacheVCard)
{
	if ( !vcardFactoryPrivate )
		vcardFactoryPrivate = new VCardFactoryPrivate;

	JT_VCard *task = new JT_VCard( rootTask );
	if ( cacheVCard )
		task->connect(task, SIGNAL(finished()), vcardFactoryPrivate, SLOT(taskFinished()));
	task->connect(task, SIGNAL(finished()), obj, slot);
	task->get(jid);
	task->go(true);
	return task;
}
	
void VCardFactory::registerVCardChanged(const QObject* obj, const char* slot)
{
	if ( !vcardFactoryPrivate )
		vcardFactoryPrivate = new VCardFactoryPrivate;
	QObject::connect(vcardFactoryPrivate,SIGNAL(vcardChanged(const Jid&)),obj,slot);
}

#include"vcardfactory.moc"

