/*
    Copyright (C) 2004 Teemu Rytilahti <tpr@d5k.net>
    Copyright (C) 2005 George Staikos <staikos@kde.org>

    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of TQt, and distribute the resulting executable,
    without including the source code for TQt in the source distribution.
*/

#include "konqmficon.h"

#include <dcopref.h>
#include <kdebug.h>
#include <kgenericfactory.h>
#include <kiconloader.h>
#include <tdeparts/statusbarextension.h>
#include <kstandarddirs.h>
#include <kstatusbar.h>
#include <kurllabel.h>

#include <tqcursor.h>
#include <tqstylesheet.h>
#include <tqtimer.h>
#include <tqtooltip.h>

typedef KGenericFactory<KonqMFIcon> KonqMFIconFactory;
K_EXPORT_COMPONENT_FACTORY(libmfkonqmficon,
                           KonqMFIconFactory("mfkonqmficon"))

KonqMFIcon::KonqMFIcon(TQObject *parent, const char *name, const TQStringList &)
: KParts::Plugin(parent, name), PluginBase(), m_part(0), m_mfIcon(0), m_statusBarEx(0), m_menu(0) {
	TDEGlobal::locale()->insertCatalogue("mf_konqplugin");

	m_part = dynamic_cast<TDEHTMLPart*>(parent);
	if (!m_part) { 
		kdDebug() << "couldn't get part" << endl;
		return;
	}
	TQTimer::singleShot(0, this, TQ_SLOT(waitPartToLoad()));
}


void KonqMFIcon::waitPartToLoad() {
	connect(m_part, TQ_SIGNAL(completed()), this, TQ_SLOT(addMFIcon()));
	connect(m_part, TQ_SIGNAL(completed(bool)), this, TQ_SLOT(addMFIcon())); // to make pages with metarefresh to work
	connect(m_part, TQ_SIGNAL(started(TDEIO::Job *)), this, TQ_SLOT(removeMFIcon()));
}


KonqMFIcon::~KonqMFIcon() {
	TDEGlobal::locale()->removeCatalogue("mf_konqplugin");
	delete m_menu;
	m_menu = 0L;
}


static TQString textForNode(DOM::Node node) {
	TQString rc;
	DOM::NodeList nl = node.childNodes();
	for (unsigned int i = 0; i < nl.length(); ++i) {
		DOM::Node n = nl.item(i);
		if (n.nodeType() == DOM::Node::TEXT_NODE) {
			rc += n.nodeValue().string();
		}
	}
	// FIXME: entries need to be escaped for vcard/vevent
	return rc.stripWhiteSpace();
}


static TQString extractAddress(DOM::Node node) {
	TQString rc = ";;";
	TQMap<TQString,TQString> entry;
	DOM::NodeList nodes = node.childNodes();
	unsigned int n = nodes.length();
	for (unsigned int i = 0; i < n; ++i) {
		DOM::Node node = nodes.item(i);
		DOM::NamedNodeMap map = node.attributes();
		for (unsigned int j = 0; j < map.length(); ++j) {
			if (map.item(j).nodeName().string() != "class") {
				continue;
			}
			TQString a = map.item(j).nodeValue().string();
			if (a == "street-address") {
				entry["street-address"] = textForNode(node);
			} else if (a == "locality") {
				entry["locality"] = textForNode(node);
			} else if (a == "region") {
				entry["region"] = textForNode(node);
			} else if (a == "postal-code") {
				entry["postal-code"] = textForNode(node);
			}
		}
	}

	rc += entry["street-address"] + ";" + entry["locality"] + ";" + entry["region"] + ";" + entry["postal-code"] + ";" + entry["country"];
	return rc.stripWhiteSpace();
}


void KonqMFIcon::extractCard(DOM::Node node) {
	TQString name, value;
	DOM::NodeList nodes = node.childNodes();
	unsigned int n = nodes.length();
	value += "BEGIN:VCARD\nVERSION:3.0\n";
	for (unsigned int i = 0; i < n; ++i) {
		DOM::Node node = nodes.item(i);
		DOM::NamedNodeMap map = node.attributes();
		for (unsigned int j = 0; j < map.length(); ++j) {
			if (map.item(j).nodeName().string() != "class") {
				continue;
			}
			TQStringList l = TQStringList::split(' ', map.item(j).nodeValue().string());
			for (TQStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
				if (*it == "photo") {
				} else if (*it == "adr") {
					value += "ADR:" + extractAddress(node) + "\n";
				} else if (*it == "tel") {
					value += "TEL;TYPE=VOICE:" + textForNode(node) + "\n";
				} else if (*it == "fn") {
					name = textForNode(node);
					value += "FN:" + name + "\n";
				} else if (*it == "url") {
					DOM::Node at = node.attributes().getNamedItem("href");
					if (!at.isNull()) {
						value += "URL:" + at.nodeValue().string().stripWhiteSpace() + "\n";
					}
				} else if (*it == "email") {
					DOM::Node at = node.attributes().getNamedItem("href");
					if (!at.isNull()) {
						TQString v = at.nodeValue().string();
						if (v.startsWith("mailto:")) {
							v = v.mid(7);
						}
						value += "EMAIL:" + v.stripWhiteSpace() + "\n";
					}
				} else if (*it == "org") {
					value += "ORG:" + textForNode(node) + "\n";
				}
			}
		}
	}

	if (!name.isEmpty()) {
		value += "END:VCARD\n";
		_cards.append(qMakePair(name, value));
	}
}


