// Copyright (c) 1997-2002  Max-Planck-Institute Saarbruecken (Germany).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v5.4/Nef_3/include/CGAL/Nef_3/Combine_with_halfspace.h $
// $Id: Combine_with_halfspace.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Michael Seel    <seel@mpi-sb.mpg.de>
//                 Miguel Granados <granados@mpi-sb.mpg.de>
//                 Susan Hert      <hert@mpi-sb.mpg.de>
//                 Lutz Kettner    <kettner@mpi-sb.mpg.de>
#ifndef CGAL_COMBINE_WITH_HALFSPACE_H
#define CGAL_COMBINE_WITH_HALFSPACE_H

#include <CGAL/license/Nef_3.h>


#include <CGAL/Nef_S2/Normalizing.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/Nef_3/SNC_const_decorator.h>
#include <CGAL/Nef_S2/SM_decorator.h>
#include <CGAL/Nef_3/SNC_SM_overlayer.h>
#include <CGAL/Nef_3/SNC_constructor.h>
#include <CGAL/Nef_3/SNC_external_structure.h>
#include <CGAL/Nef_3/ID_support_handler.h>
#include <CGAL/Nef_3/Binary_operation.h>

#undef CGAL_NEF_DEBUG
#define CGAL_NEF_DEBUG 19
#include <CGAL/Nef_2/debug.h>

namespace CGAL {

template <typename Map, typename SNC_point_locator>
class Combine_with_halfspace : public SNC_decorator<Map> {
 public:
  typedef Map SNC_structure;
  typedef typename SNC_structure::Items                Items;
  typedef typename Map::Sphere_map                     Sphere_map;
  typedef CGAL::Combine_with_halfspace
    <SNC_structure, SNC_point_locator>  Self;
  typedef CGAL::SNC_decorator<SNC_structure>           Base;
  typedef Base                                         SNC_decorator;
  typedef CGAL::SNC_constructor<Items, SNC_structure>  SNC_constructor;
  typedef CGAL::SNC_external_structure<Items, SNC_structure>
    SNC_external_structure;
  typedef CGAL::SM_decorator<Sphere_map>               SM_decorator;
  typedef CGAL::SM_const_decorator<Sphere_map>         SM_const_decorator;
  typedef CGAL::Binary_operation<SNC_structure>        Binary_operation;

  typedef typename SNC_structure::Vertex_handle Vertex_handle;
  typedef typename SNC_structure::Halffacet_handle Halffacet_handle;

  typedef typename SNC_structure::Vertex_const_iterator Vertex_const_iterator;
  typedef typename SNC_structure::Halfedge_const_iterator Halfedge_const_iterator;

  typedef typename Base::SHalfedge_iterator SHalfedge_iterator;
  typedef typename Base::SHalfedge_const_iterator SHalfedge_const_iterator;
  typedef typename Base::SHalfloop_const_iterator SHalfloop_const_iterator;

  typedef typename Base::Point_3 Point_3;
  typedef typename Base::Segment_3 Segment_3;
  typedef typename Base::Plane_3 Plane_3;

  typedef typename Base::Mark Mark;

  typedef CGAL::ID_support_handler<Items, Base> Association;

  SNC_point_locator* pl;

 public:
  enum Intersection_mode { CLOSED_HALFSPACE=0, OPEN_HALFSPACE=1, PLANE_ONLY=2 };

  Combine_with_halfspace(SNC_structure& W, SNC_point_locator* pl_)
    : Base(W), pl(pl_) {}

  template <typename Selection, typename Intersection_mode>
  void combine_with_halfspace(const SNC_structure& snc,
                              const Plane_3& plane,
                              const Selection& BOP,
                              Intersection_mode im) {

    Association A;
    SHalfedge_const_iterator sei;
    CGAL_forall_shalfedges(sei, snc)
      A.initialize_hash(sei);
    SHalfloop_const_iterator sli;
    CGAL_forall_shalfloops(sli, snc)
      A.initialize_hash(sli);

    int index0(Index_generator::get_unique_index());
    int index1(Index_generator::get_unique_index());
    Halffacet_handle dummy_facet =
      this->sncp()->new_halffacet_pair(plane, im != OPEN_HALFSPACE);
        A.initialize_hash(index0);
        A.initialize_hash(index1);

    Binary_operation bo(*this->sncp());
      Vertex_const_iterator v0;
      CGAL_forall_vertices( v0, snc) {
        Oriented_side os = plane.oriented_side(v0->point());
        if(os == ON_ORIENTED_BOUNDARY) {
          SNC_constructor C(*this->sncp());
          Vertex_handle vp =
            C.create_from_plane(plane, v0->point(),
                                im != OPEN_HALFSPACE,
                                im != PLANE_ONLY, false);
      vp->shalfloop()->set_index_facet(dummy_facet);
      vp->shalfloop()->twin()->set_index_facet(dummy_facet->twin());
      vp->shalfloop()->set_index(index0);
      vp->shalfloop()->twin()->set_index(index1);
          Vertex_handle vr =
            bo.binop_local_views(v0, vp, BOP, *this->sncp(), A);
          this->sncp()->delete_vertex(vp);
        } else if(os == ON_NEGATIVE_SIDE && im != PLANE_ONLY) {
          SNC_constructor C(*this->sncp());
          Vertex_handle v1 = C.clone_SM(v0);
        }
      }

    Halfedge_const_iterator e0;
    CGAL_forall_edges(e0, snc) {
      Segment_3 seg(e0->source()->point(),
                    e0->twin()->source()->point());
      Object o = intersection(plane, seg);
      Point_3 ip;
      if(!assign(ip,o)) continue;
      // TODO: optimize for filtering
      ip = normalized(ip);
      if(ip == e0->source()->point() ||
         ip == e0->twin()->source()->point()) continue;
      SNC_constructor C(*this->sncp());
      Vertex_handle vp =
        C.create_from_plane(plane, ip,
                            im != OPEN_HALFSPACE,
                            im != PLANE_ONLY, false);

      vp->shalfloop()->set_index_facet(dummy_facet);
      vp->shalfloop()->twin()->set_index_facet(dummy_facet->twin());
      vp->shalfloop()->set_index(index0);
      vp->shalfloop()->twin()->set_index(index1);

      Vertex_handle ve = C.create_from_edge(e0, ip);

      Vertex_handle vr =
        bo.binop_local_views(ve, vp, BOP, *this->sncp(), A);
      this->sncp()->delete_vertex(vp);
      this->sncp()->delete_vertex(ve);
    }

    this->sncp()->delete_halffacet_pair(dummy_facet);

    SHalfedge_iterator se;
    CGAL_forall_sedges(se, *this->sncp()) {
      se->circle() = normalized(se->circle());
      se->twin()->circle() = se->circle().opposite();
    }

    SNC_external_structure es(*this->sncp(), pl);
    es.build_after_binary_operation(A);
  }
};

} //namespace CGAL
#endif //CGAL_COMBINE_WITH_HALFSPACE_H
