/***************************************************************************
 *   Copyright (C) 2003 by Sébastien Laoût                                 *
 *   slaout@linux62.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.             *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "htmlexporter.h"
#include "bnpview.h"
#include "basketlistview.h"
#include "basket.h"
#include "note.h"
#include "tools.h"
#include "tag.h"

#include <tdeapplication.h>
#include <tdeglobal.h>
#include <tdeconfig.h>
#include <kiconloader.h>
#include <tdefiledialog.h>
#include <tdemessagebox.h>
#include <tqdir.h>
#include <tqfile.h>
#include <tqpainter.h>
#include <tdeglobalsettings.h>
#include <kprogress.h>

HTMLExporter::HTMLExporter(Basket *basket)
{
	TQDir dir;

	// Compute a default file name & path:
	TDEConfig *config = TDEGlobal::config();
	config->setGroup("Export to HTML");
	TQString folder = config->readEntry("lastFolder", TQDir::homeDirPath()) + "/";
	TQString url = folder + TQString(basket->basketName()).replace("/", "_") + ".html";

	// Ask a file name & path to the user:
	TQString filter = "*.html *.htm|" + i18n("HTML Documents") + "\n*|" + i18n("All Files");
	TQString destination = url;
	for (bool askAgain = true; askAgain; ) {
		// Ask:
		destination = KFileDialog::getSaveFileName(destination, filter, 0, i18n("Export to HTML"));
		// User canceled?
		if (destination.isEmpty())
			return;
		// File already existing? Ask for overriding:
		if (dir.exists(destination)) {
			int result = KMessageBox::questionYesNoCancel(
				0,
				"<qt>" + i18n("The file <b>%1</b> already exists. Do you really want to override it?")
					.arg(KURL(destination).fileName()),
				i18n("Override File?"),
				KGuiItem(i18n("&Override"), "document-save")
			);
			if (result == KMessageBox::Cancel)
				return;
			else if (result == KMessageBox::Yes)
				askAgain = false;
		} else
			askAgain = false;
	}

	// Create the progress dialog that will always be shown during the export:
	KProgressDialog dialog(0, 0, i18n("Export to HTML"), i18n("Exporting to HTML. Please wait..."), /*Not modal, for password dialogs!*/false);
	dialog.showCancelButton(false);
	dialog.setAutoClose(true);
	dialog.show();
	progress = dialog.progressBar();

	// Remember the last folder used for HTML exporation:
	config->writeEntry("lastFolder", KURL(destination).directory());
	config->sync();

	prepareExport(basket, destination);
	exportBasket(basket, /*isSubBasket*/false);

	progress->advance(1); // Finishing finished
}

HTMLExporter::~HTMLExporter()
{
}

void HTMLExporter::prepareExport(Basket *basket, const TQString &fullPath)
{
	progress->setTotalSteps(/*Preparation:*/1 + /*Finishing:*/1 + /*Basket:*/1 + /*SubBaskets:*/Global::bnpView->basketCount(Global::bnpView->listViewItemForBasket(basket)));
	progress->setValue(0);
	kapp->processEvents();

	// Remember the file path choosen by the user:
	filePath = fullPath;
	fileName = KURL(fullPath).fileName();
	exportedBasket = basket;

	BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
	withBasketTree = (item->firstChild() != 0);

	// Create and empty the files folder:
	TQString filesFolderPath = i18n("HTML export folder (files)", "%1_files").arg(filePath) + "/"; // eg.: "/home/seb/foo.html_files/"
	Tools::deleteRecursively(filesFolderPath);
	TQDir dir;
	dir.mkdir(filesFolderPath);

	// Create sub-folders:
	iconsFolderPath   = filesFolderPath + i18n("HTML export folder (icons)",   "icons")   + "/"; // eg.: "/home/seb/foo.html_files/icons/"
	imagesFolderPath  = filesFolderPath + i18n("HTML export folder (images)",  "images")  + "/"; // eg.: "/home/seb/foo.html_files/images/"
	basketsFolderPath = filesFolderPath + i18n("HTML export folder (baskets)", "baskets") + "/"; // eg.: "/home/seb/foo.html_files/baskets/"
	dir.mkdir(iconsFolderPath);
	dir.mkdir(imagesFolderPath);
	dir.mkdir(basketsFolderPath);

	progress->advance(1); // Preparation finished
}

#include <iostream>

