// Created on: 1993-06-24
// Created by: Jean Yves LEBEY
// Copyright (c) 1993-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <TopoDS.hxx>
#include <TopExp_Explorer.hxx>
#include <TopOpeBRepDS_IndexedDataMapOfVertexPoint.hxx>
#include <TopOpeBRepDS_CurveExplorer.hxx>
#include <TopOpeBRepDS_Point.hxx>
#include <TopOpeBRepDS.hxx>

#include <TopOpeBRep_define.hxx>
#include <TopOpeBRepDS_CurvePointInterference.hxx>

Standard_Integer BREP_findPDSamongIDMOVP(const TopOpeBRepDS_Point&                       PDS,
                                         const TopOpeBRepDS_IndexedDataMapOfVertexPoint& IDMOVP)
{
  Standard_Integer iIDMOVP = 0;
  Standard_Integer i = 1, n = IDMOVP.Extent();
  for (; i <= n; i++)
  {
    const TopOpeBRepDS_Point& PM = IDMOVP.FindFromIndex(i);
    if (PDS.IsEqual(PM))
    {
      iIDMOVP = i;
      break;
    }
  }
  return iIDMOVP;
}

void BREP_makeIDMOVP(const TopoDS_Shape& S, TopOpeBRepDS_IndexedDataMapOfVertexPoint& IDMOVP)
{
  TopExp_Explorer Ex;
  for (Ex.Init(S, TopAbs_VERTEX); Ex.More(); Ex.Next())
  {
    const TopoDS_Vertex& v = TopoDS::Vertex(Ex.Current());
    TopOpeBRepDS_Point   PDS(v);
    IDMOVP.Add(v, PDS);
  }
}

void BREP_mergePDS(const Handle(TopOpeBRepDS_HDataStructure)& HDS)
{
  TopOpeBRepDS_DataStructure& BDS = HDS->ChangeDS();
  TopOpeBRepDS_CurveExplorer  cex(BDS);
  if (!cex.More())
    return;

  TopOpeBRepDS_IndexedDataMapOfVertexPoint Mvp1;
  TopOpeBRepDS_IndexedDataMapOfVertexPoint Mvp2;

  for (; cex.More(); cex.Next())
  {

    const TopOpeBRepDS_Curve&                     c  = cex.Curve();
    const Standard_Integer                        ic = cex.Index();
    TopOpeBRepDS_ListIteratorOfListOfInterference itI;
    itI.Initialize(BDS.ChangeCurveInterferences(ic));
    if (!itI.More())
      continue;

    const TopoDS_Face& f1 = TopoDS::Face(c.Shape1());
#ifdef OCCT_DEBUG
    Standard_Integer if1 =
#endif
      BDS.Shape(f1);
    const TopoDS_Face& f2 = TopoDS::Face(c.Shape2());
#ifdef OCCT_DEBUG
    Standard_Integer if2 =
#endif
      BDS.Shape(f2);

    Mvp1.Clear();
    BREP_makeIDMOVP(f1, Mvp1);
    Mvp2.Clear();
    BREP_makeIDMOVP(f2, Mvp2);

    for (; itI.More(); itI.Next())
    {
      Handle(TopOpeBRepDS_Interference)           ITF = itI.Value();
      Handle(TopOpeBRepDS_CurvePointInterference) CPI =
        Handle(TopOpeBRepDS_CurvePointInterference)::DownCast(ITF);
      if (CPI.IsNull())
        continue;
      TopOpeBRepDS_Kind GK = CPI->GeometryType();
      if (GK != TopOpeBRepDS_POINT)
        continue;
      Standard_Integer GI = CPI->Geometry();
      //**!
      if (GI > BDS.NbPoints())
        continue;
      //**!
      const TopOpeBRepDS_Point& PDS = BDS.Point(GI);

      Standard_Integer  ivp1;
      TopoDS_Shape      v1;
      TopOpeBRepDS_Kind k1  = TopOpeBRepDS_UNKNOWN;
      Standard_Integer  iv1 = 0;

      ivp1 = BREP_findPDSamongIDMOVP(PDS, Mvp1);
      if (ivp1)
      {
        v1  = Mvp1.FindKey(ivp1);
        iv1 = BDS.AddShape(v1);
        k1  = TopOpeBRepDS_VERTEX;
      }

      Standard_Integer  ivp2;
      TopoDS_Shape      v2;
      TopOpeBRepDS_Kind k2  = TopOpeBRepDS_UNKNOWN;
      Standard_Integer  iv2 = 0;

      ivp2 = BREP_findPDSamongIDMOVP(PDS, Mvp2);
      if (ivp2)
      {
        v2  = Mvp2.FindKey(ivp2);
        iv2 = BDS.AddShape(v2);
        k2  = TopOpeBRepDS_VERTEX;
      }

      if (ivp1 && ivp2)
        BDS.FillShapesSameDomain(v1, v2);

      Standard_Boolean editITF = (ivp1 || ivp2);
      if (editITF)
      {
        if (ivp1)
        {
          CPI->GeometryType(k1);
          CPI->Geometry(iv1);
        }
        else if (ivp2)
        {
          CPI->GeometryType(k2);
          CPI->Geometry(iv2);
        }
      }

#ifdef OCCT_DEBUG
      if (editITF)
      {
        if (ivp1 != 0)
        {
          std::cout << TopOpeBRepDS::SPrint(TopOpeBRepDS_CURVE, ic, "# BREP_mergePDS ", " : ");
          std::cout << TopOpeBRepDS::SPrint(GK, GI, "", " = ");
          TCollection_AsciiString str(BDS.HasShape(v1) ? "old" : "new ");
          std::cout << TopOpeBRepDS::SPrint(k1, iv1, str);
          std::cout << TopOpeBRepDS::SPrint(TopOpeBRepDS::ShapeToKind(f1.ShapeType()), if1, " de ")
                    << std::endl;
        }
        if (ivp2 != 0)
        {
          std::cout << TopOpeBRepDS::SPrint(TopOpeBRepDS_CURVE, ic, "# BREP_mergePDS ", " : ");
          std::cout << TopOpeBRepDS::SPrint(GK, GI, "", " = ");
          TCollection_AsciiString str(BDS.HasShape(v2) ? "old" : "new ");
          std::cout << TopOpeBRepDS::SPrint(k2, iv2, str);
          std::cout << TopOpeBRepDS::SPrint(TopOpeBRepDS::ShapeToKind(f2.ShapeType()), if2, " de ")
                    << std::endl;
        }
      }
#endif

    } // itI.More()
  }
} // BREP_mergePDS
