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

  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 "vtkVVInformationInterface.h"

#include "vtkDataArray.h"
#include "vtkImageData.h"
#include "vtkMedicalImageProperties.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"

#include "vtkKWApplication.h"
#include "vtkKWFrame.h"
#include "vtkKWFrameWithLabel.h"
#include "vtkKWFrameWithScrollbar.h"
#include "vtkKWIcon.h"
#include "vtkKWInternationalization.h"
#include "vtkKWLabel.h"
#include "vtkKWMultiColumnList.h"
#include "vtkKWMultiColumnListWithScrollbars.h"
#include "vtkKWVolumeWidget.h"

#include "vtkVVDataItemVolume.h"
#include "vtkVVWindowBase.h"
#include "vtkVVFileInstance.h"
#include "vtkVVInformationInterfaceLabels.h"

#include <vtksys/stl/string>
#include <vtksys/ios/sstream>
#include <vtksys/SystemTools.hxx>
#include <time.h> // for strftime

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkVVInformationInterface);
vtkCxxRevisionMacro(vtkVVInformationInterface, "$Revision: 1.19 $");

//----------------------------------------------------------------------------
vtkVVInformationInterface::vtkVVInformationInterface()
{
  this->Labels = vtkVVInformationInterfaceLabels::New();
  this->SetName(ks_("Information Panel|Title|Info"));

  // Information

  this->InformationList = NULL;
}

//----------------------------------------------------------------------------
vtkVVInformationInterface::~vtkVVInformationInterface()
{
  // Information

  if (this->InformationList)
    {
    this->InformationList->Delete();
    this->InformationList = NULL;
    }

  if (this->Labels)
    {
    this->Labels->Delete();
    this->Labels = NULL;
    }
}

// ---------------------------------------------------------------------------
void vtkVVInformationInterface::Create()
{
  if (this->IsCreated())
    {
    vtkErrorMacro("The panel is already created.");
    return;
    }

  // Create the superclass instance (and set the application)

  this->Superclass::Create();

  ostrstream tk_cmd;
  vtkKWWidget *page;

  // --------------------------------------------------------------
  // Add a "Information" page

  int page_id = this->AddPage(NULL, this->GetName());
  this->SetPageIconToPredefinedIcon(
    page_id, vtkKWIcon::IconNuvola22x22ActionsHelp);
  
  page = this->GetPageWidget(page_id);

  // --------------------------------------------------------------
  // Information : label set

  if (!this->InformationList)
    {
    this->InformationList = vtkKWMultiColumnListWithScrollbars::New();
    }

  this->InformationList->SetParent(this->GetPagesParentWidget());
  this->InformationList->Create();
  this->InformationList->HorizontalScrollbarVisibilityOn();

  tk_cmd << "pack " << this->InformationList->GetWidgetName()
         << "  -side top -anchor nw -padx 2 -pady 2 -fill both -expand t"
         << " -in " << page->GetWidgetName() << endl;

  vtkKWMultiColumnList *list = this->InformationList->GetWidget();

  // Add tags to the mc list

  vtkVVInformationInterfaceLabels *labels = this->Labels;

  list->AddColumn(ks_("Information Panel|Information"));
  list->SetColumnStretchable(0, 0);
  list->SetColumnWidth(0, 18);

  list->AddColumn(ks_("Information Panel|Value"));
  list->SetColumnStretchable(1, 1);

  // --------------------------------------------------------------
  // Pack 

  tk_cmd << ends;
  this->Script(tk_cmd.str());
  tk_cmd.rdbuf()->freeze(0);

  // Update according to the current Window

  this->Update();
}

//----------------------------------------------------------------------------
void vtkVVInformationInterface::Update()
{
  this->Superclass::Update();

  if (!this->IsCreated())
    {
    return;
    }

  vtkVVDataItem *data = 
    this->Window ? this->Window->GetSelectedDataItem() : NULL;

  // Volume Information

  if (this->InformationList)
    {
    this->UpdateInformationList(vtkVVDataItemVolume::SafeDownCast(data));
    }
}

