package ip.gui;

import ip.gabor.FilterCanvas;

import java.awt.*;
import java.awt.image.*;
import java.io.FileWriter;
import java.io.PrintWriter;

import futils.Out;
import utils.MyMath;
import math.Mat;
import graphics.ImageUtils;

public class ConvolutionUtils {
    static double t0 = 0;
    static double t1 = 0;
    static double t2 = 0;
    static double t3 = 0;
    static double t4 = 0;
    static double t5 = 0;
    static double t6 = 0;
    static double t7 = 0;
    static double t8 = 0;
    static double t9 = 0;
    static double t10 = 0;
    static double t11 = 0;
    static double t12 = 0;
    static double t13 = 0;
    static double t14 = 0;
    static double t15 = 0;
    static double t16 = 0;
    static double t17 = 0;
    static double t18 = 0;
    static double t19 = 0;
    static double t20 = 0;
    static double t21 = 0;
    static double t22 = 0;
    static double t23 = 0;
    static double t24 = 0;
    static double t25 = 0;
    static double t26 = 0;
    static double t27 = 0;
    static double t28 = 0;
    static double t29 = 0;
    static double t30 = 0;
    static double t31 = 0;
    static double t32 = 0;
    static double t33 = 0;
    static double t34 = 0;
    static double t35 = 0;
    static double t36 = 0;
    static double t37 = 0;
    static double t38 = 0;
    static double t39 = 0;
    static double t40 = 0;
    static double t41 = 0;
    static double t42 = 0;
    static double t43 = 0;

    public static void drawPel(Graphics g, int x, int y) {
        int dGrid = 10;
        int x1 = x * dGrid;
        int y1 = y * dGrid;
        int h = dGrid / 2;
        g.drawOval(x1 - h, y1 - h, dGrid, dGrid);
    }

    public static void drawPel(Graphics g, Point p) {
        drawPel(g, p.x, p.y);
    }

    public static void main(String args[]) {
        GeometryUtils.getNextDirectionTest();
    }

    private static void oddTest() {
        System.out.println("24 is odd:" + MyMath.odd(24) +
                " 13 is odd:" + MyMath.odd(13));
    }

    public static Image convolution(Image img, float k[][], ImageObserver io) {
        short orig[][] = ImageUtils.getGreenFromImage(img, io);
        orig = Mat.clip(ConvolutionUtils.convolve(orig, k));
        return ImageUtils.getImageFromShort(orig);
    }

    public static int cx(int x, int width) {
        if (x > width - 1)
            return x - width + 1;
        if (x < 0)
            return width + x;
        return x;
    }

    public static int cy(int y, int height) {
        if (y > height - 1)
            return y - height + 1;
        if (y < 0)
            return height + y;
        return y;
    }

    public static short[][] convolveBruteForce(short f[][], float k[][]) {
        int uc = k.length / 2;
        int vc = k[0].length / 2;
        int width = f.length;
        int height = f[0].length;

        short h[][] = new short[width][height];
        double sum = 0;

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                sum = 0.0;
                for (int v = -vc; v <= vc; v++)
                    for (int u = -uc; u <= uc; u++)
                        sum += f[cx(x - u, width)][cy(y - v, height)] * k[u + uc][v + vc];
                //if (sum < 0) sum = 0;
                //if (sum > 255) sum = 255;
                h[x][y] = (short) sum;
            }
        }
        return h;
    }

// Convolution, optimze the edges
    public static short[][] convolve(short f[][], float k[][]) {
        if (k == null) return null;
        if (f == null) return null;
        if (!(MyMath.odd(k.length) && MyMath.odd(k[0].length))) {
            System.out.println("Error:kernel passed to convolution is not odd!");

        }
        int uc = k.length / 2;
        int vc = k[0].length / 2;

        short h[][] = convolveNoEdge(f, k);
        double sum = 0;
        int width = f.length;
        int height = f[0].length;
        //convolve bottom
        for (int x = 0; x < width - 1; x++)
            for (int y = 0; y < vc; y++) {
                sum = 0.0;
                for (int v = -vc; v <= vc; v++)
                    for (int u = -uc; u <= uc; u++)
                        sum += f[cx(x - u, width)][cy(y - v, height)] * k[u + uc][v + vc];
                //if (sum < 0) sum = 0;
                //if (sum > 255) sum = 255;
                h[x][y] = (short) sum;
            }
        //convolve left
        for (int x = 0; x < uc; x++)
            for (int y = vc; y < height - vc; y++) {

                sum = 0.0;
                for (int v = -vc; v <= vc; v++)
                    for (int u = -uc; u <= uc; u++)
                        sum += f[cx(x - u, height)][cy(y - v,height)] * k[u + uc][v + vc];
                //if (sum < 0) sum = 0;
                //if (sum > 255) sum = 255;
                h[x][y] = (short) sum;
            }
        //convolve right
        for (int x = width - uc; x < width - 1; x++)
            for (int y = vc; y < height - vc; y++) {

                sum = 0.0;
                for (int v = -vc; v <= vc; v++)
                    for (int u = -uc; u <= uc; u++)
                        sum += f[cx(x - u, width)][y - v] * k[u + uc][v + vc];
                //if (sum < 0) sum = 0;
                //if (sum > 255) sum = 255;
                h[x][y] = (short) sum;
            }

        //convolve top
        try {
            for (int x = 0; x < width - 1; x++) {
                for (int y = height - vc; y < height - 1; y++) {
                    sum = 0.0;
                    for (int v = -vc; v <= vc; v++)
                        for (int u = -uc; u <= uc; u++)
                            sum += f[cx(x - u, f.length)][cy(y - v, f[0].length)]
                                    * k[u + uc][v + vc];
                    //if (sum < 0) sum = 0;
                    //if (sum > 255) sum = 255;
                    h[x][y] = (short) sum;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return h;
    }
// Convolution, ignoring the edges
    public static short[][] convolveNoEdge(short f[][], float k[][]) {
        int uc = k.length / 2;
        int vc = k[0].length / 2;
        int width = f.length;
        int height = f[0].length;
        short h[][] = new short[width][height];
        double sum = 0;

        for (int x = uc; x < width - uc; x++) {
            for (int y = vc; y < height - vc; y++) {

                sum = 0.0;
                for (int v = -vc; v <= vc; v++)
                    for (int u = -uc; u <= uc; u++)
                        sum += f[x - u][y - v] * k[u + uc][v + vc];
                //if (sum < 0) sum = 0;
                //if (sum > 255) sum = 255;
                h[x][y] = (short) sum;
            }
        }
        return h;
    }


    public static short[][] convolveBrute2(short f[][], float k[][]) {
        return convolveBruteForce(f, k);
    }

    public static short[][] convolve2(short f[][], float k[][]) {
        //return convolveNoEdge2(f, k);
        return convolveBruteForce(f,k);
    }

    public static short[][] convolveNoEdge2(short f[][], float k[][]) {
        return convolveNoEdge(f, k);

    }


}