/// \file lockable.h
/// \brief Declares interface that allows a class to declare itself as
/// "lockable".
///
/// The meaning of a class being lockable is very much per-class
/// specific in this version of MySQL++.  In a future version, it will
/// imply that operations that aren't normally thread-safe will use
/// platform mutexes if MySQL++ is configured to support them.  This is
/// planned for a version beyond v2.0. (See the Wishlist for the plan.)
/// In the meantime, do not depend on this mechanism for thread safety;
/// you will have to serialize access to some resources yourself.
///
/// To effect this variability in what it means for an object to be
/// "locked", Lockable is only an interface.  It delegates the actual
/// implementation to a subclass of the Lock interface, using the
/// Bridge pattern.  (See Gamma et al.)

/***********************************************************************
 Copyright (c) 2005 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ 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 Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#ifndef MYSQLPP_LOCKABLE_H
#define MYSQLPP_LOCKABLE_H

namespace mysqlpp {

/// \brief Abstract base class for lock implementation, used by
/// Lockable.

class Lock
{
public:
	/// \brief Destroy object
	virtual ~Lock() { }

	/// \brief Lock the object
	///
	/// \return true if object was already locked
	virtual bool lock() = 0;

	/// \brief Unlock the object
	virtual void unlock() = 0;

	/// \brief Returns true if object is locked
	virtual bool locked() const = 0;

	/// \brief Set the lock state.
	virtual void set(bool b) = 0;
};


/// \brief Trivial Lock subclass, using a boolean variable as the
/// lock flag.
///
/// This is the only Lock implementation available in this version of
/// MySQL++.  It will be supplemented with a better implementation for
/// use with threads at a later date.

class BasicLock : public Lock
{
public:
	/// \brief Create object
	BasicLock(bool locked = false) :
	locked_(locked)
	{
	}
	
	/// \brief Destroy object
	~BasicLock() { }

	/// \brief Lock the object
	///
	/// \return true if object was already locked
	bool lock()
	{
		if (locked_) {
			return true;
		}
		locked_ = true;
		return false;
	}

	/// \brief Unlock the object
	void unlock() { locked_ = false; }

	/// \brief Returns true if object is locked
	bool locked() const { return locked_; }

	/// \brief Set the lock state.
	void set(bool b) { locked_ = b; }

private:
	bool locked_;
};


/// \brief Interface allowing a class to declare itself as "lockable".
///
/// A class derives from this one to acquire a standard interface for
/// serializing operations that may not be thread-safe.

class Lockable
{
protected:
	/// \brief Default constructor
	Lockable(bool locked) :
	pimpl_(new BasicLock(locked))
	{
	}

	/// \brief Destroy object
	virtual ~Lockable()
	{
		delete pimpl_;
	}

	/// \brief Lock the object
	///
	/// \return true if object was already locked
	virtual bool lock() { return pimpl_->lock(); }

	/// \brief Unlock the object
	virtual void unlock() { pimpl_->unlock(); }

	/// \brief Returns true if object is locked
	bool locked() const { return pimpl_->locked(); }

protected:
	/// \brief Set the lock state.  Protected, because this method is
	/// only for use by subclass assignment operators and the like.
	void set_lock(bool b) { pimpl_->set(b); }

private:
	// Don't allow default construction
	Lockable();

	// Pointer to implementation object
	Lock* pimpl_;
};

} // end namespace mysqlpp

#endif // MYSQLPP_LOCKABLE_H

