package uk.ac.soton.ecs.comp3204.l6;

import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.io.IOException;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.openimaj.content.slideshow.SlideshowApplication;
import org.openimaj.image.FImage;
import org.openimaj.image.MBFImage;
import org.openimaj.image.processing.convolution.FGaussianConvolve;
import org.openimaj.video.VideoDisplay;
import org.openimaj.video.VideoDisplayListener;

import uk.ac.soton.ecs.comp3204.l1.SimpleCameraDemo;
import uk.ac.soton.ecs.comp3204.utils.Utils;
import uk.ac.soton.ecs.comp3204.utils.annotations.Demonstration;

@Demonstration(title = "Difference of Gaussian response")
public class DoGResponseDemo extends SimpleCameraDemo implements VideoDisplayListener<MBFImage>, ChangeListener {
	static Font FONT = Font.decode("Monaco-32");
	private JSlider scaleSlider;
	private JTextField scaleField;
	private JSlider kSlider;
	private JTextField kField;

	@Override
	public JPanel getComponent(int width, int height) throws IOException {
		final JPanel c = super.getComponent(width, height);

		this.vc.getDisplay().addVideoListener(this);

		final JPanel controls = new JPanel(new GridBagLayout());
		controls.setOpaque(false);

		final JLabel scaleLbl = new JLabel("<html>Scale (\u03C3<sup>2</sup>): </html>");
		scaleLbl.setFont(FONT);
		controls.add(scaleLbl);

		scaleSlider = new JSlider(1, 500, 1);
		controls.add(scaleSlider);

		scaleField = new JTextField(5);
		scaleField.setEditable(false);
		scaleField.setFont(FONT);
		scaleField.setHorizontalAlignment(JTextField.RIGHT);
		controls.add(scaleField);

		final JLabel kLbl = new JLabel("<html>k: </html>");
		kLbl.setFont(FONT);
		controls.add(kLbl);

		kSlider = new JSlider(10, 50, 16);
		controls.add(kSlider);

		kField = new JTextField(5);
		kField.setEditable(false);
		kField.setFont(FONT);
		kField.setHorizontalAlignment(JTextField.RIGHT);
		controls.add(kField);

		scaleSlider.addChangeListener(this);
		kSlider.addChangeListener(this);

		stateChanged(null);

		final GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridy = 1;
		c.add(controls, gbc);

		return c;
	}

	@Override
	public void afterUpdate(VideoDisplay<MBFImage> display) {
		// do nothing
	}

	@Override
	public void beforeUpdate(MBFImage frame) {
		final float k = this.kSlider.getValue() / 10f;
		final float sigma2 = this.scaleSlider.getValue();

		final float ksigma2 = sigma2 * (k * k - 1);

		final FImage gimg = frame.flatten();

		final FImage blur1 = gimg.processInplace(new FGaussianConvolve((float) Math.sqrt(sigma2)));
		final FImage blur2 = gimg.process(new FGaussianConvolve((float) Math.sqrt(ksigma2)));

		blur1.subtractInplace(blur2);
		blur1.normalise();

		frame.internalAssign(blur1.toRGB());
	}

	@Override
	public void stateChanged(ChangeEvent e) {
		final float k = this.kSlider.getValue() / 10f;
		final float sigma2 = this.scaleSlider.getValue();

		this.kField.setText(String.format("%2.2f", k));
		this.scaleField.setText(String.format("%2.2f", sigma2));
	}

	public static void main(String[] args) throws IOException {
		new SlideshowApplication(new DoGResponseDemo(), 1024, 768, Utils.BACKGROUND_IMAGE);
	}

}