/////////////////////////////////////////////////////////////
//                                                         //
// Copyright (c) 2007-2017 by The University of Queensland //
// Centre for Geoscience Computing                         //
// http://earth.uq.edu.au/centre-geoscience-computing      //
//                                                         //
// Primary Business: Brisbane, Queensland, Australia       //
// Licensed under the Open Software License version 3.0    //
// http://www.apache.org/licenses/LICENSE-2.0              //
//                                                         //
/////////////////////////////////////////////////////////////

#include "DifferenceVol.h"

//--- 
#include <cmath>
#include <cstdlib>

using std::cos;
using std::sin; 

// --- STL includes ---
#include <utility>

using std::make_pair;

DifferenceVol::DifferenceVol()
{
  std::cout << "WARNING: DifferenceVol is an experimental feature and may not always work as expected. For details see doc/CSG.readme" << std::endl;
  m_vol1 = NULL; 
  m_vol2 = NULL; 
}

DifferenceVol::DifferenceVol(AVolume3D& v1, AVolume3D& v2)
{
  std::cout << "WARNING: DifferenceVol is an experimental feature and may not always work as expected. For details see doc/CSG.readme" << std::endl;
  m_vol1 = &v1;
  m_vol2 = &v2;

//  std::cout << m_vol1 << std::endl;
//  std::cout << m_vol2 << std::endl;
}

pair<Vector3,Vector3> DifferenceVol::getBoundingBox()
{
  return m_vol1->getBoundingBox();
}

Vector3 DifferenceVol::getAPoint(int ivol) const
{
  Vector3 aPoint;
  bool found = false;

  while (!(found)) {
     aPoint = m_vol1->getAPoint(ivol);
     found = !(m_vol2->isIn(aPoint));
  }

  return aPoint;
}

const map<double,const AGeometricObject*> DifferenceVol::getClosestObjects(const Vector3& P,int ival) const
{
  map<double,const AGeometricObject*> res;
  map<double,const AGeometricObject*> res2;

  res = m_vol1->getClosestObjects(P,ival);
  res2 = m_vol2->getClosestObjects(P,ival);

  res.insert(res2.begin(), res2.end());

  return res;  
}

bool DifferenceVol::isIn(const Vector3& P) const
{
  bool res = false;

  if ((m_vol1->isIn(P)) && (!(m_vol2->isIn(P)))) {
    res = true;
  }

  return res;
}

bool DifferenceVol::isIn(const Sphere& S)
{
  return m_vol1->isIn(S) && m_vol2->isFullyOutside(S);
}

/*!
  Check if a sphere is fully outside the volume. Tests if the sphere 
  is fully outside volume1 or fully inside volume2.

  \param S the sphere
*/
bool DifferenceVol::isFullyOutside(const Sphere& S)
{
  return m_vol2->isIn(S) || m_vol1->isFullyOutside(S);
}

ostream& operator << (ostream& ost,const DifferenceVol& T)
{
   return ost;
}