void KonqMFIcon::extractEvent(DOM::Node node) {
	TQString name, value = "BEGIN:VCALENDAR\nPRODID:-//Konqueror//EN\nVERSION:2.0\nBEGIN:VEVENT\n";
	DOM::NodeList nodes = node.childNodes();
	unsigned int n = nodes.length();
	for (unsigned int i = 0; i < n; ++i) {
		DOM::Node node = nodes.item(i);
		DOM::NamedNodeMap map = node.attributes();
		for (unsigned int j = 0; j < map.length(); ++j) {
			if (map.item(j).nodeName().string() != "class") {
				continue;
			}
			TQStringList l = TQStringList::split(' ', map.item(j).nodeValue().string());
			for (TQStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
				if (*it == "url") {
					DOM::Node at = node.attributes().getNamedItem("href");
					if (!at.isNull()) {
						value += "URL:" + at.nodeValue().string().stripWhiteSpace() + "\n";
					}
				} else if (*it == "dtstart") {
					DOM::Node at = node.attributes().getNamedItem("title");
					if (!at.isNull()) {
						value += "DTSTART:" + at.nodeValue().string().stripWhiteSpace() + "\n";
					}
				} else if (*it == "dtend") {
					DOM::Node at = node.attributes().getNamedItem("title");
					if (!at.isNull()) {
						value += "DTEND:" + at.nodeValue().string().stripWhiteSpace() + "\n";
					}
				} else if (*it == "summary") {
					name = textForNode(node);
					value += "SUMMARY:" + name + "\n";
				} else if (*it == "location") {
					value += "LOCATION:" + textForNode(node) + "\n";
				}
			}
		}
	}

	if (!name.isEmpty()) {
		value += "END:VEVENT\nEND:VCALENDAR\n";
		_events.append(qMakePair(name, value));
	}
}


bool KonqMFIcon::hasMicroFormat(DOM::NodeList nodes) {
	bool ok = false;
	unsigned int n = nodes.length();
	for (unsigned int i = 0; i < n; ++i) {
		DOM::Node node = nodes.item(i);
		DOM::NamedNodeMap map = node.attributes();
		for (unsigned int j = 0; j < map.length(); ++j) {
			if (map.item(j).nodeName().string() != "class") {
				continue;
			}
			if (map.item(j).nodeValue().string() == "vevent") {
				ok = true;
				extractEvent(node);
				break;
			}
			if (map.item(j).nodeValue().string() == "vcard") {
				ok = true;
				extractCard(node);
				break;
			}
		}
		if (hasMicroFormat(node.childNodes())) {
			ok = true;
		}
	}
	return ok;
}


bool KonqMFIcon::mfFound() {
	_events.clear();
	_cards.clear();
	return hasMicroFormat(m_part->document().childNodes());
}


void KonqMFIcon::contextMenu() {
	delete m_menu;
	m_menu = new TDEPopupMenu(m_part->widget());
	m_menu->insertTitle(i18n("Microformats"));
	connect(m_menu, TQ_SIGNAL(activated(int)), this, TQ_SLOT(addMF(int)));
	int id = 0;
	for (TQValueList<TQPair<TQString, TQString> >::ConstIterator it = _events.begin(); it != _events.end(); ++it) {
		m_menu->insertItem(SmallIcon("bookmark_add"), (*it).first, id);
		id++;
	}
	for (TQValueList<TQPair<TQString, TQString> >::ConstIterator it = _cards.begin(); it != _cards.end(); ++it) {
		m_menu->insertItem(SmallIcon("bookmark_add"), (*it).first, id);
		id++;
	}
	m_menu->insertSeparator();
	m_menu->insertItem(SmallIcon("bookmark_add"), i18n("Import All Microformats"), this, TQ_SLOT(addMFs()), 0, 50000 );
	m_menu->popup(TQCursor::pos());
}


void KonqMFIcon::addMFIcon() {
	if (!mfFound() || m_mfIcon) {
		return;
	}

	m_statusBarEx = KParts::StatusBarExtension::childObject(m_part);
	if (!m_statusBarEx) {
		return;
	}

	m_mfIcon = new KURLLabel(m_statusBarEx->statusBar());
	m_mfIcon->setFixedHeight(instance()->iconLoader()->currentSize(TDEIcon::Small));
	m_mfIcon->setSizePolicy(TQSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Fixed));
	m_mfIcon->setUseCursor(false);
	//FIXME hackish
	m_mfIcon->setPixmap(TQPixmap(locate("data", "microformat/pics/microformat.png")));

	TQToolTip::remove(m_mfIcon);
	TQToolTip::add(m_mfIcon, i18n("This site has a microformat entry", "This site has %n microformat entries", _events.count() + _cards.count()));

	m_statusBarEx->addStatusBarItem(m_mfIcon, 0, true);

	connect(m_mfIcon, TQ_SIGNAL(leftClickedURL()), this, TQ_SLOT(contextMenu()));
}


void KonqMFIcon::removeMFIcon() {
	_events.clear();
	_cards.clear();
	if (m_mfIcon) {
		m_statusBarEx->removeStatusBarItem(m_mfIcon);
		delete m_mfIcon;
		m_mfIcon = 0;
	}

	// Close the popup if it's open, otherwise we crash
	delete m_menu;
	m_menu = 0L;
}


void KonqMFIcon::addMF(int id) {
	if (id < int(_events.count())) {
	} else if (id < int(_cards.count())) {
		id -= _cards.count() - 1;
		addVCardViaDCOP(_cards[id].second);
	}
}


void KonqMFIcon::addMFs() {
	int n = _events.count() + _cards.count();
	for (int i = 0; i < n; ++i) {
		addMF(i);
	}
}

#include "konqmficon.moc"