//----------------------------------------------------------------------------
void vtkVVInformationInterface::UpdateInformationList(
    vtkVVDataItemVolume *volume_data)
{
  char buffer[256];

  if (!this->InformationList)
    {
    return;
    }

  // Volume Information

  vtkVVInformationInterfaceLabels *labels = this->Labels;
  vtkKWMultiColumnList *list = this->InformationList->GetWidget();
  if (!volume_data) 
    {
    list->DeleteAllRows();
    this->InformationList->SetEnabled(0);
    return;
    }

  vtkImageData *image_data = volume_data->GetImageData();
  vtkMedicalImageProperties *med_prop = 
    volume_data->GetMedicalImageProperties();

  // Scope

  switch (volume_data->GetScope())
    {
    case vtkVVDataItem::ScopeMedical:
      sprintf(buffer, ks_("Scope|Medical"));
      break;
    case vtkVVDataItem::ScopeScientific:
      sprintf(buffer, ks_("Scope|Scientific"));
      break;
    default:
    case vtkVVDataItem::ScopeUnknown:
      sprintf(buffer, ks_("Scope|Unknown"));
      break;
    }
  list->FindAndInsertCellText(0, labels->GetDataScopeLabel(),
                              1, buffer);

  // Dimension, distance units

  if (image_data)
    {
    int *dim = image_data->GetDimensions();
    
    sprintf(buffer, "%d", dim[2]);
    list->FindAndInsertCellText(0, labels->GetImagesLabel(),
                                1, buffer);
    
    list->FindAndInsertCellText(0, labels->GetDistanceUnitsLabel(), 
                                1, volume_data->GetDistanceUnits());
    
    sprintf(buffer, "%d x %d x %d voxels", dim[0], dim[1], dim[2]);
    list->FindAndInsertCellText(0, labels->GetVoxelDimensionsLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetImagesLabel());
    
    list->FindAndDeleteRow(0, labels->GetDistanceUnitsLabel());
    
    list->FindAndDeleteRow(0, labels->GetVoxelDimensionsLabel());
    }
  
  // Physical dims

  if (image_data)
    {
    int *dim = image_data->GetDimensions();
    double *spacing = image_data->GetSpacing();
    sprintf(
      buffer, "%g x %g x %g %s", 
      dim[0] * spacing[0], 
      dim[1] * spacing[1], 
      dim[2] * spacing[2],
      volume_data->GetDistanceUnits() ? volume_data->GetDistanceUnits() : "");
    list->FindAndInsertCellText(0, labels->GetPhysicalDimensionsLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetPhysicalDimensionsLabel());
    }

  // Physical origin

  if (image_data)
    {
    double *origin = image_data->GetOrigin();
    sprintf(
      buffer, "%g, %g, %g %s", 
      origin[0], 
      origin[1], 
      origin[2],
      volume_data->GetDistanceUnits() ? volume_data->GetDistanceUnits() : "");
    list->FindAndInsertCellText(0, labels->GetPhysicalOriginLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetPhysicalOriginLabel());
    }

  // Spacing

  if (image_data)
    {
    double *spacing = image_data->GetSpacing();
    sprintf(
      buffer, "%g x %g x %g %s", 
      spacing[0], 
      spacing[1], 
      spacing[2],
      volume_data->GetDistanceUnits() ? volume_data->GetDistanceUnits() : "");
    list->FindAndInsertCellText(0, labels->GetVoxelSpacingLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetVoxelSpacingLabel());
    }

  // Scalar units

  if (image_data)
    {
    vtksys_stl::string scalar_units;
    int nb_comp = image_data->GetNumberOfScalarComponents();
    for (int i = 0; i < nb_comp; i++)
      {
      const char *unit = volume_data->GetScalarUnits(i);
      if (unit && *unit)
        {
        if (scalar_units.size())
          {
          scalar_units += "; ";
          }
        scalar_units += unit;
        }
      }
    if (scalar_units.size())
      {
      list->FindAndInsertCellText(0, labels->GetScalarUnitsLabel(), 
                                  1, scalar_units.c_str());
      }
    else
      {
      list->FindAndDeleteRow(0, labels->GetScalarUnitsLabel());
      }
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetScalarUnitsLabel());
    }

  // Scalar ranges

  if (image_data)
    {
    vtksys_stl::string scalar_ranges;
    double range[2];
    int nb_comp = image_data->GetNumberOfScalarComponents();
    for (int i = 0; i < nb_comp; i++)
      {
      image_data->GetPointData()->GetScalars()->GetRange(range, i);
      sprintf(buffer, "%g to %g", range[0], range[1]);
      if (scalar_ranges.size())
        {
        scalar_ranges += "; ";
        }
      scalar_ranges += buffer;
      const char *unit = volume_data->GetScalarUnits(i);
      if (unit && *unit)
        {
        scalar_ranges += ' ';
        scalar_ranges += unit;
        }
      }
    list->FindAndInsertCellText(0, labels->GetScalarRangeLabel(), 
                                1, scalar_ranges.c_str());

    list->FindAndInsertCellText(0, labels->GetScalarTypeLabel(), 
                                1, image_data->GetScalarTypeAsString());

    sprintf(buffer, ks_("%d bytes"), image_data->GetScalarSize());
    list->FindAndInsertCellText(0, labels->GetScalarSizeLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetScalarRangeLabel());

    list->FindAndDeleteRow(0, labels->GetScalarTypeLabel());

    list->FindAndDeleteRow(0, labels->GetScalarSizeLabel());
    }

  // File attributes

  vtkVVFileInstance *file = volume_data->GetFileInstance();
  if (file)
    {
    vtksys_stl::string filename(file->GetName());
    vtksys_stl::string name =
      vtksys::SystemTools::GetFilenameName(filename);
    vtksys_stl::string path =
      vtksys::SystemTools::GetFilenamePath(filename);
      
    list->FindAndInsertCellText(0, labels->GetFilenameLabel(), 1,name.c_str());

    list->FindAndInsertCellText(0, labels->GetDirectoryLabel(),1,path.c_str());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetFilenameLabel());

    list->FindAndDeleteRow(0, labels->GetDirectoryLabel());
    }

  // Med prop

  if (med_prop && med_prop->GetStudyDescription())
    {
    list->FindAndInsertCellText(0, labels->GetStudyDescriptionLabel(), 
                                1, med_prop->GetStudyDescription());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetStudyDescriptionLabel());
    }

  if (med_prop && med_prop->GetSeriesDescription())
    {
    list->FindAndInsertCellText(0, labels->GetSeriesDescriptionLabel(), 
                                1, med_prop->GetSeriesDescription());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetSeriesDescriptionLabel());
    }

  if (med_prop && med_prop->GetInstitutionName())
    {
    list->FindAndInsertCellText(0, labels->GetInstitutionNameLabel(), 
                                1, med_prop->GetInstitutionName());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetInstitutionNameLabel());
    }

  if (med_prop && med_prop->GetPatientName())
    {
    list->FindAndInsertCellText(0, labels->GetPatientNameLabel(), 
                                1, med_prop->GetPatientName());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetPatientNameLabel());
    }
    

  if (med_prop && med_prop->GetPatientID())
    {
    list->FindAndInsertCellText(0, labels->GetPatientIDLabel(), 
                                1, med_prop->GetPatientID());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetPatientIDLabel());
    }

  int year, month, week, day;
  if (med_prop && med_prop->GetPatientAge() &&
      vtkMedicalImageProperties::GetAgeAsFields(
        med_prop->GetPatientAge(), year, month, week, day))
    {
    if (year != -1)
      {
      sprintf(buffer, ks_("Patient Age|%d year(s)"), year);
      }
    else if (month != -1)
      {
      sprintf(buffer, ks_("Patient Age|%d month(s)"), month);
      }
    else if (week != -1)
      {
      sprintf(buffer, ks_("Patient Age|%d week(s)"), week);
      }
    else if (day != -1)
      {
      sprintf(buffer, ks_("Patient Age|%d day(s)"), day);
      }
    else
      {
      vtkGenericWarningMacro(
        "Problem with parsing Patient Age"); // should not happen
      }
    list->FindAndInsertCellText(0, labels->GetPatientAgeLabel(), 1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetPatientAgeLabel());
    }

  if (med_prop && med_prop->GetPatientSex())
    {
    list->FindAndInsertCellText(0, labels->GetPatientSexLabel(), 
                                1, med_prop->GetPatientSex());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetPatientSexLabel());
    }

  char locale[200];
  if (med_prop && med_prop->GetPatientBirthDate() &&
      vtkMedicalImageProperties::GetDateAsLocale(
        med_prop->GetPatientBirthDate(), locale))
    {
    list->FindAndInsertCellText(0, labels->GetPatientBirthDateLabel(),
                                1, locale);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetPatientBirthDateLabel());
    }

  if (med_prop && med_prop->GetAcquisitionDate() &&
      vtkMedicalImageProperties::GetDateAsLocale(
        med_prop->GetAcquisitionDate(), locale))
    {
    list->FindAndInsertCellText(0, labels->GetAcquisitionDateLabel(),
                                1, locale );
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetAcquisitionDateLabel());
    }

  if (med_prop && med_prop->GetAcquisitionTime())
    {
    list->FindAndInsertCellText(0, labels->GetAcquisitionTimeLabel(),
                                1, med_prop->GetAcquisitionTime());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetAcquisitionTimeLabel());
    }

  if (med_prop && med_prop->GetModality())
    {
    list->FindAndInsertCellText(0, labels->GetModalityLabel(),
                                1, med_prop->GetModality());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetModalityLabel());
    }

  if (med_prop && med_prop->GetManufacturerModelName())
    {
    list->FindAndInsertCellText(0, labels->GetModelNameLabel(),
                                1, med_prop->GetManufacturerModelName());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetModelNameLabel());
    }

  if (med_prop && med_prop->GetStationName())
    {
    list->FindAndInsertCellText(0, labels->GetStationNameLabel(), 
                                1, med_prop->GetStationName());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetStationNameLabel());
    }

  if (med_prop && med_prop->GetStudyID())
    {
    list->FindAndInsertCellText(0, labels->GetStudyIdLabel(), 
                                1, med_prop->GetStudyID());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetStudyIdLabel());
    }

  if (med_prop && med_prop->GetSeriesNumber())
    {
    list->FindAndInsertCellText(0, labels->GetSeriesNumberLabel(), 
                                1, med_prop->GetSeriesNumber());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetSeriesNumberLabel());
    }

  if (med_prop && med_prop->GetRepetitionTime())
    {
    list->FindAndInsertCellText(0, labels->GetRepetitionTimeLabel(),
                                1, med_prop->GetRepetitionTime());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetRepetitionTimeLabel());
    }
    

  if (med_prop && med_prop->GetEchoTime())
    {
    list->FindAndInsertCellText(0, labels->GetEchoTimeLabel(),
                                1, med_prop->GetEchoTime());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetEchoTimeLabel());
    }

  if (med_prop && med_prop->GetXRayTubeCurrent())
    {
    list->FindAndInsertCellText(0, labels->GetMALabel(),
                                1, med_prop->GetXRayTubeCurrent());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetMALabel());
    }

  if (med_prop && med_prop->GetKVP())
    {
    list->FindAndInsertCellText(0, labels->GetKVPLabel(),
                                1, med_prop->GetKVP());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetKVPLabel());
    }

  if (med_prop && med_prop->GetExposureTime())
    {
    sprintf(buffer, "%li ms", atol(med_prop->GetExposureTime()));
    list->FindAndInsertCellText(0, labels->GetExposureTimeLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetExposureTimeLabel());
    }

  /*if (med_prop && med_prop->GetXRayTubeCurrent())
    {
    long int xray_tube_current = atol(med_prop->GetXRayTubeCurrent());
    sprintf(buffer, "%li mA", xray_tube_current);
    list->FindAndInsertCellText(
    0, labels->GetXrayTubeCurrentLabel(), 
    1, buffer);
    }*/
  /*
    if (med_prop && med_prop->GetExposure())
    {
    long int exposure = atol(med_prop->GetExposure());
    sprintf(buffer, "%li mAs", exposure);
    list->FindAndInsertCellText(
    0, labels->GetExposureLabel(), 
    1, buffer);
    }
  */
  if (med_prop && med_prop->GetGantryTilt())
    {
    long int gantry_tilt = atol(med_prop->GetGantryTilt());
    sprintf(buffer, "%li %s", 
            gantry_tilt, ks_("Unit|degrees")); // can not handle °
    list->FindAndInsertCellText(0, labels->GetGantryTiltLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetGantryTiltLabel());
    }

  if (med_prop && med_prop->GetSliceThickness())
    {
    sprintf(buffer, "%g mm", med_prop->GetSliceThicknessAsDouble());
    list->FindAndInsertCellText(0, labels->GetSliceThicknessLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetSliceThicknessLabel());
    }

  if (med_prop && med_prop->GetConvolutionKernel())
    {
    list->FindAndInsertCellText(0, labels->GetConvolutionKernelLabel(), 
                                1, med_prop->GetConvolutionKernel());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetConvolutionKernelLabel());
    }

  if (med_prop)
    {
    double *dcos = med_prop->GetDirectionCosine();
    sprintf(buffer, "(%g, %g, %g) (%g, %g, %g)", 
            dcos[0], dcos[1], dcos[2], dcos[3], dcos[4], dcos[5]);
    list->FindAndInsertCellText(0, labels->GetDirectionCosineLabel(), 
                                1, buffer);
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetDirectionCosineLabel());
    }

  if (med_prop && med_prop->GetTableHeight())
    {
    list->FindAndInsertCellText(0, labels->GetTableHeightLabel(), 
                                1, med_prop->GetTableHeight());
    }
  else
    {
    list->FindAndDeleteRow(0, labels->GetTableHeightLabel());
    }
  
  // Done with med_prop
}

//----------------------------------------------------------------------------
void vtkVVInformationInterface::UpdateEnableState()
{
  this->Superclass::UpdateEnableState();

  // Information

  if (this->InformationList)
    {
    this->InformationList->SetEnabled(this->GetEnabled());
    }
}

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

