#include <vtkSmartPointer.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkCommand.h>
#include <vtkGraphToPolyData.h>
#include "vtkPolyDataToGraph.h"
#include "vtkBoostGraphAdapter.h"

#include <vtkNew.h>
#include <boost/graph/graphviz.hpp>

#include <vtkCallbackCommand.h>
#include <vtkCommand.h>

#define VTK_CREATE(type, name) vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

void FilterEventHandlerVTK(vtkObject *caller, long unsigned int eventId, void *clientData, void *callData)
{

    vtkAlgorithm *filter = static_cast<vtkAlgorithm *>(caller);

    switch (eventId)
    {
    case vtkCommand::ProgressEvent:
        fprintf(stderr, "\r%s progress: %5.1f%%", filter->GetClassName(), 100.0 * filter->GetProgress()); // stderr is flushed directly
        break;
    case vtkCommand::EndEvent:
        std::cerr << std::endl
                  << std::flush;
        break;

        //// VTK does not throw errors (http://public.kitware.com/pipermail/vtkusers/2009-February/050805.html) use Error-Events: http://www.cmake.org/Wiki/VTK/Examples/Cxx/Utilities/ObserveError
    case vtkCommand::ErrorEvent:
        std::cerr << "Error: " << static_cast<char *>(callData) << std::endl
                  << std::flush;
        break;
    case vtkCommand::WarningEvent:
        std::cerr << "Warning: " << static_cast<char *>(callData) << std::endl
                  << std::flush;
        break;
    }
}

int main(int argc, char *argv[])
{

    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0]
                  << " input"
                  << " output"
                  << std::endl;
        return EXIT_FAILURE;
    }

    if (!(strcasestr(argv[1], ".vtp")))
    {
        std::cerr << "The input should end with .vtp" << std::endl;
        return -1;
    }

    if (!(strcasestr(argv[2], ".dot") || strcasestr(argv[2], ".gv")))
    {
        std::cerr << "The output should end with .dot or .gv" << std::endl;
        return -1;
    }

    VTK_CREATE(vtkCallbackCommand, eventCallbackVTK);
    eventCallbackVTK->SetCallback(FilterEventHandlerVTK);

    VTK_CREATE(vtkXMLPolyDataReader, reader);
    reader->SetFileName(argv[1]);
    reader->AddObserver(vtkCommand::AnyEvent, eventCallbackVTK);
    reader->Update();

    // VTK_CREATE(vtkPolyDataToGraph, filter);
    // vtkSmartPointer<vtkPolyDataToGraph> filter;
    vtkNew<vtkPolyDataToGraph> filter;
    filter->SetInputConnection(0, reader->GetOutputPort());
    filter->AddObserver(vtkCommand::AnyEvent, eventCallbackVTK);
    filter->Update();

    vtkUndirectedGraph *graph = vtkUndirectedGraph::SafeDownCast(filter->GetOutput());

    std::ofstream fout(argv[2]);
    boost::write_graphviz(fout, graph);

    return EXIT_SUCCESS;
}