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

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.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 notice for more information.

=========================================================================*/
#include "vtkKWOpenFileProperties.h"

#include "vtkObjectFactory.h"
#include "vtkImageData.h"

#include <vtksys/SystemTools.hxx>
#include <vtksys/stl/string>

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkKWOpenFileProperties);
vtkCxxRevisionMacro(vtkKWOpenFileProperties, "$Revision: 1.8 $");

#ifdef KWCommonPro_USE_XML_RW
#include "XML/vtkXMLKWOpenFilePropertiesReader.h"
#include "XML/vtkXMLKWOpenFilePropertiesWriter.h"
#endif
vtkKWGetXMLReaderWriterObjectsImplementationMacro(vtkKWOpenFileProperties, vtkXMLKWOpenFilePropertiesReader, vtkXMLKWOpenFilePropertiesWriter);

//----------------------------------------------------------------------------
vtkKWOpenFileProperties::vtkKWOpenFileProperties()
{
  this->ImageInformation      = vtkImageData::New();

  this->DistanceUnits         = NULL;
  this->FilePattern           = NULL;
  for (int i = 0; i < VTK_MAX_VRCOMP; i++)
    {
    this->ScalarUnits[i] = NULL;
    }

  this->IndependentComponents = 1;
  this->FileDimensionality    = 0;
  this->DataByteOrder         = vtkKWOpenFileProperties::DataByteOrderUnknown;
  this->Scope                 = vtkKWOpenFileProperties::ScopeUnknown;

  this->SliceAxis          = vtkKWOpenFileProperties::AxisOrientationUnknown;
  this->RowAxis            = vtkKWOpenFileProperties::AxisOrientationUnknown;
  this->ColumnAxis         = vtkKWOpenFileProperties::AxisOrientationUnknown;
}

