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

  Program: GDCM (Grassroots DICOM). A DICOM library

  Copyright (c) 2006-2011 Mathieu Malaterre
  All rights reserved.
  See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html 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 notice for more information.

=========================================================================*/
#include "vtkGDCMImageReader.h"
#include "vtkGDCMImageWriter.h"

#include "vtkImageData.h"
#include "vtkMultiThreader.h"
#include "vtkMedicalImageProperties.h"
#include "vtkVersion.h"

#include "gdcmTesting.h"
#include "gdcmFilename.h"
#include "gdcmSystem.h"
#include "gdcmTrace.h"
#include "gdcmImageReader.h"

#ifndef vtkFloatingPointType
#define vtkFloatingPointType double
#endif

int TestvtkGDCMImageWrite(const char *filename, bool verbose = false)
{
  int res = 0; // no error
  if( verbose )
    std::cerr << "Reading : " << filename << std::endl;
  vtkGDCMImageReader *reader = vtkGDCMImageReader::New();
  reader->FileLowerLeftOn();
  int canread = reader->CanReadFile( filename );
  if( canread )
    {
    reader->SetFileName( filename );
    reader->Update();
    if( verbose )
      {
      reader->GetOutput()->Print( cout );
      reader->GetMedicalImageProperties()->Print( cout );
      }

    // Create directory first:
    const char subdir[] = "TestvtkGDCMImageWriter";
    std::string tmpdir = gdcm::Testing::GetTempDirectory( subdir );
    if( !gdcm::System::FileIsDirectory( tmpdir.c_str() ) )
      {
      gdcm::System::MakeDirectory( tmpdir.c_str() );
      //return 1;
      }
    std::string gdcmfile = gdcm::Testing::GetTempFilename( filename, subdir );

    vtkGDCMImageWriter *writer = vtkGDCMImageWriter::New();
#if (VTK_MAJOR_VERSION >= 6)
    writer->SetInputConnection( reader->GetOutputPort() );
#else
    writer->SetInput( reader->GetOutput() );
#endif
    writer->SetFileLowerLeft( reader->GetFileLowerLeft() );
    writer->SetDirectionCosines( reader->GetDirectionCosines() );
    writer->SetImageFormat( reader->GetImageFormat() );
    writer->SetFileDimensionality( reader->GetFileDimensionality() );
    writer->SetMedicalImageProperties( reader->GetMedicalImageProperties() );
    writer->SetPlanarConfiguration( reader->GetPlanarConfiguration() );
    writer->SetShift( reader->GetShift() );
    writer->SetScale( reader->GetScale() );
    writer->SetFileName( gdcmfile.c_str() );
    writer->Write();
    if( verbose )  std::cerr << "Write out: " << gdcmfile << std::endl;

    writer->Delete();

    // Need to check we can still read this image back:
    gdcm::ImageReader r;
    if( gdcm::System::FileExists( gdcmfile.c_str() ) )
      {
      r.SetFileName( gdcmfile.c_str() );
      }
    if( !r.Read() )
      {
      std::cerr << "failed to read back:" << gdcmfile << std::endl;
      res = 1;
      }
    else
      {
      // ok could read the file, now check origin is ok:
      const gdcm::Image &image = r.GetImage();
      const double *origin = image.GetOrigin();
      if( origin )
        {
        vtkImageData * vtkimg = reader->GetOutput();
        const vtkFloatingPointType *vtkorigin = vtkimg->GetOrigin();
        if( fabs(vtkorigin[0] - origin[0]) > 1.e-3
          || fabs(vtkorigin[1] - origin[1]) > 1.e-3
          || fabs(vtkorigin[2] - origin[2]) > 1.e-3 )
          {
          std::cerr << "Problem:" << vtkorigin[0] << "," << vtkorigin[1] << "," << vtkorigin[2] ;
          std::cerr << " should be:" << origin[0] << "," << origin[1] << "," << origin[2] << std::endl ;
          std::cerr << filename << std::endl;
          res = 1;
          }
        }

      gdcm::ImageReader r2;
      r2.SetFileName( filename );
      if( !r2.Read() )
        {
        std::cerr << "failed to re-read initial image...how is that possible ?:" << filename << std::endl;
        res = 1;
        }
      const gdcm::Image &compimage = r2.GetImage();
      // Check that Media Storage is still correct:
      // Well this is difficult to implement as Retired class are replaced with newer one automatically
      gdcm::MediaStorage ms1;
      ms1.SetFromFile( r.GetFile() ); // our rewritten file
      gdcm::MediaStorage ms2;
      ms2.SetFromFile( r2.GetFile() ); // original file
      if( ms1 != ms2 )
        {
        if( ms1 == gdcm::MediaStorage::MultiframeGrayscaleByteSecondaryCaptureImageStorage )
          {
          // Hum I have this weird case when reading libido1.0-vol.acr...
          }
        else if( ms1 == gdcm::MediaStorage::XRayAngiographicImageStorage && ms2 == gdcm::MediaStorage::SecondaryCaptureImageStorage  )
          {
          // FIXME: D_CLUNIE_XA1_JPLL.dcm
          }
        else if( ms2 == gdcm::MediaStorage::XRayRadiofluoroscopingImageStorage )
          {
          // gdcmData/JDDICOM_Sample5.dcm
          }
        else if( ms1 == gdcm::MediaStorage::EnhancedMRImageStorage && ms2 == gdcm::MediaStorage::MRImageStorage )
          {
          // gdcmData/MR-MONO2-8-16x-heart.dcm
          }
        else if( ms1 == gdcm::MediaStorage::UltrasoundImageStorage && ms2 == gdcm::MediaStorage::UltrasoundImageStorageRetired )
          {
          // gdcmData/US-RGB-8-esopecho.dcm
          }
        else if( ms1 == gdcm::MediaStorage::UltrasoundMultiFrameImageStorage && ms2 == gdcm::MediaStorage::UltrasoundMultiFrameImageStorageRetired )
          {
          // gdcmData/US-MONO2-8-8x-execho.dcm
          }
        else if ( ms1 == gdcm::MediaStorage::NuclearMedicineImageStorage && ms2 == gdcm::MediaStorage::SecondaryCaptureImageStorage )
          {
          // gdcmData/Renal_Flow.dcm
          }
        else if ( ms1 == gdcm::MediaStorage::CTImageStorage && ms2 == gdcm::MediaStorage::SecondaryCaptureImageStorage )
          {
          // gdcmData/D_CLUNIE_SC1_JPLY.dcm
          }
        else if ( ms1 == gdcm::MediaStorage::EnhancedCTImageStorage && ms2 == gdcm::MediaStorage::CTImageStorage && compimage.GetNumberOfDimensions() == 3 )
          {
          // gdcmData/CroppedArm.dcm
          }
        else if( ms1 == gdcm::MediaStorage::MRImageStorage && ms2 == gdcm::MediaStorage::GeneralElectricMagneticResonanceImageStorage )
          {
          // gdcmData/MR00010001.dcm
          }
        else if( ms1 == gdcm::MediaStorage::UltrasoundImageStorage && ms2 == gdcm::MediaStorage::SecondaryCaptureImageStorage )
          {
          // gdcmData/GE_LOGIQBook-8-RGB-HugePreview.dcm
          }
        else if( ms1 == gdcm::MediaStorage::DigitalXRayImageStorageForProcessing
          && ms2 == gdcm::MediaStorage::DigitalXRayImageStorageForPresentation
        )
          {
          // gdcmData/DX_GE_FALCON_SNOWY-VOI.dcm
          }
        else
          {
          std::cerr << "MediaStorage incompatible: " << ms1 << " vs " << ms2 << " for file: " << filename << std::endl;
          res = 1;
          }
        }
      // Make sure that md5 is still ok:
      unsigned long len = image.GetBufferLength();
      char* buffer = new char[len];
      bool res2 = image.GetBuffer(buffer);
      if( !res2 )
        {
        std::cerr << "Could not get buffer" << std::endl;
        res = 1;
        }
      const char *ref = gdcm::Testing::GetMD5FromFile(filename);
      char digest[33];
      gdcm::Testing::ComputeMD5(buffer, len, digest);
      if( !ref )
        {
        std::cerr << "Could not compute md5" << std::endl;
        res = 1;
        }
      const gdcm::PixelFormat &comppf = compimage.GetPixelFormat();
      if( !ref )
        {
        std::cerr << "Missing md5: " << digest << std::endl;
        }
      else if( strcmp(digest, ref) != 0
        // I do not support rewritting 12Bits pack image (illegal anyway)
        && comppf != gdcm::PixelFormat::UINT12
      )
        {
#if 0
{
unsigned long len = compimage.GetBufferLength();
char* buffer = new char[len];
bool res2 = compimage.GetBuffer(buffer);
std::ofstream out("/tmp/debug.raw", std::ios::binary);
out.write( buffer, len );
out.close();
}
#endif
        std::cerr << "Problem reading image from: " << filename << std::endl;
        std::cerr << "Found " << digest << " instead of " << ref << std::endl;
        std::cerr << "Original TransferSyntax was: " << compimage.GetTransferSyntax() << std::endl;
        std::cerr << "Output image: " << gdcmfile << std::endl;
        res = 1;
        }
      delete[] buffer;
      }
    }
  else
    {
    if( verbose )
      std::cerr << "vtkGDCMImageReader cannot read: " << filename << std::endl;
    }
  reader->Delete();

  return res;
}

int TestvtkGDCMImageWriter1(int argc, char *argv[])
{
  if( argc == 2 )
    {
    const char *filename = argv[1];
    return TestvtkGDCMImageWrite(filename, true);
    }

  // else
  gdcm::Trace::DebugOff();
  gdcm::Trace::WarningOff();
  gdcm::Trace::ErrorOff();
  int r = 0, i = 0;
  const char *filename;
  const char * const *filenames = gdcm::Testing::GetFileNames();
  while( (filename = filenames[i]) )
    {
    r += TestvtkGDCMImageWrite( filename );
    ++i;
    }

  return r;
}
