#ifndef SEEN_INKSCAPE_XML_SP_REPR_ACTION_H
#define SEEN_INKSCAPE_XML_SP_REPR_ACTION_H

#include <glib/gtypes.h>
#include <glib/gquark.h>
#include <glibmm/ustring.h>

#include <iterator>
#include "util/share.h"
#include "util/forward-pointer-iterator.h"
#include "gc-managed.h"
#include "xml/node.h"

namespace Inkscape {
namespace XML {

class Node;
class NodeObserver;

enum EventType {
	EVENT_ADD,
	EVENT_DEL,
	EVENT_CHG_ATTR,
	EVENT_CHG_CONTENT,
	EVENT_CHG_ORDER
};
		
class Event
: public Inkscape::GC::Managed<Inkscape::GC::SCANNED, Inkscape::GC::MANUAL>
{
public:
        
        virtual ~Event() {}

	Event *next;
	int serial;
	Node *repr;

	struct IteratorStrategy {
		static Event const *next(Event const *action) {
			return action->next;
		}
	};

	typedef Inkscape::Util::ForwardPointerIterator<Event, IteratorStrategy> Iterator;
	typedef Inkscape::Util::ForwardPointerIterator<Event const, IteratorStrategy> ConstIterator;

	Event *optimizeOne() { return _optimizeOne(); }
	void undoOne(NodeObserver &observer) const {
		_undoOne(observer);
	}
	void replayOne(NodeObserver &observer) const {
		_replayOne(observer);
	}

protected:
	Event(Node *r, Event *n)
	: next(n), serial(_next_serial++), repr(r) {}

	virtual Event *_optimizeOne()=0;
	virtual void _undoOne(NodeObserver &) const=0;
	virtual void _replayOne(NodeObserver &) const=0;

private:
	static int _next_serial;
};

class EventAdd : public Event {
public:
	EventAdd(Node *repr, Node *c, Node *rr, Event *next)
	: Event(repr, next), child(c), ref(rr) {}

	Node *child;
	Node *ref;

private:
	Event *_optimizeOne();
	void _undoOne(NodeObserver &observer) const;
	void _replayOne(NodeObserver &observer) const;
};

class EventDel : public Event {
public:
	EventDel(Node *repr, Node *c, Node *rr, Event *next)
	: Event(repr, next), child(c), ref(rr) {}

	Node *child;
	Node *ref;

private:
	Event *_optimizeOne();
	void _undoOne(NodeObserver &observer) const;
	void _replayOne(NodeObserver &observer) const;
};

class EventChgAttr : public Event {
public:
	EventChgAttr(Node *repr, GQuark k,
		     Inkscape::Util::ptr_shared<char> ov,
                     Inkscape::Util::ptr_shared<char> nv,
                     Event *next)
	: Event(repr, next), key(k),
	  oldval(ov), newval(nv) {}

	GQuark key;
	Inkscape::Util::ptr_shared<char> oldval;
	Inkscape::Util::ptr_shared<char> newval;

private:
	Event *_optimizeOne();
	void _undoOne(NodeObserver &observer) const;
	void _replayOne(NodeObserver &observer) const;
};

class EventChgContent : public Event {
public:
	EventChgContent(Node *repr,
                        Inkscape::Util::ptr_shared<char> ov,
                        Inkscape::Util::ptr_shared<char> nv,
                        Event *next)
	: Event(repr, next), oldval(ov), newval(nv) {}

	Inkscape::Util::ptr_shared<char> oldval;
	Inkscape::Util::ptr_shared<char> newval;

private:
	Event *_optimizeOne();
	void _undoOne(NodeObserver &observer) const;
	void _replayOne(NodeObserver &observer) const;
};

class EventChgOrder : public Event {
public:
	EventChgOrder(Node *repr, Node *c, Node *orr, Node *nrr, Event *next)
	: Event(repr, next), child(c),
	  oldref(orr), newref(nrr) {}

	Node *child;
	Node *oldref, *newref;

private:
	Event *_optimizeOne();
	void _undoOne(NodeObserver &observer) const;
	void _replayOne(NodeObserver &observer) const;
};

}
}

#endif
