// File:	MeshVS_Mesh.cxx
// Created:	Tue Sep 9 2003
// Author:	Alexander SOLOVYOV
// Copyright:	 Open CASCADE 2003

#include <MeshVS_Mesh.ixx>

#include <Prs3d_Root.hxx>
#include <gp_Pnt.hxx>
#include <TColgp_Array1OfPnt.hxx>

#include <Select3D_SensitivePoint.hxx>
#include <SelectMgr_Selection.hxx>

#include <Aspect_MarkerStyle.hxx>
#include <Aspect_LineStyle.hxx>
#include <Aspect_InteriorStyle.hxx>

#include <Prs3d_PointAspect.hxx>
#include <Prs3d_LineAspect.hxx>
#include <Prs3d_ShadingAspect.hxx>
#include <Prs3d_Presentation.hxx>
#include <PrsMgr_ModedPresentation.hxx>
#include <PrsMgr_PresentationManager3d.hxx>

#include <SelectBasics_SensitiveEntity.hxx>
#include <SelectMgr_SequenceOfOwner.hxx>
#include <Select3D_SensitiveGroup.hxx>
#include <Select3D_SensitiveBox.hxx>

#include <Graphic3d_MaterialAspect.hxx>
#include <Graphic3d_AspectFillArea3d.hxx>
#include <Graphic3d_NameOfMaterial.hxx>

#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_HArray1OfInteger.hxx>
#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#include <TColStd_ListIteratorOfListOfReal.hxx>
#include <TColStd_SequenceOfInteger.hxx>

#include <Bnd_Box.hxx>

#include <MeshVS_DataSource.hxx>
#include <MeshVS_MeshOwner.hxx>
#include <MeshVS_DummySensitiveEntity.hxx>
#include <MeshVS_SensitiveSegment.hxx>
#include <MeshVS_SensitiveFace.hxx>
#include <MeshVS_DrawerAttribute.hxx>
#include <MeshVS_DataMapIteratorOfDataMapOfIntegerMeshOwner.hxx>
#include <MeshVS_SensitivePolyhedron.hxx>

#include <OSD_Timer.hxx>

//================================================================
// Function : Constructor MeshVS_Mesh
// Purpose  :
//================================================================
MeshVS_Mesh::MeshVS_Mesh (const Standard_Boolean theIsAllowOverlapped )
{
  myDataSource.Nullify();
  myHilighter.Nullify();
  myWholeMeshOwner.Nullify();
  mySelectionMethod = MeshVS_MSM_NODES;

  SetAutoHilight ( Standard_False );

  SetDisplayMode( MeshVS_DMF_WireFrame ); // Mode as defaut
  SetHilightMode( MeshVS_DMF_WireFrame ); // Wireframe as default hilight mode

  SetColor ( Quantity_NOC_WHITE );
  SetMaterial ( Graphic3d_NOM_PLASTIC );

  myCurrentDrawer = new MeshVS_Drawer();
  myCurrentDrawer->SetColor   ( MeshVS_DA_InteriorColor, Quantity_NOC_BLUE4 );
  myCurrentDrawer->SetInteger ( MeshVS_DA_InteriorStyle, Aspect_IS_SOLID );
  myCurrentDrawer->SetInteger ( MeshVS_DA_MaxFaceNodes, 10 );
  myCurrentDrawer->SetBoolean ( MeshVS_DA_IsAllowOverlapped, theIsAllowOverlapped );
  myCurrentDrawer->SetBoolean ( MeshVS_DA_Reflection, Standard_True );
  myCurrentDrawer->SetDouble  ( MeshVS_DA_ShrinkCoeff, 0.8 );
  myCurrentDrawer->SetBoolean ( MeshVS_DA_ComputeTime, Standard_False );
  myCurrentDrawer->SetBoolean ( MeshVS_DA_ComputeSelectionTime, Standard_False );
  myCurrentDrawer->SetBoolean ( MeshVS_DA_DisplayNodes, Standard_True );
  myCurrentDrawer->SetDouble  ( MeshVS_DA_EdgeWidth, 1.0 );
  myCurrentDrawer->SetInteger ( MeshVS_DA_EdgeType, Aspect_TOL_SOLID );
  myCurrentDrawer->SetInteger ( MeshVS_DA_MarkerType,  Aspect_TOM_O );
  myCurrentDrawer->SetColor   ( MeshVS_DA_MarkerColor, Quantity_NOC_WHITE );
  myCurrentDrawer->SetDouble  ( MeshVS_DA_MarkerScale, 1.0 );
  myCurrentDrawer->SetInteger ( MeshVS_DA_BeamType, Aspect_TOL_SOLID );
  myCurrentDrawer->SetDouble  ( MeshVS_DA_BeamWidth, 1.0 );
  myCurrentDrawer->SetBoolean ( MeshVS_DA_SmoothShading, Standard_False );
  myCurrentDrawer->SetBoolean ( MeshVS_DA_SupressBackFaces, Standard_False );

  mySelectionDrawer = new MeshVS_Drawer();
  mySelectionDrawer->Assign ( myCurrentDrawer );
  mySelectionDrawer->SetInteger ( MeshVS_DA_MarkerType,  Aspect_TOM_STAR );
  mySelectionDrawer->SetColor   ( MeshVS_DA_MarkerColor, Quantity_NOC_GRAY80 );
  mySelectionDrawer->SetDouble  ( MeshVS_DA_MarkerScale, 2.0 );

  mySelectionDrawer->SetColor   ( MeshVS_DA_BeamColor, Quantity_NOC_GRAY80 );
  mySelectionDrawer->SetInteger ( MeshVS_DA_BeamType,  Aspect_TOL_SOLID );
  mySelectionDrawer->SetDouble  ( MeshVS_DA_BeamWidth, 3.0 );

  myHilightDrawer = new MeshVS_Drawer ();
  myHilightDrawer->Assign ( myCurrentDrawer );
  myHilightDrawer->SetDouble   ( MeshVS_DA_ShrinkCoeff, 0.7 );
  myHilightDrawer->SetInteger  ( MeshVS_DA_InteriorStyle, Aspect_IS_SOLID );
  myHilightDrawer->SetColor    ( MeshVS_DA_InteriorColor, Quantity_NOC_YELLOW );
  myHilightDrawer->SetColor    ( MeshVS_DA_BackInteriorColor, Quantity_NOC_YELLOW );
  myHilightDrawer->SetColor    ( MeshVS_DA_EdgeColor, Quantity_NOC_GREEN );
  myHilightDrawer->SetInteger  ( MeshVS_DA_EdgeType, Aspect_TOL_SOLID );
  myHilightDrawer->SetDouble   ( MeshVS_DA_EdgeWidth, 1.0 );
  myHilightDrawer->SetMaterial ( MeshVS_DA_FrontMaterial, Graphic3d_NOM_PLASTIC );
  myHilightDrawer->SetMaterial ( MeshVS_DA_BackMaterial, Graphic3d_NOM_PLASTIC );

  myHilightDrawer->SetColor   ( MeshVS_DA_BeamColor, Quantity_NOC_GRAY80 );
  myHilightDrawer->SetInteger ( MeshVS_DA_BeamType,  Aspect_TOL_SOLID );
  myHilightDrawer->SetDouble  ( MeshVS_DA_BeamWidth, 3.0 );

  myHilightDrawer->SetInteger ( MeshVS_DA_MarkerType,  Aspect_TOM_STAR );
  myHilightDrawer->SetColor   ( MeshVS_DA_MarkerColor, Quantity_NOC_GRAY80 );
  myHilightDrawer->SetDouble  ( MeshVS_DA_MarkerScale, 2.0 );
}

