// Created on: 1998-06-03
// Created by: data exchange team
// Copyright (c) 1998-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.

#ifndef _ShapeFix_Face_HeaderFile
#define _ShapeFix_Face_HeaderFile

#include <Standard.hxx>
#include <Standard_Type.hxx>

#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <Standard_Integer.hxx>
#include <ShapeFix_Root.hxx>
#include <TopTools_DataMapOfShapeListOfShape.hxx>
#include <TopTools_SequenceOfShape.hxx>
#include <ShapeFix_DataMapOfShapeBox2d.hxx>
#include <ShapeExtend_Status.hxx>
class ShapeAnalysis_Surface;
class ShapeFix_Wire;
class Geom_Surface;
class ShapeExtend_BasicMsgRegistrator;
class TopoDS_Wire;
class ShapeExtend_WireData;
class TopoDS_Vertex;

// resolve name collisions with X11 headers
#ifdef Status
  #undef Status
#endif

class ShapeFix_Face;
DEFINE_STANDARD_HANDLE(ShapeFix_Face, ShapeFix_Root)

//! This operator allows to perform various fixes on face
//! and its wires: fixes provided by ShapeFix_Wire,
//! fixing orientation of wires, addition of natural bounds,
//! fixing of missing seam edge,
//! and detection and removal of null-area wires
class ShapeFix_Face : public ShapeFix_Root
{

public:
  //! Creates an empty tool
  Standard_EXPORT ShapeFix_Face();

  //! Creates a tool and loads a face
  Standard_EXPORT ShapeFix_Face(const TopoDS_Face& face);

  //! Sets all modes to default
  Standard_EXPORT virtual void ClearModes();

  //! Loads a whole face already created, with its wires, sense and
  //! location
  Standard_EXPORT void Init(const TopoDS_Face& face);

  //! Starts the creation of the face
  //! By default it will be FORWARD, or REVERSED if <fwd> is False
  Standard_EXPORT void Init(const Handle(Geom_Surface)& surf,
                            const Standard_Real         preci,
                            const Standard_Boolean      fwd = Standard_True);

  //! Starts the creation of the face
  //! By default it will be FORWARD, or REVERSED if <fwd> is False
  Standard_EXPORT void Init(const Handle(ShapeAnalysis_Surface)& surf,
                            const Standard_Real                  preci,
                            const Standard_Boolean               fwd = Standard_True);

  //! Sets message registrator
  Standard_EXPORT virtual void SetMsgRegistrator(
    const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg) Standard_OVERRIDE;

  //! Sets basic precision value (also to FixWireTool)
  Standard_EXPORT virtual void SetPrecision(const Standard_Real preci) Standard_OVERRIDE;

  //! Sets minimal allowed tolerance (also to FixWireTool)
  Standard_EXPORT virtual void SetMinTolerance(const Standard_Real mintol) Standard_OVERRIDE;

  //! Sets maximal allowed tolerance (also to FixWireTool)
  Standard_EXPORT virtual void SetMaxTolerance(const Standard_Real maxtol) Standard_OVERRIDE;

  //! Returns (modifiable) the mode for applying fixes of
  //! ShapeFix_Wire, by default True.
  Standard_Integer& FixWireMode();

  //! Returns (modifiable) the fix orientation mode, by default
  //! True. If True, wires oriented to border limited square.
  Standard_Integer& FixOrientationMode();

  //! Returns (modifiable) the add natural bound mode.
  //! If true, natural boundary is added on faces that miss them.
  //! Default is False for faces with single wire (they are
  //! handled by FixOrientation in that case) and True for others.
  Standard_Integer& FixAddNaturalBoundMode();

  //! Returns (modifiable) the fix missing seam mode, by default
  //! True. If True, tries to insert seam is missed.
  Standard_Integer& FixMissingSeamMode();

  //! Returns (modifiable) the fix small area wire mode, by default
  //! False. If True, drops small wires.
  Standard_Integer& FixSmallAreaWireMode();

  //! Returns (modifiable) the remove face with small area, by default
  //! False. If True, drops faces with small outer wires.
  Standard_Integer& RemoveSmallAreaFaceMode();

