package graphics;

import futils.Futil;
import futils.WriterUtil;
import gui.IconUtils;
import gui.ImageBean;
import gui.ImageBeanInterface;
import ip.gabor.FilterCanvas;
import ip.gui.ConvolutionUtils;
import ip.gui.Kernels;
import ip.gui.frames.ClosableFrame;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.*;


public final class ImageUtils {
    private static ColorModel cm = ColorModel.getRGBdefault();

    private ImageUtils() {
    }

    public static java.awt.Image open() {
        java.io.File f =
                Futil.getReadFile("select an image");
        if (f == null) return null;
        return open(f);
    }


    public static java.awt.Image getImage(java.awt.Component c) {
        java.awt.Dimension d = c.getSize();
        java.awt.Frame f = new java.awt.Frame();
        f.addNotify();
        f.setSize(d);
        java.awt.Image i = f.createImage(d.width, d.height);

        java.awt.Graphics g = i.getGraphics();
        c.paint(g);
        return i;
    }

    public static java.awt.Image open(
            java.io.File f) {
        java.awt.Image i =
                java.awt.Toolkit.getDefaultToolkit().getImage(
                        f.toString());
        waitForImage(new gui.ClosableJFrame(), i);
        return i;
    }

    public static void waitForImage(java.awt.Component c,
                                    java.awt.Image image) {
        java.awt.MediaTracker tracker = new java.awt.MediaTracker(c);
        try {
            tracker.addImage(image, 0);
            tracker.waitForID(0);
        } catch (InterruptedException e) {
        }
    }

    public static void main(String args[]) {
        ImageUtils iu
                = new ImageUtils();
        iu.open();

    }

    public static Image byte2Image(byte r[][]) {

        int w = r.length;
        int h = r[0].length;
        int v = 0;
        Toolkit tk = Toolkit.getDefaultToolkit();
        int pels[] = new int[w * h];
        for (int x = 0; x < w; x++)
            for (int y = 0; y < h; y++) {
                if (r[x][y] == 1)
                    v = 255;
                else
                    v = 0;
                pels[y + x * h] =
                        0xff000000
                        | (v << 16)
                        | (v << 8)
                        | v;
            }
        Image i = tk.createImage(
                new MemoryImageSource(
                        w,
                        h,
                        ColorModel.getRGBdefault(),
                        pels, 0,
                        w));
        return i;
    }

    public static Image short2Image(short r[][]) {

        int w = r.length;
        int h = r[0].length;
        int v = 0;
        Toolkit tk = Toolkit.getDefaultToolkit();
        int pels[] = new int[w * h];
        for (int x = 0; x < w; x++)
            for (int y = 0; y < h; y++) {
                v = r[x][y];
                pels[y + x * h] =
                        0xff000000
                        | (v << 16)
                        | (v << 8)
                        | v;
            }
        Image i = tk.createImage(
                new MemoryImageSource(
                        w,
                        h,
                        ColorModel.getRGBdefault(),
                        pels, 0,
                        w));
        return i;
    }

    public static Image short2FalseColorImage(short r[][]) {

        int w = r.length;
        int h = r[0].length;
        int v = 0;
        Toolkit tk = Toolkit.getDefaultToolkit();
        int pels[] = new int[w * h];
        for (int x = 0; x < w; x++)
            for (int y = 0; y < h; y++) {
                v = r[x][y];
                int red = IconUtils.getRed(v);
                int green = IconUtils.getGreen(v);
                int blue = IconUtils.getBlue(v);
                pels[y + x * h] =
                        0xff000000
                        | (red << 16)
                        | (green << 8)
                        | blue;
            }
        Image i = tk.createImage(
                new MemoryImageSource(
                        w,
                        h,
                        ColorModel.getRGBdefault(),
                        pels, 0,
                        w));
        return i;
    }

    public static ConvolveOp getConvolveOp(Kernel k) {
        return new ConvolveOp(k, ConvolveOp.EDGE_ZERO_FILL, null);
    }

    public static Kernel makeKernel(int w, int h, float blurMatrix[]) {
        return new Kernel(w, h, blurMatrix);
    }

    public static Kernel makeKernel(float k2d[][]) {
        int w = k2d.length;
        int h = k2d[0].length;
        float k[] = new float[w * h];
        int x = 0;
        for (int i = 0; i < w; i++)
            for (int j = 0; j < h; j++, x++)
                k[x] = k2d[i][j];
        return new Kernel(w, h, k);
    }