void HTMLExporter::exportBasket(Basket *basket, bool isSubBasket)
{
	if (!basket->isLoaded()) {
		basket->load();
	}

	// Compute the absolute & relative paths for this basket:
	filesFolderPath   = i18n("HTML export folder (files)", "%1_files").arg(filePath) + "/";
	if (isSubBasket) {
		basketFilePath    = basketsFolderPath + basket->folderName().left(basket->folderName().length() - 1) + ".html";
		filesFolderName   = "../";
		dataFolderName    = basket->folderName().left(basket->folderName().length() - 1) + "-" + i18n("HTML export folder (data)", "data") + "/";
		dataFolderPath    = basketsFolderPath + dataFolderName;
		basketsFolderName = "";
	} else {
		basketFilePath    = filePath;
		filesFolderName   = i18n("HTML export folder (files)", "%1_files").arg(KURL(filePath).fileName()) + "/";
		dataFolderName    = filesFolderName + i18n("HTML export folder (data)",    "data")  + "/";
		dataFolderPath    = filesFolderPath + i18n("HTML export folder (data)",    "data")  + "/";
		basketsFolderName = filesFolderName + i18n("HTML export folder (baskets)", "baskets")  + "/";
	}
	iconsFolderName   = (isSubBasket ? "../" : filesFolderName) + i18n("HTML export folder (icons)",   "icons")   + "/"; // eg.: "foo.html_files/icons/"   or "../icons/"
	imagesFolderName  = (isSubBasket ? "../" : filesFolderName) + i18n("HTML export folder (images)",  "images")  + "/"; // eg.: "foo.html_files/images/"  or "../images/"

	std::cout << "Exporting ================================================" << std::endl;
	std::cout << "  filePath:" << filePath.local8Bit() << std::endl;
	std::cout << "  basketFilePath:" << basketFilePath.local8Bit() << std::endl;
	std::cout << "  filesFolderPath:" << filesFolderPath.local8Bit() << std::endl;
	std::cout << "  filesFolderName:" << filesFolderName.local8Bit() << std::endl;
	std::cout << "  iconsFolderPath:" << iconsFolderPath.local8Bit() << std::endl;
	std::cout << "  iconsFolderName:" << iconsFolderName.local8Bit() << std::endl;
	std::cout << "  imagesFolderPath:" << imagesFolderPath.local8Bit() << std::endl;
	std::cout << "  imagesFolderName:" << imagesFolderName.local8Bit() << std::endl;
	std::cout << "  dataFolderPath:" << dataFolderPath.local8Bit() << std::endl;
	std::cout << "  dataFolderName:" << dataFolderName.local8Bit() << std::endl;
	std::cout << "  basketsFolderPath:" << basketsFolderPath.local8Bit() << std::endl;
	std::cout << "  basketsFolderName:" << basketsFolderName.local8Bit() << std::endl;

	// Create the data folder for this basket:
	TQDir dir;
	dir.mkdir(dataFolderPath);

	backgroundColorName = TQString(basket->backgroundColor().name()).lower().mid(1);

	// Generate basket icons:
	TQString basketIcon16 = iconsFolderName + copyIcon(basket->icon(), 16);
	TQString basketIcon32 = iconsFolderName + copyIcon(basket->icon(), 32);

	// Generate the [+] image for groups:
	TQPixmap expandGroup(Note::EXPANDER_WIDTH, Note::EXPANDER_HEIGHT);
	expandGroup.fill(basket->backgroundColor());
	TQPainter painter(&expandGroup);
	Note::drawExpander(&painter, 0, 0, basket->backgroundColor(), /*expand=*/true, basket);
	painter.end();
	expandGroup.save(imagesFolderPath + "expand_group_" + backgroundColorName + ".png", "PNG");

	// Generate the [-] image for groups:
	TQPixmap foldGroup(Note::EXPANDER_WIDTH, Note::EXPANDER_HEIGHT);
	foldGroup.fill(basket->backgroundColor());
	painter.begin(&foldGroup);
	Note::drawExpander(&painter, 0, 0, basket->backgroundColor(), /*expand=*/false, basket);
	painter.end();
	foldGroup.save(imagesFolderPath + "fold_group_" + backgroundColorName + ".png", "PNG");

	// Open the file to write:
	TQFile file(basketFilePath);
	if (!file.open(IO_WriteOnly))
		return;
	stream.setDevice(&file);
	stream.setEncoding(TQTextStream::UnicodeUTF8);

	// Compute the colors to draw dragient for notes:
	TQColor topBgColor;
	TQColor bottomBgColor;
	Note::getGradientColors(basket->backgroundColor(), &topBgColor, &bottomBgColor);
	// Compute the gradient image for notes:
	TQString gradientImageFileName = Basket::saveGradientBackground(basket->backgroundColor(), basket->TQScrollView::font(), imagesFolderPath);

	// Output the header:
	TQString borderColor = Tools::mixColor(basket->backgroundColor(), basket->textColor()).name();
	stream <<
		"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
		"<html>\n"
		" <head>\n"
		"  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"
		"  <meta name=\"Generator\" content=\"" << kapp->aboutData()->programName() << " " << VERSION << "\">\n"
		"  <style type=\"text/css\">\n"
//		"   @media print {\n"
//		"    span.printable { display: inline; }\n"
//		"   }\n"
		"   body { margin: 10px; font: 11px sans-serif; }\n" // TODO: Use user font
		"   h1 { text-align: center; }\n"
		"   img { border: none; vertical-align: middle; }\n";
	if (withBasketTree) {
		stream <<
			"   .tree { margin: 0; padding: 1px 0 1px 1px; width: 150px; _width: 149px; overflow: hidden; float: left; }\n"
			"   .tree ul { margin: 0 0 0 10px; padding: 0; }\n"
			"   .tree li { padding: 0; margin: 0; list-style: none; }\n"
			"   .tree a { display: block; padding: 1px; height: 16px; text-decoration: none;\n"
			"             white-space: nowrap; word-wrap: normal; text-wrap: suppress; color: black; }\n"
			"   .tree span { -moz-border-radius: 6px; display: block; float: left;\n"
			"                line-height: 16px; height: 16px; vertical-align: middle; padding: 0 1px; }\n"
			"   .tree img { vertical-align: top; padding-right: 1px; }\n"
			"   .tree .current { background-color: " << TDEGlobalSettings::highlightColor().name() << "; "
			                    "-moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; color: " << TDEGlobalSettings::highlightedTextColor().name() << "; }\n"
			"   .basketSurrounder { margin-left: 152px; _margin: 0; _float: right; }\n";
	}
	stream <<
		"   .basket { background-color: " << basket->backgroundColor().name() << "; border: solid " << borderColor << " 1px; "
		             "font: " << Tools::cssFontDefinition(basket->TQScrollView::font()) << "; color: " << basket->textColor().name() << "; padding: 1px; width: 100%; }\n"
		"   table.basket { border-collapse: collapse; }\n"
		"   .basket * { padding: 0; margin: 0; }\n"
		"   .basket table { width: 100%; border-spacing: 0; _border-collapse: collapse; }\n"
		"   .column { vertical-align: top; }\n"
		"   .columnHandle { width: " << Note::RESIZER_WIDTH << "px; background: transparent url('" << imagesFolderName << "column_handle_" << backgroundColorName << ".png') repeat-y; }\n"
		"   .group { margin: 0; padding: 0; border-collapse: collapse; width: 100% }\n"
		"   .groupHandle { margin: 0; width: " << Note::GROUP_WIDTH << "px; text-align: center; }\n"
		"   .note { padding: 1px 2px; background: " << bottomBgColor.name() << " url('" << imagesFolderName << gradientImageFileName << "')"
		          " repeat-x; border-top: solid " << topBgColor.name() <<
		          " 1px; border-bottom: solid " << Tools::mixColor(topBgColor, bottomBgColor).name() <<
		          " 1px; width: 100%; }\n"
		"   .tags { width: 1px; white-space: nowrap; }\n"
		"   .tags img { padding-right: 2px; }\n"
		<< LinkLook::soundLook->toCSS("sound", basket->textColor())
		<< LinkLook::fileLook->toCSS("file", basket->textColor())
		<< LinkLook::localLinkLook->toCSS("local", basket->textColor())
		<< LinkLook::networkLinkLook->toCSS("network", basket->textColor())
		<< LinkLook::launcherLook->toCSS("launcher", basket->textColor())
		<<
		"   .unknown { margin: 1px 2px; border: 1px solid " << borderColor << "; -moz-border-radius: 4px; }\n";
	TQValueList<State*> states = basket->usedStates();
	TQString statesCss;
	for (State::List::Iterator it = states.begin(); it != states.end(); ++it)
		statesCss += (*it)->toCSS(imagesFolderPath, imagesFolderName, basket->TQScrollView::font());
	stream <<
		statesCss <<
		"   .credits { text-align: right; margin: 3px 0 0 0; _margin-top: -17px; font-size: 80%; color: " << borderColor << "; }\n"
		"  </style>\n"
		"  <title>" << Tools::textToHTMLWithoutP(basket->basketName()) << "</title>\n"
		"  <link rel=\"shortcut icon\" type=\"image/png\" href=\"" << basketIcon16 << "\">\n";
	// Create the column handle image:
	TQPixmap columnHandle(Note::RESIZER_WIDTH, 50);
	painter.begin(&columnHandle);
	Note::drawInactiveResizer(&painter, 0, 0, columnHandle.height(), basket->backgroundColor(), /*column=*/true);
	painter.end();
	columnHandle.save(imagesFolderPath + "column_handle_" + backgroundColorName + ".png", "PNG");

	stream <<
		" </head>\n"
		" <body>\n"
		"  <h1><img src=\"" << basketIcon32 << "\" width=\"32\" height=\"32\" alt=\"\"> " << Tools::textToHTMLWithoutP(basket->basketName()) << "</h1>\n";

	if (withBasketTree)
		writeBasketTree(basket);

	// If filtering, only export filtered notes, inform to the user:
	// TODO: Filtering tags too!!
	// TODO: Make sure only filtered notes are exported!
//	if (decoration()->filterData().isFiltering)
//		stream <<
//			"  <p>" << i18n("Notes matching the filter &quot;%1&quot;:").arg(Tools::textToHTMLWithoutP(decoration()->filterData().string)) << "</p>\n";

	stream <<
		"  <div class=\"basketSurrounder\">\n";

	if (basket->isColumnsLayout())
		stream <<
			"   <table class=\"basket\">\n"
			"    <tr>\n";
	else
		stream <<
			"   <div class=\"basket\" style=\"position: relative; height: " << basket->contentsHeight() << "px; width: " << basket->contentsWidth() << "px; min-width: 100%;\">\n";

	for (Note *note = basket->firstNote(); note; note = note->next())
		exportNote(note, /*indent=*/(basket->isFreeLayout() ? 4 : 5));

	// Output the footer:
	if (basket->isColumnsLayout())
		stream <<
			"    </tr>\n"
			"   </table>\n";
	else
		stream <<
			"   </div>\n";
	stream << TQString(
		"  </div>\n"
		"  <p class=\"credits\">%1</p>\n").arg(
			i18n("Made with %1, a TDE tool to take notes and keep information at hand.")
				.arg(kapp->aboutData()->programName(), VERSION));

	// Copy a transparent GIF image in the folder, needed for the JavaScript hack:
	TQString gifFileName = "spacer.gif";
	TQFile transGIF(imagesFolderPath + gifFileName);
	if (!transGIF.exists() && transGIF.open(IO_WriteOnly)) {
		TQDataStream streamGIF(&transGIF);
		// This is a 1px*1px transparent GIF image:
		const uchar blankGIF[] = {
			0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0a, 0x00, 0x0a, 0x00,
			0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x21,
			0xfe, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
			0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47,
			0x49, 0x4d, 0x50, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00,
			0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a,
			0x00, 0x00, 0x02, 0x08, 0x8c, 0x8f, 0xa9, 0xcb, 0xed, 0x0f,
			0x63, 0x2b, 0x00, 0x3b };
		streamGIF.writeRawBytes((const char*)blankGIF, (unsigned int)74);
		transGIF.close();
	}
	stream <<
		"  <!--[if lt IE 7]>\n"
		"   <script>\n"
		"    function fixPng(img) {\n"
		"     if (!img.style.filter) {\n"
		"      img.style.filter = \"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='\" + img.src + \"')\";\n"
		"      img.src = \"" << imagesFolderName << gifFileName << "\";\n"
		"     }\n"
		"    }\n"
		"    for (i = document.images.length - 1; i >= 0; i -= 1) {\n"
		"     var img = document.images[i];\n"
		"     if (img.src.substr(img.src.length - 4) == \".png\")\n"
		"      if (img.complete)\n"
		"       fixPng(img);\n"
		"      else\n"
		"       img.attachEvent(\"onload\", function() { fixPng(window.event.srcElement); });\n"
		"    }\n"
		"   </script>\n"
		"  <![endif]-->\n"
		" </body>\n"
		"</html>\n";

	file.close();
	stream.unsetDevice();
	progress->advance(1); // Basket exportation finished

	// Recursively export child baskets:
	BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
	if (item->firstChild()) {
		for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling()) {
			exportBasket(child->basket(), /*isSubBasket=*/true);
		}
	}
}