  //! Returns (modifiable) the fix intersecting wires mode
  //! by default True.
  Standard_Integer& FixIntersectingWiresMode();

  //! Returns (modifiable) the fix loop wires mode
  //! by default True.
  Standard_Integer& FixLoopWiresMode();

  //! Returns (modifiable) the fix split face mode
  //! by default True.
  Standard_Integer& FixSplitFaceMode();

  //! Returns (modifiable) the auto-correct precision mode
  //! by default False.
  Standard_Integer& AutoCorrectPrecisionMode();

  //! Returns (modifiable) the activation flag for periodic
  //! degenerated fix. False by default.
  Standard_Integer& FixPeriodicDegeneratedMode();

  //! Returns a face which corresponds to the current state
  //! Warning: The finally produced face may be another one ... but with the
  //! same support
  TopoDS_Face Face() const;

  //! Returns resulting shape (Face or Shell if split)
  //! To be used instead of Face() if FixMissingSeam involved
  TopoDS_Shape Result() const;

  //! Add a wire to current face using BRep_Builder.
  //! Wire is added without taking into account orientation of face
  //! (as if face were FORWARD).
  Standard_EXPORT void Add(const TopoDS_Wire& wire);

  //! Performs all the fixes, depending on modes
  //! Function Status returns the status of last call to Perform()
  //! ShapeExtend_OK   : face was OK, nothing done
  //! ShapeExtend_DONE1: some wires are fixed
  //! ShapeExtend_DONE2: orientation of wires fixed
  //! ShapeExtend_DONE3: missing seam added
  //! ShapeExtend_DONE4: small area wire removed
  //! ShapeExtend_DONE5: natural bounds added
  //! ShapeExtend_FAIL1: some fails during fixing wires
  //! ShapeExtend_FAIL2: cannot fix orientation of wires
  //! ShapeExtend_FAIL3: cannot add missing seam
  //! ShapeExtend_FAIL4: cannot remove small area wire
  Standard_EXPORT Standard_Boolean Perform();

  //! Fixes orientation of wires on the face
  //! It tries to make all wires lie outside all others (according
  //! to orientation) by reversing orientation of some of them.
  //! If face lying on sphere or torus has single wire and
  //! AddNaturalBoundMode is True, that wire is not reversed in
  //! any case (supposing that natural bound will be added).
  //! Returns True if wires were reversed
  Standard_EXPORT Standard_Boolean FixOrientation();

  //! Fixes orientation of wires on the face
  //! It tries to make all wires lie outside all others (according
  //! to orientation) by reversing orientation of some of them.
  //! If face lying on sphere or torus has single wire and
  //! AddNaturalBoundMode is True, that wire is not reversed in
  //! any case (supposing that natural bound will be added).
  //! Returns True if wires were reversed
  //! OutWires return information about out wires + list of
  //! internal wires for each (for performing split face).
  Standard_EXPORT Standard_Boolean FixOrientation(TopTools_DataMapOfShapeListOfShape& MapWires);

  //! Adds natural boundary on face if it is missing.
  //! Two cases are supported:
  //! - face has no wires
  //! - face lies on geometrically double-closed surface
  //! (sphere or torus) and none of wires is left-oriented
  //! Returns True if natural boundary was added
  Standard_EXPORT Standard_Boolean FixAddNaturalBound();

  //! Detects and fixes the special case when face on a closed
  //! surface is given by two wires closed in 3d but with gap in 2d.
  //! In that case it creates a new wire from the two, and adds a
  //! missing seam edge
  //! Returns True if missing seam was added
  Standard_EXPORT Standard_Boolean FixMissingSeam();

  //! Detects wires with small area (that is less than
  //! 100*Precision::PConfusion(). Removes these wires if they are internal.
  //! Returns : True if at least one small wire removed,
  //! False if does nothing.
  Standard_EXPORT Standard_Boolean FixSmallAreaWire(const Standard_Boolean theIsRemoveSmallFace);