    public static BufferedImage getBufferedImage(Image img) {
        ImageBean ib = new ImageBean();
        ib.setImage(img);
        return getBufferedImage(ib);
    }

    public static BufferedImage getBufferedImage(ImageBeanInterface ib) {
        int w = ib.getImageWidth();
        int h = ib.getImageHeight();
        BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = bi.createGraphics();
        g2d.drawImage(ib.getImage(), 0, 0, w, h, null);
        return bi;
    }

    public static ImageBean getImageBean(BufferedImage bi) {
        ImageBean ib = new ImageBean();
        ib.setImage(
                Toolkit.getDefaultToolkit().createImage(
                        new FilteredImageSource(bi.getSource(),
                                new BufferedImageFilter(
                                        new AffineTransformOp(
                                                new AffineTransform(),
                                                AffineTransformOp.TYPE_BILINEAR)
                                )
                        )
                )
        );
        return ib;
    }

    public static ImageBean changeColors(
            float colorMatrix[][],
            ImageBean ib) {
        return getImageBean(
                changeColors(
                        colorMatrix, getBufferedImage(ib)));
    }


    public static BufferedImage changeColors(
            float colorMatrix[][],
            BufferedImage bi) {
        // create filter to change colors
        BandCombineOp changeColors =
                new BandCombineOp(colorMatrix, null);

        // create source and display Rasters
        Raster sourceRaster = bi.getRaster();

        WritableRaster displayRaster =
                sourceRaster.createCompatibleWritableRaster();

        // filter Rasters with changeColors filter
        changeColors.filter(sourceRaster, displayRaster);

        // create new BufferedImage from display Raster
        return new BufferedImage(bi.getColorModel(),
                displayRaster, true, null);
    }

    public static ColorModel getRgbColorModel() {
        return cm;
    }

    public static void fitScreen(Component c) {
        Toolkit tk = Toolkit.getDefaultToolkit();
        Dimension d
                = tk.getScreenSize();
        c.setSize(d.width, d.height);
    }

    public static Image pelsToImage(int pels[], int w, int h) {
        Toolkit tk = Toolkit.getDefaultToolkit();
        return tk.createImage(
                new MemoryImageSource(
                        w,
                        h,
                        getRgbColorModel(),
                        pels, 0,
                        w));
    }

