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

  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 "XML/vtkXMLKWRenderWidgetProReader.h"

#include "vtkKW3DMarkersWidget.h"
#include "vtkKWMarker2D.h"
#include "vtkKWRenderWidgetPro.h"
#include "vtkObjectFactory.h"
#include "vtkXMLDataElement.h"
#include "vtkVolumeProperty.h"
#include "vtkImageData.h"

#include "XML/vtkXMLKW3DMarkersWidgetReader.h"
#include "XML/vtkXMLKWMarker2DReader.h"
#include "XML/vtkXMLKWRenderWidgetProWriter.h"
#include "XML/vtkXMLVolumePropertyReader.h"

vtkStandardNewMacro(vtkXMLKWRenderWidgetProReader);
vtkCxxRevisionMacro(vtkXMLKWRenderWidgetProReader, "$Revision: 1.19 $");

//----------------------------------------------------------------------------
const char* vtkXMLKWRenderWidgetProReader::GetRootElementName()
{
  return "KWRenderWidgetPro";
}

//----------------------------------------------------------------------------
int vtkXMLKWRenderWidgetProReader::Parse(vtkXMLDataElement *elem)
{
  if (!this->Superclass::Parse(elem))
    {
    return 0;
    }

  vtkKWRenderWidgetPro *obj = vtkKWRenderWidgetPro::SafeDownCast(this->Object);
  if (!obj)
    {
    vtkWarningMacro(<< "The KWRenderWidgetPro is not set!");
    return 0;
    }

  // Get attributes

  int ival, i;
  const char *cptr;
  float fval;

  if (elem->GetScalarAttribute("IndependentComponents", ival))
    {
    obj->SetIndependentComponents(ival);
    }

  for (i = 0; i < VTK_MAX_VRCOMP; i++)
    {
    char scalarunits[256];
    sprintf(scalarunits, "ScalarUnits%d", i);
    cptr = elem->GetAttribute(scalarunits);
    if (cptr)
      {
      obj->SetScalarUnits(i, cptr);
      }
    }
  
  if (elem->GetScalarAttribute("DisplayChannels", ival))
    {
    obj->SetDisplayChannels(ival);
    }

  if (elem->GetScalarAttribute("UseOpacityModulation", ival))
    {
    obj->SetUseOpacityModulation(ival);
    }

  if (elem->GetScalarAttribute("Window", fval))
    {
    obj->SetWindow(fval);
    }

  if (elem->GetScalarAttribute("Level", fval))
    {
    obj->SetLevel(fval);
    }

  // Get nested elements

  // 2D marker

  vtkKWMarker2D *marker2d = obj->GetMarker2D();
  if (marker2d)
    {
    vtkXMLKWMarker2DReader *xmlr = vtkXMLKWMarker2DReader::New();
    xmlr->SetObject(marker2d);
    xmlr->ParseInNestedElement(
      elem, vtkXMLKWRenderWidgetProWriter::GetMarker2DWidgetElementName());
    xmlr->Delete();
    }

  // 3D markers

  vtkKW3DMarkersWidget *markers3d = obj->GetMarkers3D();
  if (markers3d)
    {
    vtkXMLKW3DMarkersWidgetReader *xmlr = vtkXMLKW3DMarkersWidgetReader::New();
    xmlr->SetObject(markers3d);
    xmlr->ParseInNestedElement(
      elem, vtkXMLKWRenderWidgetProWriter::GetMarkers3DWidgetElementName());
    xmlr->Delete();
    }

  // Transfer functions

  vtkXMLDataElement *nested_elem = elem->FindNestedElementWithName(
    vtkXMLKWRenderWidgetProWriter::GetTransferFunctionsElementName());
  if (nested_elem)
    {
    this->ParseTransferFunctionsElement(nested_elem);
    }
  obj->UpdateColorMapping();

  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLKWRenderWidgetProReader::ParseTransferFunctionsElement(
  vtkXMLDataElement *elem)
{
  vtkKWRenderWidgetPro *obj = vtkKWRenderWidgetPro::SafeDownCast(this->Object);
  if (!obj)
    {
    vtkWarningMacro(<< "The KWRenderWidgetPro is not set!");
    return 0;
    }

  return this->ParseTransferFunctionsElement(
    elem,
    obj->GetVolumeProperty(),
    obj->GetInput(),
    obj->GetIndependentComponents());
}

//----------------------------------------------------------------------------
int vtkXMLKWRenderWidgetProReader::ParseTransferFunctionsElement(
  vtkXMLDataElement *elem, 
  vtkVolumeProperty *vprop, 
  vtkImageData *input,
  int indep_comp)
{
  if (!elem)
    {
    return 0;
    }

  // Check the name of the element

  if (strcmp(elem->GetName(), 
             vtkXMLKWRenderWidgetProWriter::GetTransferFunctionsElementName()))
    {
    vtkWarningMacro(<< "Wrong XML element name! " << elem->GetName());
    return 0;
    }

  // Get the attributes, eventually complain
  
  int fix_points = 0;
  if (input)
    {
    int ival;

    if (elem->GetScalarAttribute("NumberOfScalarComponentsHint", ival) &&
        ival != input->GetNumberOfScalarComponents())
      {
      ostrstream warn;
      warn
        << "The transfer functions were designed for a number of components ("
        << ival << ") that does not match the current number of components (" 
        << input->GetNumberOfScalarComponents()
        << ") ! Ignoring." << ends;
      this->AppendToErrorLog(warn.str());
      warn.rdbuf()->freeze(0);
      return 0;
      }

    if (elem->GetScalarAttribute("ScalarTypeHint", ival) &&
        ival != input->GetScalarType())
      {
      ostrstream warn;
      warn
        << "The transfer functions were designed for a scalar type ("
        << vtkImageScalarTypeNameMacro(ival) << ") that does not match the "
        << "current scalar type (" 
        << vtkImageScalarTypeNameMacro(input->GetScalarType())
        << ") ! Expect some points to be out-of-range." << ends;
      this->AppendToErrorLog(warn.str());
      warn.rdbuf()->freeze(0);
      fix_points = 1;
      }
    }

  // Volume Property
  // Load it to a dummy vprop first, so that we can check for
  // IndependentComponents

  int res = 0;
  if (vprop)
    {
    vtkXMLVolumePropertyReader *xmlr = vtkXMLVolumePropertyReader::New();
    xmlr->SetImageData(input);
    xmlr->CheckScalarOpacityUnitDistanceOn();
    if (fix_points)
      {
      xmlr->KeepTransferFunctionPointsRangeOn();
      }
    
    vtkVolumeProperty *dummy = vtkVolumeProperty::New();
    xmlr->SetObject(dummy);

    if (indep_comp >= 0 && 
        xmlr->ParseInElement(elem) &&
        dummy->GetIndependentComponents() != indep_comp)
      {
      ostrstream warn;
      warn
        << "The transfer functions were designed for a component structure ("
        << (dummy->GetIndependentComponents() ? "" : "non-") 
        << "independent) that does not match the current component structure ("
        << (indep_comp ? "" : "non-") 
        << "independent) ! Ignoring." << ends;
      this->AppendToErrorLog(warn.str());
      warn.rdbuf()->freeze(0);
      }
    else
      {
      xmlr->SetObject(vprop);
      xmlr->ParseInElement(elem);
      res = 1;
      }
    dummy->Delete();
    xmlr->Delete();
    }

  return res;
}