  //! Detects if wire has a loop and fixes this situation by splitting on the few parts.
  //! if wire has a loops and it was split Status was set to value ShapeExtend_DONE6.
  Standard_EXPORT Standard_Boolean FixLoopWire(TopTools_SequenceOfShape& aResWires);

  //! Detects and fixes the special case when face has more than one wire
  //! and this wires have intersection point
  Standard_EXPORT Standard_Boolean FixIntersectingWires();

  //! If wire contains two coincidence edges it must be removed
  //! Queries on status after Perform()
  Standard_EXPORT Standard_Boolean FixWiresTwoCoincEdges();

  //! Split face if there are more than one out wire
  //! using inrormation after FixOrientation()
  Standard_EXPORT Standard_Boolean FixSplitFace(const TopTools_DataMapOfShapeListOfShape& MapWires);

  //! Fixes topology for a specific case when face is composed
  //! by a single wire belting a periodic surface. In that case
  //! a degenerated edge is reconstructed in the degenerated pole
  //! of the surface. Initial wire gets consistent orientation.
  //! Must be used in couple and before FixMissingSeam routine
  Standard_EXPORT Standard_Boolean FixPeriodicDegenerated();

  //! Returns the status of last call to Perform()
  //! ShapeExtend_OK   : face was OK, nothing done
  //! ShapeExtend_DONE1: some wires are fixed
  //! ShapeExtend_DONE2: orientation of wires fixed
  //! ShapeExtend_DONE3: missing seam added
  //! ShapeExtend_DONE4: small area wire removed
  //! ShapeExtend_DONE5: natural bounds added
  //! ShapeExtend_DONE8: face may be splited
  //! ShapeExtend_FAIL1: some fails during fixing wires
  //! ShapeExtend_FAIL2: cannot fix orientation of wires
  //! ShapeExtend_FAIL3: cannot add missing seam
  //! ShapeExtend_FAIL4: cannot remove small area wire
  Standard_Boolean Status(const ShapeExtend_Status status) const;

  //! Returns tool for fixing wires.
  Handle(ShapeFix_Wire) FixWireTool();

  DEFINE_STANDARD_RTTIEXT(ShapeFix_Face, ShapeFix_Root)

protected:
  Handle(ShapeAnalysis_Surface) mySurf;
  TopoDS_Face                   myFace;
  TopoDS_Shape                  myResult;
  Handle(ShapeFix_Wire)         myFixWire;
  Standard_Boolean              myFwd;
  Standard_Integer              myStatus;

private:
  //! Returns True if the face needs to add natural bound and corresponded option of shape healing
  //! is ON
  Standard_Boolean isNeedAddNaturalBound(const TopTools_SequenceOfShape& theOrientedWires);

  Standard_EXPORT Standard_Boolean SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
                                             const Standard_Integer              num,
                                             const Standard_Real                 param,
                                             const TopoDS_Vertex&                vert,
                                             const Standard_Real                 preci,
                                             ShapeFix_DataMapOfShapeBox2d&       boxes);

  Standard_EXPORT Standard_Boolean SplitEdge(const Handle(ShapeExtend_WireData)& sewd,
                                             const Standard_Integer              num,
                                             const Standard_Real                 param1,
                                             const Standard_Real                 param2,
                                             const TopoDS_Vertex&                vert,
                                             const Standard_Real                 preci,
                                             ShapeFix_DataMapOfShapeBox2d&       boxes);

  Standard_Integer myFixWireMode;
  Standard_Integer myFixOrientationMode;
  Standard_Integer myFixAddNaturalBoundMode;
  Standard_Integer myFixMissingSeamMode;
  Standard_Integer myFixSmallAreaWireMode;
  Standard_Integer myRemoveSmallAreaFaceMode;
  Standard_Integer myFixLoopWiresMode;
  Standard_Integer myFixIntersectingWiresMode;
  Standard_Integer myFixSplitFaceMode;
  Standard_Integer myAutoCorrectPrecisionMode;
  Standard_Integer myFixPeriodicDegenerated;
};

#include <ShapeFix_Face.lxx>

#endif // _ShapeFix_Face_HeaderFile
