// File:	DDataStd_DrawDriver.cxx
// Created:	Mon Sep  7 11:32:44 1998
// Author:	Denis PASCAL
//		<dp@dingox.paris1.matra-dtv.fr>


#include <DDataStd_DrawDriver.ixx>

#include <Draw.hxx>
#include <Draw_Drawable3D.hxx>
#include <DDataStd.hxx>
#include <TDF_Label.hxx>
#include <TDF_Tool.hxx>
#include <TNaming_Tool.hxx>
#include <TopoDS.hxx>
#include <DBRep.hxx>
#include <Draw_Appli.hxx>
#include <TNaming_Tool.hxx>
#include <TDataStd_Integer.hxx>
#include <TDataStd_Real.hxx>
#include <BRep_Tool.hxx>
#include <Draw_Drawable3D.hxx>
#include <Draw_Marker3D.hxx>
#include <TCollection_AsciiString.hxx>
#include <Geom_CartesianPoint.hxx>
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <TDF_Tool.hxx>
#include <TCollection_AsciiString.hxx>
#include <TDataStd.hxx>
#include <gp_Pln.hxx>
#include <gp_Ax3.hxx>
#include <Geom_Plane.hxx>
//
// attribut affichable
//
#include <TNaming_NamedShape.hxx>
#include <TDataStd.hxx>
#include <TDataStd_GeometryEnum.hxx>
#include <TDataStd_Point.hxx>
#include <TDataStd_Axis.hxx>
#include <TDataStd_Plane.hxx>
#include <TDataStd_Geometry.hxx>
#include <TDF_ChildIterator.hxx>
#include <TDF_LabelList.hxx> 
#include <TDF_ListIteratorOfLabelList.hxx>
//
// drawable object
//
#include <DrawTrSurf_Surface.hxx>
#include <Draw_Axis3D.hxx>
#include <DrawDim_Distance.hxx>
#include <DrawDim_Radius.hxx>
#include <DrawDim_Angle.hxx>
#include <DrawDim_PlanarDistance.hxx>
#include <DrawDim_PlanarRadius.hxx>
#include <DrawDim_PlanarAngle.hxx>
#include <DrawDim_PlanarDiameter.hxx>
#include <DBRep_DrawableShape.hxx>

static Standard_Integer DISCRET    = 100;
static Standard_Integer NBISOS     = 10;
static Standard_Real    THESIZE       = 1000.;

// Unused
#ifdef DEB
static Standard_Real    PLANETHESIZE  = 100.;
static Standard_Real    DEFLECTION = 0.0;
#endif

static Handle(DDataStd_DrawDriver) DrawDriver;


Handle(DDataStd_DrawDriver) DDataStd_DrawDriver::Get () {return DrawDriver; }
void DDataStd_DrawDriver::Set (const Handle(DDataStd_DrawDriver)& DD) {DrawDriver =  DD; }

//=======================================================================
//function : Displayer
//purpose  : 
//=======================================================================

DDataStd_DrawDriver::DDataStd_DrawDriver () {}


//=======================================================================
//function : Geometry
//purpose  : 
//=======================================================================

static TopoDS_Shape Geometry (const Handle(TDataStd_Constraint)& A, 
			      const Standard_Integer i, TopAbs_ShapeEnum T) 
{
  TopoDS_Shape S = TNaming_Tool::GetShape(A->GetGeometry(i));
  if (!S.IsNull()) {
    if (T != TopAbs_SHAPE && T != S.ShapeType())
      S.Nullify();
  }
  return S;
}

//=======================================================================
//function : Drawable
//purpose  : 
//=======================================================================