void MeshVS_Mesh::Destroy()
{
}

//================================================================
// Function : Compute
// Purpose  :
//================================================================
void MeshVS_Mesh::Compute ( const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
                            const Handle(Prs3d_Presentation)& thePresentation,
                            const Standard_Integer theMode )
{
  OSD_Timer gTimer;

  Standard_Boolean ShowComputeTime = Standard_True;
  myCurrentDrawer->GetBoolean( MeshVS_DA_ComputeTime, ShowComputeTime );

  if ( ShowComputeTime )
  {
    gTimer.Reset();
    gTimer.Start();
  }

  // Repair Ids in map if necessary
  Handle( MeshVS_DataSource ) aDS = GetDataSource();
  if ( aDS.IsNull() )
    return;

  Standard_Boolean HasNodes    = !aDS->GetAllNodes().IsEmpty(),
                   HasElements = !aDS->GetAllElements().IsEmpty();

  MeshVS_Array1OfIntegerBoolean aNodes( 1, HasNodes ? aDS->GetAllNodes().Extent() : 1 ),
                                anElements( 1, HasElements ? aDS->GetAllElements().Extent() : 1 );

  if( HasNodes )
    TColStdMapToMeshVSArray ( aDS->GetAllNodes(), aNodes );
  if( HasElements )
    TColStdMapToMeshVSArray ( aDS->GetAllElements(), anElements );
  
  thePresentation->Clear();
  Standard_Integer len = myBuilders.Length();
  if ( theMode > 0 )
    for ( Standard_Integer i=1; i<=len; i++ )
    {
      Handle (MeshVS_PrsBuilder) aCurrent = myBuilders.Value ( i );
      if ( !aCurrent.IsNull() && aCurrent->TestFlags ( theMode ) )
      {
        aCurrent->SetPresentationManager( thePrsMgr );
        if( HasNodes )
          aCurrent->Build ( thePresentation, aNodes,     Standard_False, theMode );
        if( HasElements )
          aCurrent->Build ( thePresentation, anElements, Standard_True,  theMode );
      }
    }


  if ( ShowComputeTime )
  {
    Standard_Real sec, cpu;
    Standard_Integer min, hour;

    gTimer.Show ( sec, min, hour, cpu );
    cout << "DisplayMode : " << theMode << endl;
    cout << "Compute : " << sec << " sec" << endl;
    cout << "Compute CPU : " << cpu << " sec" << endl << endl;
    gTimer.Stop();
  }
}

