/*
 * sxerecord.h - A class for storing the record of an individual node
 * Copyright (C) 2007  Joonas Govenius
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

#ifndef SXDEMETADATA_H
#define SXDEMETADATA_H

#include <QObject>
#include "sxerecordedit.h"
#include "sxenewedit.h"
#include "sxeremoveedit.h"

/*! \brief A class for storing the record of an individual node.*/
class SxeRecord : public QObject {
	Q_OBJECT

	public:
		/*! \brief Constructor
		 *  Constructs a SxeRecordEdit for \a node.
		 */
		SxeRecord(QString rid);
		/*! \brief Desctructor */
		~SxeRecord();

		/*! \brief Returns the node that the record underlies. */
		QDomNode node() const;
		/*! \brief Applies \a edit to the node. Takes ownership of \a edit. */
		void apply(QDomDocument &doc, SxeEdit* edit);
		/*! \brief Returns a list of edits to the node.*/
		QList<const SxeEdit*> edits() const;
		/*! \brief Returns the rid of the node that the record belongs to. */
		QString rid() const;
		/*! \brief Returns the rid of the parent.*/
		QString parent() const;
		/*! \brief Returns the primary-weight of the node.*/
		double primaryWeight() const;
		/*! \brief Returns the version of the record. */
		int version() const;
		/*! \brief Returns the name of the node, if any.*/
		QString name() const;
		/*! \brief Returns the name of the node, if any.*/
		QString nameSpace() const;
		/*! \brief Returns the chdata of the node, if any.*/
		QString chdata() const;
		/*! \brief Returns the processing instruction target, if any.*/
		QString processingInstructionTarget() const;
		/*! \brief Returns the processing instruction data, if any.*/
		QString processingInstructionData() const;

		bool hasSmallerSecondaryWeight(const SxeRecord &other) const;

		bool operator==(const SxeRecord &other) const;
		bool operator<(const SxeRecord &other) const;
		bool operator>(const SxeRecord &other) const;

	signals:
		/*! \brief Emitted when the node is first created. */
		void nodeToBeAdded(const QDomNode &node, bool remote, const QString &id);
		/*! \brief Emitted after the node has been placed in the document tree. */
		// void nodeAdded(const QDomNode &node, bool remote);
		/*! \brief Emitted just before the node is removed. */
		void nodeToBeRemoved(const QDomNode &node, bool remote);
		/*! \brief Emitted when the node is removed. */
		void nodeRemoved(const QDomNode &node, bool remote);
		/*! \brief Emitted when primary-weight or parent record is changed. */
		void nodeToBeMoved(const QDomNode &node, bool remote);
		/*! \brief Emitted after the node has been repositioned. */
		// void nodeMoved(const QDomNode &node, bool remote);
		/*! \brief Emitted when the name of the node is changed. */
		// void nameChanged(const QDomNode &node, bool remote);
		/*! \brief Emitted when the chdata of the node is changed. */
		void chdataChanged(const QDomNode &node, bool remote);
		/*! \brief Emitted just before the chdata of the node is changed. */
		void chdataToBeChanged(const QDomNode &node, bool remote);
		/*! \brief Emitted when the target of the processing instruction is changed. */
		void processingInstructionTargetChanged(const QDomNode &node, bool remote);
		/*! \brief Emitted just before the target of the processing instruction is changed. */
		void processingInstructionTargetToBeChanged(const QDomNode &node, bool remote);
		/*! \brief Emitted when the data of the processing instruction is changed. */
		void processingInstructionDataChanged(const QDomNode &node, bool remote);
		/*! \brief Emitted just before the data of the processing instruction is changed. */
		void processingInstructionDataToBeChanged(const QDomNode &node, bool remote);
		/*! \brief Emitted if a conflicting edit of some kind is applied. */
		void nodeRemovalRequired(const QDomNode &node);

	private:

		/*! \brief Applies SxeNewEdit \a edit to the record.*/
		bool applySxeNewEdit(QDomDocument &doc, SxeNewEdit* edit);
		/*! \brief Applies SxeRemoveEdit \a edit to the record.*/
		bool applySxeRemoveEdit(SxeRemoveEdit* edit);
		/*! \brief Applies SxeRecordEdit \a edit to the record.*/
		bool applySxeRecordEdit(SxeRecordEdit* edit);

		/*! \brief Applies an individual SxeRecordEdit assuming it can be applied to the current version.*/
		void processInOrderRecordEdit(const SxeRecordEdit* edit);
		/*! \brief Reorder the edits_ list and reapply edits as necessary. */
		void reorderEdits();
		/*! \brief Revert the record to version 0. */
		void revertToZero();

		/*! \brief Synchronize the state of the DOM node with the fields of the record. */
		void updateNode(bool remote);

		QList<SxeEdit*> edits_;

		QDomNode node_;

		QString rid_;
		int version_;

		/* The last* variants hold the values that were last put to the DOM node.*/
		QString parent_, lastParent_;
		double primaryWeight_, lastPrimaryWeight_;
		QString identifier_, lastIdentifier_;
		QString data_, lastData_;
};

#endif
