/***************************************************************************
 *   Copyright (C) 2003 by S�astien Laot                                 *
 *   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 <tqstring.h>
#include <tqstringlist.h>
#include <tqdir.h>
#include <tqfileinfo.h>
#include <tqdom.h>
#include <tdeglobalsettings.h>
#include <tdemessagebox.h>
#include <tdelocale.h>
#include <tdeapplication.h>

#include <iostream>

#include "formatimporter.h"
#include "notecontent.h"
#include "notefactory.h"
#include "bnpview.h"
#include "basket.h"
#include "global.h"
#include "xmlwork.h"
#include "tools.h"

bool FormatImporter::shouldImportBaskets()
{
	// We should import if the application have not successfully loaded any basket...
	if (Global::bnpView->firstListViewItem())
		return false;

	// ... And there is at least one folder in the save folder, with a ".basket" file inside that folder.
	TQDir dir(Global::savesFolder(), TQString(), TQDir::Name | TQDir::IgnoreCase, TQDir::Dirs | TQDir::NoSymLinks);
	TQStringList list = dir.entryList();
	for (TQStringList::Iterator it = list.begin(); it != list.end(); ++it)
		if (*it != "." && *it != ".." && dir.exists(Global::savesFolder() + *it + "/.basket"))
			return true;

	return false;
}

void FormatImporter::copyFolder(const TQString &folder, const TQString &newFolder)
{
	copyFinished = false;
	TDEIO::CopyJob *copyJob = TDEIO::copyAs(KURL(folder), KURL(newFolder), /*showProgressInfo=*/false);
	connect( copyJob,  TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(slotCopyingDone(TDEIO::Job*)) );
	while (!copyFinished)
		tdeApp->processEvents();
}

void FormatImporter::moveFolder(const TQString &folder, const TQString &newFolder)
{
	copyFinished = false;
	TDEIO::CopyJob *copyJob = TDEIO::moveAs(KURL(folder), KURL(newFolder), /*showProgressInfo=*/false);
	connect( copyJob,  TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(slotCopyingDone(TDEIO::Job*)) );
	while (!copyFinished)
		tdeApp->processEvents();
}

void FormatImporter::slotCopyingDone(TDEIO::Job *)
{
//	std::cout << "Copy finished of " + from.path() + " to " + to.path() << std::endl;
	copyFinished = true;
}

