package tim.prune.function.edit;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;

import tim.prune.App;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.cmd.EditPointCmd;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
import tim.prune.data.Field;
import tim.prune.function.Describer;
import tim.prune.gui.GuiGridLayout;

/**
 * Function to manage the rounding of point coordinates
 */
public class TruncatePointCoords extends GenericFunction
{
	private JDialog _dialog = null;
	private DataPoint _point = null;
	private JComboBox<String> _coordFormatDropdown = null;
	private JSpinner _numDigitsField = null;
	private JTextField _previewField = null;


	/**
	 * Constructor
	 * @param inApp application object to inform of success
	 */
	public TruncatePointCoords(App inApp) {
		super(inApp);
	}

	/** Get the name key */
	public String getNameKey() {
		return "function.truncatecoords";
	}

	/**
	 * Begin the function by showing the dialog
	 */
	public void begin()
	{
		_point = _app.getTrackInfo().getCurrentPoint();
		if (_dialog == null)
		{
			_dialog = new JDialog(_parentFrame, getName(), true);
			_dialog.setLocationRelativeTo(_parentFrame);
			// Create Gui and show it
			_dialog.getContentPane().add(makeDialogComponents());
			_dialog.pack();
		}
		showPreview();
		_dialog.setVisible(true);
	}


	/**
	 * Make the dialog components
	 * @return the GUI components for the dialog
	 */
	private Component makeDialogComponents()
	{
		JPanel dialogPanel = new JPanel();
		dialogPanel.setLayout(new BorderLayout(0, 10));
		dialogPanel.add(new JLabel(I18nManager.getText("dialog.truncatecoords.intro")), BorderLayout.NORTH);
		JPanel mainPanel = new JPanel();
		GuiGridLayout grid = new GuiGridLayout(mainPanel);

		String[] coordFormats = {I18nManager.getText("units.degminsec"),
			I18nManager.getText("units.degmin"), I18nManager.getText("units.deg")};
		_coordFormatDropdown = new JComboBox<>(coordFormats);
		_coordFormatDropdown.setSelectedIndex(1); // Go for DD MM.MMM by default
		_numDigitsField = new JSpinner(new SpinnerNumberModel(3, 0, 10, 1));
		_numDigitsField.setValue(3);

		KeyAdapter keyListener = new KeyAdapter() {
			/** Key released */
			public void keyReleased(KeyEvent inE) {
				if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
					_dialog.dispose();
				}
			}
		};
		_coordFormatDropdown.addKeyListener(keyListener);
		_coordFormatDropdown.addActionListener(e -> showPreview());
		_numDigitsField.addChangeListener(e -> showPreview());

		// Coordinate format
		JLabel formatLabel = new JLabel(I18nManager.getText("details.coordformat"));
		formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		grid.add(formatLabel);
		grid.add(_coordFormatDropdown);

		// Num digits
		JLabel digitsLabel = new JLabel(I18nManager.getText("dialog.truncatecoords.numdigits"));
		digitsLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		grid.add(digitsLabel);
		grid.add(_numDigitsField);

		// Preview
		JLabel previewLabel = new JLabel(I18nManager.getText("dialog.truncatecoords.preview"));
		previewLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		grid.add(previewLabel);
		_previewField = new JTextField("", 26);
		_previewField.setEditable(false);
		grid.add(_previewField);
		dialogPanel.add(mainPanel, 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());
		buttonPanel.add(okButton);
		JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
		cancelButton.addActionListener(e -> _dialog.dispose());
		buttonPanel.add(cancelButton);
		dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
		dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
		return dialogPanel;
	}


	/**
	 * Update the preview with the current values
	 */
	private void showPreview()
	{
		String[] coordStrings = getTruncatedCoords();
		_previewField.setText(coordStrings[0] + ", " + coordStrings[1]);
	}

	/**
	 * @return the truncated latitude and longitude strings
	 */
	private String[] getTruncatedCoords()
	{
		Coordinate.Format[] formatIds = {Coordinate.Format.DEG_MIN_SEC,
			Coordinate.Format.DEG_MIN, Coordinate.Format.DECIMAL_FORCE_POINT};
		final Coordinate.Format selectedFormat = formatIds[_coordFormatDropdown.getSelectedIndex()];
		final int numDigits = ((SpinnerNumberModel) _numDigitsField.getModel()).getNumber().intValue();
		return new String[] {_point.getLatitude().output(selectedFormat, numDigits),
			_point.getLongitude().output(selectedFormat, numDigits)};
	}

	/**
	 * Confirm the edit and inform the app
	 */
	private void finish()
	{
		// Set latitude and longitude
		String[] coordStrings = getTruncatedCoords();
		List<FieldEdit> edits = List.of(new FieldEdit(Field.LATITUDE, coordStrings[0]),
			new FieldEdit(Field.LONGITUDE, coordStrings[1]));
		int pointIndex = _app.getTrackInfo().getSelection().getCurrentPointIndex();
		EditPointCmd command = new EditPointCmd(pointIndex, edits);
		Describer undoDescriber = new Describer("undo.editpoint", "undo.editpoint.withname");
		String pointName = _app.getTrackInfo().getCurrentPoint().getWaypointName();
		command.setDescription(undoDescriber.getDescriptionWithNameOrNot(pointName));
		command.setConfirmText(I18nManager.getText("confirm.point.edit"));
		_app.execute(command);
		_dialog.dispose();
	}
}
