class ShotgunDistance implements IDistanceMetric {

	@Override
	public double distance(final double[] a, final double[] b) {
		// Assure that max(A.length, B.length) <= windowLength, otherwise
		// the result is undefined.

		double totalDistance = 0;
		IVectorTransform transform;
		if (this.meanNormalization) {
			transform = new ZTransform();
		} else {
			transform = new NormalizeByStdTransform();
		}

		// For each disjoint query window with lenth this.windowLength.
		int numberOfDisjointWindows = a.length / this.windowLength;
		for (int i = 0; i < numberOfDisjointWindows; i++) {
			int startOfDisjointWindow = i * this.windowLength;
			double[] disjointWindow = Arrays.copyOfRange(a, startOfDisjointWindow, startOfDisjointWindow + this.windowLength);

			// Vertical alignment.
			disjointWindow = transform.transform(disjointWindow);

			// Holds the minumum distance between the current disjoint window and all
			// sliding windows.
			double windowDistance = Double.MAX_VALUE;

			// Slide window with length windowLength and stride 1 over the time series B.
			int numberOfSlidingWindows = b.length - this.windowLength + 1;
			for (int j = 0; j < numberOfSlidingWindows; j++) {
				int startOfSlidingWindow = j;
				double[] slidingWindow = Arrays.copyOfRange(b, startOfSlidingWindow, startOfSlidingWindow + this.windowLength);

				// Vertical alignment.
				slidingWindow = transform.transform(slidingWindow);

				// Calculate distance between disjoint and sliding window. For each disjoint
				// window, keep the minumum distance to all sliding windows.
				double distanceDisjointSliding = this.euclideanDistance.distance(disjointWindow, slidingWindow);
				if (distanceDisjointSliding < windowDistance) {
					windowDistance = distanceDisjointSliding;
				}
			}
			// Aggregate the distance for all disjoint windows to the total distance.
			totalDistance += windowDistance;
		}

		return totalDistance;
	}

	public  ShotgunDistance(final int windowLength, final boolean meanNormalization);

}