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

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

#include "vtkObjectFactory.h"
#include "vtkXMLUtilities.h"
#include "vtkXMLDataElement.h"

#include <vtksys/SystemTools.hxx>
#include <vtksys/ios/sstream>

vtkCxxRevisionMacro(vtkXMLObjectWriter, "$Revision: 1.20 $");

//----------------------------------------------------------------------------
vtkXMLObjectWriter::vtkXMLObjectWriter()
{
  this->WriteFactored = 1;
  this->WriteIndented = 0;
}

//----------------------------------------------------------------------------
int vtkXMLObjectWriter::AddAttributes(vtkXMLDataElement *elem)
{
  if (!elem)
    {
    return 0;
    }

  // Add revisions (actually output only the last rev number)

  vtksys_ios::stringstream revisions;
  this->CollectRevisions(revisions);

  vtksys_stl::string revs = revisions.str();
  const char *ptr = 
    vtksys::SystemTools::FindLastString(revs.c_str(), "$Revision: ");
  if (ptr)
    {
    char buffer[256];
    strcpy(buffer, ptr + strlen("$Revision: "));
    buffer[strlen(buffer) - 3] = '\0';
    elem->SetAttribute("Version", buffer);
    }

  // Add the class name of the object being serialized

  if (this->Object)
    {
    elem->SetAttribute("ClassName", this->Object->GetClassName());
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLObjectWriter::AddNestedElements(vtkXMLDataElement *elem)
{
  if (!elem)
    {
    return 0;
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLObjectWriter::Create(vtkXMLDataElement *elem)
{
  if (!elem)
    {
    return 0;
    }

  elem->SetName(this->GetRootElementName());
  this->AddAttributes(elem);
  this->AddNestedElements(elem);

  return 1;
}

//----------------------------------------------------------------------------
vtkXMLDataElement* 
vtkXMLObjectWriter::CreateInElement(vtkXMLDataElement *parent)
{
  if (!parent)
    {
    return NULL;
    }

  // Don't bother inserting if we can't create the final element

  vtkXMLDataElement *nested_elem = this->NewDataElement();
  if (!this->Create(nested_elem))
    {
    nested_elem->Delete();
    return NULL;
    }

  // Insert the element

  parent->AddNestedElement(nested_elem);
  nested_elem->Delete();

  return nested_elem;
}

//----------------------------------------------------------------------------
vtkXMLDataElement* vtkXMLObjectWriter::CreateInNestedElement(
  vtkXMLDataElement *grandparent, 
  const char *name)
{
  if (!grandparent || !name || !*name)
    {
    return NULL;
    }

  // Create the first nested element (parent)

  vtkXMLDataElement *parent = this->NewDataElement();

  // Create and insert the element inside the parent

  vtkXMLDataElement *nested_elem = this->CreateInElement(parent);
  if (!nested_elem)
    {
    parent->Delete();
    return NULL;
    }

  // Set the parent name and insert it into grandparent

  parent->SetName(name);
  grandparent->AddNestedElement(parent);
  parent->Delete();

  return nested_elem;
}

//----------------------------------------------------------------------------
int vtkXMLObjectWriter::WriteToStream(ostream &os, vtkIndent *indent)
{
  // Create the element

  vtkXMLDataElement *elem = this->NewDataElement();
  this->Create(elem);

  // Factor it

  if (this->WriteFactored)
    {
    vtkXMLUtilities::FactorElements(elem);
    }

  // Output the element

  vtkIndent internal_indent;
  if (this->WriteIndented)
    {
    if (!indent)
      {
      indent = &internal_indent;
      }
    }
  else
    {
    indent = 0;
    }

  vtkXMLUtilities::FlattenElement(elem, os, indent);

  elem->Delete();

  os.flush();
  if (os.fail())
    {
    return 0;
    }
  
  return 1;
}

//----------------------------------------------------------------------------
int vtkXMLObjectWriter::WriteToFile(const char *filename)
{
  ofstream os(filename, ios::out);
  int ret = this->WriteToStream(os);
  
  if (!ret)
    {
    os.close();
    vtksys::SystemTools::RemoveFile(filename);
    }
  
  return ret;
}

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

  os << indent << "WriteFactored: " 
     << (this->WriteFactored ? "On" : "Off") << endl;

  os << indent << "WriteIndented: " 
     << (this->WriteIndented ? "On" : "Off") << endl;
}