void HTMLExporter::exportNote(Note *note, int indent)
{
	TQString spaces;

	if (note->isColumn()) {
		TQString width = "";
		if (false/*TODO: DEBUG AND REENABLE: hasResizer()*/) {
			// As we cannot be precise in CSS (say eg. "width: 50%-40px;"),
			// we output a percentage that is approximatively correct.
			// For instance, we compute the currently used percentage of width in the basket
			// and try make make it the same on a 1024*768 display in a Web browser:
			int availableSpaceForColumnsInThisBasket = note->basket()->contentsWidth() - (note->basket()->columnsCount() - 1) * Note::RESIZER_WIDTH;
			int availableSpaceForColumnsInBrowser    = 1024    /* typical screen width */
			                                           - 25    /* window border and scrollbar width */
			                                           - 2 * 5 /* page margin */
			                                           - (note->basket()->columnsCount() - 1) * Note::RESIZER_WIDTH;
			if (availableSpaceForColumnsInThisBasket <= 0)
				availableSpaceForColumnsInThisBasket = 1;
			int widthValue = (int)(availableSpaceForColumnsInBrowser * (double) note->groupWidth() / availableSpaceForColumnsInThisBasket);
			if (widthValue <= 0)
				widthValue = 1;
			if (widthValue > 100)
				widthValue = 100;
			width = TQString(" width=\"%1%\"").arg(TQString::number(widthValue));
		}
		stream << spaces.fill(' ', indent) << "<td class=\"column\"" << width << ">\n";

		// Export child notes:
		for (Note *child = note->firstChild(); child; child = child->next()) {
			stream << spaces.fill(' ', indent + 1);
			exportNote(child, indent + 1);
			stream << '\n';
		}

		stream << spaces.fill(' ', indent) << "</td>\n";
		if (note->hasResizer())
			stream << spaces.fill(' ', indent) << "<td class=\"columnHandle\"></td>\n";
		return;
	}

	TQString freeStyle;
	if (note->isFree())
		freeStyle = " style=\"position: absolute; left: " + TQString::number(note->x()) + "px; top: " + TQString::number(note->y()) + "px; width: " + TQString::number(note->groupWidth()) + "px\"";

	if (note->isGroup()) {
		stream << '\n' << spaces.fill(' ', indent) << "<table" << freeStyle << ">\n"; // Note content is expected to be on the same HTML line, but NOT groups
		int i = 0;
		for (Note *child = note->firstChild(); child; child = child->next()) {
			stream << spaces.fill(' ', indent);
			if (i == 0)
				stream << " <tr><td class=\"groupHandle\"><img src=\"" << imagesFolderName << (note->isFolded() ? "expand_group_" : "fold_group_") << backgroundColorName << ".png"
				       << "\" width=\"" << Note::EXPANDER_WIDTH << "\" height=\"" << Note::EXPANDER_HEIGHT << "\"></td>\n";
			else if (i == 1)
				stream << " <tr><td class=\"freeSpace\" rowspan=\"" << note->countDirectChilds() << "\"></td>\n";
			else
				stream << " <tr>\n";
			stream << spaces.fill(' ', indent) << "  <td>";
			exportNote(child, indent + 3);
			stream << "</td>\n"
			       << spaces.fill(' ', indent) << " </tr>\n";
			++i;
		}
		stream << '\n' << spaces.fill(' ', indent) << "</table>\n" /*<< spaces.fill(' ', indent - 1)*/;
	} else {
		// Additionnal class for the content (link, netword, color...):
		TQString additionnalClasses = note->content()->cssClass();
		if (!additionnalClasses.isEmpty())
			additionnalClasses = " " + additionnalClasses;
		// Assign the style of each associted tags:
		for (State::List::Iterator it = note->states().begin(); it != note->states().end(); ++it)
			additionnalClasses += " tag_" + (*it)->id();
		//stream << spaces.fill(' ', indent);
		stream << "<table class=\"note" << additionnalClasses << "\"" << freeStyle << "><tr>";
		if (note->emblemsCount() > 0) {
			stream << "<td class=\"tags\"><nobr>";
			for (State::List::Iterator it = note->states().begin(); it != note->states().end(); ++it)
				if (!(*it)->emblem().isEmpty()) {
					int emblemSize = 16;
					TQString iconFileName = copyIcon((*it)->emblem(), emblemSize);
					stream << "<img src=\"" << iconsFolderName << iconFileName
					       << "\" width=\"" << emblemSize << "\" height=\"" << emblemSize
					       << "\" alt=\"" << (*it)->textEquivalent() << "\" title=\"" << (*it)->fullName() << "\">";
				}
				stream << "</nobr></td>";
		}
		stream << "<td>";
		note->content()->exportToHTML(this, indent);
		stream << "</td></tr></table>";
	}
}