    public static Image getImage(short r[][], short g[][], short b[][]) {
        int width = r.length;
        int height = r[0].length;
        int pels[] = new int[width * height];
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++) {
                pels[x + y * width] =
                        0xff000000
                        | (r[x][y] << 16)
                        | (g[x][y] << 8)
                        | b[x][y];
            }
        Image i = pelsToImage(pels, width, height);
        return i;
    }

    public static int[] imageToPels(Image img, int width, int height) {
        int pels[] = new int[width * height];

        PixelGrabber grabber =
                new PixelGrabber(
                        img, 0, 0,
                        width, height, pels, 0, width);

        try {
            grabber.grabPixels();
        } catch (InterruptedException e) {
        }
        return pels;
    }

    public static void pelsToShort(short r[][], short g[][], short b[][],
                                   int[] pels, int width, int height) {
        int i;
        ColorModel cm = getRgbColorModel();
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++) {
                i = x + y * width;
                b[x][y] = (short) cm.getBlue(pels[i]);
                g[x][y] = (short) cm.getGreen(pels[i]);
                r[x][y] = (short) cm.getRed(pels[i]);
            }
    }

    public static Image getGrayImage(short g[][]) {
        Toolkit tk =
                Toolkit.getDefaultToolkit();
        ColorModel cm = tk.getColorModel();
        int width = g.length;
        int height = g[0].length;
        int pels[] = new int[width * height];
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++) {
                pels[x + y * width] =
                        0xff000000
                        | (g[y][x] << 16)
                        | (g[y][x] << 8)
                        | g[y][x];
            }
        return tk.createImage(
                new
                        MemoryImageSource(
                                width,
                                height,
                                cm,
                                pels, 0,
                                width));
    }

    public static void writeHexImage(ImageBeanInterface ib) {
        WriterUtil.writeString(getHexImage(ib));
    }

    public static String getHexImage(ImageBeanInterface ib) {
        StringBuffer sb = new StringBuffer("");
        int width = ib.getImageWidth();
        int height = ib.getImageHeight();
        Image img = ib.getImage();

        int pixels[] = new int[width * height];
        PixelGrabber pg = new PixelGrabber(
                img,
                0,
                0,
                width,
                height,
                pixels,
                0,
                width);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
        }
        String newline = new String("\n");
        int i = 0;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                i = x + y * width;

                sb.append("0x" + Integer.toHexString(pixels[i]) + ", ");
            }
            sb.append(newline);
        }
        return sb.toString();
    }

    public static Image getImageFromShort(short g[][]) {
        if (g == null) return null;
        int width = g.length;
        int height = g[0].length;
        Toolkit tk =
                Toolkit.getDefaultToolkit();
        ColorModel cm = tk.getColorModel();
        int pels[] = new int[width * height];
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++) {
                pels[x + y * width] =
                        0xff000000
                        | (g[x][y] << 16)
                        | (g[x][y] << 8)
                        | g[x][y];
            }
        return tk.createImage(
                new
                        MemoryImageSource(
                                width,
                                height,
                                cm,
                                pels, 0,
                                width));
    }

    public static short[][] getGreenFromImage(Image img, ImageObserver io) {
        if (img == null) return null;
        int width = img.getWidth(io);
        int height = img.getHeight(io);
        int pels[] = new int[width * height];
        ColorModel cm = ColorModel.getRGBdefault();

        PixelGrabber grabber =
                new PixelGrabber(
                        img, 0, 0,
                        width, height, pels, 0, width);

        try {
            grabber.grabPixels();
        } catch (InterruptedException e) {
        }
        ;
        short g[][] = new short[width][height];
        int i = 0;
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++) {
                i = x + y * width;
                g[x][y] = (short) cm.getGreen(pels[i]);
            }
        return g;
    }

    public static FilterCanvas[] getFilterCanvas(Image img, ImageObserver io) {
        FilterCanvas fc[] = {
            new FilterCanvas(img),
            new FilterCanvas(
                    ConvolutionUtils.convolution(img,
                            Kernels.getRobinson1(), io)),
            new FilterCanvas(
                    ConvolutionUtils.convolution(img,
                            Kernels.getRobinson2(), io)),
            new FilterCanvas(
                    ConvolutionUtils.convolution(img,
                            Kernels.getRobinson3(), io)),
            new FilterCanvas(
                    ConvolutionUtils.convolution(img,
                            Kernels.getRobinson4(), io)),
            new FilterCanvas(
                    ConvolutionUtils.convolution(img,
                            Kernels.getRobinson5(), io)),
            new FilterCanvas(
                    ConvolutionUtils.convolution(img,
                            Kernels.getRobinson6(), io)),
            new FilterCanvas(
                    ConvolutionUtils.convolution(img,
                            Kernels.getRobinson7(), io)),
            new FilterCanvas(
                    ConvolutionUtils.convolution(img,
                            Kernels.getRobinson8(), io))
        };
        return fc;
    }

    public static FilterCanvas[] getSubBands(Image img, ImageObserver io) {
        ClosableFrame f = new ClosableFrame();
        f.setLayout(new GridLayout(4, 4));
        FilterCanvas[] fc = getFilterCanvas(img, io);
        for (int i = 0; i < fc.length; i++)
            f.add(fc[i]);
        f.show();
        return fc;
    }

    public static BufferedImage convolve(BufferedImage bi, float[][] blurMatrix) {
        // create ConvolveOp for blurring BufferedImage
        BufferedImageOp convolveOp =
                getConvolveOp(makeKernel(blurMatrix));

        // apply blurFilter to BufferedImage
        return convolveOp.filter(bi, null);
    }

    public static Image convolution(Image img, float k[][]) {
        BufferedImage bi = getBufferedImage(img);
        bi = convolve(bi, k);
        return getImageBean(bi).getImage();

    }

    public static void print(Component c, String title) {
        java.awt.Toolkit tk = java.awt.Toolkit.getDefaultToolkit();
        java.awt.PrintJob pj =
                tk.getPrintJob(
                        new Frame(),
                        title,
                        null);
        c.paint(pj.getGraphics());
        pj.end();
    }

    public static void print(Component c) {
        print(c, null);
    }
}