// Copyright (c) 2006  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1.1/Filtered_kernel/include/CGAL/Filtered_kernel/Cartesian_coordinate_iterator_3.h $
// $Id: include/CGAL/Filtered_kernel/Cartesian_coordinate_iterator_3.h 08b27d3db14 $
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Andreas Fabri, Sylvain Pion

#ifndef CGAL_CARTESIAN_COORDINATE_ITERATOR_3_H
#define CGAL_CARTESIAN_COORDINATE_ITERATOR_3_H

#include <cstddef>
#include <iterator>
#include <variant>

namespace CGAL {

// This class should go away.
// It is now only used by the Filtered_kernel.
// It allows to iterate over the coordinates of both a Point_3 and a Vector_3,
// using a std::variant, as the iterator types are the same at the kernel level.

template <class K>
class Cartesian_coordinate_iterator_3
{

protected:
  typedef typename K::Point_3 P;
  typedef typename K::Vector_3 V;
  std::variant<const P*, const V*> var;
  int index;
  typedef Cartesian_coordinate_iterator_3<K> Self;

public:

  typedef typename K::FT FT;

  typedef std::random_access_iterator_tag iterator_category;
  typedef FT                              value_type;
  typedef int                             difference_type;
  typedef void                            pointer;
  typedef value_type                      reference;

  Cartesian_coordinate_iterator_3()
    : var((const P*) nullptr), index(0) {}

  Cartesian_coordinate_iterator_3(const P * const p, int _index = 0)
    : var(p), index(_index) {}

  Cartesian_coordinate_iterator_3(const V * const v, int _index = 0)
    : var(v), index(_index) {}


  reference
  operator*() const {
    if (const P* const* p = std::get_if<const P*>(&var))
      return (*p)->cartesian(index);
    const V* const* v = std::get_if<const V*>(&var);
    CGAL_assertion(v != 0);
    return (*v)->cartesian(index);
  }

  Self&
  operator++() {
    index++;
    return *this;
  }

  Self&
  operator--() {
    index--;
    return *this;
  }

  Self
  operator++(int) {
    Self tmp(*this);
    ++(*this);
    return tmp;
  }

  Self
  operator--(int) {
    Self tmp(*this);
    --(*this);
    return tmp;
  }

  Self&
  operator+=(difference_type i) {
    index += i;
    return *this;
  }

  Self&
  operator-=(difference_type i) {
    index -= i;
    return *this;
  }

  Self
  operator+(difference_type i) const {
    Self tmp=*this;
    return tmp += i;
  }

  Self
  operator-(difference_type i) const {
    Self tmp=*this;
    return tmp -= i;
  }

  difference_type
  operator-(const Self& x) const {
    CGAL_kernel_assertion(var == x.var);
    return index - x.index;
  }

  reference
  operator[](difference_type i) const {
    return *(*this + i);
  }

  bool
  operator==(const Self& x) const {
    CGAL_kernel_assertion(var == x.var);
    return (index == x.index);
  }

  bool
  operator!=(const Self& x) const {
    return ! (*this==x);
  }

  bool
  operator<(const Self& x) const
  {
    return (x - *this) > 0;
  }

};

} //namespace CGAL

#endif // CGAL_CARTESIAN_COORDINATE_ITERATOR_3_H