void HTMLExporter::writeBasketTree(Basket *currentBasket)
{
	stream << "  <ul class=\"tree\">\n";
	writeBasketTree(currentBasket, exportedBasket, 3);
	stream << "  </ul>\n";
}

void HTMLExporter::writeBasketTree(Basket *currentBasket, Basket *basket, int indent)
{
	// Compute variable HTML code:
	TQString spaces;
	TQString cssClass = (basket == currentBasket ? " class=\"current\"" : "");
	TQString link = "#";
	if (currentBasket != basket) {
		if (currentBasket == exportedBasket) {
			link = basketsFolderName + basket->folderName().left(basket->folderName().length() - 1) + ".html";
		} else if (basket == exportedBasket) {
			link = "../../" + fileName;
		} else {
			link = basket->folderName().left(basket->folderName().length() - 1) + ".html";
		}
	}
	TQString spanStyle = "";
	if (basket->backgroundColorSetting().isValid() || basket->textColorSetting().isValid()) {
		spanStyle = " style=\"background-color: " + basket->backgroundColor().name() + "; color: " + basket->textColor().name() + "\"";
	}

	// Write the basket tree line:
	stream <<
		spaces.fill(' ', indent) << "<li><a" << cssClass << " href=\"" << link << "\">"
		"<span" << spanStyle << " title=\"" << Tools::textToHTMLWithoutP(basket->basketName()) << "\">"
		"<img src=\"" << iconsFolderName <<  copyIcon(basket->icon(), 16) << "\" width=\"16\" height=\"16\" alt=\"\">" << Tools::textToHTMLWithoutP(basket->basketName()) << "</span></a>";

	// Write the sub-baskets lines & end the current one:
	BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
	if (item->firstChild() != 0) {
		stream <<
			"\n" <<
			spaces.fill(' ', indent) << " <ul>\n";
		for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling())
			writeBasketTree(currentBasket, child->basket(), indent + 2);
		stream <<
			spaces.fill(' ', indent) << " </ul>\n" <<
			spaces.fill(' ', indent) << "</li>\n";
	} else {
		stream << "</li>\n";
	}
}

