//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt 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 <iostream>
#include <sstream>

#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/FileItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/attribute/System.h"

#include "smtk/common/UUID.h"

#include "smtk/io/AttributeReader.h"
#include "smtk/io/AttributeWriter.h"
#include "smtk/io/Logger.h"

//force to use filesystem version 3
#define BOOST_FILESYSTEM_VERSION 3
#include <boost/filesystem.hpp>
using namespace boost::filesystem;

namespace
{
std::string write_root = SMTK_SCRATCH_DIR;

void cleanup(const std::string& file_path)
{
  //first verify the file exists
  ::boost::filesystem::path path(file_path);
  if (::boost::filesystem::is_regular_file(path))
  {
    //remove the file_path if it exists.
    ::boost::filesystem::remove(path);
  }
}

const char* testInput =
  "<?xml version=\"1.0\" encoding=\"utf-8\" ?>                                   "
  "<SMTK_AttributeSystem Version=\"2\">                                          "
  "  <Definitions>                                                               "
  "    <AttDef Type=\"att1\" BaseType=\"\">                                      "
  "      <ItemDefinitions>                                                       "
  "	<String Name=\"myStrings\" Extensible=\"1\"                            "
  "               NumberOfRequiredValues=\"1\">                                  "
  "	</String>                                                              "
  "	<File Name=\"myFiles\" Extensible=\"1\" ShouldExist=\"false\"          "
  "               NumberOfRequiredValues=\"1\">                                  "
  "	</File>                                                                "
  "      </ItemDefinitions>                                                      "
  "    </AttDef>                                                                 "
  "  </Definitions>                                                              "
  "  <Attributes>                                                                "
  "    <Att Name=\"att\" Type=\"att1\"/>                                         "
  "  </Attributes>                                                               "
  "</SMTK_AttributeSystem>                                                       ";
}

int main()
{
  smtk::attribute::SystemPtr system = smtk::attribute::System::create();
  smtk::io::Logger logger;
  smtk::io::AttributeReader reader;

  if (reader.readContents(system, testInput, logger))
  {
    std::cerr << "Encountered Errors while reading input data\n";
    std::cerr << logger.convertToString();
    return -2;
  }

  std::vector<smtk::attribute::AttributePtr> atts;
  system->attributes(atts);
  if (atts.size() != 1)
  {
    std::cerr << "Unexpected number of attributes: " << atts.size() << "\n";
    std::cerr << logger.convertToString();
    return -2;
  }
  smtk::attribute::AttributePtr att = atts[0];

  smtk::attribute::StringItemPtr myStrings = att->findString("myStrings");
  myStrings->setNumberOfValues(2);
  myStrings->setValue(0, "string0");
  myStrings->setValue(1, "string1");

  smtk::attribute::FileItemPtr myFiles = att->findFile("myFiles");
  myFiles->setNumberOfValues(2);
  myFiles->setValue(0, "/path/to/file0");
  myFiles->setValue(1, "/path/to/file1");

  if (!att->isValid())
  {
    std::cerr << "Input attributes are invalid\n";
    std::cerr << logger.convertToString();
    return -2;
  }

  std::stringstream s;
  s << write_root << "/" << smtk::common::UUID::random().toString() << ".xml";
  std::string fileName = s.str();

  smtk::io::AttributeWriter writer;

  if (writer.write(system, fileName, logger))
  {
    std::cerr << "Failed to write to " << fileName << "\n";
    std::cerr << logger.convertToString();
    return -2;
  }

  smtk::attribute::SystemPtr copiedSystem = smtk::attribute::System::create();
  if (reader.read(copiedSystem, fileName, logger))
  {
    std::cerr << "Failed to read from " << fileName << "\n";
    std::cerr << logger.convertToString();
    return -2;
  }

  {
    std::vector<smtk::attribute::AttributePtr> copiedAtts;
    copiedSystem->attributes(copiedAtts);
    if (copiedAtts.size() != 1)
    {
      std::cerr << "Unexpected number of attributes: " << copiedAtts.size() << "\n";
      std::cerr << logger.convertToString();
      return -2;
    }

    smtk::attribute::AttributePtr copiedAtt = copiedAtts[0];
    if (!copiedAtt->isValid())
    {
      std::cerr << "Copied attributes are invalid\n";
      std::cerr << logger.convertToString();
      return -2;
    }

    smtk::attribute::StringItemPtr myCopiedStrings = copiedAtt->findString("myStrings");
    smtk::attribute::ItemPtr myStringsAsItems =
      std::static_pointer_cast<smtk::attribute::Item>(myStrings);
    smtk::attribute::ConstItemPtr myStringsAsConstItems =
      std::const_pointer_cast<smtk::attribute::Item>(myStringsAsItems);
    myCopiedStrings->assign(myStringsAsConstItems);

    if (myCopiedStrings->numberOfValues() != myStrings->numberOfValues())
    {
      std::cerr << "Unexpected number of string values: " << myCopiedStrings->numberOfValues()
                << " vs " << myStrings->numberOfValues() << "\n";
      std::cerr << logger.convertToString();
      return -2;
    }

    smtk::attribute::FileItemPtr myCopiedFiles = copiedAtt->findFile("myFiles");
    smtk::attribute::ItemPtr myFilesAsItems =
      std::static_pointer_cast<smtk::attribute::Item>(myFiles);
    smtk::attribute::ConstItemPtr myFilesAsConstItems =
      std::const_pointer_cast<smtk::attribute::Item>(myFilesAsItems);
    myCopiedFiles->assign(myFilesAsConstItems);

    if (myCopiedFiles->numberOfValues() != myFiles->numberOfValues())
    {
      std::cerr << "Unexpected number of file values: " << myCopiedFiles->numberOfValues() << " vs "
                << myFiles->numberOfValues() << "\n";
      std::cerr << logger.convertToString();
      return -2;
    }
  }

  cleanup(fileName);

  return 0;
}
