class LoessInterpolator {

	Double smoothOnePoint(final double x, final int left, final int right) {

		// Ordinarily, one doesn't do linear regression one x-value at a time, but LOESS does since
		// each x-value will typically have a different window. As a result, the weighted linear regression
		// is recast as a linear operation on the input data, weighted by this.fWeights.

		State state = computeNeighborhoodWeights(x, left, right);

		if (state == State.WEIGHTS_FAILED)
			return null;

		if (state == State.LINEAR_OK)
			updateWeights(x, left, right);

		double ys = 0.0;
		for (int i = left; i <= right; ++i)
			ys += fWeights[i] * fData[i];

		return ys;
	}

}

class LoessInterpolatorTest {

	@Test
	public void constantDataExtrapolatesConstantValues() {


		double[] data = createConstantDataArray();

		for (int degree = 0; degree < 3; ++degree) {
			LoessInterpolator loess = new LoessInterpolator.Builder().setWidth(7).setDegree(degree).interpolate(data);

			Double y = loess.smoothOnePoint(-100, 0, data.length - 1);
			assertNotNull(y);
			assertEquals("Bad value extrapolating left", data[0], y, 3.0e-9);

			y = loess.smoothOnePoint(1000.0, 0, data.length - 1);
			assertNotNull(y);
			assertEquals("Bad value extrapolating right", data[0], y, 3.0e-9);
		}
	}

}