//================================================================
// Function : ComputeSelection
// Purpose  :
//================================================================
void MeshVS_Mesh::ComputeSelection ( const Handle(SelectMgr_Selection)& theSelection,
                                     const Standard_Integer theMode )
{
  OSD_Timer gTimer;

  Standard_Boolean ShowComputeSelectionTime = Standard_True;
  myCurrentDrawer->GetBoolean( MeshVS_DA_ComputeSelectionTime, ShowComputeSelectionTime );

  if ( ShowComputeSelectionTime )
  {
    gTimer.Reset();
    gTimer.Start();
  }

  Standard_Integer aMaxFaceNodes;
  Handle( MeshVS_DataSource ) aSource = GetDataSource();

  if ( aSource.IsNull() || myCurrentDrawer.IsNull() || !myCurrentDrawer->GetInteger
         ( MeshVS_DA_MaxFaceNodes, aMaxFaceNodes ) || aMaxFaceNodes<=0 )
    return;

  TColStd_Array1OfReal aCoords (1, 3*aMaxFaceNodes);
  Standard_Integer NbNodes;

  MeshVS_EntityType aType;
  Standard_Address   anAddr;
  TColStd_MapIteratorOfPackedMapOfInteger anIter;
  Standard_Real x, y, z;

  Standard_Integer aMode = HasDisplayMode() ? DisplayMode() : DefaultDisplayMode();
  if ( myHilighter.IsNull() || ( aMode & MeshVS_DMF_OCCMask ) == 0 )
    return;

  const TColStd_PackedMapOfInteger& anAllNodesMap   = aSource->GetAllNodes();
  const TColStd_PackedMapOfInteger& anAllElementsMap= aSource->GetAllElements();
//agv  Standard_Integer i;

  switch ( theMode )
  {
  case MeshVS_ET_Node:   // Nodes
    myNodeOwners.Clear();

    for ( anIter.Initialize( anAllNodesMap ); anIter.More(); anIter.Next() )
    {
      Standard_Integer aKey = anIter.Key();
      if ( !myDataSource->GetGeom ( aKey, Standard_False, aCoords, NbNodes, aType ) )
        continue;

      anAddr = myDataSource->GetAddr ( aKey, Standard_False );

      Handle (MeshVS_MeshOwner) anOwner = new MeshVS_MeshOwner
        ( this, aKey, anAddr, aType, 5 );

      myNodeOwners.Bind ( aKey, anOwner );

      if ( IsSelectableNode( aKey ) )
      {
        x = aCoords(1);
        y = aCoords(2);
        z = aCoords(3);
        Handle (Select3D_SensitivePoint) aPoint = new Select3D_SensitivePoint
          ( anOwner, gp_Pnt (x, y, z) );
        theSelection->Add ( aPoint );
      }
      else
        theSelection->Add ( new MeshVS_DummySensitiveEntity ( anOwner ) );
    }
    break;
  case 0:
    {
      if( myWholeMeshOwner.IsNull() )
        myWholeMeshOwner = new SelectMgr_EntityOwner( this );

      switch( mySelectionMethod )
      {
      case MeshVS_MSM_BOX:
        {
          Standard_Real min[3], max[3]; Standard_Boolean first = Standard_True;
          TColStd_MapIteratorOfPackedMapOfInteger anIterN( anAllNodesMap );

          for( ; anIterN.More(); anIterN.Next() )
            if( myDataSource->GetGeom( anIterN.Key(), Standard_False, aCoords, NbNodes, aType ) )
              if( first )
              {
                for( Standard_Integer i=1; i<=3; i++ )
                  min[i-1] = max[i-1] = aCoords( i );
                first = Standard_False;
              }
              else
                for( Standard_Integer i=1; i<=3; i++ )
                {
                  if( aCoords( i )<min[i-1] )
                    min[i-1] = aCoords( i );
                  if( aCoords( i )>max[i-1] )
                    max[i-1] = aCoords( i );
                }
          Bnd_Box box;
          box.Add( gp_Pnt( min[0], min[1], min[2] ) );
          box.Add( gp_Pnt( max[0], max[1], max[2] ) );

          theSelection->Add( new Select3D_SensitiveBox( myWholeMeshOwner, box ) );
        }
        break;

      case MeshVS_MSM_NODES:
        {
          TColStd_MapIteratorOfPackedMapOfInteger anIterN( anAllNodesMap );
          for( ; anIterN.More(); anIterN.Next() )
            if( myDataSource->GetGeom( anIterN.Key(), Standard_False, aCoords, NbNodes, aType ) &&
                !IsHiddenNode( anIterN.Key() ) )
              theSelection->Add( new Select3D_SensitivePoint( myWholeMeshOwner, gp_Pnt ( aCoords(1), aCoords(2), aCoords(3) ) ) );
        }
        break;

      case MeshVS_MSM_PRECISE:
        {
          Handle( Select3D_SensitiveEntity ) anEnt;
          TColStd_MapIteratorOfPackedMapOfInteger anIterMV( anAllElementsMap );

          TColStd_PackedMapOfInteger aSharedNodes;
          for( ; anIterMV.More(); anIterMV.Next() )
          {
            Standard_Integer aKey = anIterMV.Key();

            if( IsSelectableElem( aKey ) && 
                myDataSource->GetGeomType( aKey, Standard_True, aType ) && 
                aType==MeshVS_ET_Face )
            {
              myDataSource->GetGeom ( aKey, Standard_True, aCoords, NbNodes, aType );
              if( NbNodes==0 )
                continue;
              
              Handle(TColStd_HArray1OfInteger) aElemNodes = 
                myDataSource->GetNodesByElement( aKey );

              TColgp_Array1OfPnt Points( 1, NbNodes );
              for ( Standard_Integer i=1; i<=NbNodes; i++ )
              {
                Points (i) = gp_Pnt ( aCoords (3*i-2), aCoords (3*i-1), aCoords (3*i) );
                aSharedNodes.Add( aElemNodes->Value( i ) );
              }

              anEnt = new Select3D_SensitiveFace( myWholeMeshOwner, Points );
              theSelection->Add( anEnt );
            }
          }
          for( anIterMV.Initialize( anAllElementsMap ); anIterMV.More(); anIterMV.Next() )
          {
            Standard_Integer aKey = anIterMV.Key();

            if( IsSelectableElem( aKey ) && 
                myDataSource->GetGeomType( aKey, Standard_True, aType ) && 
                aType==MeshVS_ET_Link )
            {
              myDataSource->GetGeom ( aKey, Standard_True, aCoords, NbNodes, aType );
              if( NbNodes==0 )
                continue;
              
              Handle(TColStd_HArray1OfInteger) aElemNodes = 
                myDataSource->GetNodesByElement( aKey );

              TColgp_Array1OfPnt Points( 1, NbNodes );
              Standard_Boolean all_shared = Standard_True;
              for ( Standard_Integer i=1; i<=NbNodes; i++ )
              {
                Points (i) = gp_Pnt ( aCoords (3*i-2), aCoords (3*i-1), aCoords (3*i) );
                all_shared = all_shared && aSharedNodes.Contains( aElemNodes->Value( i ) );
                aSharedNodes.Add( aElemNodes->Value( i ) );
              }

              if( !all_shared )
              {
                anEnt = new Select3D_SensitiveSegment( myWholeMeshOwner, Points.Value( 1 ), Points.Value( 2 ) );
                theSelection->Add( anEnt );
              }
            }
          }
          for( anIterMV.Initialize( anAllNodesMap ); anIterMV.More(); anIterMV.Next() )
          {
            Standard_Integer aKey = anIterMV.Key();
            if( IsSelectableElem( aKey ) && 
                myDataSource->GetGeom ( aKey, Standard_False, aCoords, NbNodes, aType ) && 
                !aSharedNodes.Contains( aKey ) )
            {
              anEnt = new Select3D_SensitivePoint( myWholeMeshOwner, gp_Pnt ( aCoords(1), aCoords(2), aCoords(3) ) ) ;
              theSelection->Add( anEnt );
            }
          }
        }
        break;
      }
    }
    break;

  default: // all residuary modes
    {
      Handle( MeshVS_HArray1OfSequenceOfInteger ) aTopo;

      myElementOwners.Clear();

      MeshVS_DataMapOfIntegerMeshOwner* CurMap = &my0DOwners;
      if ( theMode == MeshVS_ET_Link )
        CurMap = &myLinkOwners;
      else if ( theMode == MeshVS_ET_Face )
        CurMap = &myFaceOwners;
      else if ( theMode == MeshVS_ET_Volume )
        CurMap = &myVolumeOwners;

      CurMap->Clear();

      for (TColStd_MapIteratorOfPackedMapOfInteger anIterMV (anAllElementsMap);
           anIterMV.More(); anIterMV.Next() )
      {
        Standard_Integer aKey = anIterMV.Key();

        if ( myDataSource->GetGeomType ( aKey, Standard_True, aType ) && theMode == aType )
        {
          myDataSource->GetGeom ( aKey, Standard_True, aCoords, NbNodes, aType );
          anAddr = myDataSource->GetAddr ( aKey, Standard_True );

          Standard_Integer aPrior = 0;

          if( aType == MeshVS_ET_Volume )
            aPrior = 1;
          if ( aType == MeshVS_ET_Face )
            aPrior = 2;
          else if ( aType == MeshVS_ET_Link )
            aPrior = 3;
          else if ( aType == MeshVS_ET_0D )
            aPrior = 4;

          Handle (MeshVS_MeshOwner) anOwner = new MeshVS_MeshOwner
            ( this, aKey, anAddr, aType, aPrior );

          CurMap->Bind ( aKey, anOwner );

          if ( IsSelectableElem( aKey ) ) //The element is selectable
          {
            TColgp_Array1OfPnt anArr( 1, NbNodes );
            for ( Standard_Integer i=1; i<=NbNodes; i++ )
            {
              x = aCoords(3*i-2);
              y = aCoords(3*i-1);
              z = aCoords(3*i);
              anArr.SetValue ( i, gp_Pnt ( x, y, z ) );
            }

            if ( aType == MeshVS_ET_Face && NbNodes > 0 )      // Faces: 2D-elements
            {
              Handle (MeshVS_SensitiveFace) aFace = 
                  new MeshVS_SensitiveFace( anOwner, anArr );
              theSelection->Add ( aFace );
            }
            else if ( aType == MeshVS_ET_Link && NbNodes > 0 ) // Links: 1D-elements
            {
              Handle (MeshVS_SensitiveSegment) aSeg = new MeshVS_SensitiveSegment
                ( anOwner, anArr(1), anArr(2) );
              theSelection->Add ( aSeg );
            }
            else if( aType == MeshVS_ET_Volume && aSource->Get3DGeom( aKey, NbNodes, aTopo ) )
            {
              Handle( MeshVS_SensitivePolyhedron ) aPolyhedron = 
                  new MeshVS_SensitivePolyhedron( anOwner, anArr, aTopo );
              theSelection->Add( aPolyhedron );
            }
            else //if ( aType == MeshVS_ET_0D )   // Custom : not only 0D-elements !!!
            {
              Handle (SelectBasics_SensitiveEntity) anEnt =
                myHilighter->CustomSensitiveEntity ( anOwner, aKey );
              if (!anEnt.IsNull())
                theSelection->Add ( anEnt );
            }
          }
          else
            theSelection->Add ( new MeshVS_DummySensitiveEntity ( anOwner ) );
        }
      }
    }
    break;
  }

  if ( ShowComputeSelectionTime )
  {
    Standard_Real sec, cpu;
    Standard_Integer min, hour;

    gTimer.Show ( sec, min, hour, cpu );
    cout << "SelectionMode : " << theMode << endl;
    cout << "Compute selection: " << sec << " sec" << endl;
    cout << "Compute selection CPU : " << cpu << " sec" << endl << endl;
    gTimer.Stop();
  }
}

