package net.azib.ipscan.gui;

import net.azib.ipscan.config.Labels;
import net.azib.ipscan.config.OpenersConfig;
import net.azib.ipscan.fetchers.FetcherRegistry;
import net.azib.ipscan.gui.util.LayoutHelper;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.*;

import java.io.File;

import static net.azib.ipscan.gui.util.LayoutHelper.formData;
import static net.azib.ipscan.gui.util.LayoutHelper.iconFont;

public class EditOpenersDialog extends AbstractModalDialog {
	private final FetcherRegistry fetcherRegistry;
	private final OpenersConfig openersConfig;

	private List openersList;
	private Group editFieldsGroup;
	private Text openerNameText;
	private Text openerStringText;
	private Text workingDirText;
	private Button isInTerminalCheckbox;
	private int currentSelectionIndex;
	
	public EditOpenersDialog(FetcherRegistry fetcherRegistry, OpenersConfig openersConfig) {
		this.fetcherRegistry = fetcherRegistry;
		this.openersConfig = openersConfig;
	}

	@Override
	protected void populateShell() {
		var currentDisplay = Display.getCurrent();
		var parent = currentDisplay != null ? currentDisplay.getActiveShell() : null;
		shell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);

		shell.setText(Labels.getLabel("title.openers.edit"));
		shell.setLayout(LayoutHelper.formLayout(10, 10, 4));

		var messageLabel = new Label(shell, SWT.NONE);
		messageLabel.setText(Labels.getLabel("text.openers.edit"));
		
		openersList = new List(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL);
		editFieldsGroup = new Group(shell, SWT.NONE);

		openersList.setLayoutData(formData(140, 200, null, null, new FormAttachment(messageLabel, 10), new FormAttachment(editFieldsGroup, 0, SWT.BOTTOM)));
		for (var name : openersConfig) {
			openersList.add(name);
		}
		openersList.addListener(SWT.Selection, new ItemSelectListener());

		var iconFont = iconFont(shell);

		var upButton = new Button(shell, SWT.NONE);
		upButton.setText(Labels.getLabel("button.up"));
		upButton.setToolTipText(Labels.getLabel("button.up.hint"));
		upButton.setFont(iconFont);
		upButton.addListener(SWT.Selection, new UpButtonListener(openersList) {
			@Override public void handleEvent(Event event) {
				super.handleEvent(event);
				currentSelectionIndex = openersList.getSelectionIndex();
			}
		});

		var downButton = new Button(shell, SWT.NONE);
		downButton.setText(Labels.getLabel("button.down"));
		downButton.setToolTipText(Labels.getLabel("button.down.hint"));
		downButton.setFont(iconFont);
		downButton.addListener(SWT.Selection, new DownButtonListener(openersList) {
			@Override public void handleEvent(Event event) {
				super.handleEvent(event);
				currentSelectionIndex = openersList.getSelectionIndex();
			}
		});

		var addButton = new Button(shell, SWT.NONE);
		addButton.setText(Labels.getLabel("button.add"));
		addButton.addListener(SWT.Selection, new AddButtonListener());

		var deleteButton = new Button(shell, SWT.NONE);
		deleteButton.setText(Labels.getLabel("button.delete"));
		deleteButton.addListener(SWT.Selection, new DeleteButtonListener());

		upButton.setLayoutData(formData(new FormAttachment(openersList), null, new FormAttachment(messageLabel, 10), null));
		downButton.setLayoutData(formData(new FormAttachment(openersList), null, new FormAttachment(upButton), null));
		addButton.setLayoutData(formData(new FormAttachment(openersList), new FormAttachment(deleteButton, 0, SWT.RIGHT), new FormAttachment(downButton, 16), null));
		deleteButton.setLayoutData(formData(new FormAttachment(openersList), null, new FormAttachment(addButton), null));
						
		editFieldsGroup.setLayoutData(formData(new FormAttachment(deleteButton, 10), null, new FormAttachment(messageLabel, 10), null));
		var rowLayout = new RowLayout(SWT.VERTICAL);
		rowLayout.fill = true;
		rowLayout.justify = true; 
		rowLayout.marginTop = 5;
		rowLayout.marginBottom = 20;
		rowLayout.marginWidth = 5;
		editFieldsGroup.setLayout(rowLayout);

		var openerNameLabel = new Label(editFieldsGroup, SWT.NONE);
		openerNameLabel.setText(Labels.getLabel("text.openers.name"));
		openerNameLabel.setSize(SWT.DEFAULT, 18);
		openerNameText = new Text(editFieldsGroup, SWT.BORDER);
		openerNameText.setSize(SWT.DEFAULT, 22);
		openerNameText.addListener(SWT.KeyUp, new OpenerNameChange());

		isInTerminalCheckbox = new Button(editFieldsGroup, SWT.CHECK);
		isInTerminalCheckbox.setText(Labels.getLabel("text.openers.inTerminal"));
		isInTerminalCheckbox.setSize(SWT.DEFAULT, 18);

