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

  Program:   Advanced Normalization Tools
  Date:      $$
  Version:   $ $

  Copyright (c) ConsortiumOfANTS. All rights reserved.
  See accompanying COPYING.txt or
 https://github.com/stnava/ANTs/blob/master/ANTSCopyright.txt 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 __itkVectorImageFileWriter_h
#define __itkVectorImageFileWriter_h

#include "itkProcessObject.h"
#include "itkImageIOBase.h"
#include "itkExceptionObject.h"
#include "itkSize.h"
#include "itkImageIORegion.h"

namespace itk
{
/** \brief Base exception class for IO problems during writing. */
class VectorImageFileWriterException : public ExceptionObject
{
public:
  /** Run-time information. */
  itkTypeMacro( VectorImageFileWriterException, ExceptionObject );

  /** Constructor. */
  VectorImageFileWriterException(const char *file, unsigned int line, const char* message = "Error in IO",
                                 const char* loc = "Unknown" ) :
    ExceptionObject(file, line, message, loc)
  {
  }

  /** Constructor. */
  VectorImageFileWriterException(const std::string & file, unsigned int line, const char* message = "Error in IO",
                                 const char* loc = "Unknown" ) :
    ExceptionObject(file, line, message, loc)
  {
  }
};

/** \class VectorImageFileWriter
 * \brief Writes the deformation field as component images files.
 *
 * \sa VectorImageFileWriter
 * \sa ImageSeriesReader
 * \sa ImageIOBase
 *
 * \ingroup IOFilters
 */
template <class TVectorImage, class TImage>
class VectorImageFileWriter :
  public         ProcessObject
{
public:
  /** Standard class typedefs. */
  typedef VectorImageFileWriter    Self;
  typedef ProcessObject            Superclass;
  typedef SmartPointer<Self>       Pointer;
  typedef SmartPointer<const Self> ConstPointer;

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

  /** Run-time type information (and related methods). */
  itkTypeMacro(VectorImageFileWriter, VectorImageFileWriter);

  /** Some convenient typedefs. */
  typedef TVectorImage                         VectorImageType;
  typedef typename VectorImageType::Pointer    VectorImagePointer;
  typedef typename VectorImageType::RegionType VectorImageRegionType;
  typedef typename VectorImageType::PixelType  VectorImagePixelType;
  typedef TImage                               ImageType;
  typedef typename ImageType::Pointer          ImagePointer;
  typedef typename ImageType::RegionType       ImageRegionType;
  typedef typename ImageType::PixelType        ImagePixelType;

  /** Set/Get the image input of this writer.  */
  void SetInput(const VectorImageType *input);

  const VectorImageType * GetInput();

  const VectorImageType * GetInput(unsigned int idx);

  /** Specify the name of the output file to write. */
  itkSetStringMacro(FileName);
  itkGetStringMacro(FileName);

  /** Set/Get the ImageIO helper class. Usually this is created via the object
   * factory mechanism that determines whether a particular ImageIO can
   * write a certain file. This method provides a way to get the ImageIO
   * instance that is created, or one can be manually set where the
   * IO factory mechanism may not work (for example, raw image files or
   * image files with non-standard filename suffix's.
   * If the user specifies the ImageIO, we assume she makes the
   * correct choice and will allow a file to be created regardless of
   * the file extension. If the factory has set the ImageIO, the
   * extension must be supported by the specified ImageIO. */
  void SetImageIO(ImageIOBase* io)
  {
    if( this->m_ImageIO != io )
      {
      this->Modified();
      this->m_ImageIO = io;
      }
    m_FactorySpecifiedImageIO = false;
  }

  itkGetModifiableObjectMacro(ImageIO, ImageIOBase);

  /** A special version of the Update() method for writers.  It
   * invokes start and end events and handles releasing data. It
   * eventually calls GenerateData() which does the actual writing.
   * Note: the write method will write data specified by the
   * IORegion. If not set, then then the whole image is written.  Note
   * that the region will be cropped to fit the input image's
   * LargestPossibleRegion. */
  virtual void Write();

  /** Specify the region to write. If left NULL, then the whole image
   * is written. */
  void SetIORegion(const ImageIORegion & region);

  itkGetConstReferenceMacro( IORegion, ImageIORegion );

  /** Aliased to the Write() method to be consistent with the rest of the
   * pipeline. */
  virtual void Update()
  {
    this->Write();
  }

  /** Set the compression On or Off */
  itkSetMacro(UseCompression, bool);
  itkGetConstReferenceMacro(UseCompression, bool);
  itkBooleanMacro(UseCompression);

  /** Set the Avants' naming convention On or Off */
  itkSetMacro(UseAvantsNamingConvention, bool);
  itkGetConstReferenceMacro(UseAvantsNamingConvention, bool);
  itkBooleanMacro(UseAvantsNamingConvention);

  /** Set the Avants' naming convention On or Off */
  itkSetMacro(UseZhangNamingConvention, bool);
  itkGetConstReferenceMacro(UseZhangNamingConvention, bool);
  itkBooleanMacro(UseZhangNamingConvention);

  /** By default the MetaDataDictionary is taken from the input image and
   *  passed to the ImageIO. In some cases, however, a user may prefer to
   *  introduce her/his own MetaDataDictionary. This is often the case of
   *  the ImageSeriesWriter. This flag defined whether the MetaDataDictionary
   *  to use will be the one from the input image or the one already set in
   *  the ImageIO object. */
  itkSetMacro(UseInputMetaDataDictionary, bool);
  itkGetConstReferenceMacro(UseInputMetaDataDictionary, bool);
  itkBooleanMacro(UseInputMetaDataDictionary);
protected:
  VectorImageFileWriter();
  ~VectorImageFileWriter();
  void PrintSelf(std::ostream& os, Indent indent) const;

  /** Does the real work. */
  void GenerateData();

private:
  VectorImageFileWriter(const Self &); // purposely not implemented
  void operator=(const Self &);        // purposely not implemented

  std::string m_FileName;
  std::string m_ComponentImageFileName;
  bool        m_UseAvantsNamingConvention;
  bool        m_UseZhangNamingConvention;

  ImagePointer m_Image;

  ImageIOBase::Pointer m_ImageIO;
  bool                 m_UserSpecifiedImageIO; // track whether the ImageIO is user specified

  ImageIORegion m_IORegion;
  bool          m_UserSpecifiedIORegion; //
                                         // track whether the region is user specified
  bool m_FactorySpecifiedImageIO;        // track whether the factory mechanism set the ImageIO
  bool m_UseCompression;
  bool m_UseInputMetaDataDictionary; // whether to use the MetaDataDictionary from the input or not.
};
} // end namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
#include "itkVectorImageFileWriter.hxx"
#endif

#endif // __itkVectorImageFileWriter_h
