package ip.gabor;

/* ip.gabor.DrawGabor - Decompiled by JODE
 * Visit http://jode.sourceforge.net/
 */

import math.Mat;
import ip.gui.ConvolutionUtils;

import java.awt.*;
import java.awt.image.MemoryImageSource;

class GaborCanvas extends FilterCanvas {
    private Image image;
    private int[] spatialGaborIntArray = null;
    private int[] frequencyGaborIntArray = null;
    private int lat = 64;
    private int sz = lat;

    public GaborCanvas() {

    }

    public float[] getKernelf() {
        float k[] = new float[spatialGaborIntArray.length];
        for (int i = 0; i < k.length; i++)
            k[i] = spatialGaborIntArray[i] / 255.0f;
        return k;
    }

    public float[][] getKernel() {
        short s[][] = graphics.ImageUtils.getGreenFromImage(image, this);
        float f[][] = Mat.normalize(s);
        Mat.scale(f, 2.0);
        return f;
    }

    public void drawImage(String string) {
        if (string.equals("space"))
            image = getImage(spatialGaborIntArray);
        if (string.equals("fourier"))
            image = getImage(frequencyGaborIntArray);
        this.repaint();
    }

    public Image getImage() {
        return image;
    }

    public void setImage(Image img) {
        image = img;
    }

    public Image getImage(int ia[]) {
        return this.createImage(new MemoryImageSource(sz, sz,
                ia,
                0, sz));
    }

    public void paint(Graphics graphics) {
        if (image != null)
            graphics.drawImage(image, 0, 0, getWidth(), getHeight(), null);
    }

    // DrawGabor.ComputeImageArrays(size, lambda_val, theta_val, phi_val,
    //            gamma_val, sigma_val);
    public void ComputeImageArrays
            (int kernelSize, double lambda, double theta, double phi, double gamma, double sigma) {
        theta = theta * Math.PI / 180.0;
        spatialGaborIntArray = new int[kernelSize * kernelSize];
        frequencyGaborIntArray = new int[kernelSize * kernelSize];
        sz = kernelSize;
        double sigmaSquared = sigma * sigma;
        double sigmaSquaredOnSizeSquared = -19.739208802178716 * sigmaSquared /
                (double) (kernelSize * kernelSize);
        double sizeOnLambda = (double) kernelSize / lambda;
        double sineTheta = Math.sin(theta);
        double cosTheta = Math.cos(theta);
        double twoPi = 2 * Math.PI;
        double gammaSquared = gamma * gamma;
        //I am guessing that these are IEEE TIP V 8 No 10 variables, but I am not sure,
        // - DL
        for (int xMinusU = -kernelSize / 2; xMinusU < kernelSize / 2; xMinusU++) {
            for (int yMinusV = -kernelSize / 2; yMinusV < kernelSize / 2; yMinusV++) {
                double U = (double) xMinusU * cosTheta - (double) yMinusV * sineTheta;
                double V = (double) xMinusU * sineTheta + (double) yMinusV * cosTheta;
                double vSquared = V * V;
                double uSquared = U * U;
                // This is the g of eq 2...? DL.
                computeGabor(uSquared, gammaSquared, vSquared, sigmaSquared,
                        twoPi, U, lambda, phi,
                        yMinusV, kernelSize, xMinusU);
                //computeFourier(sigmaSquaredOnSizeSquared, U,
                //         sizeOnLambda, vSquared,
                //         gammaSquared, yMinusV, kernelSize, xMinusU);
            }
        }
    }

    private void computeGabor(double uSquared,
                              double gammaSquared,
                              double vSquared,
                              double sigmaSquared,
                              double twoPi,
                              double U,
                              double lambda,
                              double phi,
                              int yMinusV,
                              int size,
                              int xMinusU) {
        double g
                = Math.exp(-(uSquared + gammaSquared * vSquared)
                / (2.0 * sigmaSquared)) *
                Math.cos(twoPi * U / lambda + phi);
        int gScaled = (int) Math.round((1.0 + g) / 2.0 * 255.0);
        spatialGaborIntArray[getArrayIndex(yMinusV, size, xMinusU)]
                = packPixel(gScaled);
    }

    private void computeFourier(double sigmaSquaredOnSizeSquared,
                                double U, double sizeOnLambda,
                                double Vsquared, double gammaSquared,
                                int yMinusV, int size, int xMinusU) {
        double g;
        int gScaled;
        g = (Math.exp(sigmaSquaredOnSizeSquared * ((U - sizeOnLambda)
                * (U - sizeOnLambda)
                + Vsquared / gammaSquared))
                + Math.exp(sigmaSquaredOnSizeSquared * ((U + sizeOnLambda)
                * (U + sizeOnLambda)
                + Vsquared / gammaSquared)));
        gScaled = (int) Math.round(g * 255.0);
        if (g > 1.0)
            gScaled = 255;
        frequencyGaborIntArray[getArrayIndex(yMinusV, size, xMinusU)]
                = packPixel(gScaled);
    }

    private static int packPixel(int gScaled) {
        return gScaled + (gScaled << 8) + (gScaled << 16) + -16777216;
    }

    private static int getArrayIndex(int yMinusEta, int size, int xMinusPsi) {
        return (yMinusEta + size / 2) * size + xMinusPsi + size / 2;
    }
}