///////////////////////////////////////////////////////////////////////////////
//
// File: CountedObject.h
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: 
//
///////////////////////////////////////////////////////////////////////////////

#ifndef NEKTAR_UNIT_TESTS_COUNTED_OBJECT_H
#define NEKTAR_UNIT_TESTS_COUNTED_OBJECT_H


#include <boost/test/unit_test.hpp>
#include <iostream>

#include <ExpressionTemplates/Node.hpp>
#include <ExpressionTemplates/ExpressionEvaluator.hpp>

namespace Nektar
{
    
    template<typename DerivedType>
    class CountedObject
    {
        public:
            CountedObject() :
                value(0)
            {
                ++numberDefaultConstructed;
            }

            explicit CountedObject(unsigned int v) :
                value(v)
            {
                ++numberConstructedFromInt;
                ++numberOf1ParameterConstructions;
            }

            CountedObject(unsigned int a1, unsigned int a2) :
                value(a1 + a2)
            {
                ++numberOf2ParameterConstructions;
            }

            CountedObject(unsigned int a1, unsigned int a2, unsigned int a3) :
                value(a1 + a2 + a3)
            {
                ++numberOf3ParameterConstructions;
            }

            CountedObject(const CountedObject<DerivedType>& rhs) :
                value(rhs.value)
            {
                ++numberCopied;
            }

            #ifdef NEKTAR_USE_EXPRESSION_TEMPLATES
            template<typename L, typename Op, typename R>
            CountedObject(const expt::Node<L, Op, R>& rhs) :
                value(0)
            {
                ++numberOfExpressionConstructions;
                expt::ExpressionEvaluator::Evaluate(rhs, *this);
            }

            template<typename L, typename Op, typename R>
            CountedObject<DerivedType> operator=(const expt::Node<L, Op, R>& rhs)
            {
                ++numberOfExpressionAssignments;
                value = 0;
                expt::ExpressionEvaluator::Evaluate(rhs, *this);
                return *this;
            }
            #endif
            
            virtual ~CountedObject()
            {
                ++numberDestroyed;
            }

            CountedObject<DerivedType>& operator=(const CountedObject<DerivedType>& rhs)
            {
                ++numberAssigned;
                value = rhs.value;
                return *this;
            }

            bool operator==(const CountedObject<DerivedType>& rhs) const
            {
                return value == rhs.value;
            }

            bool operator!=(const CountedObject<DerivedType>& rhs) const
            {
                return !(*this == rhs);
            }

            CountedObject<DerivedType>* clone() const
            {
                ++numberCloned;
                return new CountedObject<DerivedType>(*this);
            }

            static void ClearCounters()
            {
                numberDefaultConstructed = 0;
                numberConstructedFromInt = 0;
                numberDestroyed = 0;
                numberCopied = 0;
                numberAssigned = 0;
                numberCloned = 0;
                numberOf1ParameterConstructions = 0;
                numberOf2ParameterConstructions = 0;
                numberOf3ParameterConstructions = 0;
                numberOfExpressionConstructions = 0;
                numberOfExpressionAssignments = 0;
            }

            static void Check(unsigned int expectedDefaultConstructed, unsigned int expectedConstructedFromInt,
                                unsigned int expectedDestroyed, unsigned int expectedCopied, unsigned int expectedCloned,
                                unsigned int expectedAssigned)
            {
                BOOST_CHECK_EQUAL(numberDefaultConstructed, expectedDefaultConstructed);
                BOOST_CHECK_EQUAL(numberConstructedFromInt, expectedConstructedFromInt);
                BOOST_CHECK_EQUAL(numberDestroyed, expectedDestroyed);
                BOOST_CHECK_EQUAL(numberCopied, expectedCopied);
                BOOST_CHECK_EQUAL(numberAssigned, expectedAssigned);
                BOOST_CHECK_EQUAL(numberCloned, expectedCloned);
            }

            unsigned int GetValue() const { return value; }
            operator unsigned int() const { return value; }
            unsigned int value;

            static unsigned int numberDefaultConstructed;
            static unsigned int numberConstructedFromInt;
            static unsigned int numberDestroyed;
            static unsigned int numberCopied;
            static unsigned int numberAssigned;
            static unsigned int numberCloned;
            static unsigned int numberOf1ParameterConstructions;
            static unsigned int numberOf2ParameterConstructions;
            static unsigned int numberOf3ParameterConstructions;
            static unsigned int numberOfExpressionConstructions;
            static unsigned int numberOfExpressionAssignments;
    };
    
    template<typename T>
    std::ostream& operator<<(std::ostream& os, const CountedObject<T>& lhs)
    {
        os << lhs.GetValue();
        return os;
    }

    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberDefaultConstructed = 0;
    
    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberConstructedFromInt = 0;
    
    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberDestroyed = 0;
    
    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberCopied = 0;
    
    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberAssigned = 0;
    
    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberCloned = 0;

    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberOf1ParameterConstructions = 0;

    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberOf2ParameterConstructions = 0;

    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberOf3ParameterConstructions = 0;

    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberOfExpressionConstructions = 0;

    template<typename DerivedType>
    unsigned int CountedObject<DerivedType>::numberOfExpressionAssignments = 0;
}

#endif //NEKTAR_UNIT_TESTS_COUNTED_OBJECT_H

/**
    $Log: CountedObject.h,v $
    Revision 1.6  2008/01/20 04:07:46  bnelson
    *** empty log message ***

    Revision 1.5  2007/09/12 03:59:41  bnelson
    *** empty log message ***

    Revision 1.4  2007/05/16 02:47:29  bnelson
    Fixed a non-explicit constructor.

    Revision 1.3  2007/01/29 01:37:16  bnelson
    *** empty log message ***

    Revision 1.2  2006/11/12 17:59:47  bnelson
    *** empty log message ***

    Revision 1.1  2006/11/11 01:32:52  bnelson
    *** empty log message ***

**/
