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

  Program:   ITK-SNAP
  Module:    $RCSfile: ImageWrapper.txx,v $
  Language:  C++
  Date:      $Date: 2010/10/14 16:21:04 $
  Version:   $Revision: 1.11 $
  Copyright (c) 2007 Paul A. Yushkevich

  This file is part of ITK-SNAP

  ITK-SNAP 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, either version 3 of the License, or
  (at your option) any later version.

  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

  -----

  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.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.

  -----

  Copyright (c) 2003 Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.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 ADAPTIVESLICINGPIPELINE_H
#define ADAPTIVESLICINGPIPELINE_H

#include "itkImageToImageFilter.h"
#include "itkTransform.h"
#include "itkDataObjectDecorator.h"
#include "IRISSlicer.h"
#include "NonOrthogonalSlicer.h"
#include "SNAPCommon.h"

class ImageCoordinateTransform;

using itk::DataObjectDecorator;
using itk::ProcessObject;

namespace itk
{
template <typename TParametersValueType, unsigned int NInputDimensions, unsigned int NOutputDimensions>
class Transform;
}


/**
 * This filter encapsulates the ITK-SNAP slicing pipeline. It includes both
 * the straight (orthogonal) slicer and the oblique slicer. The input to this
 * pipeline is a 3D image, and it will generate slices for selected time points
 */
template <typename TInputImage, typename TOutputImage, typename TPreviewImage>
class AdaptiveSlicingPipeline : public itk::ImageToImageFilter<TInputImage, TOutputImage>
{
public:
  /** Standard class typedefs. */
  typedef AdaptiveSlicingPipeline                            Self;
  typedef itk::ImageToImageFilter<TInputImage, TOutputImage> Superclass;
  typedef itk::SmartPointer<Self>                            Pointer;
  typedef itk::SmartPointer<const Self>                      ConstPointer;

  typedef TInputImage                                InputImageType;
  typedef typename InputImageType::ConstPointer      InputImagePointer;
  typedef typename InputImageType::PixelType         InputPixelType;
  typedef typename InputImageType::InternalPixelType InputComponentType;

  typedef TOutputImage                                OutputImageType;
  typedef typename OutputImageType::Pointer           OutputImagePointer;
  typedef typename OutputImageType::PixelType         OutputPixelType;
  typedef typename OutputImageType::InternalPixelType OutputComponentType;

  typedef TPreviewImage                                PreviewImageType;
  typedef typename PreviewImageType::Pointer           PreviewImagePointer;
  typedef typename PreviewImageType::PixelType         PreviewPixelType;
  typedef typename PreviewImageType::InternalPixelType PreviewComponentType;

  // Output slice image dimension, should be 2
  itkStaticConstMacro(SliceDimension, unsigned int, TOutputImage::ImageDimension);

  // Input image dimension, should be 3
  itkStaticConstMacro(InputImageDimension, unsigned int, TInputImage::ImageDimension);

  /** Slicers */
  typedef IRISSlicer<TInputImage, TOutputImage, TPreviewImage> OrthogonalSlicerType;
  typedef NonOrthogonalSlicer<TInputImage, TOutputImage>       NonOrthogonalSlicerType;

  /** Reference space for non-orthogonal slicing */
  typedef typename itk::ImageBase<InputImageDimension> NonOrthogonalSliceReferenceSpace;

  /** Transform */
  typedef ImageCoordinateTransform                                         OrthogonalTransformType;
  typedef itk::Transform<double, InputImageDimension, InputImageDimension> ObliqueTransformType;

  /** Some more typedefs. */
  typedef typename InputImageType::RegionType  InputImageRegionType;
  typedef typename OutputImageType::RegionType OutputImageRegionType;

  /** Slice index */
  typedef itk::Index<InputImageDimension> IndexType;

  /** Method for creation through the object factory. */
  itkNewMacro(Self)

  /** Run-time type information (and related methods). */
  itkTypeMacro(AdaptiveSlicingPipeline, ImageToImageFilter)

  /** Reference image input */
  virtual void SetObliqueReferenceImage(const NonOrthogonalSliceReferenceSpace *input);
  virtual const NonOrthogonalSliceReferenceSpace *GetObliqueReferenceImage() const;
  // itkSetInputMacro(ObliqueReferenceImage, NonOrthogonalSliceReferenceSpace)
  // itkGetInputMacro(ObliqueReferenceImage, NonOrthogonalSliceReferenceSpace)

  /** Preview image input */
  itkSetInputMacro(PreviewImage, PreviewImageType)
  itkGetInputMacro(PreviewImage, PreviewImageType)

  /** Orthogonal Transform input */
  itkSetDecoratedObjectInputMacro(OrthogonalTransform, OrthogonalTransformType)
  itkGetDecoratedObjectInputMacro(OrthogonalTransform, OrthogonalTransformType)

  /** Oblique Transform input */
  itkSetDecoratedObjectInputMacro(ObliqueTransform, ObliqueTransformType)
  itkGetDecoratedObjectInputMacro(ObliqueTransform, ObliqueTransformType)

  /** Which slicing pipeline to use */
  virtual void SetUseOrthogonalSlicing(bool value);
  itkGetMacro(UseOrthogonalSlicing, bool)

  /** Get the slice index for the orthogonal slicer */
  itkGetMacro(SliceIndex, IndexType)

  /** Set the slice index for orthogonal slicer */
  void SetSliceIndex(const IndexType &index);

  /** Interpolation type */
  void SetUseNearestNeighbor(bool flag);
  bool GetUseNearestNeighbor() const;

  /** Access the internal orthogonal slicer */
  itkGetMacro(OrthogonalSlicer, OrthogonalSlicerType *)

  /** Access the internal oblique slicer */
  itkGetMacro(ObliqueSlicer, NonOrthogonalSlicerType *)

protected:
  AdaptiveSlicingPipeline();
  ~AdaptiveSlicingPipeline();

  virtual void VerifyInputInformation() const ITK_OVERRIDE {}

  virtual void GenerateOutputInformation() ITK_OVERRIDE;

  virtual void PropagateRequestedRegion(itk::DataObject *object) ITK_OVERRIDE;

  virtual void CallCopyOutputRegionToInputRegion(InputImageRegionType &destRegion,
                                                 const OutputImageRegionType &srcRegion) ITK_OVERRIDE;

  virtual void GenerateData() ITK_OVERRIDE;

  itk::SmartPointer<OrthogonalSlicerType>                   m_OrthogonalSlicer;
  itk::SmartPointer<NonOrthogonalSlicerType>                m_ObliqueSlicer;
  itk::SmartPointer<const NonOrthogonalSliceReferenceSpace> m_ObliqueReferenceImage;

  bool m_UseOrthogonalSlicing;

  IndexType m_SliceIndex;

  void MapInputsToSlicers();
};


#ifndef ITK_MANUAL_INSTANTIATION
#  include "AdaptiveSlicingPipeline.txx"
#endif


#endif // ADAPTIVESLICINGPIPELINE_H