//================================================================
// Function : GetBuildersCount
// Purpose  :
//================================================================
Standard_Integer MeshVS_Mesh::GetBuildersCount () const
{
  return myBuilders.Length();
}

//================================================================
// Function : GetFreeId
// Purpose  :
//================================================================
Standard_Integer MeshVS_Mesh::GetFreeId () const
{
  TColStd_PackedMapOfInteger Ids;
  Standard_Integer i, len = myBuilders.Length(), curId;

  for ( i=1; i<=len; i++ )
    Ids.Add( myBuilders.Value(i)->GetId () );

  curId = 0;
  while ( Ids.Contains( curId ) )
    curId++;

  return curId;
}

//================================================================
// Function : GetBuilder
// Purpose  :
//================================================================
Handle (MeshVS_PrsBuilder) MeshVS_Mesh::GetBuilder ( const Standard_Integer Index ) const
{
  if ( Index>=1 && Index<=myBuilders.Length() )
    return myBuilders.Value( Index );
  else
    return 0;
}

//================================================================
// Function : GetBuilderById
// Purpose  :
//================================================================
Handle (MeshVS_PrsBuilder) MeshVS_Mesh::GetBuilderById ( const Standard_Integer Id ) const
{
  Handle (MeshVS_PrsBuilder) Result;

  Standard_Integer i, len = myBuilders.Length();
  for ( i=1; i<=len; i++ )
    if ( myBuilders.Value(i)->GetId () == Id )
    {
      Result = myBuilders.Value(i);
      break;
    }
  return Result;
}

