/* Copyright (C) 2005-2011 Fabio Riccardi */

package com.lightcrafts.jai.opimage;

import com.lightcrafts.mediax.jai.PointOpImage;
import com.lightcrafts.mediax.jai.ImageLayout;

import java.awt.image.*;
import java.awt.color.ColorSpace;
import java.awt.*;
import java.util.Map;

import sun.awt.image.ShortInterleavedRaster;
import sun.awt.image.ByteInterleavedRaster;

/**
 * Created by IntelliJ IDEA.
 * User: fabio
 * Date: Mar 13, 2007
 * Time: 2:36:29 PM
 * To change this template use File | Settings | File Templates.
 */
public class RedMaskOpImage extends PointOpImage {
    private final double tolerance;

    private static ImageLayout createLayout(RenderedImage source) {
        ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
                                                false, false,
                                                Transparency.OPAQUE, DataBuffer.TYPE_BYTE);

        ImageLayout layout = new ImageLayout(source);
        layout.setColorModel(cm);
        layout.setSampleModel(cm.createCompatibleSampleModel(source.getWidth(), source.getHeight()));
        return layout;
    }

    public RedMaskOpImage(RenderedImage source, double tolerance, Map config) {
        super(source, createLayout(source), config, true);
        this.tolerance = tolerance;
    }

    protected void computeRect(Raster[] sources,
                               WritableRaster dest,
                               Rectangle destRect) {
        ushortLoop((ShortInterleavedRaster) sources[0], (ByteInterleavedRaster) dest);
    }

    protected void ushortLoop(ShortInterleavedRaster src, ByteInterleavedRaster dst) {
        int width = src.getWidth();
        int height = src.getHeight();

        byte dstData[] = dst.getDataStorage();
        int dstBandOffsets[] = dst.getDataOffsets();
        int dstLineStride = dst.getScanlineStride();
        int dstPixelStride = dst.getPixelStride();

        short srcData[] = src.getDataStorage();
        int srcBandOffsets[] = src.getDataOffsets();
        int srcLineStride = src.getScanlineStride();
        int srcPixelStride = src.getPixelStride();

        int srcLOffset = srcBandOffsets[0];
        int srcAOffset = srcBandOffsets[1];
        int srcBOffset = srcBandOffsets[2];

        int dstOffset = dstBandOffsets[0];

//        double ra = 68; double radev = 15.3 * tolerance;
//        double rb = 39; double rbdev = 14.5 * tolerance;
//
//        int raMin = (int) ((ra - radev) * 256);
//        int raMax = (int) ((ra + radev) * 256);
//        int rbMin = (int) ((rb - rbdev) * 256);
//        int rbMax = (int) ((rb + rbdev) * 256);
//
//        double sa = 19; double sadev = 5.1 * 3.5;
//        double sb = 17; double sbdev = 2.66 * 3.5;
//
//        int saMin = (int) ((sa - sadev) * 256);
//        int saMax = (int) ((sa + sadev) * 256);
//        int sbMin = (int) ((sb - sbdev) * 256);
//        int sbMax = (int) ((sb + sbdev) * 256);

        // Sclera Red
        int raMin = (int) ((71.5 - 48.5 * tolerance) * 256);
        int raMax = (int) ((71.5 + 48.5 * tolerance) * 256);
        int rbMin = (int) ((8 - 35 * tolerance) * 256);
        int rbMax = (int) ((8 + 35 * tolerance) * 256);

        // Really Red
        int rraMin = (int) ((62 - 6.8 * 2) * 256);
        int rraMax = (int) ((62 + 6.8 * 2) * 256);
        int rrbMin = (int) ((35 - 6.5 * 2) * 256);
        int rrbMax = (int) ((35 + 6.5 * 2) * 256);

        // Kinda Orange
        int oaMin = (int) ((31 - 15 * 2) * 256);
        int oaMax = (int) ((31 + 15 * 2) * 256);
        int obMin = (int) ((56 - 5 * 2) * 256);
        int obMax = (int) ((56 + 5 * 2) * 256);

        // Magenta
        int maMin = (int) ((30 - 12 * 2) * 256);
        int maMax = (int) ((30 + 12 * 2) * 256);
        int mbMin = (int) ((-12 - 13 * 2) * 256);
        int mbMax = (int) ((-12 + 13 * 2) * 256);

        // Skin
        int sLMin = (int) (43.3593 * 0xffff / 100);
        int sLMax = (int) (99.6093 * 0xffff / 100);
        int saMin = (int) (1.5 * 256);
        int saMax = (int) (43.125 * 256);
        int sbMin = (int) (-4.6875 * 256);
        int sbMax = (int) (34.6875 * 256);

        for (int row = 0; row < height; row++) {
            for (int col = 0; col < width; col++) {
                int L = 0xffff & srcData[3 * col + row * srcLineStride + srcLOffset];
                int a = 0xffff & srcData[srcPixelStride * col + row * srcLineStride + srcAOffset] - 128 * 256;
                int b = 0xffff & srcData[srcPixelStride * col + row * srcLineStride + srcBOffset] - 128 * 256;

                if (((a > raMin && a < raMax && b > rbMin && b < rbMax)
                    || (a > oaMin && a < oaMax && b > obMin && b < obMax)
                    || (a > rraMin && a < rraMax && b > rrbMin && b < rrbMax))
                    // || (a > maMin && a < maMax && b > mbMin && b < mbMax))
                     && !(L > sLMin && L < sLMax && a > saMin && a < saMax && b > sbMin && b < sbMax))
                    dstData[dstPixelStride * col + row * dstLineStride + dstOffset] = (byte) 0xff;
                else
                    dstData[dstPixelStride * col + row * dstLineStride + dstOffset] = (byte) 0;
            }
        }
    }
}
