/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework 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 as in version 2 of the License.

 * 
 * The iWear Framework 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
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_ATOMICCOUNTER_H
#define __IWEAR_ATOMICCOUNTER_H

#ifndef __IWEAR_THREADLOCKER_H
#include <iwear/threadlocker.h>
#endif

#include <memory>

namespace iwear
{

/**
 * class that can atomically 
 */    
template<class T>
class AtomicCounter
{
protected:
    std::auto_ptr<Mutex> aptr;
    Mutex* mutex;
    T counter;
public:
    AtomicCounter( const AtomicCounter& ac );

    AtomicCounter( Mutex* m = 0);
    AtomicCounter( Mutex& m );

    AtomicCounter( const T& in, Mutex* m = 0);
    AtomicCounter( const T& in, Mutex& m );

    operator T& ( void ) { return counter; }
    operator const T& ( void ) const { return counter; }

    const AtomicCounter& operator++( void );
    const AtomicCounter operator++( int );

    const AtomicCounter& operator--( void );
    const AtomicCounter operator--( int );
};

template<class T>
AtomicCounter<T>::AtomicCounter( const AtomicCounter& ac )/*{{{*/

    : aptr(0),
	mutex(ac.mutex),
	counter(ac.counter)
{
    if( ac.aptr.get() )
    {
	// We cant use its private mutex...
	mutex = new Mutex;
	aptr = std::auto_ptr<Mutex>(mutex);
    }
}/*}}}*/

template<class T>
AtomicCounter<T>::AtomicCounter( const T& in, Mutex* m )/*{{{*/
    : aptr(0), 
      mutex(m),
      counter(in)
{
    if( ! m )
    {
	mutex = new Mutex;
	aptr = std::auto_ptr<Mutex>(mutex);
    }
}/*}}}*/

template<class T>
AtomicCounter<T>::AtomicCounter( const T& in, Mutex& m )/*{{{*/
    : aptr(0),
    mutex(&m),
    counter(in)
{
}/*}}}*/

template<class T>
AtomicCounter<T>::AtomicCounter( Mutex* m )/*{{{*/
    : aptr(0), 
      mutex(m),
      counter(T())
{
    if( ! m )
    {
	mutex = new Mutex;
	aptr = std::auto_ptr<Mutex>(mutex);
    }
}/*}}}*/

template<class T>
AtomicCounter<T>::AtomicCounter( Mutex& m )/*{{{*/
    : aptr(0),
    mutex(&m),
    counter(T())
{
}/*}}}*/

template<class T>
const AtomicCounter<T>& AtomicCounter<T>::operator++( void )/*{{{*/
{
    ThreadLocker tl(mutex);
    ++counter;
    return *this;
}/*}}}*/

template<class T>
const AtomicCounter<T> AtomicCounter<T>::operator++( int )/*{{{*/
{
    ThreadLocker tl(mutex);
    if( aptr.get() )
    {
	AtomicCounter<T> ret(counter);
	counter ++;
	return ret;
    }
    else
    {
	AtomicCounter<T> ret(counter,mutex);
	counter ++;
	return ret;
    }
}/*}}}*/

template<class T>
const AtomicCounter<T>& AtomicCounter<T>::operator--( void )/*{{{*/
{
    ThreadLocker tl(mutex);
    --counter;
    return *this;
}/*}}}*/

template<class T>
const AtomicCounter<T> AtomicCounter<T>::operator--( int )/*{{{*/
{
    ThreadLocker tl(mutex);
    if( aptr.get() )
    {
	AtomicCounter<T> ret(counter);
	counter --;
	return ret;
    }
    else
    {
	AtomicCounter<T> ret(counter,mutex);
	counter --;
	return ret;
    }
}/*}}}*/


}
#endif

