/***************************************************************************
 *   Copyright (C) 2004, 2005 Thomas Nagy                                  *
 *   tnagy2^8@yahoo.fr                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License version 2        *
 *   as published by the Free Software Foundation (see COPYING)            *
 *                                                                         *
 *   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.                          *
 ***************************************************************************/

#ifndef _DDATACONTROL_H
#define _DDATACONTROL_H

#include <qobject.h>
#include <qptrstack.h>
#include <qdatastream.h>
#include <qmap.h>
#include <qptrlist.h>
#include <qpoint.h>
#include <qstringlist.h>

#include "settings.h"
%:include "aux.h"
#include "DBase.h"
#include "DItem.h"
#include "DDelta.h"

class DissertParser;
class DGenerator;
class QTextStream;
class KURL;
class DDataItem;
class QDir;
class KTempDir;
class DSpell;
class DGuiView;

class DDeltaCreate;

/**
 * This class handles the necessary code for registering
 * and handling the mindmap items (data side)
 *
 * @short Main handler for mindmap item data
 * @author Thomas Nagy <tnagy2^8@yahoo.fr>
 */
class DDataControl : public QObject, public DBase
{
	Q_OBJECT

	/**
	 * The friends are classes used for importing documents
	 * ie: freemind, knowit ..
	 */
	friend class DissertParser;
	friend class DDeltaCreate;
	friend class FFParser;
	friend class DSpell;

	public:

		/**
		 *  These values represent the flags used in the gui (annotations)
		 */
		enum flags
		{
			e_warning,
			e_good,
			e_idea,
			e_work,
			e_clarify,
			e_question,
			e_trash,
			e_meeting,
			e_trouble
		};

		/**
		 * Default constructor
		 */
		DDataControl(QObject* parent=0, const char* name=0);

		/**
		 * Default destructor
		 */
		~DDataControl();

		/**
		 * This method creates a new item
		 * A unique id is generated, and a bug checking is performed
		 */
		int createItem(int parentid=DItem::NOITEM, int uniqueid=DItem::NOITEM);

		/**
		 * This method removes a mindmap item of the given id. 
		 * it does nothing if the item does not exist
		 */
		void removeItem( int );

		/**
		 * This method sets a mindmap item's parent
		 */
		void linkItems( int parent, int child );

		/**
		 * This method unlinks two mindmap items
		 */
		void unlinkItems( int parent, int child );

		/**
		 * Remove the parent of a mindmap item 
		 * this is a shortcut for unlinkItem(NOITEM, child)
		 */
		void setOrphan(int child);

		/**
		 * Unlinks all children from a particular mindmap item
		 */
		void killChildren(int id);

		/**
		 * Unlink the item from its references
		 */
		void killRefs(int id);
		
		/**
		 * Unlinks all children from a particular mindmap item recursively
		 */
		void killFamily(int id);

		/**
		 * Disconnects an item completely from
		 * its parents, children and references
		 */
		void disconnectItem(int);

		/**
		 * Notify all views that a mindmap item has changed (sort)
		 */
		void notifyChildChange(int id);

		/**
		 * Notify all children of the item of id
		 * that something has changed (position)
		 */
		void notifyChildren(int id);

		/**
		 * Save the mindmap data to a file
		 */
		bool saveToFile(const KURL &);

		/**
		 * Load a mindmap from a file
		 */
		bool loadFromFile(const KURL &, bool import=0, bool nogui=0);

		/**
		 * Dump the data to a file
		 */
		void printTree(QTextStream&);

		/** 
		 * Return to total amount of items
		 */
		int countItems();

		/**
		 * Return the root of the biggest mindmap tree
		 */
		int rootID();

		/*
		 * Indicates if the document generators can operate
		 */
		bool canGenerate();

		/**
		 *  Debug a mindmap item, dump the connections
		 */
		void debugItem(int id);

		/**
		 * Checks the consistency of the mindmap trees
		 * and try to fix them when an error is detected
		 */
		void checkConsistency();

		/**
		 * Return the temporary directory for the cached documents (pictures)
		 */
		QDir* getTmpDir();

		/**
		 * Compare two items by their position in the hierarchy
		 */
		int compare(int id1, int id2) const;

		/**
		 * Notify all view that one item is set to state selected
		 * The id can be DItem::NOITEM
		 * This method caches the item used
		 */
		void setItemSelected(int id, DGuiView*);

		/**
		 * Returns the item selected, cached from a previous call to setItemSelected
		 */
		inline DDataItem *singleSelection() { return m_itemselected; }

		/**
		 * Notify all views that the item has changed by emitting itemChanged
		 */
		void notifyItemModified(int id);

		/**
		 * Check if a project name has already be defined.
		 */
		bool hasProject() const;

