/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         https://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkSimpleFilterWatcher.h"
#include "itkVectorGradientMagnitudeImageFilter.h"
#include "itkComposeImageFilter.h"
#include "itkRGBToVectorImageAdaptor.h"


// Pasting enables the writing of a sub-region to a file. This example
// updates a small portion of the 2D coronal slice. The file
// streamed_paste_vm.mha can either not exist or can be copied from
// the output of the previous example.
//

// Below we begin by creating a reader for the file just written that
// is capable of streaming.


int
main(int argc, char * argv[])
{

  if (argc < 3)
  {
    std::cerr << "Missing Parameters " << std::endl;
    std::cerr << "Usage: " << argv[0];
    std::cerr << " inputImageFile  outputImageFile" << std::endl;
    return EXIT_FAILURE;
  }


  const std::string inputImageFile = argv[1];
  const std::string outputImageFile = argv[2];

  using RGBPixelType = itk::RGBPixel<unsigned char>;
  using RGB2DImageType = itk::Image<RGBPixelType, 2>;

  //  we begin by creating a reader for the file just written that is
  //  capable of streaming
  using ImageReaderType = itk::ImageFileReader<RGB2DImageType>;
  auto reader = ImageReaderType::New();
  reader->SetFileName(inputImageFile);

  // The pipeline is continued through a gradient magnitude filter,
  // which works on vector images to produce a scalar output. Then a
  // color image is recreated by compositing the output as red, green,
  // and blue channels.
  using GradientMagnitudeImageFilter =
    itk::VectorGradientMagnitudeImageFilter<RGB2DImageType>;
  auto grad = GradientMagnitudeImageFilter::New();
  grad->SetInput(reader->GetOutput());

  grad->UseImageSpacingOn();

  using GradientMagnitudeOutputImageType =
    GradientMagnitudeImageFilter::OutputImageType;

  using ComposeRGBFilterType =
    itk::ComposeImageFilter<GradientMagnitudeOutputImageType, RGB2DImageType>;
  auto composeRGB = ComposeRGBFilterType::New();
  composeRGB->SetInput1(grad->GetOutput());
  composeRGB->SetInput2(grad->GetOutput());
  composeRGB->SetInput3(grad->GetOutput());


  // Next we begin to specify the paste region, by creating an
  // ImageIORegion that is half the size and centered on the entire
  // image. The ImageIORegion class is similar to the ImageRegion class
  // except that it is not templated over the image dimension, because
  // of the runtime nature of IO.
  composeRGB->UpdateOutputInformation();
  const RGB2DImageType::RegionType largest =
    composeRGB->GetOutput()->GetLargestPossibleRegion();
  itk::ImageIORegion halfIO(2);
  halfIO.SetIndex(0,
                  largest.GetIndex(0) +
                    static_cast<unsigned long>(0.25 * largest.GetSize(0)));
  halfIO.SetIndex(1,
                  largest.GetIndex(1) +
                    static_cast<unsigned long>(0.25 * largest.GetSize(1)));
  halfIO.SetSize(0, static_cast<unsigned long>(0.5 * largest.GetSize(0)));
  halfIO.SetSize(1, static_cast<unsigned long>(0.5 * largest.GetSize(1)));


  // After using an adaptor to convert the color image into a vector
  // image, so that the pixel type will match the type in the file, we
  // create a writer. Here both streaming and pasting are used.  To
  // enable pasting, a call to SetIORegion is made with a valid
  // region. Finally, the pipeline is updated, causing the streaming of
  // regions
  using ToVectorImageAdaptorType =
    itk::RGBToVectorImageAdaptor<RGB2DImageType>;
  auto adaptor = ToVectorImageAdaptorType::New();
  adaptor->SetImage(composeRGB->GetOutput());

  using ImageWriterType = itk::ImageFileWriter<ToVectorImageAdaptorType>;
  auto writer = ImageWriterType::New();
  writer->SetFileName(outputImageFile);
  writer->SetNumberOfStreamDivisions(10);
  writer->SetIORegion(halfIO);
  writer->SetInput(adaptor);

  const itk::SimpleFilterWatcher watcher1(writer, "stream pasting writing");

  const itk::SimpleFilterWatcher watcher(grad, "stream gradient magnitude");


  try
  {
    writer->Update();
  }
  catch (const itk::ExceptionObject & err)
  {
    std::cerr << "ExceptionObject caught !" << std::endl;
    std::cerr << err << std::endl;
    return EXIT_FAILURE;
  }

  // This pasting example only writes the small halfIO region to the
  // file, the remainder is not touched. The manner in which the
  // pipeline executed is very similar to the previous streaming
  // example. The main difference is that the writer only breaks up the
  // IORegion for streaming, not the entire image. The other difference
  // is that the reader fully supports streaming and only reads the
  // required region from the file.

  return EXIT_SUCCESS;
}
