/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: itkImageToImageFilterDetail.h,v $
  Language:  C++
  Date:      $Date: 2005/05/13 19:44:21 $
  Version:   $Revision: 1.8 $

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef __itkImageToImageFilterDetail_h
#define __itkImageToImageFilterDetail_h

#include "itkImageRegion.h"
#include "itkSmartPointer.h"

namespace itk
{

/** ImageToImageFilterDetail namespace to house implementations of
 * functions that are dependent on dimension. These functions are
 * overloaded based on type unique for each different dimension.
 * These functions cannot be member functions of a class like
 * ImageToImageFilter since explicit instantiation of an
 * ImageToImageFilter would force the instantiation of all versions of
 * these overloaded functions.
 */
namespace ImageToImageFilterDetail
{
  /** \struct  DispatchBase
   * \brief Base class for a class used to dispatch to dimension specific implementations.
   *
   * DispatchBase is base class used as the default case when implementations
   * are dispatched to overloaded routines based on dimension.
   *
   * \sa Dispatch
   */
  struct DispatchBase {};

  /** \struct BooleanDispatch
   * \brief Templated class to produce a unique type "true" and "false".
   *
   * BooleanDispatch is a templated class that produce a unique type for
   * for "true" and for "false".  These types may be used to decide which
   * version of an overloaded function to call.
   */
  template <bool>
  struct BooleanDispatch {};

  /** \struct IntDispatch
   * \brief Templated class to produce a unique type for each integer
   *
   * IntDispatch is a templated class that produces a unique
   * type for each integer.  IntDispatch is typically
   * used as a parameter to an overloaded function where a different
   * version of the routine would need to be called for each integer value.
   */
  template <int>
  struct IntDispatch : public DispatchBase {};
  
  /** \struct UnsignedIntDispatch
   * \brief Templated class to produce a unique type for each unsigned integer (usually a dimension).
   *
   * UnsignedIntDispatch is a templated class that produces a unique
   * type for each unsigned integer.  UnsignedIntDispatch is typically
   * used as a parameter to an overloaded function where each version
   * of the overloaded function is for a unique dimension.  For
   * instance, an algorithm may provide two implementations: one
   * optimized for two-dimensional images and another for any of other
   * data dimension.  For instance:
   *
   *     void Calculate(const DispatchBase&);           // General ND version
   *     void Calculate(const UnsignedIntDispatch<2>&); // 2D optimized version
   */
  template <unsigned int>
  struct UnsignedIntDispatch : public DispatchBase {};

  /** \struct BinaryBooleanDispatch
   * \brief Templated class to produce a unique type for a pairing of booleans.
   *
   * BinaryBooleanDispatch is a templated class that produces a unique type
   * for each pairing of two boolean values ((true, true), (true, false),
   * (false, true), (false, false)).
   */
  template <bool B1, bool B2>
  struct BinaryBooleanDispatch
  {
    /** Typedefs to extract the unique types for the first and second
        template parameters (true/false) */
    typedef BooleanDispatch<B1> FirstType;
    typedef BooleanDispatch<B2> SecondType;
  };

  /** \struct BinaryIntDispatch
   * \brief Templated class to produce a unique type for a pairing of integers.
   *
   * IntBooleanDispatch is a templated class that produces a unique type
   * for each pairing of two integer values.
   */
  template <int D1, int D2>
  struct BinaryIntDispatch
  {
    /** Typedefs to extract the unique types for the first and second
        template parameters (unique type for the integer value) */
    typedef IntDispatch<D1> FirstType;
    typedef IntDispatch<D2> SecondType;
  };
  
  /** \struct BinaryUnsignedIntDispatch
   * \brief Templated class to produce a unique type for a pairing of unsigned integers (usually two dimensions).
   *
   * BinaryUnsignedIntDispatch is a templated class that produces a
   * unique type for a pairing of unsigned integers.
   * BinaryUnsignedIntDispatch is typically used a parameter to an
   * overloaded function where each version of the overloaded function
   * is for a different pairing of unsigned integers.  This type may
   * be used to produce a unique type for an (input dimension, output
   * dimension) pairing.
   */
  template <unsigned int D1, unsigned int D2>
  struct BinaryUnsignedIntDispatch : public DispatchBase
  {
    /** Typedefs to extract the unique types for the first and second
        template parameters (unique type for the unsigned integer value) */
    typedef UnsignedIntDispatch<D1> FirstType;
    typedef UnsignedIntDispatch<D2> SecondType;
    