//================================================================
// Function : AddBuilder
// Purpose  :
//================================================================
void MeshVS_Mesh::AddBuilder ( const Handle (MeshVS_PrsBuilder)& theBuilder,
                               const Standard_Boolean TreatAsHilighter )
{
  if ( theBuilder.IsNull() )
    return;

  Standard_Integer i, n = myBuilders.Length();
  for ( i = 1; i<=n; i++ )
    if ( myBuilders(i)->GetPriority() < theBuilder->GetPriority() )
      break;

  if ( i>n )
    myBuilders.Append ( theBuilder );
  else
    myBuilders.InsertBefore ( i, theBuilder );

  if( TreatAsHilighter )
    myHilighter = theBuilder;
}

//================================================================
// Function : RemoveBuilder
// Purpose  :
//================================================================
void MeshVS_Mesh::RemoveBuilder ( const Standard_Integer theIndex )
{
  Handle( MeshVS_PrsBuilder ) aBuild = GetBuilder( theIndex );
  if ( !aBuild.IsNull() )
  {
    if ( aBuild == myHilighter )
      myHilighter.Nullify();
    myBuilders.Remove ( theIndex );
  }
}

//================================================================
// Function : RemoveBuilderById
// Purpose  :
//================================================================
void MeshVS_Mesh::RemoveBuilderById ( const Standard_Integer Id )
{
  Standard_Integer i, n = myBuilders.Length();
  for ( i=1; i<=n; i++ )
  {
    Handle( MeshVS_PrsBuilder ) aCur = myBuilders(i);
    if ( !aCur.IsNull() && aCur->GetId()==Id )
      break;
  }
  if ( i>=1 && i<=n )
  {
    if ( GetBuilder( i )==myHilighter )
      myHilighter.Nullify();
    RemoveBuilder ( i );
  }
}

//================================================================
// Function : TColStdMapToMeshVSMap
// Purpose  :
//================================================================
void MeshVS_Mesh::TColStdMapToMeshVSArray(const TColStd_PackedMapOfInteger& Map,
                                          MeshVS_Array1OfIntegerBoolean& Array)
{
  Standard_Integer i, low = Array.Lower();
  TColStd_MapIteratorOfPackedMapOfInteger anIter (Map);

  for( i=0; anIter.More(); anIter.Next(), i++ )
  {
    MeshVS_IntegerBoolean& anArrayElem = Array.ChangeValue (low+i);
    anArrayElem.Key = anIter.Key();
    anArrayElem.Value = Standard_True;
  }
}

//================================================================
// Function : SetHiddenElems
// Purpose  :
//================================================================
void MeshVS_Mesh::SetHiddenElems ( const Handle(TColStd_HPackedMapOfInteger)& theMap )
{
  myHiddenElements = theMap;

  // Note: update of list of selectable nodes -- this is not optimal!
  Standard_Boolean AutoSelUpdate = Standard_False;
  if ( !GetDrawer().IsNull() && GetDrawer()->GetBoolean( MeshVS_DA_SelectableAuto, AutoSelUpdate ) &&
       AutoSelUpdate )
    UpdateSelectableNodes();
}

//================================================================
// Function : SetHiddenNodes
// Purpose  :
//================================================================
void MeshVS_Mesh::SetHiddenNodes ( const Handle(TColStd_HPackedMapOfInteger)& theMap )
{
  myHiddenNodes = theMap;

  // Note: update of list of selectable nodes -- this is not optimal!
  Standard_Boolean AutoSelUpdate = Standard_False;
  if ( !GetDrawer().IsNull() && GetDrawer()->GetBoolean( MeshVS_DA_SelectableAuto, AutoSelUpdate ) &&
       AutoSelUpdate )
    UpdateSelectableNodes();
}

//================================================================
// Function : GetHiddenElems
// Purpose  :
//================================================================
const Handle(TColStd_HPackedMapOfInteger)& MeshVS_Mesh::GetHiddenElems () const
{
  return myHiddenElements;
}

