Source: spatial-metadata.js

const Vector = require('./vector');
const Piece = require('./piece');
const Pair = require('./pair');
const {PuzzleValidator} = require('./validator');

/**
 * @typedef {object} SpatialMetadata
 * @property {import('./vector').Vector} [targetPosition]
 * @property {import('./vector').Vector} [currentPosition]
 */

/**
 * Functions for handling spatial metadata
 * and pieces and puzzles that are annotated with it
 *
 * @module SpatialMetadata
 */

 /**
  *
  * @param {Piece} piece
  */
function diffToTarget(piece) {
  return Vector.diff(piece.metadata.targetPosition, piece.centralAnchor.asVector());
}

/**
 * @type {import('../src/validator').PuzzleCondition}
 */
const solved = (puzzle) => relativePosition(puzzle) && PuzzleValidator.connected(puzzle);

/**
 * @type {import('../src/validator').PuzzleCondition}
 */
const relativePosition = (puzzle) => {
  const diff0 = diffToTarget(puzzle.head);
  return puzzle.pieces.every(piece => PuzzleValidator.equalDiffs(diff0, diffToTarget(piece)));
}

/**
 *@type {import('../src/validator').PieceCondition}
 */
const absolutePosition = (piece) => Vector.equal(piece.centralAnchor.asVector(), piece.metadata.targetPosition);


/**
 * @param {SpatialMetadata} metadata
 * @param {import('./vector').Vector} target
 * @param {import('./vector').Vector} [current]
 */
function initialize(metadata, target, current) {
  metadata.targetPosition = metadata.targetPosition || target;
  metadata.currentPosition = metadata.currentPosition || current || Vector.copy(metadata.targetPosition);
}

module.exports = {
  initialize,
  solved,
  relativePosition,
  absolutePosition
}