/**
 * Example of a test. To be completed.
 *
 */
bool testExpander()
{
  unsigned int nbok = 0;
  unsigned int nb = 0;
  
  // ------------------------------ Types ------------------------------
  typedef SpaceND< 3 > Z3;
  typedef Z3::Point Point;
  typedef Point::Coordinate Coordinate;
  typedef HyperRectDomain< Z3 > Domain; 
  typedef Domain::ConstIterator DomainConstIterator; 

  typedef MetricAdjacency< Z3, 1 > MetricAdj6;
  typedef MetricAdjacency< Z3, 2 > MetricAdj18;
  typedef DomainAdjacency< Domain, MetricAdj6 > Adj6;
  typedef DomainAdjacency< Domain, MetricAdj18 > Adj18;
  // typedef MetricAdjacency< Z3, 1 > Adj6;
  // typedef MetricAdjacency< Z3, 2 > Adj18;

  typedef DigitalTopology< Adj6, Adj18 > DT6_18;

  typedef DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet;
  typedef Object<DT6_18, DigitalSet> ObjectType;
  typedef Expander< ObjectType > ObjectExpander;
  // ----------------------- Domain, Topology ------------------------------
  Point p1( -50, -50, -50 );
  Point p2( 50, 50, 50 );
  Domain domain( p1, p2 );

  MetricAdj6 madj6;
  MetricAdj18 madj18;
  Adj6 adj6( domain, madj6 );
  Adj18 adj18( domain, madj18 );
  // Adj6 adj6;
  // Adj18 adj18;

  DT6_18 dt6_18( adj6, adj18, JORDAN_DT );
  // ------------------------------- Object ------------------------------
  Coordinate r = 49;
  double radius = (double) (r+1);
  Point c( 0, 0 );
  Point l( r, 0 );
  DigitalSet ball_set( domain );
  ostringstream sstr;
  sstr << "Creating 3D ball( r < " << radius << " ) ...";
  trace.beginBlock ( sstr.str() );
  for ( DomainConstIterator it = domain.begin(); 
  it != domain.end();
  ++it )
    {
      if ( (*it - c ).norm() < radius )
  // insertNew is very important for vector container.
  ball_set.insertNew( *it );
    }
  trace.endBlock();

  trace.beginBlock ( "Testing Object instanciation and smart copy  ..." );
  ObjectType ball( dt6_18, ball_set );
  ObjectType ball2( ball );
  INBLOCK_TEST( ball.size() == 523155 );
  trace.info() << "ball.size() = " << ball.size() 
         << " 4/3*pi*r^3 = " << ( 4.0*M_PI*radius*radius*radius/3.0 )
         << endl;
  trace.info() << "ball  = " << ball << endl;
  trace.info() << "ball2 = " << ball2 << endl;
  trace.endBlock();

  trace.beginBlock ( "Testing border extraction ..." );
  ObjectType sphere = ball.border();
  INBLOCK_TEST( sphere.size() == 39546 );
  trace.info() << sphere << endl;
  trace.info() << "sphere.size() = " << sphere.size()
         << " 4*pi*r^2 = " << ( 4.0*M_PI*radius*radius )
         << endl;
  trace.endBlock();

  trace.beginBlock ( "Testing expansion by layers in the ball from center..." );
  ObjectExpander expander( ball, c );
  while ( ! expander.finished() )
    {
      trace.info() << expander << std::endl;
      expander.nextLayer();
    }
  nbok += expander.distance() <= sqrt(3.0)*radius ? 1 : 0; 
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
         << "expander.distance() = " << expander.distance()
         << " <= " << sqrt(3.0)*radius << std::endl;
  trace.endBlock();

  trace.beginBlock ( "Testing expansion by layers on the sphere from a point ..." );
  ObjectExpander expander2( sphere, l );
  while ( ! expander2.finished() )
    {
      trace.info() << expander2 << std::endl;
      expander2.nextLayer();
    }
  nbok += expander2.distance() <= sqrt(2.0)*M_PI*radius ? 1 : 0; 
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
         << "expander2.distance() = " << expander2.distance()
         << " <= " << sqrt(2.0)*M_PI*radius << std::endl;
  trace.endBlock();

  
  return nbok == nb;
}
/**
 * Example of a test. To be completed.
 *
 */