void FormatImporter::importBaskets()
{
	std::cout << "Import Baskets: Preparing..." << std::endl;

	// Some preliminary preparations (create the destination folders and the basket tree file):
	TQDir dirPrep;
	dirPrep.mkdir(Global::savesFolder());
	dirPrep.mkdir(Global::basketsFolder());
	TQDomDocument document("basketTree");
	TQDomElement root = document.createElement("basketTree");
	document.appendChild(root);

	// First up, establish a list of every baskets, ensure the old order (if any), and count them.
	TQStringList baskets;

	// Read the 0.5.0 baskets order:
	TQDomDocument *doc = XMLWork::openFile("container", Global::savesFolder() + "container.baskets");
	if (doc != 0) {
		TQDomElement docElem = doc->documentElement();
		TQDomElement basketsElem = XMLWork::getElement(docElem, "baskets");
		TQDomNode n = basketsElem.firstChild();
		while (!n.isNull()) {
			TQDomElement e = n.toElement();
			if ((!e.isNull()) && e.tagName() == "basket")
				baskets.append(e.text());
			n = n.nextSibling();
		}
	}

	// Then load the baskets that weren't loaded (import < 0.5.0 ones):
	TQDir dir(Global::savesFolder(), TQString(), TQDir::Name | TQDir::IgnoreCase, TQDir::Dirs | TQDir::NoSymLinks);
	TQStringList list = dir.entryList();
	if (list.count() > 2) // Pass "." and ".."
		for (TQStringList::Iterator it = list.begin(); it != list.end(); ++it) // For each folder
			if (*it != "." && *it != ".." && dir.exists(Global::savesFolder() + *it + "/.basket")) // If it can be a basket folder
				if ( baskets.find((*it) + "/") == baskets.end() &&
				     baskets.find(*it)         == baskets.end()    ) // And if it is not already in the imported baskets list
					baskets.append(*it);

	std::cout << "Import Baskets: Found " << baskets.count() << " baskets to import." << std::endl;

	// Import every baskets:
	int i = 0;
	for (TQStringList::iterator it = baskets.begin(); it != baskets.end(); ++it) {
		++i;
		std::cout << "Import Baskets: Importing basket " << i << " of " << baskets.count() << "..." << std::endl;

		// Move the folder to the new repository (normal basket) or copy the folder (mirorred folder):
		TQString folderName = *it;
		if (folderName.startsWith("/")) { // It was a folder mirror:
			KMessageBox::information(0, i18n("<p>Folder mirroring is not possible anymore.</p>"
				"<p>The folder <b>%1</b> has been copied for the basket needs. You can either delete this folder or delete the basket, or use both. But remember that "
				"modifying one will not modify the other anymore as they are now separate entities.</p>").arg(folderName), i18n("Folder Mirror Import"),
				"", KMessageBox::AllowLink);
			// Also modify folderName to be only the folder name and not the full path anymore:
			TQString newFolderName = folderName;
			if (newFolderName.endsWith("/"))
				newFolderName = newFolderName.left(newFolderName.length() - 1);
			newFolderName = newFolderName.mid(newFolderName.findRev('/') + 1);
			newFolderName = Tools::fileNameForNewFile(newFolderName, Global::basketsFolder());
			FormatImporter f;
			f.copyFolder(folderName, Global::basketsFolder() + newFolderName);
			folderName = newFolderName;
		} else
			dir.rename(Global::savesFolder() + folderName, Global::basketsFolder() + folderName); // Move the folder

		// Import the basket structure file and get the properties (to add them in the tree basket-properties cache):
		TQDomElement properties = importBasket(folderName);

		// Add it to the XML document:
		TQDomElement basketElement = document.createElement("basket");
		root.appendChild(basketElement);
		basketElement.setAttribute("folderName", folderName);
		basketElement.appendChild(properties);
	}

	// Finalize (write to disk and delete now useless files):
	std::cout << "Import Baskets: Finalizing..." << std::endl;

	TQFile file(Global::basketsFolder() + "baskets.xml");
	if (file.open(IO_WriteOnly)) {
		TQTextStream stream(&file);
		stream.setEncoding(TQTextStream::UnicodeUTF8);
		TQString xml = document.toString();
		stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
		stream << xml;
		file.close();
	}

	Tools::deleteRecursively(Global::savesFolder() + ".tmp");
	dir.remove(Global::savesFolder() + "container.baskets");

	std::cout << "Import Baskets: Finished." << std::endl;
}

