// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkLineRepresentation.h"

#include <cstdlib>
#include <iostream>

#include "WidgetTestingMacros.h"

#include "vtkFollower.h"
#include "vtkPointHandleRepresentation3D.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"

int vtkLineRepresentationTest1(int, char*[])
{
  vtkSmartPointer<vtkLineRepresentation> node1 = vtkSmartPointer<vtkLineRepresentation>::New();

  vtkSmartPointer<vtkPointHandleRepresentation3D> handleRep =
    vtkSmartPointer<vtkPointHandleRepresentation3D>::New();
  node1->SetHandleRepresentation(handleRep);
  node1->InstantiateHandleRepresentation();

  EXERCISE_BASIC_REPRESENTATION_METHODS(vtkLineRepresentation, node1);

  double pos[3] = { -100.0, 0.0, 99.9 };
  double pos2[3];
  double* posptr = nullptr;

  // point 1 world
  node1->SetPoint1WorldPosition(pos);
  posptr = node1->GetPoint1WorldPosition();
  if (!posptr)
  {
    std::cerr << "Error in get double * for Point1WorldPosition, null pointer returned."
              << std::endl;
    return EXIT_FAILURE;
  }
  else if (posptr[0] != pos[0] || posptr[1] != pos[1] || posptr[2] != pos[2])
  {
    std::cerr << "Error in double * Set/Get Point1WorldPosition, expected " << pos[0] << ", "
              << pos[1] << ", " << pos[2] << " but got " << posptr[0] << ", " << posptr[1] << ", "
              << posptr[2] << std::endl;
    return EXIT_FAILURE;
  }
  else
  {
    std::cout << "GetPoint1WorldPosition double * = " << posptr[0] << ", " << posptr[1] << ", "
              << posptr[2] << std::endl;
  }
  node1->GetPoint1WorldPosition(pos2);
  if (pos2[0] != pos[0] || pos2[1] != pos[1] || pos2[2] != pos[2])
  {
    std::cerr << "Error in Set/Get Point1WorldPosition, expected " << pos[0] << ", " << pos[1]
              << ", " << pos[2] << " but got " << pos2[0] << ", " << pos2[1] << ", " << pos2[2]
              << std::endl;
    return EXIT_FAILURE;
  }
  else
  {
    std::cout << "GetPoint1WorldPosition = " << pos2[0] << ", " << pos2[1] << ", " << pos2[2]
              << std::endl;
  }

  // point 1 display
  /// causes seg faults, don't test yet
  /*
  pos[1] = -99.9;
  //node1->SetPoint1DisplayPosition(pos);
  posptr = node1->GetPoint1DisplayPosition();
  if (!posptr)
    {
    std::cerr << "Error in get double * for Point1DisplayPosition, null pointer returned." <<
  std::endl; return EXIT_FAILURE;
    }
  else if (posptr[0] != pos[0] ||
           posptr[1] != pos[1] ||
           posptr[2] != pos[2])
    {
    std::cerr << "Error in double * Set/Get Point1DisplayPosition, expected " << pos[0] << ", " <<
  pos[1] << ", " << pos[2] << " but got " << posptr[0] << ", " << posptr[1] << ", " << posptr[2] <<
  std::endl; return EXIT_FAILURE;
    }
  else
    {
    std::cout << "GetPoint1DisplayPosition double * = " << posptr[0] << ", " << posptr[1] << ", " <<
  posptr[2] << std::endl;
    }
  node1->GetPoint1DisplayPosition(pos2);
  if (pos2[0] != pos[0] ||
      pos2[1] != pos[1] ||
      pos2[2] != pos[2])
    {
    std::cerr << "Error in Set/Get Point1DisplayPosition, expected " << pos[0] << ", " << pos[1] <<
  ", " << pos[2] << " but got " << pos2[0] << ", " << pos2[1] << ", " << pos2[2] <<  std::endl;
    return EXIT_FAILURE;
    }
  else
    {
    std::cout << "GetPoint1DisplayPosition = " << pos2[0] << ", " << pos2[1] << ", " << pos2[2] <<
  std::endl;
    }
  */

  // point 2 world

  pos[1] = 77.0;
  node1->SetPoint2WorldPosition(pos);
  posptr = node1->GetPoint2WorldPosition();
  if (!posptr)
  {
    std::cerr << "Error in get double * for Point2WorldPosition, null pointer returned."
              << std::endl;
    return EXIT_FAILURE;
  }
  else if (posptr[0] != pos[0] || posptr[1] != pos[1] || posptr[2] != pos[2])
  {
    std::cerr << "Error in double * Set/Get Point2WorldPosition, expected " << pos[0] << ", "
              << pos[1] << ", " << pos[2] << " but got " << posptr[0] << ", " << posptr[1] << ", "
              << posptr[2] << std::endl;
    return EXIT_FAILURE;
  }
  else
  {
    std::cout << "GetPoint2WorldPosition double * = " << posptr[0] << ", " << posptr[1] << ", "
              << posptr[2] << std::endl;
  }
  node1->GetPoint2WorldPosition(pos2);
  if (pos2[0] != pos[0] || pos2[1] != pos[1] || pos2[2] != pos[2])
  {
    std::cerr << "Error in Set/Get Point2WorldPosition, expected " << pos[0] << ", " << pos[1]
              << ", " << pos[2] << " but got " << pos2[0] << ", " << pos2[1] << ", " << pos2[2]
              << std::endl;
    return EXIT_FAILURE;
  }
  else
  {
    std::cout << "GetPoint2WorldPosition = " << pos2[0] << ", " << pos2[1] << ", " << pos2[2]
              << std::endl;
  }

  vtkSmartPointer<vtkPointHandleRepresentation3D> subHandleRep;
  subHandleRep = node1->GetPoint1Representation();
  subHandleRep = node1->GetPoint2Representation();
  subHandleRep = node1->GetLineHandleRepresentation();

  vtkSmartPointer<vtkProperty> prop = node1->GetEndPointProperty();
  if (prop == nullptr)
  {
    std::cout << "End Point Property is nullptr." << std::endl;
  }
  prop = node1->GetSelectedEndPointProperty();
  if (prop == nullptr)
  {
    std::cout << "Selected End Point Property is nullptr." << std::endl;
  }

  prop = node1->GetEndPoint2Property();
  if (prop == nullptr)
  {
    std::cout << "End Point2 Property is nullptr." << std::endl;
  }
  prop = node1->GetSelectedEndPoint2Property();
  if (prop == nullptr)
  {
    std::cout << "Selected End Point2 Property is nullptr." << std::endl;
  }

  prop = node1->GetLineProperty();
  if (prop == nullptr)
  {
    std::cout << "Line Property is nullptr." << std::endl;
  }
  prop = node1->GetSelectedLineProperty();
  if (prop == nullptr)
  {
    std::cout << "Selected Line Property is nullptr." << std::endl;
  }

  TEST_SET_GET_INT_RANGE(node1, Tolerance, 2, 99);
  // 0 is invalid
  TEST_SET_GET_INT_RANGE(node1, Resolution, 2, 100);

  vtkSmartPointer<vtkPolyData> pd = vtkSmartPointer<vtkPolyData>::New();
  node1->GetPolyData(pd);
  if (pd == nullptr)
  {
    std::cout << "Polydata is null" << std::endl;
  }

  // clamped 0-6
  TEST_SET_GET_INT_RANGE(node1, InteractionState, 1, 5);
  // fails on 0
  TEST_SET_GET_INT_RANGE(node1, RepresentationState, 2, 5);

  std::cout << "MTime = " << node1->GetMTime() << std::endl;

  TEST_SET_GET_BOOLEAN(node1, DistanceAnnotationVisibility);
  TEST_SET_GET_STRING(node1, DistanceAnnotationFormat);

  TEST_SET_GET_VECTOR3_DOUBLE_RANGE(node1, DistanceAnnotationScale, 0.0, 100.0);

  std::cout << "Distance = " << node1->GetDistance() << std::endl;

  node1->SetLineColor(1.0, 0.5, 0.75);

  prop = node1->GetDistanceAnnotationProperty();

  vtkSmartPointer<vtkFollower> follower = node1->GetTextActor();

  return EXIT_SUCCESS;
}