//----------------------------------------------------------------------------
vtkKWOpenFileProperties::~vtkKWOpenFileProperties()
{
  if (this->ImageInformation)
    {
    this->ImageInformation->Delete();
    this->ImageInformation = 0;
    }

  this->SetDistanceUnits(NULL);
  this->SetFilePattern(NULL);

  int i;
  for (i = 0; i < VTK_MAX_VRCOMP; i++)
    {
    this->SetScalarUnits(i, NULL);
    }
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::Reset()
{
  if (this->ImageInformation)
    {
    this->ImageInformation->Delete();
    }
  this->ImageInformation = vtkImageData::New();

  this->SetDistanceUnits(NULL);
  this->SetFilePattern(NULL);
  for (int i = 0; i < VTK_MAX_VRCOMP; i++)
    {
    this->SetScalarUnits(i, NULL);
    }

  this->SetIndependentComponents(1);
  this->SetFileDimensionality(0);
  this->SetDataByteOrder(vtkKWOpenFileProperties::DataByteOrderUnknown);
  this->SetScope(vtkKWOpenFileProperties::ScopeUnknown);

  this->SetSliceAxis(vtkKWOpenFileProperties::AxisOrientationUnknown);
  this->SetRowAxis(vtkKWOpenFileProperties::AxisOrientationUnknown);
  this->SetColumnAxis(vtkKWOpenFileProperties::AxisOrientationUnknown);
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::DeepCopy(vtkKWOpenFileProperties *obj)
{
  this->SetOrigin(obj->GetOrigin());
  this->SetSpacing(obj->GetSpacing());
  this->SetWholeExtent(obj->GetWholeExtent());
  this->SetScalarType(obj->GetScalarType());
  this->SetNumberOfScalarComponents(obj->GetNumberOfScalarComponents());
  this->SetIndependentComponents(obj->GetIndependentComponents());
  this->SetDistanceUnits(obj->GetDistanceUnits());
  for (int i = 0; i < VTK_MAX_VRCOMP; i++)
    {
    this->SetScalarUnits(i, obj->GetScalarUnits(i));
    }
  this->SetDataByteOrder(obj->GetDataByteOrder());
  this->SetFileDimensionality(obj->GetFileDimensionality());
  this->SetScope(obj->GetScope());
  this->SetSliceAxis(obj->GetSliceAxis());
  this->SetRowAxis(obj->GetRowAxis());
  this->SetColumnAxis(obj->GetColumnAxis());
  this->SetFilePattern(obj->GetFilePattern());
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::CopyToImageData(vtkImageData *img)
{
  if (!img)
    {
    return;
    }

  img->SetOrigin(this->ImageInformation->GetOrigin());
  img->SetSpacing(this->ImageInformation->GetSpacing());
  img->SetWholeExtent(this->ImageInformation->GetWholeExtent());
  img->SetScalarType(this->ImageInformation->GetScalarType());
  img->SetNumberOfScalarComponents(
    this->ImageInformation->GetNumberOfScalarComponents());
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::CopyFromImageData(vtkImageData *img)
{
  if (!img)
    {
    return;
    }

  this->ImageInformation->SetOrigin(img->GetOrigin());
  this->ImageInformation->SetSpacing(img->GetSpacing());
  this->ImageInformation->SetWholeExtent(img->GetWholeExtent());
  this->ImageInformation->SetScalarType(img->GetScalarType());
  this->ImageInformation->SetNumberOfScalarComponents(
    img->GetNumberOfScalarComponents());
}

//----------------------------------------------------------------------------
int vtkKWOpenFileProperties::IsEqual(vtkKWOpenFileProperties *obj)
{
  if (!obj)
    {
    return 0;
    }

  double *origin = this->GetOrigin();
  double *obj_origin = obj->GetOrigin();

  double *spacing = this->GetSpacing();
  double *obj_spacing = obj->GetSpacing();

  int *wextent = this->GetWholeExtent();
  int *obj_wextent = obj->GetWholeExtent();

  if (
    (origin[0]  != obj_origin[0] ||
     origin[1]  != obj_origin[1] ||
     origin[2]  != obj_origin[2]
      ) ||
    (spacing[0] != obj_spacing[0] ||
     spacing[1] != obj_spacing[1] ||
     spacing[2] != obj_spacing[2]
      ) ||
    (wextent[0] != obj_wextent[0] ||
     wextent[1] != obj_wextent[1] ||
     wextent[2] != obj_wextent[2] ||
     wextent[3] != obj_wextent[3] ||
     wextent[4] != obj_wextent[4] ||
     wextent[5] != obj_wextent[5]
      ) ||
    this->GetScalarType()               != obj->GetScalarType() ||
    this->GetNumberOfScalarComponents() != obj->GetNumberOfScalarComponents()||
    this->GetIndependentComponents()    != obj->GetIndependentComponents() ||
    this->GetDataByteOrder()            != obj->GetDataByteOrder() ||
    this->GetFileDimensionality()       != obj->GetFileDimensionality() ||
    this->GetScope()                    != obj->GetScope() ||
    this->GetSliceAxis()                != obj->GetSliceAxis() ||
    this->GetRowAxis()                  != obj->GetRowAxis() ||
    this->GetColumnAxis()               != obj->GetColumnAxis()
    )
    {
    return 0;
    }

  const char *distance_units = this->GetDistanceUnits();
  const char *obj_distance_units = obj->GetDistanceUnits();
 
  int same_distance_units = 
    (distance_units == obj_distance_units ||
     (distance_units && obj_distance_units && 
      !strcmp(distance_units, obj_distance_units)));
  if (!same_distance_units)
    {
    return 0;
    }

  for (int i = 0; i < VTK_MAX_VRCOMP; i++)
    {
    const char *scalar_units = this->GetScalarUnits(i);
    const char *obj_scalar_units = obj->GetScalarUnits(i);
    int same_scalar_units = 
      (scalar_units == obj_scalar_units ||
       (scalar_units && obj_scalar_units && 
        !strcmp(scalar_units, obj_scalar_units)));
    if (!same_scalar_units)
      {
      return 0;
      }
    }

  const char *file_pattern = this->GetFilePattern();
  const char *obj_file_pattern = obj->GetFilePattern();
 
  int same_file_pattern = 
    (file_pattern == obj_file_pattern ||
     (file_pattern && obj_file_pattern && 
      !strcmp(file_pattern, obj_file_pattern)));
  if (!same_file_pattern)
    {
    return 0;
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetSpacing(double arg[3])
{
  this->ImageInformation->SetSpacing(arg);
}

void vtkKWOpenFileProperties::SetSpacing(
  double arg1, double arg2, double arg3)
{
  this->ImageInformation->SetSpacing(arg1, arg2, arg3);
}

//----------------------------------------------------------------------------
double* vtkKWOpenFileProperties::GetSpacing()
{
  return this->ImageInformation->GetSpacing();
}

void vtkKWOpenFileProperties::GetSpacing(
  double &arg1, double &arg2, double &arg3)
{
  this->ImageInformation->GetSpacing(arg1, arg2, arg3);
}

void vtkKWOpenFileProperties::GetSpacing(double arg[3])
{
  this->ImageInformation->GetSpacing(arg);
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetOrigin(double arg[3])
{
  this->ImageInformation->SetOrigin(arg);
}

void vtkKWOpenFileProperties::SetOrigin(
  double arg1, double arg2, double arg3)
{
  this->ImageInformation->SetOrigin(arg1, arg2, arg3);
}

//----------------------------------------------------------------------------
double* vtkKWOpenFileProperties::GetOrigin()
{
  return this->ImageInformation->GetOrigin();
}

void vtkKWOpenFileProperties::GetOrigin(
  double &arg1, double &arg2, double &arg3)
{
  this->ImageInformation->GetOrigin(arg1, arg2, arg3);
}

void vtkKWOpenFileProperties::GetOrigin(double arg[3])
{
  this->ImageInformation->GetOrigin(arg);
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetWholeExtent(int arg[6])
{
  this->ImageInformation->SetWholeExtent(arg);
}

void vtkKWOpenFileProperties::SetWholeExtent(
  int arg1, int arg2, int arg3,
  int arg4, int arg5, int arg6)
{
  this->ImageInformation->SetWholeExtent(
    arg1, arg2, arg3, arg4, arg5, arg6);
}

//----------------------------------------------------------------------------
int* vtkKWOpenFileProperties::GetWholeExtent()
{
  return this->ImageInformation->GetWholeExtent();
}

void vtkKWOpenFileProperties::GetWholeExtent(
  int &arg1, int &arg2, int &arg3,
  int &arg4, int &arg5, int &arg6)
{
  this->ImageInformation->GetWholeExtent(
    arg1, arg2, arg3, arg4, arg5, arg6);
}

void vtkKWOpenFileProperties::GetWholeExtent(int arg[6])
{
  this->ImageInformation->GetWholeExtent(arg);
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetScalarType(int arg)
{
  this->ImageInformation->SetScalarType(arg);
}

//----------------------------------------------------------------------------
int vtkKWOpenFileProperties::GetScalarType()
{
  return this->ImageInformation->GetScalarType();
}

//----------------------------------------------------------------------------
int vtkKWOpenFileProperties::GetScalarSize()
{
  return this->ImageInformation->GetScalarSize();
}

//----------------------------------------------------------------------------
double vtkKWOpenFileProperties::GetScalarTypeMin()
{
  return this->ImageInformation->GetScalarTypeMin();
}

//----------------------------------------------------------------------------
double vtkKWOpenFileProperties::GetScalarTypeMax()
{
  return this->ImageInformation->GetScalarTypeMax();
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetNumberOfScalarComponents(int arg)
{
  this->ImageInformation->SetNumberOfScalarComponents(arg);
}

//----------------------------------------------------------------------------
int vtkKWOpenFileProperties::GetNumberOfScalarComponents()
{
  return this->ImageInformation->GetNumberOfScalarComponents();
}

//----------------------------------------------------------------------------
const char *vtkKWOpenFileProperties::GetScalarUnits(int i)
{
  if (i < 0 || i >= VTK_MAX_VRCOMP)
    {
    return 0;
    }
  return this->ScalarUnits[i];
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetScalarUnits(int i, const char *_arg)
{
  if (i < 0 || i >= VTK_MAX_VRCOMP)
    {
    return;
    }

  if (this->ScalarUnits[i] == NULL && _arg == NULL) 
    { 
    return;
    } 

  if (this->ScalarUnits[i] && _arg && (!strcmp(this->ScalarUnits[i], _arg))) 
    { 
    return;
    } 

  if (this->ScalarUnits[i]) 
    { 
    delete [] this->ScalarUnits[i]; 
    } 

  if (_arg) 
    { 
    this->ScalarUnits[i] = new char[strlen(_arg) + 1]; 
    strcpy(this->ScalarUnits[i], _arg);
    } 
  else 
    { 
    this->ScalarUnits[i] = NULL; 
    } 

  this->Modified(); 
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetDataByteOrder(int arg)
{
  if (arg < vtkKWOpenFileProperties::DataByteOrderBigEndian ||
      arg > vtkKWOpenFileProperties::DataByteOrderUnknown ||
      this->DataByteOrder == arg)
    {
    return;
    }

  this->DataByteOrder = arg;
  this->Modified();
}

void vtkKWOpenFileProperties::SetDataByteOrderToBigEndian()
{
  this->SetDataByteOrder(vtkKWOpenFileProperties::DataByteOrderBigEndian);
}

void vtkKWOpenFileProperties::SetDataByteOrderToLittleEndian()
{
  this->SetDataByteOrder(vtkKWOpenFileProperties::DataByteOrderLittleEndian);
}

void vtkKWOpenFileProperties::SetDataByteOrderToUnknown()
{
  this->SetDataByteOrder(vtkKWOpenFileProperties::DataByteOrderUnknown);
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetScope(int arg)
{
  if (arg < vtkKWOpenFileProperties::ScopeUnknown ||
      arg > vtkKWOpenFileProperties::ScopeScientific ||
      this->Scope == arg)
    {
    return;
    }

  this->Scope = arg;
  this->Modified();
}

void vtkKWOpenFileProperties::SetScopeToUnknown()
{ 
  this->SetScope(vtkKWOpenFileProperties::ScopeUnknown); 
}

void vtkKWOpenFileProperties::SetScopeToMedical()
{ 
  this->SetScope(vtkKWOpenFileProperties::ScopeMedical); 
}

void vtkKWOpenFileProperties::SetScopeToScientific()
{ 
  this->SetScope(vtkKWOpenFileProperties::ScopeScientific); 
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetSliceAxis(int arg)
{
  if (arg < vtkKWOpenFileProperties::AxisOrientationPlusX ||
      arg > vtkKWOpenFileProperties::AxisOrientationUnknown ||
      this->SliceAxis == arg)
    {
    return;
    }

  this->SliceAxis = arg;
  this->Modified();
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetRowAxis(int arg)
{
  if (arg < vtkKWOpenFileProperties::AxisOrientationPlusX ||
      arg > vtkKWOpenFileProperties::AxisOrientationUnknown ||
      this->RowAxis == arg)
    {
    return;
    }

  this->RowAxis = arg;
  this->Modified();
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::SetColumnAxis(int arg)
{
  if (arg < vtkKWOpenFileProperties::AxisOrientationPlusX ||
      arg > vtkKWOpenFileProperties::AxisOrientationUnknown ||
      this->ColumnAxis == arg)
    {
    return;
    }

  this->ColumnAxis = arg;
  this->Modified();
}

//----------------------------------------------------------------------------
int vtkKWOpenFileProperties::IsOrientationValid(
  int col_axis, int row_axis, int slice_axis)
{
  int hasThreeAxes[3];
  hasThreeAxes[0] = 0;
  hasThreeAxes[1] = 0;
  hasThreeAxes[2] = 0;

  hasThreeAxes[(col_axis%6)/2] = 1;
  hasThreeAxes[(row_axis%6)/2] = 1;
  hasThreeAxes[(slice_axis%6)/2] = 1;

  return hasThreeAxes[0]*hasThreeAxes[1]*hasThreeAxes[2];
}

//----------------------------------------------------------------------------
const char* vtkKWOpenFileProperties::GetAbsoluteFilePatternForFile(
  const char *filename)
{
  if (!this->GetFilePattern() || !filename)
    {
    return this->GetFilePattern();
    }

  // Absolute already

  vtksys_stl::string fp_dir = 
    vtksys::SystemTools::GetFilenamePath(this->GetFilePattern());
  if (vtksys::SystemTools::FileExists(fp_dir.c_str()) &&
      vtksys::SystemTools::FileIsDirectory(fp_dir.c_str()))
    {
    return this->GetFilePattern();
    }


  // Get the filename dir

  vtksys_stl::string f_dir = 
    vtksys::SystemTools::GetFilenamePath(filename);
  if (!vtksys::SystemTools::FileExists(f_dir.c_str()) ||
      !vtksys::SystemTools::FileIsDirectory(f_dir.c_str()))
    {
    return this->GetFilePattern();
    }

  // Assemble the absolute file pattern

  static vtksys_stl::string abs_fp;

  vtksys_stl::string fp_name = 
    vtksys::SystemTools::GetFilenameName(this->GetFilePattern());

  abs_fp = f_dir;
  abs_fp += '/';
  abs_fp += fp_name;

  return abs_fp.c_str();
}

//----------------------------------------------------------------------------
void vtkKWOpenFileProperties::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "DistanceUnits: " 
     << (this->DistanceUnits ? this->DistanceUnits : "(NULL)") << endl;
  os << indent << "FilePattern: " 
     << (this->FilePattern ? this->FilePattern : "(NULL)") << endl;
  os << indent << "IndependentComponents: "
     << this->IndependentComponents << endl;
  os << indent << "FileDimensionality: "
     << this->FileDimensionality << endl;
  os << indent << "DataByteOrder: "
     << this->DataByteOrder << endl;
  os << indent << "Scope: " << this->Scope << endl;
  os << indent << "ImageInformation:";
  os << indent << "RowAxis: " << this->RowAxis << endl;
  os << indent << "SliceAxis: " << this->SliceAxis << endl;
  os << indent << "ColumnAxis: " << this->ColumnAxis << endl;
  if (this->ImageInformation)
    {
    os << " " << this->ImageInformation->GetClassName()
      << " (" << this->ImageInformation << ")" << endl;
    this->ImageInformation->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << " (none)" << endl;
    }
}
