//=======================================================================
//function : Execute
//purpose  :
//=======================================================================
Standard_Integer GEOMImpl_CylinderDriver::Execute(TFunction_Logbook& log) const
{
  if (Label().IsNull()) return 0;
  Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());

  GEOMImpl_ICylinder aCI (aFunction);
  Standard_Integer aType = aFunction->GetType();

  gp_Pnt aP;
  gp_Vec aV;

  if (aType == CYLINDER_R_H) {
    aP = gp::Origin();
    aV = gp::DZ();
  }
  else if (aType == CYLINDER_PNT_VEC_R_H) {
    Handle(GEOM_Function) aRefPoint  = aCI.GetPoint();
    Handle(GEOM_Function) aRefVector = aCI.GetVector();
    TopoDS_Shape aShapePnt = aRefPoint->GetValue();
    TopoDS_Shape aShapeVec = aRefVector->GetValue();
    if (aShapePnt.IsNull() || aShapeVec.IsNull()) {
      Standard_NullObject::Raise("Cylinder creation aborted: point or vector is not defined");
    }
    if (aShapePnt.ShapeType() != TopAbs_VERTEX ||
        aShapeVec.ShapeType() != TopAbs_EDGE) {
      Standard_TypeMismatch::Raise("Cylinder creation aborted: point or vector shapes has wrong type");
    }

    aP = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt));

    TopoDS_Edge anE = TopoDS::Edge(aShapeVec);
    TopoDS_Vertex V1, V2;
    TopExp::Vertices(anE, V1, V2, Standard_True);
    if (V1.IsNull() || V2.IsNull()) {
      Standard_NullObject::Raise("Cylinder creation aborted: vector is not defined");
    }
    aV = gp_Vec(BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
  }
  else {
    return 0;
  }

  if (aCI.GetH() < 0.0) aV.Reverse();
  gp_Ax2 anAxes (aP, aV);

  BRepPrimAPI_MakeCylinder MC (anAxes, aCI.GetR(), Abs(aCI.GetH()));
  MC.Build();
  if (!MC.IsDone()) {
    StdFail_NotDone::Raise("Cylinder can't be computed from the given parameters");
  }

  TopoDS_Shape aShape = MC.Shape();
  if (aShape.IsNull()) return 0;

  aFunction->SetValue(aShape);

  log.SetTouched(Label());

  return 1;
}
//=======================================================================
//function : Execute
//purpose  :
//======================================================================= 
Standard_Integer GEOMImpl_TorusDriver::Execute(TFunction_Logbook& log) const
{
  if (Label().IsNull()) return 0;    
  Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());

  GEOMImpl_ITorus aCI (aFunction);
  Standard_Integer aType = aFunction->GetType();

  TopoDS_Shape aShape;

  if (aType == TORUS_RR) {
    aShape = BRepPrimAPI_MakeTorus(aCI.GetRMajor(), aCI.GetRMinor()).Shape();

  } else if (aType == TORUS_PNT_VEC_RR) {
    Handle(GEOM_Function) aRefPoint  = aCI.GetCenter();
    Handle(GEOM_Function) aRefVector = aCI.GetVector();
    TopoDS_Shape aShapePnt = aRefPoint->GetValue();
    TopoDS_Shape aShapeVec = aRefVector->GetValue();
    if (aShapePnt.ShapeType() != TopAbs_VERTEX) {
      Standard_TypeMismatch::Raise("Torus Center must be a vertex");
    }
    if (aShapeVec.ShapeType() != TopAbs_EDGE) {
      Standard_TypeMismatch::Raise("Torus Axis must be an edge");
    }

    gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt));
    TopoDS_Edge anE = TopoDS::Edge(aShapeVec);
    TopoDS_Vertex V1, V2;
    TopExp::Vertices(anE, V1, V2, Standard_True);
    if (V1.IsNull() || V2.IsNull()) {
      Standard_ConstructionError::Raise("Bad edge for the Torus Axis given");
    }

    gp_Vec aV (BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
    if (aV.Magnitude() < Precision::Confusion()) {
      Standard_ConstructionError::Raise
        ("End vertices of edge, defining the Torus Axis, are too close");
    }

    gp_Ax2 anAxes (aP, aV);
    BRepPrimAPI_MakeTorus MT (anAxes, aCI.GetRMajor(), aCI.GetRMinor());
    if (!MT.IsDone()) MT.Build();
    if (!MT.IsDone()) StdFail_NotDone::Raise("Torus construction algorithm has failed");
    aShape = MT.Shape();
  } else {
  }

  if (aShape.IsNull()) return 0;
  aFunction->SetValue(aShape);

  log.SetTouched(Label()); 

  return 1;    
}
//=======================================================================
//function : Execute
//purpose  :
//======================================================================= 
Standard_Integer GEOMImpl_CircleDriver::Execute(TFunction_Logbook& log) const
{
  if (Label().IsNull()) return 0;    
  Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());

  GEOMImpl_ICircle aCI (aFunction);
  Standard_Integer aType = aFunction->GetType();

  TopoDS_Shape aShape;

  if (aType == CIRCLE_PNT_VEC_R) {
    // Center
    gp_Pnt aP = gp::Origin();
    Handle(GEOM_Function) aRefPoint = aCI.GetCenter();
    if (!aRefPoint.IsNull()) {
      TopoDS_Shape aShapePnt = aRefPoint->GetValue();
      if (aShapePnt.ShapeType() != TopAbs_VERTEX) {
        Standard_ConstructionError::Raise
          ("Circle creation aborted: invalid center argument, must be a point");
      }
      aP = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt));
    }
    // Normal
    gp_Vec aV = gp::DZ();
    Handle(GEOM_Function) aRefVector = aCI.GetVector();
    if (!aRefVector.IsNull()) {
      TopoDS_Shape aShapeVec = aRefVector->GetValue();
      if (aShapeVec.ShapeType() != TopAbs_EDGE) {
        Standard_ConstructionError::Raise
          ("Circle creation aborted: invalid vector argument, must be a vector or an edge");
      }
      TopoDS_Edge anE = TopoDS::Edge(aShapeVec);
      TopoDS_Vertex V1, V2;
      TopExp::Vertices(anE, V1, V2, Standard_True);
      if (!V1.IsNull() && !V2.IsNull()) {
        aV = gp_Vec(BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
        if (aV.Magnitude() < gp::Resolution()) {
          Standard_ConstructionError::Raise
            ("Circle creation aborted: vector of zero length is given");
        }
      }
    }
    // Axes
    gp_Ax2 anAxes (aP, aV);

    // Radius
    double anR = aCI.GetRadius();
    char aMsg[] = "Circle creation aborted: radius value less than 1e-07 is not acceptable";
    if (anR < Precision::Confusion())
      Standard_ConstructionError::Raise(aMsg);

    // Circle
    gp_Circ aCirc (anAxes, anR);
    aShape = BRepBuilderAPI_MakeEdge(aCirc).Edge();
  }
  else if (aType == CIRCLE_CENTER_TWO_PNT) {
    Handle(GEOM_Function) aRefPoint1 = aCI.GetPoint1();
    Handle(GEOM_Function) aRefPoint2 = aCI.GetPoint2();
    Handle(GEOM_Function) aRefPoint3 = aCI.GetPoint3();
    TopoDS_Shape aShapePnt1 = aRefPoint1->GetValue();
    TopoDS_Shape aShapePnt2 = aRefPoint2->GetValue();
    TopoDS_Shape aShapePnt3 = aRefPoint3->GetValue();
    if (aShapePnt1.ShapeType() == TopAbs_VERTEX &&
        aShapePnt2.ShapeType() == TopAbs_VERTEX &&
        aShapePnt3.ShapeType() == TopAbs_VERTEX)
    {
      gp_Pnt aP1 = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt1));
      gp_Pnt aP2 = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt2));
      gp_Pnt aP3 = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt3));

      if (aP1.Distance(aP2) < gp::Resolution() ||
          aP1.Distance(aP3) < gp::Resolution() ||
          aP2.Distance(aP3) < gp::Resolution())
        Standard_ConstructionError::Raise("Circle creation aborted: coincident points given");

      if (gp_Vec(aP1, aP2).IsParallel(gp_Vec(aP1, aP3), Precision::Angular()))
        Standard_ConstructionError::Raise("Circle creation aborted: points lay on one line");

      double x, y, z, x1, y1, z1, x2, y2, z2, dx, dy, dz, dx2, dy2, dz2, dx3, dy3, dz3, aRadius;
      //Calculations for Radius
      x = aP1.X(); y = aP1.Y(); z = aP1.Z();
      x1 = aP2.X(); y1 = aP2.Y(); z1 = aP2.Z();
      dx = x1 - x;
      dy = y1 - y;
      dz = z1 - z;
      aRadius = sqrt(dx*dx + dy*dy + dz*dz);
      //Calculations for Plane Vector
      x2 = aP3.X(); y2 = aP3.Y(); z2 = aP3.Z();
      dx2 = x2 - x; dy2 = y2 - y; dz2 = z2 - z;
      dx3 = ((dy*dz2) - (dy2*dz))/100;
      dy3 = ((dx2*dz) - (dx*dz2))/100;
      dz3 = ((dx*dy2) - (dx2*dy))/100;
      //Make Plane Vector
      gp_Dir aDir ( dx3, dy3, dz3 );
      //Make Circle
      gp_Ax2 anAxes (aP1, aDir);
      gp_Circ aCirc (anAxes, aRadius);
      aShape = BRepBuilderAPI_MakeEdge(aCirc).Edge();  
    }
  }
  else if (aType == CIRCLE_THREE_PNT) {
    Handle(GEOM_Function) aRefPoint1 = aCI.GetPoint1();
    Handle(GEOM_Function) aRefPoint2 = aCI.GetPoint2();
    Handle(GEOM_Function) aRefPoint3 = aCI.GetPoint3();
    TopoDS_Shape aShapePnt1 = aRefPoint1->GetValue();
    TopoDS_Shape aShapePnt2 = aRefPoint2->GetValue();
    TopoDS_Shape aShapePnt3 = aRefPoint3->GetValue();
    if (aShapePnt1.ShapeType() == TopAbs_VERTEX &&
        aShapePnt2.ShapeType() == TopAbs_VERTEX &&
        aShapePnt3.ShapeType() == TopAbs_VERTEX) {
      gp_Pnt aP1 = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt1));
      gp_Pnt aP2 = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt2));
      gp_Pnt aP3 = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt3));
      if (aP1.Distance(aP2) < gp::Resolution() ||
          aP1.Distance(aP3) < gp::Resolution() ||
          aP2.Distance(aP3) < gp::Resolution())
        Standard_ConstructionError::Raise("Circle creation aborted: coincident points given");
      if (gp_Vec(aP1, aP2).IsParallel(gp_Vec(aP1, aP3), Precision::Angular()))
        Standard_ConstructionError::Raise("Circle creation aborted: points lay on one line");
      Handle(Geom_Circle) aCirc = GC_MakeCircle(aP1, aP2, aP3).Value();
      aShape = BRepBuilderAPI_MakeEdge(aCirc).Edge();
    }  
  }
  else {
  }

  if (aShape.IsNull()) return 0;

  aFunction->SetValue(aShape);

  log.SetTouched(Label()); 

  return 1;    
}
//=======================================================================
//function : Execute
//purpose  :
//=======================================================================
Standard_Integer GEOMImpl_ConeDriver::Execute(TFunction_Logbook& log) const
{
  if (Label().IsNull()) return 0;
  Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());

  GEOMImpl_ICone aCI (aFunction);
  Standard_Integer aType = aFunction->GetType();

  gp_Pnt aP;
  gp_Vec aV;

  Standard_Real aR1 = aCI.GetR1();
  Standard_Real aR2 = aCI.GetR2();

  if (aType == CONE_R1_R2_H) {
    aP = gp::Origin();
    aV = gp::DZ();

  } else if (aType == CONE_PNT_VEC_R1_R2_H) {
    Handle(GEOM_Function) aRefPoint  = aCI.GetPoint();
    Handle(GEOM_Function) aRefVector = aCI.GetVector();
    TopoDS_Shape aShapePnt = aRefPoint->GetValue();
    TopoDS_Shape aShapeVec = aRefVector->GetValue();
    if (aShapePnt.IsNull() || aShapeVec.IsNull()) {
      Standard_NullObject::Raise
        ("Cone creation aborted: point or vector is not defined");
    }
    if (aShapePnt.ShapeType() != TopAbs_VERTEX ||
        aShapeVec.ShapeType() != TopAbs_EDGE) {
      Standard_TypeMismatch::Raise
        ("Cone creation aborted: point or vector shapes has wrong type");
    }

    aP = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt));

    TopoDS_Edge anE = TopoDS::Edge(aShapeVec);
    TopoDS_Vertex V1, V2;
    TopExp::Vertices(anE, V1, V2, Standard_True);
    if (V1.IsNull() || V2.IsNull()) {
      Standard_NullObject::Raise
        ("Cylinder creation aborted: vector is not defined");
    }
    aV = gp_Vec(BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));

  } else {
    return 0;
  }

  if (aCI.GetH() < 0.0) aV.Reverse();
  gp_Ax2 anAxes (aP, aV);

  double theAngle = aCI.GetAngle();
  if (theAngle == 0.)
	theAngle = PI*2.;

  TopoDS_Shape aShape;
  // Cone does not work if same radius
  if (fabs(aR1 - aR2) <= Precision::Confusion()) {
  
	BRepPrimAPI_MakeCylinder MC (anAxes, (aR1 + aR2)/2.0, Abs(aCI.GetH()), theAngle);

	MC.Build();
    if (!MC.IsDone()) {
      StdFail_NotDone::Raise("Cylinder can't be computed from the given parameters");
    }
    aShape = MC.Shape();
  } else {
    BRepPrimAPI_MakeCone MC (anAxes, aCI.GetR1(), aCI.GetR2(), Abs(aCI.GetH()), theAngle);
    MC.Build();
    if (!MC.IsDone()) {
      StdFail_NotDone::Raise("Cylinder can't be computed from the given parameters");
    }
    aShape = MC.Shape();
  }
  if (aShape.IsNull()) return 0;

  log.SetTouched(Label());

  aFunction->SetValue(aShape);
  return 1;
}
//=======================================================================
//function : Execute
//purpose  :
//======================================================================= 
Standard_Integer GEOMImpl_EllipseDriver::Execute(TFunction_Logbook& log) const
{
  if (Label().IsNull()) return 0;    
  Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());

  GEOMImpl_IEllipse aCI (aFunction);
  Standard_Integer aType = aFunction->GetType();

  TopoDS_Shape aShape;

  if (aType == ELLIPSE_PNT_VEC_RR) {
    // Center
    gp_Pnt aP = gp::Origin();
    Handle(GEOM_Function) aRefPoint = aCI.GetCenter();
    if (!aRefPoint.IsNull()) {
      TopoDS_Shape aShapePnt = aRefPoint->GetValue();
      if (aShapePnt.ShapeType() != TopAbs_VERTEX) {
        Standard_ConstructionError::Raise
          ("Ellipse creation aborted: invalid center argument, must be a point");
      }
      aP = BRep_Tool::Pnt(TopoDS::Vertex(aShapePnt));
    }
    // Normal
    gp_Vec aV = gp::DZ();
    Handle(GEOM_Function) aRefVector = aCI.GetVector();
    if (!aRefVector.IsNull()) {
      TopoDS_Shape aShapeVec = aRefVector->GetValue();
      if (aShapeVec.ShapeType() != TopAbs_EDGE) {
        Standard_ConstructionError::Raise
          ("Ellipse creation aborted: invalid normal vector argument, must be a vector or an edge");
      }
      TopoDS_Edge anE = TopoDS::Edge(aShapeVec);
      TopoDS_Vertex V1, V2;
      TopExp::Vertices(anE, V1, V2, Standard_True);
      if (!V1.IsNull() && !V2.IsNull()) {
        aV = gp_Vec(BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
        if (aV.Magnitude() < gp::Resolution()) {
          Standard_ConstructionError::Raise
            ("Ellipse creation aborted: normal vector of zero length is given");
        }
      }
    }

    // Axes
    gp_Ax2 anAxes (aP, aV);

    // Main Axis vector
    Handle(GEOM_Function) aRefVectorMaj = aCI.GetVectorMajor();
    if (!aRefVectorMaj.IsNull()) {
      TopoDS_Shape aShapeVec = aRefVectorMaj->GetValue();
      if (aShapeVec.ShapeType() != TopAbs_EDGE) {
        Standard_ConstructionError::Raise
          ("Ellipse creation aborted: invalid major axis vector argument, must be a vector or an edge");
      }
      TopoDS_Edge anE = TopoDS::Edge(aShapeVec);
      TopoDS_Vertex V1, V2;
      TopExp::Vertices(anE, V1, V2, Standard_True);
      if (!V1.IsNull() && !V2.IsNull()) {
	gp_Vec aVM (BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
        if (aVM.Magnitude() < gp::Resolution()) {
          Standard_ConstructionError::Raise
            ("Ellipse creation aborted: major axis vector of zero length is given");
        }
	if (aV.IsParallel(aVM, Precision::Angular())) {
	  Standard_ConstructionError::Raise
	    ("Ellipse creation aborted: normal and major axis vectors are parallel");
	}
	// Axes defined with main axis vector
	anAxes  = gp_Ax2 (aP, aV, aVM);
      }
    }
    // Radiuses
    double radiusMaj = aCI.GetRMajor();
    double radiusMin = aCI.GetRMinor();
    if ( radiusMaj < radiusMin )
      Standard_ConstructionError::Raise
        ("Ellipse creation aborted: a major radius is less that a minor one");
    if ( radiusMin < 0.0 )
      Standard_ConstructionError::Raise
        ("Ellipse creation aborted: raduis must be positive");

    // Ellipse
    gp_Elips anEll (anAxes, radiusMaj, radiusMin);
    aShape = BRepBuilderAPI_MakeEdge(anEll).Edge();
  } 
  else if(aType == ELLIPSE_THREE_PNT) {
    Handle(GEOM_Function) aRefPoint  = aCI.GetCenter();
    Handle(GEOM_Function) aRefPMajor = aCI.GetPMajor();
    Handle(GEOM_Function) aRefPMinor = aCI.GetPMinor();
    TopoDS_Shape aShCenter = aRefPoint->GetValue();
    TopoDS_Shape aShMajor = aRefPMajor->GetValue();
    TopoDS_Shape aShMinor = aRefPMinor->GetValue();
    if (aShCenter.ShapeType() == TopAbs_VERTEX &&
        aShMajor.ShapeType() == TopAbs_VERTEX && 
        aShMinor.ShapeType() == TopAbs_VERTEX ) {
      gp_Pnt aCenter = BRep_Tool::Pnt(TopoDS::Vertex(aShCenter));
      gp_Pnt aMajor = BRep_Tool::Pnt(TopoDS::Vertex(aShMajor));
      gp_Pnt aMinor = BRep_Tool::Pnt(TopoDS::Vertex(aShMinor));
      GC_MakeEllipse aEllipse( aMajor, aMinor, aCenter );
   	  if (!aEllipse.IsDone()) {
		StdFail_NotDone::Raise("Ellipse operation can not be performed on the given vertices");
	  }
      Handle_Geom_TrimmedCurve aCurve = new Geom_TrimmedCurve(aEllipse.Value(), .0, 2*PI, Standard_True);
      aShape = BRepBuilderAPI_MakeEdge( aCurve ).Edge();
    }
  }
  else {
  }

  if (aShape.IsNull()) return 0;

  aFunction->SetValue(aShape);

  log.SetTouched(Label()); 

  return 1;    
}