    /** Helper types to determine whether the two integers are the same,
     * the first greater than the second, or the first less than the second.
     *
     * ComparisonType will be either IntDispatch<0>, IntDispatch<1>, or
     * IntDispatch<-1>. 
     *
     * IntDispatch<0> means the two specified integers are the same.
     * IntDispatch<1> means the first integer is greater than the second
     * IntDispatch<-1> means the first integer is less than the second
     *
     * The FirstEqualsSecondType, FirstGreaterThanSecondType,
     * FirstLessThanSecondType typedefs are provided as convenience types
     * which can be used to declare arguments to functions.  They themselves
     * do not indicate the relationship between D1 and D2.
     */
    typedef IntDispatch<(D1 > D2) - (D1 < D2)> ComparisonType;
    typedef IntDispatch<0>  FirstEqualsSecondType;  
    typedef IntDispatch<1>  FirstGreaterThanSecondType;  
    typedef IntDispatch<-1> FirstLessThanSecondType;  
  };

  /**
   * Copy an image region (start index and size) for the case where
   * the source and destination region are the same dimension.  This
   * is a trivial copy of a region. This is an overloaded function.
   * The other versions of this functions handle the case where the
   * destination dimension is greater than the source dimension and
   * the case where the destination dimension is less than the source
   * dimension.
   *
   * Note that the use of source and destination reflect where where
   * is information is coming from and going to.  When used in the
   * pipeline mechanism, the region requested by the output of a
   * filter is used to define the region required on the input.  In
   * this case the output of the filter is the source region and the
   * input of the filter is the destination region.
   */
  template <unsigned int D1, unsigned int D2>
  void ImageToImageFilterDefaultCopyRegion(const typename
                  BinaryUnsignedIntDispatch<D1, D2>::FirstEqualsSecondType &,
                  ImageRegion<D1> &destRegion,
                  const ImageRegion<D2> &srcRegion)
  {
    destRegion = srcRegion;
  }

  /**
   * Copy an image region (start index and size) for the case where
   * the source region has a greater dimension than the destination
   * region.  This copies the first portion of the source into
   * destination. This is an overloaded function.  The other versions
   * of this functions handle the case where the source dimension is
   * less than the destination dimension and the case where the
   * destination and source are the same dimension.
   *
   * Note that the use of source and destination reflect where
   * where is information is coming from and going to.  When used
   * in the pipeline mechanism, the region requested by the output
   * of a filter is used to define the region required on the input.
   * In this case the output of the filter is the source and the
   * input of the filter is the destination.
   */
  template <unsigned int D1, unsigned int D2>
  void ImageToImageFilterDefaultCopyRegion(const typename
                  BinaryUnsignedIntDispatch<D1, D2>::FirstLessThanSecondType &,
                  ImageRegion<D1> &destRegion,
                  const ImageRegion<D2> &srcRegion)
  {
    // Source dimension is greater than the destination dimension, copy the
    // first part of the source into the destination
    unsigned int dim;
    Index<D1> destIndex;
    Size<D1>  destSize;
    const Index<D2> &srcIndex = srcRegion.GetIndex();
    const Size<D2> &srcSize = srcRegion.GetSize();
    
    // copy what we can
    for (dim=0; dim < D1; ++dim)
      {
      destIndex[dim] = srcIndex[dim];
      destSize[dim] = srcSize[dim];
      }
    
    destRegion.SetIndex(destIndex);
    destRegion.SetSize(destSize);
  }
  