Handle(Draw_Drawable3D) DDataStd_DrawDriver::Drawable (const TDF_Label& L) const
{ 
  // CONSTRAINT

  Handle(TDataStd_Constraint) CTR;
  if (L.FindAttribute(TDataStd_Constraint::GetID(),CTR)) {
    return DrawableConstraint(CTR);
  }
  
  // OBJECT
  
  TopoDS_Shape s;

  //Handle(TDataStd_Object) OBJ;  
  //if (L.FindAttribute(TDataStd_Object::GetID(),OBJ)) { 
  //  return DrawableShape (L,Draw_vert);
  //}  

  // DATUM


  Handle(TDataStd_Point) POINT;
  if (L.FindAttribute(TDataStd_Point::GetID(),POINT)) {  
    return DrawableShape (L,Draw_magenta,Standard_False);
  }
  
  Handle(TDataStd_Axis) AXIS;
  if (L.FindAttribute(TDataStd_Axis::GetID(),AXIS)) {  
    return DrawableShape (L,Draw_magenta,Standard_False);
  }

  Handle(TDataStd_Plane) PLANE;
  if (L.FindAttribute(TDataStd_Plane::GetID(),PLANE)) {  
    return DrawableShape(L,Draw_magenta,Standard_False);
  }

  // Standard GEOMETRY
  

  Handle(TDataStd_Geometry) STD_GEOM;
  if (L.FindAttribute(TDataStd_Geometry::GetID(),STD_GEOM)) {  
    switch (STD_GEOM->GetType()) {
    case TDataStd_POINT :
      {  
	return DrawableShape(L,Draw_jaune,Standard_False);
	break;
      }
    case TDataStd_LINE :
    case TDataStd_CIRCLE :
    case TDataStd_ELLIPSE : 
    case TDataStd_SPLINE :
      {  
	return DrawableShape(L,Draw_cyan,Standard_False);
	break;
      }  
    case TDataStd_ANY_GEOM :
      { 
	break;
      }
      default :
	{
	  break;
	}
    }
  }

  // PURE SHAPE

  Handle(TNaming_NamedShape) NS;
  if (L.FindAttribute(TNaming_NamedShape::GetID(),NS)) {   
    return DrawableShape (NS->Label(),Draw_jaune);
  }

  Handle(Draw_Drawable3D) D3D;
  return D3D;
}




//=======================================================================
//function : DrawableConstraint
//purpose  : 
//=======================================================================