//================================================================
// Function : GetHiddenNodes
// Purpose  :
//================================================================
const Handle(TColStd_HPackedMapOfInteger)& MeshVS_Mesh::GetHiddenNodes () const
{
  return myHiddenNodes;
}

//================================================================
// Function : AddToMap
// Purpose  :
//================================================================
void AddToMap ( MeshVS_DataMapOfIntegerMeshOwner& Result, const MeshVS_DataMapOfIntegerMeshOwner& Addition )
{
  MeshVS_DataMapIteratorOfDataMapOfIntegerMeshOwner anIt ( Addition );
  for ( ; anIt.More(); anIt.Next() )
    if ( Result.IsBound ( anIt.Key() ) )
      Result.ChangeFind ( anIt.Key() ) = anIt.Value();
    else
      Result.Bind( anIt.Key(), anIt.Value() );
}

//================================================================
// Function : GetOwnerMaps
// Purpose  :
//================================================================
const MeshVS_DataMapOfIntegerMeshOwner& MeshVS_Mesh::GetOwnerMaps ( const Standard_Boolean IsElements )
{
  if ( IsElements )
  {
    if ( myElementOwners.IsEmpty() )
    {
      AddToMap ( myElementOwners, my0DOwners );
      AddToMap ( myElementOwners, myLinkOwners );
      AddToMap ( myElementOwners, myFaceOwners );
      AddToMap ( myElementOwners, myVolumeOwners );
    }
    return myElementOwners;
  }
  else
    return myNodeOwners;
}

//================================================================
// Function : IsHiddenElem
// Purpose  :
//================================================================
Standard_Boolean MeshVS_Mesh::IsHiddenElem ( const Standard_Integer theID ) const
{
  return ! myHiddenElements.IsNull() && myHiddenElements->Map().Contains( theID );
}

//================================================================
// Function : IsHiddenNode
// Purpose  :
//================================================================
Standard_Boolean MeshVS_Mesh::IsHiddenNode ( const Standard_Integer theID ) const
{
  // note that by default all nodes are hidden
  return myHiddenNodes.IsNull() || myHiddenNodes->Map().Contains( theID );
}

//================================================================
// Function : GetDrawer
// Purpose  :
//================================================================
Handle( MeshVS_Drawer ) MeshVS_Mesh::GetDrawer() const
{
  return myCurrentDrawer;
}

//================================================================
// Function : SetDrawer
// Purpose  :
//================================================================
void MeshVS_Mesh::SetDrawer(const Handle(MeshVS_Drawer)& aDrawer)
{
  myCurrentDrawer = aDrawer;
}

//================================================================
// Function : GetDataSource
// Purpose  :
//================================================================
Handle(MeshVS_DataSource) MeshVS_Mesh::GetDataSource() const
{
  return myDataSource;
}

//================================================================
// Function : SetDataSource
// Purpose  :
//================================================================
void MeshVS_Mesh::SetDataSource( const Handle(MeshVS_DataSource)& theDataSource )
{
  myDataSource = theDataSource;
}

//================================================================
// Function : HilightSelected
// Purpose  :
//================================================================
void MeshVS_Mesh::HilightSelected ( const Handle(PrsMgr_PresentationManager3d)& thePM,
                                    const SelectMgr_SequenceOfOwner& theOwners )
{
  if ( myHilighter.IsNull() )
    return;

//  if ( mySelectionPrs.IsNull() )
//    mySelectionPrs = new Prs3d_Presentation ( thePM->StructureManager() );

  //new functionality

  Handle( Prs3d_Presentation ) aSelectionPrs;

  aSelectionPrs = GetSelectPresentation( thePM );

  if( HasPresentation() )
    aSelectionPrs->SetTransformPersistence( Presentation()->TransformPersistenceMode(), Presentation()->TransformPersistencePoint() );
  //----------------

  //   It is very important to call this parent method, because it check whether
  // mySelectionPrs is created and if not, create it.

#ifdef _DEBUG
  OSD_Timer gTimer;
  gTimer.Reset();
  gTimer.Start();
#endif

  Standard_Integer len = theOwners.Length(), i;

  Handle (MeshVS_MeshOwner) anOwner;
  TColStd_PackedMapOfInteger aSelNodes, aSelElements;

  for( i=1; i<=len; i++ )
  {
    anOwner = Handle (MeshVS_MeshOwner)::DownCast ( theOwners.Value ( i ) );
    if ( !anOwner.IsNull() )
    {
      if( anOwner->Type() == MeshVS_ET_Node )
        aSelNodes.Add( anOwner->ID() );
      else
        aSelElements.Add( anOwner->ID() );
    }
//agv    else if( theOwners.Value ( i )==myWholeMeshOwner )
    else if (IsWholeMeshOwner (theOwners.Value ( i )))
    {
      TColStd_MapIteratorOfPackedMapOfInteger anIt(GetDataSource()->GetAllNodes());
      for( ; anIt.More(); anIt.Next() )
        if( !IsHiddenNode( anIt.Key() ) )
          aSelNodes.Add( anIt.Key() );

      anIt = TColStd_MapIteratorOfPackedMapOfInteger( GetDataSource()->GetAllElements() );
      for( ; anIt.More(); anIt.Next() )
        if( !IsHiddenElem( anIt.Key() ) )
          aSelElements.Add( anIt.Key() );

      break;
    }
  }

  Standard_Boolean IsNeedToRedisplay = Standard_False;

  aSelectionPrs->Clear();

  myHilighter->SetDrawer ( mySelectionDrawer );

  if( aSelNodes.Extent()>0 )
  {
    MeshVS_Array1OfIntegerBoolean aNodes( 1, aSelNodes.Extent() );
    TColStdMapToMeshVSArray( aSelNodes, aNodes );
    myHilighter->Build ( aSelectionPrs, aNodes, Standard_False, MeshVS_DMF_SelectionPrs );
  }
  if( aSelElements.Extent()>0 )
  {
    MeshVS_Array1OfIntegerBoolean anElems( 1, aSelElements.Extent() );
    TColStdMapToMeshVSArray( aSelElements, anElems );
    myHilighter->Build( aSelectionPrs, anElems, Standard_True, MeshVS_DMF_SelectionPrs );
  }

  myHilighter->SetDrawer ( 0 );

  IsNeedToRedisplay = Standard_True;

  if ( IsNeedToRedisplay )
  {
    aSelectionPrs->SetDisplayPriority(9);
    aSelectionPrs->Display();
  }

#ifdef _DEBUG
    Standard_Real sec, cpu;
    Standard_Integer min, hour;

    gTimer.Show ( sec, min, hour, cpu );
    cout << "HilightSelected : " << endl;
    cout << aSelNodes.Extent() << " nodes " << endl;
    cout << aSelElements.Extent() << " elements " << endl;
    cout << "Time : " << sec << " sec" << endl;
    cout << "CPU time : " << cpu << " sec" << endl << endl;
    gTimer.Stop();
#endif
}