		/**
		 * Set a new project name from a KURL object.
		 * Extracts the filename part of the URL, without
		 * path and @c .kdi extension.
		 */
		void setProject(const KURL&);

		/** 
		 * The following variables represent per-document settings
		 * They are public, but one has to be careful when setting them:
		 * call updateSettings() when needed
		 */

		/// The project's name
		QString m_project;
		/// The project's path
		QString m_path;
		/// Author first name
		QString m_fname;
		/// Author last name
		QString m_sname;
		/// Author e-mail address
		QString m_email;
		/// Author's company or institution
		QString m_company;
		/// preview size of the picture
		int m_pixSize;
		/// background color
		QColor m_col_background;
		/// link color
		QColor m_col_link;
		/// reference color
		QColor m_col_ref;
		/// default font for new map items
		QFont m_canvasFont;
		/// display pictures on the map view or not
		bool m_picturesOnCanvas;
		/// show the directions of the connections
		int m_showDirectionSize;
		/// link style : lines, splines or thick splines
		int m_linkstyle;
		/// last url used to generate a document
		QString m_generator_lasturl;
		/// last generator library used to generate a document
		QStringList m_generator_lastgen;
		
		/*
		 * Use this to ask for adding or removing a reference
		 */
		bool requestRefChange(int orig, int dest, bool add = true, bool check=true);

		/**
		 * Ask the control to make a new delta to undo the changes
		 *
		 * It is innocuous to call newDelta multiple times (it will not make empty delta lists)
		 * Calling it too many times however can fragment the undo delta too much
		 */
		void newDelta();

		/**
		 * An item has changed position on the canvas view
		 */
		void registerMapPositionChange(int id, DDataItem::Coord oldx, DDataItem::Coord oldy, DDataItem::Coord newx, DDataItem::Coord newy);

		/**
		 * Item color change
		 */
		void registerMapColorChange(int id, int oldc, int newc, QColor oldcustcol, QColor newcustcol);

		/**
		 * Item flag change
		 */
		void registerMapFlagChange(int id, int flag, bool add=true);

		/**
		 * Undo Redo state
		 */
		inline bool isUndoRedoLocked() { return m_undoredo_locked; }

	signals:
		/**
		 *  Used to refresh the views whenever a particular item changes
		 */
		void itemChanged(int);

		/**
		 *  Synchronize the views when an item is created
		 */
		void itemCreated(int);

		/**
		 *  Synchronize the views when an item is removed
		 */
		void itemRemoved(int);

		/**
		 *  Synchronize the views when a reference is added or removed
		 */
		void refChanged(int, int, bool add);

		/**
		 *  This is used to notify the views that a single item is selected
		 */
		void itemSelected(int, DGuiView*);

		/**
		 *  This signal is emitted to notify that the document is in state save_me
		 */
		void documentChanged(bool save_me);

		/**
		 *  This signal is emitted to tell the views to reload the settings
		 */
		void settingsChanged();


		void undoState(bool b);
		void redoState(bool b);

		/**
		 *  This signal is emitted to display a tip in the statusbar
		 */
		void tip(const QString &);
		
	public slots:
		/**
		 *  Clear the current document
		 */
		void clearDocument();

		/**
		 *  This method is used to set the mindmap state to "changed"
		 */
		void docChanged();

		/**
		 *  This method is used to set the mindmap state to "not changed"
		 */
		void docNotChanged();

		/**
		 * This slot launches the spellcheck
		 */
		void slotFileSpell();

		/**
		 * This method is called when the settings change
		 */
		void updateSettings();

		void slotUndo();
		void slotRedo();
		
	protected:
		/*
		 * Create a mindmap item with a particular id
		 */
		DDataItem* createItemWithId(int id);

		void notifySpecial(DDataItem *item);

	private:
		/**
		 *  Last item id used, mandatory for generating new items with unique ids
		 */
		int m_lastid;

		/**
		 *  This is a shortcut for getting an item data from its id
		 */
		DDataItem* dataItem(int id) const;

		/**
		 *  Store the last item selected (single selection)
		 */
		DDataItem *m_itemselected;

		/**
		 *  Temporary directory for caching documents (pictures especially)
		 */
		KTempDir *m_fileholder;

		/**
		 *  Spellcheck-enabled
		 */
		DSpell *m_spell;


		/**
		 * Add a delta to the undo stack
		 * The redo stack is cleared automatically
		 */
		void addDelta(DDelta *);

		bool m_undoredo_locked;
		
		QPtrStack<DDeltaList> m_undostack;
		QPtrStack<DDeltaList> m_redostack;

		/**
		 *  We keep an internal map of all references that have been added for easy removel
		 */
		QPtrList<QPoint> m_reflist;
};

#endif // _DDATACONTROL_H
