package ip.gui.frames;


import ip.gui.FFTImage;
import ip.gui.Timer;
import ip.gui.FFTRadix2;

import java.awt.*;
import java.awt.event.ActionEvent;

public class FFTFrame extends XformFrame {
    private Menu fftMenu = getMenu("FFT");
    private MenuItem fftpfa_mi = addMenuItem(fftMenu, "pfa transforms.fft");
    private MenuItem fftipfa_mi = addMenuItem(fftMenu, "pfa ifft");

    private MenuItem fftR2_mi = addMenuItem(fftMenu, "[E-T-f]ft radix 2");
    private MenuItem ifftR2_mi = addMenuItem(fftMenu, "[E-T-i]transforms.fft radix 2");
    private MenuItem complexMultR2_mi = addMenuItem(fftMenu, "complex multR2");
    private MenuItem rgb2Complex_mi = addMenuItem(fftMenu, "rgb2Complex");
    private MenuItem phaseFFTR2_mi = addMenuItem(fftMenu, "[p]haseFFTR2");
    private MenuItem filterGabor_mi = addMenuItem(fftMenu, "[T-f]ilterGabor");
    private MenuItem radix2fftStats_mi = addMenuItem(fftMenu, "Radix2 fft stats");


    FFTFrame(String title) {
        super(title);
        getXformMenu().add(fftMenu);
    }


    public void actionPerformed(ActionEvent e) {

        if (match(e, radix2fftStats_mi)) {
            radix2fftStats();
            return;
        }

        if (match(e, filterGabor_mi)) {
            filterGabor();
            return;
        }
        if (match(e, phaseFFTR2_mi)) {
            phaseFFTR2();
            return;
        }
        if (match(e, fftpfa_mi)) {
            fftpfa();
            return;
        }
        if (match(e, fftipfa_mi)) {
            fftipfa();
            return;
        }

        if (match(e, complexMultR2_mi)) {
            complexMultR2();
            return;
        }
        if (match(e, rgb2Complex_mi)) {
            rgb2Complex();
            return;
        }
        if (match(e, fftR2_mi)) {
            fftR2();
            return;
        }
        if (match(e, ifftR2_mi)) {
            ifftR2();
            return;
        }
        super.actionPerformed(e);
    }


    public void test1DFFTvs() {
        String args[] = {};
        transforms.FFT1d.main(args);
    }

    private FFTImage fftimage = null;

    public void fftpfa() {
        Timer t = new Timer();
        t.start();
        fftimage = new FFTImage(getPels(), getImageWidth(), 100.0f, true);
        pels2Image(fftimage.getFftIntArray());
        image2Short();
        t.print("PSA is done");
    }

    public void fftipfa() {
        pels2Image(fftimage.getIfftIntArray());
        image2Short();
    }

    public static int gcd(int a, int b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }

    public void radix2fftStats() {
        fftradix2.fft.printStats();
    }

    public void fftR2() {
        //Timer t = new Timer();
        //t.start();
        isSquareAndPowerOfTwoCheck();
        fftradix2 = new FFTRadix2(this);
        int psd[] = fftradix2.fft();
        viewPsd(psd);
        //t.print("transforms.fft done");
    }

    private void viewPsd(int psd[]) {

        pels2Image(psd);
        image2Short();
    }

    public void phaseFFTR2() {
        //Timer t = new Timer();
        //t.start();
        isSquareAndPowerOfTwoCheck();
        fftradix2 = new FFTRadix2(this);
        int psd[] = fftradix2.getPhaseImage();
        viewPsd(psd);
        //t.print("transforms.fft done");
    }

    public void filterGabor() {
        if (getChild() == null)
            copyToChildFrame();
        revert();
        getChild().grabGabor();
        getChild().fftR2();
        fftR2();
        complexMultR2();
        ifftR2();
    }

    public void complexMultR2() {
        fftradix2.complexMult(getChild().fftradix2);
        viewPsd(fftradix2.getPsd());
    }

    private static double LOG2 = Math.log(2);

    private int log2(int l) {
        return (int) (Math.log(l) / LOG2);
    }

    private double log2(double l) {
        return Math.log(l) / LOG2;
    }

    private boolean isPowerOfTwo(double l) {
        return log2(l) == log2((int) l);
    }

    private boolean bothDimensionsPowerOfTwo() {
        return
                isPowerOfTwo(getImageWidth()) && isPowerOfTwo(getImageHeight());
    }

    private boolean isSquare() {
        return getImageWidth() == getImageHeight();
    }

    private boolean isSquareAndPowerOfTwo() {
        return isSquare() && bothDimensionsPowerOfTwo();
    }

    private void isSquareAndPowerOfTwoCheck() {
        if (isSquareAndPowerOfTwo()) return;
        System.out.println("Image is not square and power of two");
    }

    public void ifftR2() {
        //Timer t = new Timer();
        //System.out.println("Computing ifft...");
        //t.start();
        int psd[] = fftradix2.ifft();
        //t.print("ifft is done");
        pels2Image(psd);
        image2Short();
    }

    public FFTRadix2 fftradix2 = null;

    public void rgb2Complex() {
        fftradix2 = new FFTRadix2(this);
    }

    public Menu getFftMenu() {
        return fftMenu;
    }

    public MenuItem getFftpfa_mi() {
        return fftpfa_mi;
    }

    public MenuItem getFftipfa_mi() {
        return fftipfa_mi;
    }

    public MenuItem getFftR2_mi() {
        return fftR2_mi;
    }

    public MenuItem getIfftR2_mi() {
        return ifftR2_mi;
    }

    public MenuItem getComplexMultR2_mi() {
        return complexMultR2_mi;
    }

    public MenuItem getRgb2Complex_mi() {
        return rgb2Complex_mi;
    }

    public MenuItem getPhaseFFTR2_mi() {
        return phaseFFTR2_mi;
    }

    public MenuItem getFilterGabor_mi() {
        return filterGabor_mi;
    }

    public MenuItem getRadix2fftStats_mi() {
        return radix2fftStats_mi;
    }

    public FFTImage getFftimage() {
        return fftimage;
    }

    public static double getLOG2() {
        return LOG2;
    }

    public FFTRadix2 getFftradix2() {
        return fftradix2;
    }

}