//================================================================
// Function : HilightOwnerWithColor
// Purpose  :
//================================================================
void MeshVS_Mesh::HilightOwnerWithColor ( const Handle(PrsMgr_PresentationManager3d)& PM,
                                          const Quantity_NameOfColor Color,
                                          const Handle(SelectMgr_EntityOwner)& Owner)
{
  if ( myHilighter.IsNull() )
    return;

  SelectMgr_SequenceOfOwner theOwners;
  //new functionality

  //if ( myHilightPrs.IsNull() )
  //  myHilightPrs = new Prs3d_Presentation ( PM->StructureManager() );

  Handle( Prs3d_Presentation ) aHilightPrs;
  aHilightPrs = GetHilightPresentation( PM );

  aHilightPrs->Clear();

  //new functionality
  if( HasPresentation() )
    aHilightPrs->SetTransformPersistence( Presentation()->TransformPersistenceMode(), Presentation()->TransformPersistencePoint() );
  //----------------

  const Standard_Boolean isElementOwner   =
    !Owner.IsNull() && Owner->IsKind ( STANDARD_TYPE ( MeshVS_MeshOwner ) );
  const Standard_Boolean isWholeMeshOwner =
//agv    !Owner.IsNull() && Owner==myWholeMeshOwner;
    IsWholeMeshOwner (Owner);

  if( isElementOwner || isWholeMeshOwner/* || IsGroupOwner( Owner ) */)
  {
    Handle ( MeshVS_MeshOwner ) theAISOwner = Handle ( MeshVS_MeshOwner )::DownCast ( Owner );

    Standard_Integer aDispMode = MeshVS_DMF_Shading;
    if ( HasDisplayMode() && ( DisplayMode() & MeshVS_DMF_OCCMask ) > MeshVS_DMF_WireFrame )
      aDispMode = ( DisplayMode() & MeshVS_DMF_OCCMask );
    //It because we draw hilighted owners only in shading or shrink (not in wireframe)

    myHilightDrawer->SetColor( MeshVS_DA_InteriorColor, Color );
    myHilightDrawer->SetColor( MeshVS_DA_BackInteriorColor, Color );
    myHilightDrawer->SetColor( MeshVS_DA_EdgeColor, Color );
    myHilightDrawer->SetColor( MeshVS_DA_BeamColor, Color );
    myHilightDrawer->SetColor( MeshVS_DA_MarkerColor, Color );
    myHilighter->SetDrawer( myHilightDrawer );

    if( isElementOwner )
    {
      MeshVS_EntityType aType = theAISOwner->Type();
      Standard_Integer  anID  = theAISOwner->ID();

      MeshVS_Array1OfIntegerBoolean anOne( 1, 1 );
      anOne.ChangeValue( 1 ).Key = anID;
      anOne.ChangeValue( 1 ).Value = Standard_True;

      myHilighter->Build( aHilightPrs, anOne, aType!=MeshVS_ET_Node, aDispMode | MeshVS_DMF_HilightPrs );
    }
//      else if( IsGroupOwner( Owner ))
//      {
//        MeshVS_Array1OfIntegerBoolean anElements( 1, GetAllElementsFromGroup().Extent() );
//        TColStdMapToMeshVSArray ( GetAllElementsFromGroup(), anElements );

//        myHilighter->Build( aHilightPrs, anElements, Standard_True, MeshVS_DMF_WireFrame );
//      }
    else if( ! GetDataSource().IsNull() )
    {
      MeshVS_Array1OfIntegerBoolean anElements( 1, GetDataSource()->GetAllElements().Extent() );
      TColStdMapToMeshVSArray ( GetDataSource()->GetAllElements(), anElements );

      myHilighter->Build( aHilightPrs, anElements, Standard_True, MeshVS_DMF_WireFrame );
    }

    if( PM->IsImmediateModeOn() )
      PM->AddToImmediateList( aHilightPrs );
    myHilighter->SetDrawer ( 0 );
  }
}

