/*
    This file is part of the KDE games library
    Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
    Copyright (C) 2001 Martin Heni (kde at heni-online.de)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#ifndef __KGAMEPROPERTYHANDLER_H_
#define __KGAMEPROPERTYHANDLER_H_

#include <QObject>
#include <QMultiHash>

#include "kgameproperty.h"
#include "libkdegamesprivate_export.h"

class QDataStream;
class KGame;
//class KGamePropertyBase;

class KGamePropertyHandlerPrivate; // wow - what a name ;-)

/**
 * \class KGamePropertyHandler kgamepropertyhandler.h <KGame/KGamePropertyHandler>
 *
 * @short A collection class for KGameProperty objects
 *
 * The KGamePropertyHandler class is some kind of a collection class for
 * KGameProperty. You usually don't have to create one yourself, as both
 * KPlayer and KGame provide a handler. In most cases you do not even have
 * to care about the KGamePropertHandler. KGame and KPlayer implement
 * all features of KGamePropertyHandler so you will rather use it there.
 *
 * You have to use the KGamePropertyHandler as parent for all KGameProperty
 * objects but you can also use KPlayer or KGame as parent - then
 * KPlayer::dataHandler or KGame::dataHandler will be used.
 *
 * Every KGamePropertyHandler must have - just like every KGameProperty -
 * a unique ID. This ID is provided either in the constructor or in
 * registerHandler. The ID is used to assign an incoming message (e.g. a changed
 * property) to the correct handler. Inside the handler the property ID is used
 * to change the correct property.
 *
 * The constructor or registerHandler takes 3 addittional arguments: a
 * receiver and two slots. The first slot is connected to
 * signalSendMessage, the second to signalPropertyChanged. You must provide
 * these in order to use the KGamePropertyHandler.
 *
 * The most important function of KGamePropertyHandler is processMessage
 * which assigns an incoming value to the correct property.
 *
 * A KGamePropertyHandler is also used - indirectly using emitSignal - to
 * emit a signal when the value of a property changes. This is done this way
 * because a KGameProperty does not inherit QObject because of memory
 * advantages. Many games can have dozens or even hundreds of KGameProperty
 * objects so every additional variable in KGameProperty would be
 * multiplied.
 *
 **/
class KDEGAMESPRIVATE_EXPORT KGamePropertyHandler : public QObject
{
	Q_OBJECT

public:
	/**
	 * Construct an unregistered KGamePropertyHandler
	 *
	 * You have to call registerHandler before you can use this
	 * handler!
	 **/
	KGamePropertyHandler(QObject* parent = 0);

	/**
	 * Construct a registered handler.
	 *
	 * @see registerHandler
	 **/
	KGamePropertyHandler(int id, const QObject* receiver, const char* sendf, const char* emitf, QObject* parent = 0);
	~KGamePropertyHandler();

	/**
	 * Register the handler with a parent. This is to use
	 * if the constructor without arguments has been chosen.
	 * Otherwise you need not call this.
	 *
	 * @param id The id of the message to listen for
	 * @param receiver The object that will receive the signals of
	 * KGamePropertyHandler
	 * @param send A slot that is being connected to signalSendMessage
	 * @param emit A slot that is being connected to signalPropertyChanged
	 **/
	void registerHandler(int id, const QObject *receiver, const char * send, const char *emit);

	/**
	 * Main message process function. This has to be called by
	 * the parent's message event handler. If the id of the message
	 * agrees with the id of the handler, the message is extracted
	 * and processed. Otherwise false is returned.
	 * Example:
	 * \code
	 *   if (mProperties.processMessage(stream,msgid,sender==gameId())) return ;
	 * \endcode
	 *
	 * @param stream The data stream containing the message
	 * @param id the message id of the message
	 * @param isSender Whether the receiver is also the sender
	 * @return true on message processed otherwise false
	 **/
	bool processMessage(QDataStream &stream, int id, bool isSender );

	/**
	 * @return the id of the handler
	 **/
	int id() const;

	/**
	 * Adds a KGameProperty property to the handler
	 * @param data the property
	 * @param name A description of the property, which will be returned by
	 * propertyName. This is used for debugging
	 * @return true on success
	 **/
	bool addProperty(KGamePropertyBase *data, const QString& name=QString());

	/**
	 * Removes a property from the handler
	 * @param data the property
	 * @return true on success
	 **/
	bool removeProperty(KGamePropertyBase *data);

	/**
	 * returns a unique property ID starting called usually with a base of
	 * KGamePropertyBase::IdAutomatic. This is used internally by
	 * the property base to assign automtic id's. Not much need to
	 * call this yourself.
	 **/
	int uniquePropertyId();


	/**
	 * Loads properties from the datastream
	 *
	 * @param stream the datastream to load from
	 * @return true on success otherwise false
	 **/
	virtual bool load(QDataStream &stream);

	/**
	 * Saves properties into the datastream
	 *
	 * @param stream the datastream to save to
	 * @return true on success otherwise false
	 **/
	virtual bool save(QDataStream &stream);

	/**
	 * called by a property to send itself into the
	 * datastream. This call is simply forwarded to
	 * the parent object
	 **/
	bool sendProperty(QDataStream &s);

	void sendLocked(bool l);

	/**
	 * called by a property to emit a signal
	 * This call is simply forwarded to
	 * the parent object
	 **/
	void emitSignal(KGamePropertyBase *data);