		var openerStringLabel = new Label(editFieldsGroup, SWT.NONE);
		openerStringLabel.setText(Labels.getLabel("text.openers.string"));
		openerStringLabel.setSize(SWT.DEFAULT, 18);
		openerStringText = new Text(editFieldsGroup, SWT.BORDER);
		openerStringText.setSize(SWT.DEFAULT, 22);

		var hintButton = new Button(editFieldsGroup, SWT.NONE);
		hintButton.setText(Labels.getLabel("text.openers.hint"));
		hintButton.addListener(SWT.Selection, new HintButtonListener());

		var openerDirLabel = new Label(editFieldsGroup, SWT.NONE);
		openerDirLabel.setText(Labels.getLabel("text.openers.directory"));
		openerDirLabel.setSize(SWT.DEFAULT, 18);
		workingDirText = new Text(editFieldsGroup, SWT.BORDER);
		workingDirText.setSize(SWT.DEFAULT, 22);
				
		editFieldsGroup.pack();

		var okButton = new Button(shell, SWT.NONE);
		okButton.setText(Labels.getLabel("button.OK"));

		var cancelButton = new Button(shell, SWT.NONE);
		cancelButton.setText(Labels.getLabel("button.cancel"));

		positionButtonsInFormLayout(okButton, cancelButton, editFieldsGroup);

		shell.pack();

		okButton.addListener(SWT.Selection, e -> {
			saveOpeners();
			close();
		});
		cancelButton.addListener(SWT.Selection, e -> close());

		openersList.select(0);
		loadFieldsForSelection();
	}
	
	private void saveOpeners() {
		// save any possible changes in text boxes
		saveCurrentFields();			

		// now save everything else (order, etc)
		openersConfig.update(openersList.getItems());
		openersConfig.store();
	}

	private void saveCurrentFields() {
		if (currentSelectionIndex < 0) return;

		var openerName = openerNameText.getText();
		var workingDir = workingDirText.getText().length() > 0 ? new File(workingDirText.getText()) : null;
		openersConfig.add(openerName, new OpenersConfig.Opener(openerStringText.getText(), isInTerminalCheckbox.getSelection(), workingDir));
		openersList.setItem(currentSelectionIndex, openerName);
	}
	
	private void loadFieldsForSelection() {
		currentSelectionIndex = openersList.getSelectionIndex();
		if (currentSelectionIndex < 0) return;

		var openerName = openersList.getItem(currentSelectionIndex);
		editFieldsGroup.setText(openerName);
		var opener = openersConfig.getOpener(openerName);
		openerNameText.setText(openerName);
		openerStringText.setText(opener.execString);
		workingDirText.setText(opener.workingDir != null ? opener.workingDir.toString() : "");
		isInTerminalCheckbox.setSelection(opener.inTerminal);
	}

	class HintButtonListener implements Listener {
		public void handleEvent(Event event) {
			// compose the message with all available fetchers
			var message = new StringBuilder(Labels.getLabel("text.openers.hintText"));
			for (var fetcher : fetcherRegistry.getSelectedFetchers()) {
				message.append("${").append(fetcher.getId()).append("}   - ").append(fetcher.getName()).append('\n');
			}

			var mb = new MessageBox(shell, SWT.ICON_INFORMATION | SWT.OK);
			mb.setText(Labels.getLabel("title.openers.edit"));
			mb.setMessage(message.toString());
			mb.open();
		}
	}
	
	class DeleteButtonListener implements Listener {
		public void handleEvent(Event event) {
			var oldIndex = openersList.getSelectionIndex();
			openersList.remove(openersList.getSelectionIndices());
			if (oldIndex >= openersList.getItemCount()) oldIndex = openersList.getItemCount()-1;
			openersList.setSelection(oldIndex);
			loadFieldsForSelection();
		}
	}

	class AddButtonListener implements Listener {
		public void handleEvent(Event event) {
			saveCurrentFields();

			currentSelectionIndex = openersList.getSelectionIndex();
			if (currentSelectionIndex < 0) {
				currentSelectionIndex = openersList.getItemCount();
			}
			var newName = Labels.getLabel("text.openers.new");
			openersList.add(newName, currentSelectionIndex);
			openersList.setSelection(currentSelectionIndex);

			// reset fields
			editFieldsGroup.setText(newName);
			openerNameText.setText(newName);
			openerStringText.setText("${fetcher.ip}");
			workingDirText.setText("");
			isInTerminalCheckbox.setSelection(false);

			openerNameText.forceFocus();
			openerNameText.setSelection(0, newName.length());
		}
	}

	class ItemSelectListener implements Listener {
		public void handleEvent(Event event) {
			if (openersList.getSelectionCount() == 0)
				return;

			saveCurrentFields();
			loadFieldsForSelection();
		}
	}
	
	class OpenerNameChange implements Listener {
		public void handleEvent(Event event) {
			if (currentSelectionIndex < 0) return;
			var name = openerNameText.getText();
			editFieldsGroup.setText(name);
			openersList.setItem(currentSelectionIndex, name);
		}
	}
}
