/*
 *  Copyright (c) 2008,2010 Cyrille Berger <cberger@cberger.net>
 *
 * 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, or (at your option) any later version of the License.
 *
 * 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; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifndef _CAUCHY_MACROS_P_H_
#define _CAUCHY_MACROS_P_H_

/**
 * @internal
 * @ingroup Cauchy
 * 
 * Allows to execute code at library initialisation.
 *
 * @code
 * class CoolObject {};
 * static std::vector\<CoolObject*\> staticCoolInstances;
 * STATIC_INITIALISATION( CoolObjects )
 * {
 *  for(int i =0; i < 10; ++i)
 *    staticCoolInstances.push_back( new CoolObject() );
 * }
 * @endcode
 * 
 * This will create a CoolObjectsFactory that you can use
 * to declare a friend class.
 * 
 */
#define STATIC_INITIALISATION(_name_) \
  class _name_##Factory { \
    public: \
      _name_##Factory(); \
  }; \
  _name_##Factory instance##_name_ ; \
  _name_##Factory::_name_##Factory()


/**
 * @internal
 * @ingroup Cauchy
 * 
 * Allows to execute code at library deletion.
 *
 * @code
 * class CoolObject {};
 * static std::vector\<CoolObject*\> staticCoolInstances;
 * STATIC_DELETER( CoolObjects )
 * {
 *  for(int i =0; i \< staticCoolInstances.size(); ++i)
 *    delete staticCoolInstances[i];
 * }
 * @endcode
 * 
 * This will create a CoolObjectsDeleter that you can use
 * to declare a friend class.
 * 
 */
#define STATIC_DELETER( _name_ ) \
  class _name_##Deleter { \
    public: \
      _name_##Deleter() {} \
      ~_name_##Deleter(); \
  }; \
  _name_##Deleter instance##_name_ ; \
  _name_##Deleter::~_name_##Deleter()

#define UNUSED( _var_) (void)_var_;

/**
 * @internal
 * @ingroup Cauchy
 * 
 * Used for static pointer that are deleted at exit time.
 */
#define STATIC_POINTER( _type_, _name_ ) \
  namespace { \
    class StaticPointer##_type_ { \
        _type_* t; \
        StaticPointer##_type_(const StaticPointer##_type_& ); \
        StaticPointer##_type_& operator=(const StaticPointer##_type_& ); \
      public: \
        StaticPointer##_type_() : t(0) {} \
        ~StaticPointer##_type_() { delete t; t = 0; } \
        inline operator _type_*() { return t; } \
        inline _type_* operator->() { return t; } \
        StaticPointer##_type_& operator=(_type_* _t) { t = _t; return *this; } \
    }; \
    StaticPointer##_type_ _name_; \
  }

namespace Cauchy {
  namespace Details {

    /**
     * @internal
     * @ingroup Cauchy
     * Helper class for the @ref foreach macro
     */
    struct ForeachInfoBase {};

    /**
     * @internal
     * @ingroup Cauchy
     * Helper class for the @ref foreach macro
     */
    template<typename T>
    struct ForeachInfo : public ForeachInfoBase {
      inline ForeachInfo( const T& t ) : it( t.begin() ), end( t.end() ), count(0)
      {
      }
      inline bool finished() const
      {
        return it == end;
      }
      inline void next() const
      {
        count = 0;
        ++it;
      }
      mutable typename T::const_iterator it, end;
      mutable int count;
    };
    template <typename T>
    inline ForeachInfo<T> CreateForeachInfo(const T& t)
    {
      return ForeachInfo<T>( t );
    }

    template <typename T>
    inline const ForeachInfo<T> *getForeachInfo(const ForeachInfoBase *base, const T *)
    {
      return static_cast<const ForeachInfo<T> *>(base); 
    }
    template <typename T>
    inline T* getForeachType(const T &) { return 0; }

  }
}

/**
 * @internal
 * @ingroup Cauchy
 * 
 * Macro to easilly iterate over elements of a countainer.
 *
 * @code
 * std::vector\<Object\> objects;
 * foreach(const Object& object, objects)
 * {
 *   ...
 * }
 * @endcode
 */
#define foreach(var, cont ) \
  for( const Cauchy::Details::ForeachInfoBase&  contInfo = Cauchy::Details::CreateForeachInfo( cont ); \
       not Cauchy::Details::getForeachInfo( &contInfo, true ? 0 : Cauchy::Details::getForeachType(cont) )->finished(); \
       Cauchy::Details::getForeachInfo( &contInfo, true ? 0 : Cauchy::Details::getForeachType(cont) )->next() ) \
    for( var = *Cauchy::Details::getForeachInfo( &contInfo, true ? 0 : Cauchy::Details::getForeachType(cont) )->it; \
         Cauchy::Details::getForeachInfo( &contInfo, true ? 0 : Cauchy::Details::getForeachType(cont) )->count < 1; \
         ++Cauchy::Details::getForeachInfo( &contInfo, true ? 0 : Cauchy::Details::getForeachType(cont) )->count )

#endif
