package org.khelekore.jsizer;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.KeyStroke;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;

/** An action that pops up a dialog that sets the SizeFilter */
class SetFilterAction extends AbstractAction {
    private static final long serialVersionUID = 1;
    private JFrame f;
    private SizePanel sp;
    
    public SetFilterAction (JFrame f, SizePanel sp) {
	super ("Set size filter...");
	this.f = f;
	this.sp = sp;
    }
    
    public void actionPerformed (ActionEvent e) {
	final JDialog d = new JDialog (f, "Set filter", true);
	GridBagLayout gb = new GridBagLayout ();
	GridBagConstraints c = new GridBagConstraints ();
	d.setLayout (gb);
	
	c.gridx = 0;
	c.gridy = 0;
	c.anchor = GridBagConstraints.NORTHWEST;
	JLabel l1 = new JLabel ("Minimum number of fields: ");
	d.add (l1, c);
	c.gridy++;
	JLabel l2 = new JLabel ("Minimum number of methods: ");
	d.add (l2, c);
	c.gridy++;
	JLabel l3 = new JLabel ("Minimum number of method lines: ");
	d.add (l3, c);
	
	int mf = 0;
	int mm = 0;
	int ml = 0;
	SizeFilter sf = sp.getSizeFilter ();
	if (sf != null) {
	    mf = sf.getMinFields ();
	    mm = sf.getMinMethods ();
	    ml = sf.getMinLines ();
	}
	
	c.weightx = 1;
	c.gridx = 1;
	c.gridy = 0;
	c.anchor = GridBagConstraints.NORTH;
	c.fill = GridBagConstraints.HORIZONTAL;
	SpinnerModel sm = new SpinnerNumberModel (mf, 0, Integer.MAX_VALUE, 1);
	final JSpinner s1 = new JSpinner (sm);
	d.add (s1, c);
	c.gridy++;
	sm = new SpinnerNumberModel (mm, 0, Integer.MAX_VALUE, 1);
	final JSpinner s2 = new JSpinner (sm);
	d.add (s2, c);
	c.gridy++;
	sm = new SpinnerNumberModel (ml, 0, Integer.MAX_VALUE, 5);
	final JSpinner s3 = new JSpinner (sm);
	d.add (s3, c);
	c.gridy++;
	    
	JButton ok = new JButton ("Set filter");
	ok.addActionListener (new ActionListener () {
		public void actionPerformed (ActionEvent e) {
		    setFilter (s1, s2, s3);
		    d.dispose ();
		}
	    });
	JButton clear = new JButton ("Clear filter");
	clear.addActionListener (new ActionListener () {
		public void actionPerformed (ActionEvent e) {
		    sp.setSizeFilter (null);
		    d.dispose ();
		}
	    });
	JButton suggest = new JButton ("Suggest filter");
	suggest.addActionListener (new ActionListener () {
		public void actionPerformed (ActionEvent e) {
		    suggestFilter (s1, s2, s3);
		}
	    });
	JButton cancel = new JButton ("Cancel");
	cancel.addActionListener (new ActionListener () {
		public void actionPerformed (ActionEvent e) {
		    d.dispose ();
		}
	    });
	addEscapeAsCancel (cancel);
	
	JPanel filler = new JPanel ();
	c.gridx = 0;
	c.weightx = 1;
	c.weighty = 1;
	c.gridwidth = 2;
	d.add (filler, c);
	c.gridy++;

	JPanel p = new JPanel ();
	p.add (cancel);
	p.add (suggest);
	p.add (clear);
	p.add (ok);
	c.fill = GridBagConstraints.NONE;
	c.anchor = GridBagConstraints.SOUTHEAST;
	d.add (p, c);

	d.validate ();
	d.pack ();
	d.setLocationRelativeTo (f);
	d.setVisible (true);
    }

    private void setFilter (JSpinner s1, JSpinner s2, JSpinner s3) {
	int mf = ((Number)s1.getValue ()).intValue ();
	int mm = ((Number)s2.getValue ()).intValue ();
	int ml = ((Number)s3.getValue ()).intValue ();
	SizeFilter sf = new SizeFilter (mf, mm, ml);
	sp.setSizeFilter (sf);
    }

    private void suggestFilter (JSpinner s1, JSpinner s2, JSpinner s3) {
	List<ClassSize> ls = sp.getClassSizes ();
	if (ls == null || ls.isEmpty ()) {
	    s1.setValue (0); 
	    s2.setValue (0); 
	    s3.setValue (0); 
	    return;
	}
	int[] is = new int[ls.size ()];
	for (int i = 0; i < ls.size (); i++)
	    is[i] = ls.get (i).getNumFields ();
	Arrays.sort (is);
	int value = is[Math.max (0, is.length - 100)];
	s1.setValue (value);

	for (int i = 0; i < ls.size (); i++)
	    is[i] = ls.get (i).getNumMethods ();
	Arrays.sort (is);
	value = is[Math.max (0, is.length - 100)];
	s2.setValue (value);

	for (int i = 0; i < ls.size (); i++)
	    is[i] = ls.get (i).getNumMethodLines ();
	Arrays.sort (is);
	value = is[Math.max (0, is.length - 100)];
	s3.setValue (value);
    }

    public static void addEscapeAsCancel (final JButton cancel) {
	cancel.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW).
	    put (KeyStroke.getKeyStroke (KeyEvent.VK_ESCAPE, 0), 
		 "abort");
	cancel.getActionMap ().put ("abort", new AbstractAction () {
		private static final long serialVersionUID = 1;
		public void actionPerformed (ActionEvent e) {
		    cancel.doClick ();
		}
	    });	
    }
}
