/////////////////////////////////////////////////////////////
//                                                         //
// Copyright (c) 2007-2014 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.opensource.org/licenses/osl-3.0.php          //
//                                                         //
/////////////////////////////////////////////////////////////

#include "IntersectionVol.h"

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

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

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

using std::make_pair;

IntersectionVol::IntersectionVol()
{
  std::cout << "WARNING: IntersectionVol 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; 
}

IntersectionVol::IntersectionVol(AVolume3D& v1, AVolume3D& v2)
{
  std::cout << "WARNING: IntersectionVol 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> IntersectionVol::getBoundingBox()
{
  // BoundingBox is the box containing both volumes

  pair<Vector3,Vector3> bbx1=m_vol1->getBoundingBox();
//  std::cout << "bbx1 = (" << bbx1.first.X() << " , " << bbx1.first.Y() << " , " << bbx1.first.Z() << ") ; (" << bbx1.second.X() << " , " << bbx1.second.Y() << " , " << bbx1.second.Z() << ")" << std::endl;

  pair<Vector3,Vector3> bbx2=m_vol2->getBoundingBox();
//  std::cout << "bbx2 = (" << bbx2.first.X() << " , " << bbx2.first.Y() << " , " << bbx2.first.Z() << ") ; (" << bbx2.second.X() << " , " << bbx2.second.Y() << " , " << bbx2.second.Z() << ")" << std::endl;

  double X0,X1;
  double Y0,Y1;
  double Z0,Z1;

  if (bbx1.first.X() < bbx2.first.X()) {
    X0 = bbx1.first.X();
  }
  else {
    X0 = bbx2.first.X();
  }
  if (bbx1.first.Y() < bbx2.first.Y()) {
    Y0 = bbx1.first.Y();
  }
  else {
    Y0 = bbx2.first.Y();
  }
  if (bbx1.first.Z() < bbx2.first.Z()) {
    Z0 = bbx1.first.Z();
  }
  else {
    Z0 = bbx2.first.Z();
  }
  Vector3 minPt = Vector3(X0,Y0,Z0);

  if (bbx1.second.X() > bbx2.second.X()) {
    X1 = bbx1.second.X();
  }
  else {
    X1 = bbx2.second.X();
  }
  if (bbx1.second.Y() > bbx2.second.Y()) {
    Y1 = bbx1.second.Y();
  }
  else {
    Y1 = bbx2.second.Y();
  }
  if (bbx1.second.Z() > bbx2.second.Z()) {
    Z1 = bbx1.second.Z();
  }
  else {
    Z1 = bbx2.second.Z();
  }
  Vector3 maxPt = Vector3(X1,Y1,Z1);

//  std::cout << "minPt = (" << X0 << " , " << Y0 << " , " << Z0 << ")" << std::endl;
//  std::cout << "maxPt = (" << X1 << " , " << Y1 << " , " << Z1 << ")" << std::endl;

  return make_pair(minPt,maxPt);
}

Vector3 IntersectionVol::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*> IntersectionVol::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 IntersectionVol::isIn(const Vector3& P) const
{
  bool res = false;

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

  return res;
}

bool IntersectionVol::isIn(const Sphere& S)
{
  bool res = false;

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

  return res;
}

/*!
  Check if sphere is fully outside the volume. Tests if the sphere
  is outside one of the subvolumes.

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

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