TQDomElement FormatImporter::importBasket(const TQString &folderName)
{
	// Load the XML file:
	TQDomDocument *document = XMLWork::openFile("basket", Global::basketsFolder() + folderName + "/.basket");
	if (!document) {
		std::cout << "Import Baskets: Failed to read the basket file!" << std::endl;
		return TQDomElement();
	}
	TQDomElement docElem = document->documentElement();

	// Import properties (change <background color=""> to <appearance backgroundColor="">, and figure out if is a checklist or not):
	TQDomElement properties = XMLWork::getElement(docElem, "properties");
	TQDomElement background = XMLWork::getElement(properties, "background");
	TQColor backgroundColor = TQColor(background.attribute("color"));
	if (backgroundColor.isValid() && (backgroundColor != TDEGlobalSettings::baseColor())) { // Use the default color if it was already that color:
		TQDomElement appearance = document->createElement("appearance");
		appearance.setAttribute("backgroundColor", backgroundColor.name());
		properties.appendChild(appearance);
	}
	TQDomElement disposition = document->createElement("disposition");
	disposition.setAttribute("mindMap",     "false");
	disposition.setAttribute("columnCount", "1");
	disposition.setAttribute("free",        "false");
	bool isCheckList = XMLWork::trueOrFalse( XMLWork::getElementText(properties, "showCheckBoxes", "") );

	// Insert all notes in a group (column): 1/ rename "items" to "group", 2/ add "notes" to root, 3/ move "group" into "notes"
	TQDomElement column = XMLWork::getElement(docElem, "items");
	column.setTagName("group");
	TQDomElement notes = document->createElement("notes");
	notes.appendChild(column);
	docElem.appendChild(notes);

	// Import notes from older representations:
	TQDomNode n = column.firstChild();
	while ( ! n.isNull() ) {
		TQDomElement e = n.toElement();
		if (!e.isNull()) {
			e.setTagName("note");
			TQDomElement content = XMLWork::getElement(e, "content");
			// Add Check tag:
			if (isCheckList) {
				bool isChecked = XMLWork::trueOrFalse(e.attribute("checked", "false"));
				XMLWork::addElement(*document, e, "tags", (isChecked ? "todo_done" : "todo_unchecked"));
			}
			// Import annotations as folded groups:
			TQDomElement parentE = column;
			TQString annotations = XMLWork::getElementText(e, "annotations", "");
			if (!annotations.isEmpty()) {
				TQDomElement annotGroup = document->createElement("group");
				column.insertBefore(annotGroup, e);
				annotGroup.setAttribute("folded", "true");
				annotGroup.appendChild(e);
				parentE = annotGroup;
				// Create the text note and add it to the DOM tree:
				TQDomElement annotNote = document->createElement("note");
				annotNote.setAttribute("type", "text");
				annotGroup.appendChild(annotNote);
				TQString annotFileName = Tools::fileNameForNewFile("annotations1.txt", Basket::fullPathForFolderName(folderName));
				TQString annotFullPath = Basket::fullPathForFolderName(folderName) + "/" + annotFileName;
				TQFile file(annotFullPath);
				if (file.open(IO_WriteOnly)) {
					TQTextStream stream(&file);
					stream << annotations;
					file.close();
				}
				XMLWork::addElement(*document, annotNote, "content", annotFileName);
				n = annotGroup;
			}
			// Import Launchers from 0.3.x, 0.4.0 and 0.5.0-alphas:
			TQString runCommand = e.attribute("runcommand"); // Keep compatibility with 0.4.0 and 0.5.0-alphas versions
			runCommand = XMLWork::getElementText(e, "action", runCommand); // Keep compatibility with 0.3.x versions
			if ( ! runCommand.isEmpty() ) { // An import should be done
				// Prepare the launcher note:
				TQString title = content.attribute("title", "");
				TQString icon  = content.attribute("icon",  "");
				if (title.isEmpty()) title = runCommand;
				if (icon.isEmpty())  icon  = NoteFactory::iconForCommand(runCommand);
				// Import the launcher note:
				// Adapted version of "TQString launcherName = NoteFactory::createNoteLauncherFile(runCommand, title, icon, this)":
				TQString launcherContent = TQString(
					"[Desktop Entry]\n"
					"Exec=%1\n"
					"Name=%2\n"
					"Icon=%3\n"
					"Encoding=UTF-8\n"
					"Type=Application\n").arg(runCommand, title, icon.isEmpty() ? TQString("application-x-executable") : icon);
				TQString launcherFileName = Tools::fileNameForNewFile("launcher.desktop", Global::basketsFolder() + folderName /*+ "/"*/);
				TQString launcherFullPath = Global::basketsFolder() + folderName /*+ "/"*/ + launcherFileName;
				TQFile file(launcherFullPath);
				if (file.open(IO_WriteOnly)) {
					TQTextStream stream(&file);
					stream.setEncoding(TQTextStream::UnicodeUTF8);
					stream << launcherContent;
					file.close();
				}
				// Add the element to the DOM:
				TQDomElement launcherElem = document->createElement("note");
				parentE.insertBefore(launcherElem, e);
				launcherElem.setAttribute("type", "launcher");
				XMLWork::addElement(*document, launcherElem, "content", launcherFileName);
			}
			// Import unknown ns to 0.6.0:
			if (e.attribute("type") == "unknow")
				e.setAttribute("type", "unknown");
			// Import links from version < 0.5.0:
			if (!content.attribute("autotitle").isEmpty() && content.attribute("autoTitle").isEmpty())
				content.setAttribute("autoTitle", content.attribute("autotitle"));
			if (!content.attribute("autoicon").isEmpty() && content.attribute("autoIcon").isEmpty())
				content.setAttribute("autoIcon", content.attribute("autoicon"));
		}
		n = n.nextSibling();
	}

	// Save the resulting XML file:
	TQFile file(Global::basketsFolder() + folderName + "/.basket");
	if (file.open(IO_WriteOnly)) {
		TQTextStream stream(&file);
		stream.setEncoding(TQTextStream::UnicodeUTF8);
//		TQString xml = document->toString();
//		stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
//		stream << xml;
		stream << document->toString(); // Document is ALREADY using UTF-8
		file.close();
	} else
		std::cout << "Import Baskets: Failed to save the basket file!" << std::endl;

	// Return the newly created properties (to put in the basket tree):
	return properties;
}

#include "formatimporter.moc"