bool testObject()
{
  unsigned int nbok = 0;
  unsigned int nb = 0;

  typedef SpaceND< 2 > Z2;
  typedef Z2::Point Point;
  typedef Point::Coordinate Coordinate;
  typedef HyperRectDomain< Z2 > DomainType;
  Point p1(  -449, -449  );
  Point p2( 449, 449  );
  DomainType domain( p1, p2 );

  // typedef DomainMetricAdjacency< DomainType, 1 > Adj4;
  // typedef DomainMetricAdjacency< DomainType, 2 > Adj8;
  typedef MetricAdjacency< Z2, 1 > MetricAdj4;
  typedef MetricAdjacency< Z2, 2 > MetricAdj8;
  typedef DomainAdjacency< DomainType, MetricAdj4 > Adj4;
  typedef DomainAdjacency< DomainType, MetricAdj8 > Adj8;
  typedef DigitalTopology< Adj4, Adj8 > DT48;
  typedef DigitalSetSelector < DomainType, MEDIUM_DS + HIGH_BEL_DS >::Type
  MediumSet;
//   typedef DigitalSetSelector< DomainType, SMALL_DS >::Type
//     MediumSet;
  typedef Object<DT48, MediumSet> ObjectType;
  typedef ObjectType::SmallSet SmallSet;
  typedef Object<DT48, SmallSet> SmallObjectType;
  typedef ObjectType::Size Size;

  // Adj4 adj4( domain );
  // Adj8 adj8( domain );
  MetricAdj4 madj4;
  MetricAdj8 madj8;
  Adj4 adj4( domain, madj4 );
  Adj8 adj8( domain, madj8 );
  DT48 dt48( adj4, adj8, JORDAN_DT );

  Coordinate r = 449;
  double radius = (double) (r + 1);
  Point c(  0, 0  );
  Point l(  r, 0  );
  MediumSet disk( domain );
  ostringstream sstr;
  sstr << "Creating disk( r < " << radius << " ) ...";
  trace.beginBlock ( sstr.str() );
  for ( DomainType::ConstIterator it = domain.begin();
      it != domain.end();
      ++it )
  {
    if ( (*it - c ).norm() < radius ) // 450.0
      // insertNew is very important for vector container.
      disk.insertNew( *it );
  }
  trace.endBlock();

  trace.beginBlock ( "Testing Object instanciation and smart copy  ..." );
  ObjectType disk_object( dt48, disk );
  nbok += disk_object.size() == 636101 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "Disk (r=450.0) " << disk_object << std::endl;
  trace.info() << "  size=" << disk_object.size() << std::endl;
  ObjectType disk_object2( disk_object );
  nbok += disk_object2.size() == 636101 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "Disk2 (r=450.0) " << disk_object2 << std::endl;
  trace.info() << "  size=" << disk_object2.size() << std::endl;
  trace.endBlock();

  trace.beginBlock ( "Testing copy on write system ..." );
  trace.info() << "Removing center point in Disk." << std::endl;
  disk_object.pointSet().erase( c );
  disk_object2.pointSet().insert( c );
  nbok += disk_object.size() == 636100 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "Disk - c (r=450.0) " << disk_object << std::endl;
  trace.info() << "  size=" << disk_object.size() << std::endl;
  nbok += disk_object2.size() == 636101 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "Disk2 + c (r=450.0) " << disk_object2 << std::endl;
  trace.info() << "  size=" << disk_object2.size() << std::endl;
  trace.endBlock();

  trace.beginBlock ( "Testing neighborhoods ..." );
  Object<DT48, SmallSet> neigh = disk_object.neighborhood( c );
  nbok += neigh.size() == 4 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "N_4(Disk, c).size() = " << neigh.size()
  << " == 4" << std::endl;
  neigh = disk_object.properNeighborhood( l );
  nbok += neigh.size() == 3 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "N*_4(Disk, " << l << ").size() = " << neigh.size()
  << " == 3" << std::endl;
  Size size = disk_object.properNeighborhoodSize( l );
  nbok += size == 3 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "#N*_4(Disk, " << l << ") = " << size
  << " == 3" << std::endl;

  neigh = disk_object2.neighborhood( c );
  nbok += neigh.size() == 5 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "N_4(Disk2, c).size() = " << neigh.size()
  << " == 5" << std::endl;
  trace.endBlock();

  trace.beginBlock ( "Testing set converters ..." );
  DigitalSetConverter<SmallSet>::assign
  ( neigh.pointSet(), disk_object.pointSet() );
  nbok += neigh.size() == 636100 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "neigh = disk_object, size() = " << neigh.size()
  << " == 636100" << std::endl;
  SmallObjectType neigh2 = disk_object2.neighborhood( c );
  DigitalSetConverter<SmallSet>::assign
  ( neigh.pointSet(), neigh2.pointSet() );
  nbok += neigh.size() == 5 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "neigh = N_4(Disk2, c), size() = " << neigh.size()
  << " == 5" << std::endl;
  trace.endBlock();

  trace.beginBlock ( "Testing border extraction ..." );
  ObjectType bdisk = disk_object.border();
  nbok += bdisk.size() == 3372 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "Border(Disk, c), size() = " << bdisk.size()
  << " == 3372" << std::endl;
  ObjectType bdisk2 = disk_object2.border();
  nbok += bdisk2.size() == 3364 ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "Border(Disk2, c), size() = " << bdisk2.size()
  << " == 3364" << std::endl;
  trace.endBlock();

  trace.beginBlock ( "Testing expansion by layers on the boundary ..." );
  typedef Expander< ObjectType > ObjectExpander;
  ObjectExpander expander( bdisk, *(bdisk.pointSet().begin()) );
  while ( ! expander.finished() )
  {
    nbok += expander.layer().size() <= 2 ? 1 : 0;
    nb++;
    trace.info() << "(" << nbok << "/" << nb << ") "
    << "expander.layer.size() <= 2 "
    << expander << std::endl;
    expander.nextLayer();
  }
  trace.endBlock();

  trace.beginBlock ( "Testing expansion by layers on the disk from center..." );
  ObjectExpander expander2( disk_object2, c );
  while ( ! expander2.finished() )
  {
    trace.info() << expander2 << std::endl;
    expander2.nextLayer();
  }
  nbok += expander2.distance() <= sqrt(2.0) * radius ? 1 : 0;
  nb++;
  trace.info() << "(" << nbok << "/" << nb << ") "
  << "expander.distance() = " << expander2.distance()
  << " <= " << sqrt(2.0)*radius << std::endl;
  trace.endBlock();

  return nbok == nb;
}