part of sprites;

abstract class Constraint {
  void preUpdate(Node node, double dt) {
  }

  void constrain(Node node, double dt);
}

double _dampenRotation(double src, double dst, double dampening) {
  if (dampening == null)
    return dst;

  double delta = dst - src;
  while (delta > 180.0) delta -= 360;
  while (delta < -180) delta += 360;
  delta *= dampening;

  return src + delta;
}

class ConstraintRotationToMovement {
  ConstraintRotationToMovement([this.baseRotation = 0.0, this.dampening]);

  final double dampening;
  final double baseRotation;

  Point _lastPosition;

  void preUpdate(Node node, double dt) {
    _lastPosition = node.position;
  }

  void constrain(Node node, double dt) {
    if (_lastPosition == null) return;
    if (_lastPosition == node.position) return;

    // Get the target angle
    Offset offset = node.position - _lastPosition;
    double target = degrees(GameMath.atan2(offset.dy, offset.dx)) + baseRotation;

    node.rotation = _dampenRotation(node.rotation, target, dampening);
  }
}

class ConstraintRotationToNode {
  ConstraintRotationToNode(this.targetNode, [this.baseRotation, this.dampening]);

  final Node targetNode;
  final double baseRotation;
  final double dampening;

  void constrain(Node node, double dt) {
    Offset offset;

    if (targetNode.parent == node.parent) {
      offset = targetNode.position - node.position;
    } else {
      offset = node.convertPointToBoxSpace(Point.origin)
        - targetNode.convertPointToBoxSpace(Point.origin);
    }

    double target = degrees(GameMath.atan2(offset.dy, offset.dx)) + baseRotation;

    node.rotation = _dampenRotation(node.rotation, target, dampening);
  }
}