// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

part of vector_math;

/// Defines a 2-dimensional axis-aligned bounding box between a [min] and a
/// [max] position.
class Aabb2 {
  final Vector2 _min;
  final Vector2 _max;

  /// The minimum point defining the AABB.
  Vector2 get min => _min;

  /// The maximum point defining the AABB.
  Vector2 get max => _max;

  /// The center of the AABB.
  Vector2 get center => _min.clone()
    ..add(_max)
    ..scale(0.5);

  /// Create a new AABB with [min] and [max] set to the origin.
  Aabb2()
      : _min = Vector2.zero(),
        _max = Vector2.zero();

  /// Create a new AABB as a copy of [other].
  Aabb2.copy(Aabb2 other)
      : _min = Vector2.copy(other._min),
        _max = Vector2.copy(other._max);

  /// Create a new AABB with a [min] and [max].
  Aabb2.minMax(Vector2 min, Vector2 max)
      : _min = Vector2.copy(min),
        _max = Vector2.copy(max);

  /// Create a new AABB with a [center] and [halfExtents].
  factory Aabb2.centerAndHalfExtents(Vector2 center, Vector2 halfExtents) =>
      Aabb2()..setCenterAndHalfExtents(center, halfExtents);

  /// Constructs [Aabb2] with a min/max storage that views given [buffer]
  /// starting at [offset]. [offset] has to be multiple of
  /// [Float32List.bytesPerElement].
  Aabb2.fromBuffer(ByteBuffer buffer, int offset)
      : _min = Vector2.fromBuffer(buffer, offset),
        _max = Vector2.fromBuffer(
            buffer, offset + Float32List.bytesPerElement * 2);

  /// Set the AABB by a [center] and [halfExtents].
  void setCenterAndHalfExtents(Vector2 center, Vector2 halfExtents) {
    _min
      ..setFrom(center)
      ..sub(halfExtents);
    _max
      ..setFrom(center)
      ..add(halfExtents);
  }

  /// Copy the [center] and the [halfExtents] of this.
  void copyCenterAndHalfExtents(Vector2 center, Vector2 halfExtents) {
    center
      ..setFrom(_min)
      ..add(_max)
      ..scale(0.5);
    halfExtents
      ..setFrom(_max)
      ..sub(_min)
      ..scale(0.5);
  }

  /// Copy the [min] and [max] from [other] into this.
  void copyFrom(Aabb2 other) {
    _min.setFrom(other._min);
    _max.setFrom(other._max);
  }

  static Vector2 _center;
  static Vector2 _halfExtents;
  void _updateCenterAndHalfExtents() => copyCenterAndHalfExtents(
        _center ??= Vector2.zero(),
        _halfExtents ??= Vector2.zero(),
      );

  /// Transform this by the transform [t].
  void transform(Matrix3 t) {
    _updateCenterAndHalfExtents();
    t
      ..transform2(_center)
      ..absoluteRotate2(_halfExtents);
    _min
      ..setFrom(_center)
      ..sub(_halfExtents);
    _max
      ..setFrom(_center)
      ..add(_halfExtents);
  }

  /// Rotate this by the rotation matrix [t].
  void rotate(Matrix3 t) {
    _updateCenterAndHalfExtents();
    t.absoluteRotate2(_halfExtents);
    _min
      ..setFrom(_center)
      ..sub(_halfExtents);
    _max
      ..setFrom(_center)
      ..add(_halfExtents);
  }

  /// Create a copy of this that is transformed by the transform [t] and store
  /// it in [out].
  Aabb2 transformed(Matrix3 t, Aabb2 out) => out
    ..copyFrom(this)
    ..transform(t);

  /// Create a copy of this that is rotated by the rotation matrix [t] and
  /// store it in [out].
  Aabb2 rotated(Matrix3 t, Aabb2 out) => out
    ..copyFrom(this)
    ..rotate(t);

  /// Set the min and max of this so that this is a hull of this and
  /// [other].
  void hull(Aabb2 other) {
    Vector2.min(_min, other._min, _min);
    Vector2.max(_max, other._max, _max);
  }

  /// Set the min and max of this so that this contains [point].
  void hullPoint(Vector2 point) {
    Vector2.min(_min, point, _min);
    Vector2.max(_max, point, _max);
  }

  /// Return if this contains [other].
  bool containsAabb2(Aabb2 other) {
    final Vector2 otherMax = other._max;
    final Vector2 otherMin = other._min;

    return (_min.x < otherMin.x) &&
        (_min.y < otherMin.y) &&
        (_max.y > otherMax.y) &&
        (_max.x > otherMax.x);
  }

  /// Return if this contains [other].
  bool containsVector2(Vector2 other) =>
      (_min.x < other.x) &&
      (_min.y < other.y) &&
      (_max.x > other.x) &&
      (_max.y > other.y);

  /// Return if this intersects with [other].
  bool intersectsWithAabb2(Aabb2 other) {
    final Vector2 otherMax = other._max;
    final Vector2 otherMin = other._min;

    return (_min.x <= otherMax.x) &&
        (_min.y <= otherMax.y) &&
        (_max.x >= otherMin.x) &&
        (_max.y >= otherMin.y);
  }

  /// Return if this intersects with [other].
  bool intersectsWithVector2(Vector2 other) =>
      (_min.x <= other.x) &&
      (_min.y <= other.y) &&
      (_max.x >= other.x) &&
      (_max.y >= other.y);
}