/** Save an icon to a folder.
  * If an icon with the same name already exist in the destination,
  * it is assumed the icon is already copied, so no action is took.
  * It is optimized so that you can have an empty folder receiving the icons
  * and call copyIcon() each time you encounter one during export process.
  */
TQString HTMLExporter::copyIcon(const TQString &iconName, int size)
{
	if (iconName.isEmpty())
		return "";

	// Sometimes icon can be "favicons/www.kde.org", we replace the '/' with a '_'
	TQString fileName = iconName; // TQString::replace() isn't const, so I must copy the string before
	fileName = "ico" + TQString::number(size) + "_" + fileName.replace("/", "_") + ".png";
	TQString fullPath = iconsFolderPath + fileName;
	if (!TQFile::exists(fullPath))
		DesktopIcon(iconName, size).save(fullPath, "PNG");
	return fileName;
}

/** Done: Sometimes we can call two times copyFile() with the same srcPath and dataFolderPath
  *       (eg. when exporting basket to HTML with two links to same filename
  *            (but not necesary same path, as in "/home/foo.txt" and "/foo.txt") )
  *       The first copy isn't yet started, so the dest file isn't created and this method
  *       returns the same filename !!!!!!!!!!!!!!!!!!!!
  */
TQString HTMLExporter::copyFile(const TQString &srcPath, bool createIt)
{
	TQString fileName = Tools::fileNameForNewFile(KURL(srcPath).fileName(), dataFolderPath);
	TQString fullPath = dataFolderPath + fileName;

	if (createIt) {
		// We create the file to be sure another very near call to copyFile() willn't choose the same name:
		TQFile file(KURL(fullPath).path());
		if (file.open(IO_WriteOnly))
			file.close();
		// And then we copy the file AND overwriting the file we juste created:
		new TDEIO::FileCopyJob(
			KURL(srcPath), KURL(fullPath), 0666, /*move=*/false,
			/*overwrite=*/true, /*resume=*/true, /*showProgress=*/false );
	} else
		/*TDEIO::CopyJob *copyJob = */TDEIO::copy(KURL(srcPath), KURL(fullPath)); // Do it as before

	return fileName;
}
