//===========================================================================
// Copyright (C) 1998, 2000-2007, 2010, 2011, 2012 SINTEF ICT, Applied
// Mathematics, Norway.
//
// This file is part of GoTools
//
// This program is free software; you can redistribute it and/or          
// modify it under the terms of the GNU General Public License            
// as published by the Free Software Foundation version 2 of the License. 
//
// This program is distributed in the hope that it will be useful,        
// but WITHOUT ANY WARRANTY; without even the implied warranty of         
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          
// GNU General Public License for more details.                           
//
// You should have received a copy of the GNU General Public License      
// along with this program; if not, see <http://www.gnu.org/licenses>
//
// Contact information: E-mail: tor.dokken@sintef.no                      
// SINTEF ICT, Department of Applied Mathematics,                         
// P.O. Box 124 Blindern,                                                 
// 0314 Oslo, Norway.                                                     
//
// Other licenses are also available for this software, notably licenses
// for:
// - Building commercial software.                                        
// - Building software whose source code you wish to keep private.        
//===========================================================================

#ifndef _BODY_H
#define _BODY_H

#include "GoTools/compositemodel/SurfaceModel.h"
#include "GoTools/utils/CoordinateSystem.h"
#include "GoTools/utils/BoundingBox.h"
#include <vector>

namespace Go
{

  /// \brief A boundary represented solid.

    class Body
	{
	public:

	    /// Constructor with coordinate system. NB! The coordinate system is not in use
	    Body(const CoordinateSystem<3> xyz);

	    /// Default constructor 
	    Body();

	    /// Constructor with multiple shells
	    Body(const CoordinateSystem<3> xyz, std::vector<shared_ptr<SurfaceModel> >& shells);

	    /// Constructor with multiple shells
	    Body(std::vector<shared_ptr<SurfaceModel> >& shells);

	    /// Constructor with one outer shell
	    Body(const CoordinateSystem<3> xyz, shared_ptr<SurfaceModel> shell);

	    /// Constructor with one outer shell
	    Body(shared_ptr<SurfaceModel> shell);

	    /// Destructor
	    ~Body();

	    /// Add another shell to the solid description. Used in
	    /// connection with building the solid
	    void addshell(shared_ptr<SurfaceModel> shell);

	    /// Fetch the outer shell belonging to this solid
	    shared_ptr<SurfaceModel> getOuterShell() const
		{
		  shared_ptr<SurfaceModel> dummy;
		  if (shells_.size() == 0)
		    return dummy;
		  else
		    return shells_[0];
		}

	    /// Fetch all shells belonging to this solid. The first
	    /// shell corresponds to the outer boundary of the solid,
	    /// any subsequent shells are void
	    std::vector<shared_ptr<SurfaceModel> > getAllShells() const
	      {
		return shells_;
	      }

	    /// The number of shells belonging to this solid
	    int nmbOfShells() const
	    {
	      return (int)(shells_.size());
	    }

	    /// Fetch a specified shell. Index zero corresponds to
	    /// the outer shell
	    shared_ptr<SurfaceModel> getShell(int idx) const
	    {
	       shared_ptr<SurfaceModel> dummy;
	      if (idx < 0 || int(shells_.size()) <= idx)
		return dummy;
	      else
		return shells_[idx];
	    }

	    /// Fetch all vertices
	    std::vector<shared_ptr<Vertex> > vertices() const;

	    /// The bounding box corresponding to this solid
	    virtual BoundingBox boundingBox() const;

	    /// Check if two bodies are neighbours
	    virtual bool areNeighbours(Body *other, shared_ptr<ftSurface>& bd_face1,
				       shared_ptr<ftSurface>& bd_face2, int adj_idx = 0) const;

	    /// Fetch all bodies adjacent to this one. This function is
	    /// relevant in an assembly system or in an isogeometric setting
	    void getAdjacentBodies(std::vector<Body*>& neighbours);

	    /// Check if a point lies inside this body
	    bool isInside(const Point& pnt);

	    /// Find the shell containing a given face (if any)
	    shared_ptr<SurfaceModel> getShell(ftSurface* face) const;

	protected:
	    /// Coordinate system of the body. Default is the xyz system.
	    /// The coordinate system is currently not used
	    CoordinateSystem<3> coordinate_;
	    
	    /// Outer and possibly inner void shells
	    std::vector<shared_ptr<SurfaceModel> > shells_;

	    /// Tolerances used in topology analysis
	    // These tolerances needs to be stored with the class as a topology
	    // structure may become obsolete if the tolerances change
	    // The tolerances are fetched from the related CompositeModels.
	    tpTolerances toptol_;
   
	    // Add back pointers from boundary face entities
	    void addBodyPointers();
	};

} // namespace Go

#endif // _BODY_H
