/*
 *  ZThreads, a platform-independant, multithreading and 
 *  synchroniation library
 *
 *  Copyright (C) 2000-2002, Eric Crahen, See LGPL.TXT for details
 *
 *  This library 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.
 *
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  SUNY @ Buffalo, hereby disclaims all copyright interest in the
 *  ZThreads library written by Eric Crahen
 */

#ifndef __ZTCOUNTED_H__
#define __ZTCOUNTED_H__

#include "zthread/ZThread.h"
#include "zthread/Guard.h"
#include "zthread/FastMutex.h"

namespace ZThread {
  
/**
 * @class Counted
 *
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-03-05T09:32:50-0500>
 * @version 2.0.0
 *
 * Thread-safe wrapper to implement a counted reference. 
 *
 * This is a class wide lock. In otherwords, all AutoPtr<MyClass> 
 * objects are locked with the same Mutex no matter how many actual 
 * MyClass implementations are being used.
 *
 * Instance level locking would be possible to implement - but would
 * not be practical for a large number of objects.
 *
 */
template <class COUNTED, class MUTEX = FastMutex>
class Counted {
  
  COUNTED*  _pInstance;
  
  public:
  
  
  /**
   * Create a new COUNTED reference from the default constructor
   */
  Counted() throw() {
    
    Guard<MUTEX> guard(_Mutex);
    
    _pInstance = new COUNTED;
    _pCount = new int(1);
    
  };
  
  /**
   * Create a new Counted from an existing COUNTED reference 
   *
   * The use of this constructor is really discouraged. Possible
   * candidate for deprecation. The absence of this method would allow
   * for a streamlined way to lock at implementation level rather than class
   * level - However, for a large number of implementations this will not
   * be practical. So class level locking is used for now
   *
   */
  Counted(COUNTED* pImpl) 
    throw() {
    
    Guard<MUTEX> guard(_Mutex);
    
    _pInstance = pImpl;
    _pCount = new int(1);
    
  };
  
  /**
   * Create a new Counted from another Counted
   */
  Counted(const Counted& ptr) 
    throw() {
    
    Guard<MUTEX> guard(_Mutex);
    
    _pInstance  = ptr._pInstance;
    _pCount = ptr._pCount;
    
    (*_pCount)++;
    
  }
  
  /**
   * Destroy the Counted and check for release of the implementation
   */
  ~Counted() 
    throw() {
    
    Guard<MUTEX> guard(_Mutex);   
    
    --(*_pCount);
    
    if( (*_pCount) < 1 ) {
      delete _pInstance;
      delete _pCount;
    }
    
  };
  
  /**
   * Assignment
   */
  Counted& operator=(const Counted& ptr) 
    throw() {
    
    Guard<MUTEX> guard(_Mutex);   
    
    if(ptr._pInstance != _pInstance) {

      --(*_pCount);
      
      if( (*_pCount) < 1 ) {

        delete _pInstance;
        delete _pCount;

      }
      
      _pInstance  = ptr._pInstance;
      _pCount = ptr._pCount;
      
      (*_pCount)++;

    }
    
    return *this;
    
  }
  
  /**
   * Get a reference to the underlying implementation
   */
  COUNTED* operator->() throw() { return _pInstance; }
  
  /**
   * Get a reference to the underlying implementation
   */
  const COUNTED* operator->() const throw() { return _pInstance; }
  

  private:
  
  static MUTEX  _Mutex;
  int* _pCount;
  
}; /*Counted */

template <class COUNTED, class MUTEX>
MUTEX Counted<COUNTED, MUTEX>::_Mutex;


};

#endif
