// File:	StepToGeom_MakeSurface.cxx
// Created:	Mon Jul  5 09:56:37 1993
// Author:	Martine LANGLOIS
//		<mla@mastox>
//:n7 abv 15.02.99: S4132: adding translation of surface_replica
//:p0 abv 19.02.99: management of 'done' flag improved
//:s5 abv 22.04.99  Adding debug printouts in catch {} blocks
//sln 03.10.01. BUC61003. creation of  offset surface is corrected

#include <StepToGeom_MakeSurface.ixx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <StdFail_NotDone.hxx>
#include <StepGeom_Surface.hxx>
#include <StepToGeom_MakeSurface.hxx>
#include <StepGeom_BoundedSurface.hxx>
#include <StepToGeom_MakeBoundedSurface.hxx>
#include <StepGeom_ElementarySurface.hxx>
#include <StepToGeom_MakeElementarySurface.hxx>
#include <StepGeom_SweptSurface.hxx>
#include <StepToGeom_MakeSweptSurface.hxx>

//:d4
#include <StepGeom_OffsetSurface.hxx>
#include <Geom_OffsetSurface.hxx>
#include <StepGeom_SurfaceReplica.hxx>
#include <StepGeom_CartesianTransformationOperator3d.hxx>
#include <StepToGeom_MakeTransformation3d.hxx>
#include <UnitsMethods.hxx>
  
#include <BRepBuilderAPI_MakeFace.hxx>
#include <TopoDS_Face.hxx>
#include <ShapeAlgo.hxx>
#include <ShapeAlgo_AlgoContainer.hxx>
#include <TopoDS.hxx>
#include <BRep_Tool.hxx>  

//=============================================================================
// Creation d' une Surface de Geom a partir d' une Surface de Step
//=============================================================================

StepToGeom_MakeSurface::StepToGeom_MakeSurface ( const Handle(StepGeom_Surface)& S)
{
   // sln 01.10.2001 BUC61003. If entry shell is NULL do nothing
  if(S.IsNull()) {
#ifdef DEB 
      cout<<"Warning: StepToGeom_MakeSurface: Null Surface:"; 
#endif
      done = Standard_False;
      return;
  }
  
  done = Standard_False;
  try {
    OCC_CATCH_SIGNALS
    if (S->IsKind(STANDARD_TYPE(StepGeom_BoundedSurface))) {
      Handle(StepGeom_BoundedSurface) S1 = 
	Handle(StepGeom_BoundedSurface)::DownCast(S);
      StepToGeom_MakeBoundedSurface MkBoundedS(S1);
      if ( MkBoundedS.IsDone() ) theSurface = MkBoundedS.Value();
    }
    else if (S->IsKind(STANDARD_TYPE(StepGeom_ElementarySurface))) {
      Handle(StepGeom_ElementarySurface) S1 = 
	Handle(StepGeom_ElementarySurface)::DownCast(S);
      StepToGeom_MakeElementarySurface MkElementatryS(S1);
      if ( MkElementatryS.IsDone() ) theSurface = MkElementatryS.Value();
    }
    else if (S->IsKind(STANDARD_TYPE(StepGeom_SweptSurface))) {
      Handle(StepGeom_SweptSurface) S1 = 
	Handle(StepGeom_SweptSurface)::DownCast(S);
      StepToGeom_MakeSweptSurface MkSweptS(S1);
      if ( MkSweptS.IsDone() ) theSurface = MkSweptS.Value();
    }
    else if (S->IsKind(STANDARD_TYPE(StepGeom_OffsetSurface))) { //:d4 abv 12 Mar 98
      Handle(StepGeom_OffsetSurface) OS = 
	Handle(StepGeom_OffsetSurface)::DownCast(S);
      StepToGeom_MakeSurface MkBasis ( OS->BasisSurface() );
      if ( MkBasis.IsDone() ) 
      {
        // sln 03.10.01. BUC61003. creation of  offset surface is corrected
        Handle(Geom_Surface) aBasisSurface = MkBasis.Value();
        Standard_Real anOffset = OS->Distance() * UnitsMethods::LengthFactor();
        if(aBasisSurface->Continuity() == GeomAbs_C0)
          {
            BRepBuilderAPI_MakeFace aBFace(aBasisSurface);
            if (aBFace.IsDone())
              {
                TopoDS_Face aFace = aBFace.Face();
                TopoDS_Shape aResult =  ShapeAlgo::AlgoContainer()->C0ShapeToC1Shape(aFace, Abs(anOffset));
                if(aResult.ShapeType() == TopAbs_FACE) 
                  {
                    Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aResult));
                    aBasisSurface = aSurf;
                  }
              }
          }
        if(aBasisSurface->Continuity() != GeomAbs_C0)
        theSurface = new Geom_OffsetSurface ( aBasisSurface, anOffset );
      }
    }
    else if (S->IsKind(STANDARD_TYPE(StepGeom_SurfaceReplica))) { //:n7 abv 16 Feb 99
      Handle(StepGeom_SurfaceReplica) SR = 
	Handle(StepGeom_SurfaceReplica)::DownCast(S);
      Handle(StepGeom_Surface) PS = SR->ParentSurface();
      Handle(StepGeom_CartesianTransformationOperator3d) T = 
	Handle(StepGeom_CartesianTransformationOperator3d)::DownCast(SR->Transformation());
      // protect against cyclic references and wrong type of cartop
      if ( ! T.IsNull() && PS != S ) {
	StepToGeom_MakeSurface MkS(PS);
	if ( MkS.IsDone() ) {
	  theSurface = MkS.Value();
	  StepToGeom_MakeTransformation3d MkT ( T );
	  theSurface->Transform ( MkT.Value() );
	}
      }
    }
    done = ! theSurface.IsNull();
  }
  catch(Standard_Failure) {
//   ShapeTool_DB ?
#ifdef DEB //:s5
    cout<<"Warning: StepToGeom_MakeSurface: Exception:"; 
    Standard_Failure::Caught()->Print(cout); cout << endl;
#endif
    done = Standard_False;
  }
}	 

//=============================================================================
// renvoi des valeurs
//=============================================================================

const Handle(Geom_Surface) &
      StepToGeom_MakeSurface::Value() const
{
  StdFail_NotDone_Raise_if(!done == Standard_True,"");
  return theSurface;
}