//=======================================================================
//function : ClearSelected
//purpose  :
//=======================================================================
void MeshVS_Mesh::ClearSelected ()
{
  Handle( Prs3d_Presentation ) aSelectionPrs = GetSelectPresentation( NULL );  
  if( !aSelectionPrs.IsNull() )
    aSelectionPrs->Clear();
}

//=======================================================================
//function : FindBuilder
//purpose  :
//=======================================================================
Handle (MeshVS_PrsBuilder) MeshVS_Mesh::FindBuilder ( const Standard_CString theTypeName ) const
{
  Standard_Integer len = myBuilders.Length();
  Handle(MeshVS_PrsBuilder) aBuilder;
  Standard_Boolean IsExist = Standard_False;

  Handle ( Standard_Type ) aType = new Standard_Type ( theTypeName );

  for ( Standard_Integer i=1; i<=len && !IsExist; i++)
    if ( myBuilders.Value (i)->IsKind ( aType ) )
    {
      aBuilder = myBuilders.Value (i);
      IsExist = Standard_True;
    }

  return aBuilder;
}

//=======================================================================
//function : SetHilighter
//purpose  :
//=======================================================================
void MeshVS_Mesh::SetHilighter ( const Handle( MeshVS_PrsBuilder )& Builder )
{
  myHilighter = Builder;
}

//=======================================================================
//function : SetHilighter
//purpose  :
//=======================================================================
Standard_Boolean MeshVS_Mesh::SetHilighter ( const Standard_Integer Index )
{
  Handle( MeshVS_PrsBuilder ) aBuild = GetBuilder( Index );
  Standard_Boolean aRes = ( !aBuild.IsNull() );
  if ( aRes )
    myHilighter = aBuild;
  return aRes;
}

//=======================================================================
//function : SetHilighter
//purpose  :
//=======================================================================
Standard_Boolean MeshVS_Mesh::SetHilighterById ( const Standard_Integer Id )
{
  Handle( MeshVS_PrsBuilder ) aBuild = GetBuilderById( Id );
  Standard_Boolean aRes = ( !aBuild.IsNull() );
  if ( aRes )
    myHilighter = aBuild;
  return aRes;
}

//=======================================================================
//function : GetHilighter
//purpose  :
//=======================================================================
Handle( MeshVS_PrsBuilder ) MeshVS_Mesh::GetHilighter () const
{
  return myHilighter;
}

//=======================================================================
//function : IsSelectableElem
//purpose  :
//=======================================================================
Standard_Boolean MeshVS_Mesh::IsSelectableElem ( const Standard_Integer ID ) const
{
  return ! IsHiddenElem ( ID );
}

//=======================================================================
//function : IsSelectableNode
//purpose  :
//=======================================================================
Standard_Boolean MeshVS_Mesh::IsSelectableNode ( const Standard_Integer ID ) const
{
  // by default, all nodes are selectable
  return mySelectableNodes.IsNull() || mySelectableNodes->Map().Contains( ID );
}

//=======================================================================
//function : GetSelectableNodes
//purpose  :
//=======================================================================
const Handle(TColStd_HPackedMapOfInteger)& MeshVS_Mesh::GetSelectableNodes () const
{
  return mySelectableNodes;
}

//=======================================================================
//function : SetSelectableNodes
//purpose  :
//=======================================================================
void MeshVS_Mesh::SetSelectableNodes ( const Handle(TColStd_HPackedMapOfInteger)& Ids )
{
  mySelectableNodes = Ids;
}

//=======================================================================
//function : UpdateSelectableNodes
//purpose  :
//=======================================================================
void MeshVS_Mesh::UpdateSelectableNodes()
{
  mySelectableNodes = new TColStd_HPackedMapOfInteger;
  
  Handle( MeshVS_DataSource ) aSource = GetDataSource();
  if ( aSource.IsNull() )
    return;

  // all non-hidden nodes are selectable;
  // by default (i.e. if myHiddenNodes.IsNull()) all nodes are hidden
  if ( ! myHiddenNodes.IsNull() )
  {
    mySelectableNodes->ChangeMap().Subtraction (aSource->GetAllNodes(),
                                                myHiddenNodes->Map());
  } 
  
  // add all nodes belonging to non-hidden elements
  TColStd_MapIteratorOfPackedMapOfInteger anIter( aSource->GetAllElements() );
  for ( ; anIter.More(); anIter.Next() )
  {
    Standard_Integer aKey = anIter.Key();
    if ( IsHiddenElem (aKey) )
      continue;

    Handle(TColStd_HArray1OfInteger) aNodes = 
      myDataSource->GetNodesByElement ( aKey );
    for ( Standard_Integer i=1, n=aNodes->Length(); i<=n; i++ )
      mySelectableNodes->ChangeMap().Add ( aNodes->Value(i) );
  }
}

//=======================================================================
//function : GetMeshSelMethod
//purpose  :
//=======================================================================
MeshVS_MeshSelectionMethod MeshVS_Mesh::GetMeshSelMethod() const
{
  return mySelectionMethod;
}

//=======================================================================
//function : SetMeshSelMethod
//purpose  :
//=======================================================================
void MeshVS_Mesh::SetMeshSelMethod( const MeshVS_MeshSelectionMethod M )
{
  mySelectionMethod = M;
}

//=======================================================================
//function : IsWholeMeshOwner
//purpose  : 
//=======================================================================

Standard_Boolean MeshVS_Mesh::IsWholeMeshOwner
                            (const Handle(SelectMgr_EntityOwner)& theOwn) const
{
  return theOwn.IsNull() ? Standard_False : (theOwn == myWholeMeshOwner);
}
