/*
 * This file is part of the Owl Positioning System (OwlPS) project.
 * It is subject to the copyright notice and license terms in the
 * COPYRIGHT.t2t file found in the top-level directory of this
 * distribution and at
 *   https://code.lm7.fr/mcy/owlps/src/master/COPYRIGHT.t2t
 * No part of the OwlPS Project, including this file, may be copied,
 * modified, propagated, or distributed except according to the terms
 * contained in the COPYRIGHT.t2t file; the COPYRIGHT.t2t file must be
 * distributed along with this file, either separately or by replacing
 * this notice by the COPYRIGHT.t2t file's contents.
 */


#include "area.hh"
#include "building.hh"


using namespace std ;



/* *** Constructors *** */


Area::Area(const Building *const _building, const string &_name,
           const Point3D &p1, const Point3D &p2):
  building(_building), name(_name)
{
  set_coordinates(p1, p2) ;
}



/* *** Operations *** */


/**
 * @returns `true` if `p` is into the Area.
 * @returns `false` if `p` is not into the Area.
 */
bool Area::contains_point(const Point3D &p) const
{
  return
    p.get_x() >= p_min.get_x() &&
    p.get_x() <= p_max.get_x() &&
    p.get_y() >= p_min.get_y() &&
    p.get_y() <= p_max.get_y() &&
    p.get_z() >= p_min.get_z() &&
    p.get_z() <= p_max.get_z() ;
}


/**
 * Changes the Area coordinates so that #p_min is the South-West-lower
 * point and #p_max the North-East-higher point.
 */
void Area::reorder_coordinates()
{
  float
  x1 = p_min.get_x(),
  y1 = p_min.get_y(),
  z1 = p_min.get_z(),
  x2 = p_max.get_x(),
  y2 = p_max.get_y(),
  z2 = p_max.get_z(),
  x_min, x_max, y_min,
  y_max, z_min, z_max ;

  // 2-D coordinates (X and Y) //

  // First point is North-West
  if (x1 < x2 && y1 > y2)
    {
      x_min = x1 ;
      x_max = x2 ;
      y_min = y2 ; // We swap the two Y
      y_max = y1 ;
    }

  // First point is South-East
  else if (x1 > x2 && y1 < y2)
    {
      x_min = x2 ; // We swap the two X
      x_max = x1 ;
      y_min = y1 ;
      y_max = y2 ;
    }

  // First point is North-East
  else if (x1 > x2 && y1 > y2)
    {
      x_min = x2 ; // We swap the two X
      x_max = x1 ;
      y_min = y2 ; // and we swap the two Y
      y_max = y1 ;
    }

  // First point is South-West
  // (or other cases such as coordinates equal to zero)
  else
    {
      // We swap nothing
      x_min = x1 ;
      x_max = x2 ;
      y_min = y1 ;
      y_max = y2 ;
    }

  // Vertical coordinate (Z) //

  // First point is lower
  if (z1 < z2)
    {
      z_min = z1 ;
      z_max = z2 ;
    }

  // First point is higher
  else
    {
      // We swap the two Z
      z_min = z2 ;
      z_max = z1 ;
    }

  p_min = Point3D(x_min, y_min, z_min) ;
  p_max = Point3D(x_max, y_max, z_max) ;
}



/* *** Operators *** */


Area& Area::operator=(const Area &source)
{
  if (this == &source)
    return *this ;

  building = source.building ;
  name = source.name ;
  p_min = source.p_min ;
  p_max = source.p_max ;

  return *this ;
}


bool Area::operator==(const Area &source) const
{
  if (this == &source)
    return true ;

  return
    building == source.building &&
    name == source.name &&
    p_min == source.p_min &&
    p_max == source.p_max ;
}



/**
 * Note: to avoid looping, the Building associated with the Area is
 * not displayed.
 */
ostream &operator<<(ostream &os, const Area &a)
{
  os
      << (a.building ? a.building->get_name() : "No building") << ';'
      << a.name << ';'
      << a.p_min.get_x() << ';'
      << a.p_max.get_x() << ';'
      << a.p_min.get_y() << ';'
      << a.p_max.get_y() << ';'
      << a.p_min.get_z() << ';'
      << a.p_max.get_z() ;
  return os ;
}
