package tim.prune.function;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

import tim.prune.App;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.cmd.PointReference;
import tim.prune.data.SortMode;

/**
 * Abstract superclass for the functions which rearrange points,
 * such as waypoints or photo points
 */
public abstract class RearrangeFunction extends GenericFunction
{
	/** Function dialog */
	private JDialog _dialog = null;
	/** Radio buttons for start/end/nearest */
	private JRadioButton[] _positionRadios = null;
	/** Radio buttons for sorting */
	private JRadioButton[] _sortRadios = null;
	/** Is the "nearest" option available? */
	private final boolean _nearestAvailable;


	/** Enumeration for rearrange commands */
	protected enum Rearrange
	{
		/** Rearrange all waypoints to start */
		TO_START,
		/** Rearrange all waypoints to end */
		TO_END,
		/** Rearrange each waypoint to nearest track point */
		TO_NEAREST
	}


	/**
	 * Constructor
	 * @param inApp app object
	 * @param isNearestAvailable true if nearest option is visible
	 */
	public RearrangeFunction(App inApp, boolean isNearestAvailable)
	{
		super(inApp);
		_nearestAvailable = isNearestAvailable;
	}

	/**
	 * Begin the function by showing the dialog
	 */
	public void begin()
	{
		// Make dialog window
		if (_dialog == null)
		{
			_dialog = new JDialog(_parentFrame, getName(), true);
			_dialog.setLocationRelativeTo(_parentFrame);
			_dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			_dialog.getContentPane().add(makeDialogComponents());
			_dialog.pack();
		}
		// If sorting by time isn't available, then disable radio button
		_sortRadios[2].setEnabled(isSortByTimeAllowed());
		// Show dialog
		_dialog.setVisible(true);
	}


	/**
	 * Create dialog components
	 * @return Panel containing all gui elements in dialog
	 */
	private JPanel makeDialogComponents()
	{
		JPanel dialogPanel = new JPanel();
		dialogPanel.setLayout(new BorderLayout());
		JLabel descLabel = new JLabel(I18nManager.getText(getDescriptionKey()));
		descLabel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
		dialogPanel.add(descLabel, BorderLayout.NORTH);
		// Radios for position (start / end / nearest)
		_positionRadios = new JRadioButton[3];
		final String[] posNames = {"tostart", "toend", "tonearest"};
		ButtonGroup posGroup = new ButtonGroup();
		JPanel posPanel = new JPanel();
		posPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
		for (int i=0; i<posNames.length; i++)
		{
			_positionRadios[i] = new JRadioButton(I18nManager.getText("dialog.rearrange." + posNames[i]));
			posGroup.add(_positionRadios[i]);
			posPanel.add(_positionRadios[i]);
		}
		_positionRadios[0].setSelected(true);
		_positionRadios[2].setVisible(_nearestAvailable);

		// Radios for sort (none / filename / time)
		_sortRadios = new JRadioButton[3];
		final String[] sortNames = {"nosort", getSortNameKey(), "sortbytime"};
		ButtonGroup sortGroup = new ButtonGroup();
		JPanel sortPanel = new JPanel();
		sortPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
		for (int i=0; i<3; i++)
		{
			_sortRadios[i] = new JRadioButton(I18nManager.getText("dialog.rearrange." + sortNames[i]));
			sortGroup.add(_sortRadios[i]);
			sortPanel.add(_sortRadios[i]);
		}
		_sortRadios[0].setSelected(true);
		// Use listener to disable all sort options if nearest type chosen, re-enable otherwise
		ActionListener rearrListener = e -> {
			final boolean sortAvailable = !_positionRadios[2].isSelected();
			for (JRadioButton sortRadio : _sortRadios) {
				sortRadio.setEnabled(sortAvailable);
			}
		};
		for (JRadioButton positionRadio : _positionRadios) {
			positionRadio.addActionListener(rearrListener);
		}
		// add to middle of dialog
		JPanel centrePanel = new JPanel();
		centrePanel.setLayout(new BoxLayout(centrePanel, BoxLayout.Y_AXIS));
		centrePanel.add(posPanel);
		centrePanel.add(sortPanel);
		dialogPanel.add(centrePanel, BorderLayout.CENTER);
		// button panel at bottom
		JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
		JButton okButton = new JButton(I18nManager.getText("button.ok"));
		okButton.addActionListener(e -> {
			finish();
			_dialog.dispose();
		});
		buttonPanel.add(okButton);
		JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
		cancelButton.addActionListener(e -> _dialog.dispose());
		buttonPanel.add(cancelButton);
		dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
		return dialogPanel;
	}

	/**
	 * @return true if sorting by time is allowed, false otherwise
	 */
	protected boolean isSortByTimeAllowed() {
		return true;
	}

	/**
	 * @return the selected rearrange option
	 */
	protected Rearrange getRearrangeOption()
	{
		if (_positionRadios[0].isSelected()) {
			return Rearrange.TO_START;
		}
		if (_positionRadios[1].isSelected()) {
			return Rearrange.TO_END;
		}
		return Rearrange.TO_NEAREST;
	}

	/**
	 * @return the selected sort mode
	 */
	protected SortMode getSortMode()
	{
		if (_sortRadios[0].isSelected()) {
			return SortMode.DONT_SORT;
		}
		if (_sortRadios[1].isSelected()) {
			return SortMode.SORTBY_NAME;
		}
		return SortMode.SORTBY_TIME;
	}

	/** @return key for description */
	protected abstract String getDescriptionKey();

	/** @return partial key for the sort by name radio */
	protected abstract String getSortNameKey();

	/**
	 * Perform the rearrange
	 */
	protected abstract void finish();

	/**
	 * Verify a rearrange result and see if it does anything or not
	 * @return true if the operation has no effect
	 */
	protected static boolean isResultANop(List<PointReference> result)
	{
		// Compare all indices with their original ones
		for (int i=0; i<result.size(); i++)
		{
			if (result.get(i).getIndex() != i) {
				return false;
			}
		}
		// Must be all the same
		return true;
	}
}