  /**
   * Copy an image region (start index and size) for the case where
   * the source region has a lesser dimension than the destination
   * region.  This copies the source into the first part of the
   * destination. This is an overloaded function.  The other versions
   * of this functions handle the case where the source dimension is
   * less than the destination dimension and the case where the
   * destination and source are the same dimension.
   *
   * Note that the use of source and destination reflect where
   * where is information is coming from and going to.  When used
   * in the pipeline mechanism, the region requested by the output
   * of a filter is used to define the region required on the input.
   * In this case the output of the filter is the source and the
   * input of the filter is the destination.
   */
  template <unsigned int D1, unsigned int D2>
  void ImageToImageFilterDefaultCopyRegion(const typename
               BinaryUnsignedIntDispatch<D1, D2>::FirstGreaterThanSecondType &,
               ImageRegion<D1> &destRegion,
               const ImageRegion<D2> &srcRegion)
  {
    // Source dimension is less than the destination dimension, copy source
    // into the first part of the destination and set zeros elsewhere.
    unsigned int dim;
    Index<D1> destIndex;
    Size<D1>  destSize;
    const Index<D2> &srcIndex = srcRegion.GetIndex();
    const Size<D2> &srcSize = srcRegion.GetSize();
    
    // copy what we can
    for (dim=0; dim < D2; ++dim)
      {
      destIndex[dim] = srcIndex[dim];
      destSize[dim] = srcSize[dim];
      }
    // fill in the rest of the dimensions with zero/one
    for (; dim < D1; ++dim)
      {
      destIndex[dim] = 0;
      destSize[dim] = 1;
      }
    
    destRegion.SetIndex(destIndex);
    destRegion.SetSize(destSize);
  }


  /** \class ImageRegionCopier
   * \brief Function object used to dispatching to a routine to copy a region (start index and size).
   *
   * Function object used for dispatching to various routines to copy
   * a region (start index and size).  Most filters use this function
   * object as trivial copy because they require the input image
   * dimension to match the output image dimension.  However, some
   * filters like itk::ExtractImageFilter can support output images of
   * a lower dimension that the input.
   *
   * This function object is used by the default implementation of
   * ImageToImageFilter::GenerateInputRequestedRegion(). It can also
   * be used in routines like ImageSource::ThreadedGenerateData()
   * where a filter may need to map the the output region for a
   * particular thread to an input region.
   *
   * This copier uses a "dispatch pattern" to call one of three
   * overloaded functions depending on whether the source and
   * destination dimensions are the same, the source is of a higher
   * dimension than the destination, or the source is of a lower
   * dimension than the destination. The use of an overloaded function
   * is required for proper compilation of the various cases.
   * 
   * For the latter two cases, trivial implementations are used.  If
   * the source dimension is a lower dimension than the destination,
   * the output region information is copied into the first portion of
   * the destination region and the rest of the input region is set to
   * zero.  If the source region is a higher dimension than the
   * destination, the first portion of the source region is copied to
   * the destination region.
   *
   * If a filter needs a different behavior is will need to override
   * the CallCopyOutputRegionToInputRegion() method or the 
   * CallCopyInputRegionToOutputRegion() method and delegate to the
   * appropriate RegionCopier class. 
   */
  template <unsigned int D1, unsigned int D2>
    class ITK_EXPORT ImageRegionCopier 
  {
  public:
    virtual void operator() (ImageRegion<D1> &destRegion,
                            const ImageRegion<D2> &srcRegion) const
    {
      typedef typename BinaryUnsignedIntDispatch<D1, D2>::ComparisonType ComparisonType;
      ImageToImageFilterDefaultCopyRegion<D1, D2>(
                      ComparisonType(),
                      destRegion, srcRegion);
    }
    virtual ~ImageRegionCopier() {}
  };


  /** Stream operator for ImageRegionCopier objects. Just prints the RTTI
      typename. */
  template<unsigned int D1, unsigned int D2>
  std::ostream & operator<<(std::ostream &os, const ImageRegionCopier<D1, D2> &
                            copier)
  {
    os << "ImageRegionCopier: "
       << typeid(ImageRegionCopier<D1, D2>).name() << std::endl;
    return os;
  }

  /** operator!= for ImageRegionCopier objects. */
  template<unsigned int D1, unsigned int D2>
  bool operator!=(const ImageRegionCopier<D1, D2> &c1,
                  const ImageRegionCopier<D1, D2> &c2)
  {
    return &c1 != &c2;
  }
  
} // end of namespace ImageToImageFilterDetail
    
} // end namespace itk

//#ifndef ITK_MANUAL_INSTANTIATION
//#include "itkImageToImageFilterDetail.txx"
//#endif

#endif
