/**
 * The `Paeth` filter computes a simple linear function of the three neighboring pixels (left, above, upper left), then chooses as predictor the neighboring pixel closest to the computed value.
 *
 * This technique is due to Alan W. Paeth.
 *
 * @param {Uint8Array} scanline raw data
 * @param {number} scanline_offset
 * @param {Uint8Array} pixels processed output
 * @param {number} bpp bytes-per-pixel
 * @param {number} offset
 * @param {number} output_offset_previous pass a negative value when there is no previous scanline
 * @param {number} length
 *
 * @see https://www.w3.org/TR/PNG-Filters.html
 */
export function png_filter_unFilterPaeth(
    scanline,
    scanline_offset,
    pixels,
    bpp,
    offset,
    output_offset_previous,
    length
) {
    let i = 0, raw, a, b, c, p, pa, pb, pc, pr;

    if (output_offset_previous < 0) {

        // Prior(x) == 0 && Raw(x - bpp) == 0
        for (; i < bpp; i++) {
            pixels[offset + i] = scanline[i + scanline_offset];
        }

        // Prior(x) == 0 && Raw(x - bpp) != 0
        // paethPredictor(x, 0, 0) is always x
        for (; i < length; i++) {
            pixels[offset + i] = (scanline[i + scanline_offset] + pixels[offset + i - bpp]) & 0xFF;
        }

    } else {

        // Prior(x) != 0 && Raw(x - bpp) == 0
        // paethPredictor(x, 0, 0) is always x
        for (; i < bpp; i++) {
            pixels[offset + i] = (scanline[i + scanline_offset] + pixels[output_offset_previous + i]) & 0xFF;
        }

        // Prior(x) != 0 && Raw(x - bpp) != 0
        for (; i < length; i++) {
            raw = scanline[i + scanline_offset];

            c = pixels[output_offset_previous + i - bpp];
            b = pixels[output_offset_previous + i];
            a = pixels[offset + i - bpp];

            p = a + b - c;

            pa = Math.abs(p - a);
            pb = Math.abs(p - b);
            pc = Math.abs(p - c);

            if (pa <= pb && pa <= pc) {
                pr = a;
            } else if (pb <= pc) {
                pr = b;
            } else {
                pr = c;
            }

            pixels[offset + i] = (raw + pr) & 0xFF;
        }

    }
}