Handle(Draw_Drawable3D) DDataStd_DrawDriver::DrawableConstraint (const Handle(TDataStd_Constraint)& A) const
{
  Handle(DrawDim_Dimension) D;
  
  switch (A->GetType()) {
    
  case TDataStd_RADIUS:
    {
      if (A->IsPlanar()) {
	D = new DrawDim_PlanarRadius (TNaming_Tool::GetShape(A->GetGeometry(1)));
      }
      else {
	TopoDS_Shape aLocalShape = Geometry(A,1,TopAbs_FACE);
	TopoDS_Face F1 = TopoDS::Face(aLocalShape);
//	TopoDS_Face F1 = TopoDS::Face(Geometry(A,1,TopAbs_FACE));
	if (!F1.IsNull()) D = new DrawDim_Radius(F1);
      }
    }
    break;

  case TDataStd_DIAMETER:
    if (A->IsPlanar()) {
      D = new DrawDim_PlanarDiameter (TNaming_Tool::GetShape(A->GetGeometry(1)));
    }
    break;

  case TDataStd_MINOR_RADIUS:
    break;

  case TDataStd_MAJOR_RADIUS:
    break;

  case TDataStd_TANGENT:
    break;

  case TDataStd_PARALLEL:
    break;

  case TDataStd_PERPENDICULAR:
    break;

  case TDataStd_CONCENTRIC:
    break;

  case TDataStd_COINCIDENT:
    break;

  case TDataStd_DISTANCE:
    {
      if (A->IsPlanar()) {
	D = new DrawDim_PlanarDistance (TNaming_Tool::GetShape(A->GetGeometry(1)),
					TNaming_Tool::GetShape(A->GetGeometry(2)));
      }
      else {
	break;
	TopoDS_Shape aLocalShape = (Geometry (A, 1, TopAbs_FACE));
	TopoDS_Face F1 = TopoDS::Face (aLocalShape);
//	TopoDS_Face F1 = TopoDS::Face (Geometry (A, 1, TopAbs_FACE));
	if (A->NbGeometries() == 1) D = new DrawDim_Distance (F1);
	else {
	  TopoDS_Shape aLocalShape = Geometry(A,2,TopAbs_FACE);
	  TopoDS_Face F2 = TopoDS::Face(aLocalShape);
//	  TopoDS_Face F2 = TopoDS::Face(Geometry(A,2,TopAbs_FACE));
	  D = new DrawDim_Distance(F1,F2);
	}
      }
    }
    break;
    
  case TDataStd_ANGLE:
    {     
      if (A->IsPlanar()) {
	Handle(DrawDim_PlanarAngle) DAng = new 
	  DrawDim_PlanarAngle (TNaming_Tool::GetShape(A->GetGeometry(1)),
			       TNaming_Tool::GetShape(A->GetGeometry(2)));
	DAng->Sector(A->Reversed(),A->Inverted());
	TopoDS_Shape aLocalShape = TNaming_Tool::GetShape(A->GetPlane());
	DAng->SetPlane(TopoDS::Face(aLocalShape));
//	DAng->SetPlane(TopoDS::Face(TNaming_Tool::GetShape(A->GetPlane())));
	D = DAng;
      }
      else {
	TopoDS_Shape aLocalShape = Geometry(A,1,TopAbs_FACE);
	TopoDS_Face F1 = TopoDS::Face(aLocalShape);
	aLocalShape = Geometry(A,2,TopAbs_FACE);
	TopoDS_Face F2 = TopoDS::Face(aLocalShape);
//	TopoDS_Face F1 = TopoDS::Face(Geometry(A,1,TopAbs_FACE));
//	TopoDS_Face F2 = TopoDS::Face(Geometry(A,2,TopAbs_FACE));
	if (!F1.IsNull() && !F2.IsNull()) D = new DrawDim_Angle(F1,F2);
      }
    }
    break;

  case TDataStd_EQUAL_RADIUS:
    {

    }
    
    break;

  case TDataStd_SYMMETRY:
    break;

  case TDataStd_MIDPOINT:
    break;

  case TDataStd_EQUAL_DISTANCE:
    break;

  case TDataStd_FIX:
    break;

  case TDataStd_RIGID:
    break;

  case TDataStd_FROM:
    break;

  case TDataStd_AXIS:
    break;

  case TDataStd_MATE:
    {
      TopoDS_Shape aLocalShape = Geometry(A,1,TopAbs_FACE);
      TopoDS_Face F1 = TopoDS::Face(aLocalShape);
      aLocalShape = Geometry(A,2,TopAbs_FACE);
      TopoDS_Face F2 = TopoDS::Face(aLocalShape);
//      TopoDS_Face F1 = TopoDS::Face(Geometry(A,1,TopAbs_FACE));
//      TopoDS_Face F2 = TopoDS::Face(Geometry(A,2,TopAbs_FACE));
      if (!F1.IsNull() && !F2.IsNull())
	D = new DrawDim_Distance(F1,F2);
    }
    break;

  case TDataStd_ALIGN_FACES:
    {
      TopoDS_Shape aLocalShape = Geometry(A,1,TopAbs_FACE) ;
      TopoDS_Face F1 = TopoDS::Face(aLocalShape);
      aLocalShape = Geometry(A,2,TopAbs_FACE) ;
      TopoDS_Face F2 = TopoDS::Face(aLocalShape);
//      TopoDS_Face F1 = TopoDS::Face(Geometry(A,1,TopAbs_FACE));
//      TopoDS_Face F2 = TopoDS::Face(Geometry(A,2,TopAbs_FACE));
      if (!F1.IsNull() && !F2.IsNull())
	D = new DrawDim_Distance(F1,F2);
    }
    break;

  case TDataStd_ALIGN_AXES:
    break;

  case TDataStd_AXES_ANGLE:
    break;

  case TDataStd_FACES_ANGLE:
    break;

  case TDataStd_ROUND:
    break;

  case TDataStd_OFFSET          :
    break;

  }

  if (!D.IsNull()) {
    if (!A->GetValue().IsNull()) {
      Standard_Real val = A->GetValue()->Get();
      if (A->GetValue()->GetDimension() == TDataStd_ANGULAR) val = (180.*val)/PI;
      D->SetValue(val);
    }
    // unverified constraints are red (default is white)
    if (!A->Verified()) D->TextColor(Draw_rouge);  
  }
  return D;
}

//=======================================================================
//function : DrawableShape
//purpose  : 
//=======================================================================

Handle(Draw_Drawable3D) DDataStd_DrawDriver::DrawableShape (const TDF_Label& L,
							      const Draw_ColorKind color,
							      const Standard_Boolean current) const
{  
  Handle(Draw_Drawable3D) DS;
  Handle(TNaming_NamedShape) NS;
  if (L.FindAttribute(TNaming_NamedShape::GetID(),NS)) {
    TopoDS_Shape S;
    if (current) S = TNaming_Tool::CurrentShape (NS);
    else S =  TNaming_Tool::GetShape (NS);
    DS = DrawableShape (S,color);
  }
  return DS;
}

//=======================================================================
//function : DrawableShape
//purpose  : 
//=======================================================================

Handle(Draw_Drawable3D) DDataStd_DrawDriver::DrawableShape (const TopoDS_Shape& s,
								 const Draw_ColorKind color)
{  
  Handle(DBRep_DrawableShape) DS;
  DS = new DBRep_DrawableShape (s,color,color,color,Draw_bleu,THESIZE,NBISOS,DISCRET);
  return DS;
}