	/**
	 * @param id The ID of the property
	 * @return A name of the property which can be used for debugging. Don't
	 * depend on this function! It it possible not to provide a name or to
	 * provide the same name for multiple properties!
	 **/
	QString propertyName(int id) const;

	/**
	 * @param id The ID of the property. See KGamePropertyBase::id
	 * @return The KGameProperty this ID is assigned to
	 **/
	KGamePropertyBase *find(int id);

	/**
	 * Clear the KGamePropertyHandler. Note that the properties are
	 * <em>not</em> deleted so if you created your KGameProperty
	 * objects dynamically like
	 * \code
	 * KGamePropertyInt* myProperty = new KGamePropertyInt(id, dataHandler());
	 * \endcode
	 * you also have to delete it:
	 * \code
	 * dataHandler()->clear();
	 * delete myProperty;
	 * \endcode
	 **/
	void clear();

	/**
	 * Use id as new ID for this KGamePropertyHandler. This is used
	 * internally only.
	 **/
	void setId(int id);//AB: TODO: make this protected in KGamePropertyHandler!!

	/**
	 * Calls KGamePropertyBase::setReadOnly(false) for all properties of this
	 * player. See also lockProperties
	 **/
	void unlockProperties();

	/**
	 * Set the policy for all kgame variables which are currently registerd in
	 * the KGame proeprty handler. See KGamePropertyBase::setPolicy
	 *
	 * @param p is the new policy for all properties of this handler
	 * @param userspace if userspace is true (default) only user properties are changed.
	 * Otherwise the system properties are also changed.
	 **/
	void setPolicy(KGamePropertyBase::PropertyPolicy p, bool userspace=true);

	/**
	 * Called by the KGame or KPlayer object or the handler itself to delay
	 * emmiting of signals. Lockign keeps a counter and unlock is only achieved
	 * when every lock is canceld by an unlock.
	 * While this is set signals are  quequed and only emmited after this
	 * is reset. Its deeper meaning is to prevent inconsistencies in a game
	 * load or network transfer where a emit could access a property not
	 * yet loaded or transmitted. Calling this by yourself you better know
	 * what your are doing.
	 **/
	void lockDirectEmit();

	/**
	 * Removes the lock from the emitting of property signals. Corresponds to
	 * the lockIndirectEmits
	 **/
	void unlockDirectEmit();

	/**
	 * Returns the default policy for this property handler. All properties
	 * registered newly, will have this property.
	 **/
	KGamePropertyBase::PropertyPolicy policy();

	/**
	 * Calls KGamePropertyBase::setReadOnly(true) for all properties of this
	 * handler
	 *
	 * Use with care! This will even lock the core properties, like name,
	 * group and myTurn!!
	 *
	 * @see unlockProperties
	 **/
	void lockProperties();

	/**
	 * Sends all properties which are marked dirty over the network. This will
	 * make a forced synchornisation of the properties and mark them all not dirty.
	 **/
	void flush();

	/**
	 * Reference to the internal dictionary
	 **/
        QMultiHash<int, KGamePropertyBase*> &dict() const;

	/**
	 * In several situations you just want to have a QString of a
	 * KGameProperty object. This
	 * function will provide you with such a QString for all the types
	 * used inside of all KGame classes. If you have a non-standard
	 * property (probably a self defined class or something like this) you
	 * also need to connect to signalRequestValue to make this function
	 * useful.
	 * @param property Return the value of this KGameProperty
	 * @return The value of a KGameProperty
	 **/
	QString propertyValue(KGamePropertyBase* property);


	/**
	 * Writes some debug output to the console.
	 **/
	void Debug();


Q_SIGNALS:
	/**
	 * This is emitted by a property. KGamePropertyBase::emitSignal
	 * calls emitSignal which emits this signal.
	 *
	 * This signal is emitted whenever the property is changed. Note that
	 * you can switch off this behaviour using
	 * KGamePropertyBase::setEmittingSignal in favor of performance. Note
	 * that you won't experience any performance loss using signals unless
	 * you use dozens or hundreds of properties which change very often.
	 **/
	void signalPropertyChanged(KGamePropertyBase *);

	/**
	 * This signal is emitted when a property needs to be sent. Only the
	 * parent has to react to this.
	 * @param msgid The id of the handler
	 * @param sent set this to true if the property was sent successfully -
	 * otherwise don't touch
	 **/
	void signalSendMessage(int msgid, QDataStream &, bool* sent); // AB shall we change bool* into bool& again?

	/**
	 * If you call propertyValue with a non-standard KGameProperty
	 * it is possible that the value cannot automatically be converted into a
	 * QString. Then this signal is emitted and asks you to provide the
	 * correct value. You probably want to use something like this to achieve
	 * this:
	 * \code
	 * #include <typeinfo>
	 * void slotRequestValue(KGamePropertyBase* p, QString& value)
	 * {
	 * 	if (*(p->typeinfo()) == typeid(MyType) {
	 * 		value = QString(((KGameProperty<MyType>*)p)->value());
	 * 	}
	 * }
	 * \endcode
	 *
	 * @param property The KGamePropertyBase the value is requested for
	 * @param value The value of this property. You have to set this.
	 **/
	void signalRequestValue(KGamePropertyBase* property, QString& value);

private:
	friend class KGamePropertyHandlerPrivate;
	KGamePropertyHandlerPrivate *const d;

	Q_DISABLE_COPY(KGamePropertyHandler)
};

#endif
