/* 
-*- coding: latin-1 -*-

This file is part of RefactorErl.

RefactorErl is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

RefactorErl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with RefactorErl.  If not, see <http://plc.inf.elte.hu/erlang/>.

The Original Code is RefactorErl.

The Initial Developer of the Original Code is Eötvös Loránd University.
Portions created  by Eötvös Loránd University and ELTE-Soft Ltd.
are Copyright 2007-2025 Eötvös Loránd University, ELTE-Soft Ltd.
and Ericsson Hungary. All Rights Reserved.
*/

package com.refactorerl.ui.presentation.refactoring;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.SortedMap;
import java.util.logging.Logger;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.ui.handlers.HandlerUtil;

import com.refactorerl.ui.common.Pair;
import com.refactorerl.ui.communication.ReferlProxy;
import com.refactorerl.ui.communication.exceptions.ReferlException;
import com.refactorerl.ui.logic.filelist.FileListRequest;
import com.refactorerl.ui.logic.queries.QueryRequest;
import com.refactorerl.ui.logic.queries.QueryResultElement;
import com.refactorerl.ui.logic.refactoring.RefactoringRequest;
import com.refactorerl.ui.logic.refactoring.RefactoringRequestFactory;
import com.refactorerl.ui.presentation.Activator;

/**
 * This handler is responsible for executing refactorings. 	
 * It accepts the following command parameters:
 * {@code com.refactorerl.ui.refactorNameParameter}
 * {@code com.refactorerl.ui.refactorFilePathParameter}
 * {@code com.refactorerl.ui.refactorStartPosParameter}
 * {@code com.refactorerl.ui.refactorEndPosParameter}
 * 
 * The name and the file path is mandatory, the start and end positions are needed if the refactoring specified by the name needs it.
 * The names of the available refactorings are defined in the globally accessible RefactoringHandler.Refactoring enum.
 * 
 * The execution methods in this class do additional queries from the RefactorErl server and from the user.
 * 
 * @author Daniel Lukacs, 2014 ELTE IK
 *
 */
public class RefactoringHandler extends AbstractHandler {

	private static final String DEFAULT_DIALOG_MESSAGE = Messages.RefactoringHandler_0;

	static public enum Refactoring {
		RENAME_FUNCTION, RENAME_RECORD, RENAME_RECORD_FIELD, RENAME_MACRO, //
		RENAME_VARIABLE, RENAME_MODULE, RENAME_OVERLOADED_FUNCTIONS, //
		RENAME_UNUSED_VARIABLES, RENAME_HEADER, FUNAPP_TO_PROC, UPGRADE_REGEXP, //
		INLINE_FUNCTION, EXTRACT_FUNCTION, GENERALIZE_FUNCTION, TUPLE_FUNCTION_PARAMETERS, //
		REORDER_FUNCTION_PARAMETERS, ELIMINATE_VARIABLE, MERGE_EXPRESSION, //
		EXPAND_FUNCTION_EXPRESSION, TOGGLE_LIST_COMPREHENSION, INLINE_MACRO, //
		INTRODUCE_RECORD, INTRODUCE_IMPORT, ELIMINATE_IMPORT, MOVE_FUNCTION, //
		MOVE_MACRO, MOVE_RECORD
	}

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {

		IWorkbenchWindow wb = HandlerUtil.getActiveWorkbenchWindow(event);

		Refactoring name = Refactoring.valueOf(event.getParameter("com.refactorerl.ui.refactorNameParameter")); //$NON-NLS-1$
		String filePath = event.getParameter("com.refactorerl.ui.refactorFilePathParameter"); //$NON-NLS-1$
		String startPosStr = event.getParameter("com.refactorerl.ui.refactorStartPosParameter"); //$NON-NLS-1$
		String endPosStr = event.getParameter("com.refactorerl.ui.refactorEndPosParameter"); //$NON-NLS-1$

		int startPos = startPosStr != null ? Integer.parseInt(startPosStr) : 0;
		int endPos = endPosStr != null ? Integer.parseInt(endPosStr) : 0;

		Logger logger = null;
		ReferlProxy proxy = Activator.getProxy();

		try {
			switch (name) {
			case RENAME_FUNCTION: 
				executeRenameFunction(wb, filePath, startPos, logger, proxy);
				break;
			case RENAME_MACRO:
				executeRenameMacro(wb, filePath, startPos, logger, proxy);
				break;
			case RENAME_MODULE:
				executeRenameModule(wb, filePath, startPos, logger, proxy);
				break;
			case RENAME_OVERLOADED_FUNCTIONS:
				executeRenameOverloadedFunctions(wb, filePath, startPos, logger, proxy);
				break;
			case RENAME_HEADER:
				executeRenameHeader(wb, filePath, startPos, logger, proxy);
				break;
			case RENAME_RECORD:
				executeRenameRecord(wb, filePath, startPos, logger, proxy);
				break;
			case RENAME_RECORD_FIELD:
				executeRenameRecordField(wb, filePath, startPos, logger, proxy);
				break;
			case RENAME_VARIABLE:
				executeRenameVariable(wb, filePath, startPos, logger, proxy);
				break;
			case RENAME_UNUSED_VARIABLES:
				executeRenameUnusedVariables(wb, filePath, logger, proxy);
				break;
			case UPGRADE_REGEXP:
				executeUpgradeRegexp(wb, filePath, logger, proxy);
				break;
			case FUNAPP_TO_PROC:
				executeFunAppToProc(wb, filePath, startPos, logger, proxy);
				break;
			case INLINE_FUNCTION:
				executeInlineFunction(wb, filePath, startPos, logger, proxy);
				break;
			case EXTRACT_FUNCTION:
				executeExtractFunction(wb, filePath, startPos, endPos, logger, proxy);
				break;
			case ELIMINATE_IMPORT:
				executeEliminateImport(wb, filePath, startPos, logger, proxy);
				break;
			case TOGGLE_LIST_COMPREHENSION:
				executeToggleListComprehension(wb, filePath, startPos, endPos, logger, proxy);
				break;
			case ELIMINATE_VARIABLE:
				executeEliminateVariable(wb, filePath, startPos, logger, proxy);
				break;
			case EXPAND_FUNCTION_EXPRESSION:
				executeExpandFunctionExpression(wb, filePath, startPos, logger, proxy);
				break;
			case GENERALIZE_FUNCTION:
				executeGeneralizeFunction(wb, filePath, startPos, endPos, logger, proxy);
				break;
			case INLINE_MACRO:
				executeInlineMacro(wb, filePath, startPos, logger, proxy);
				break;
			case INTRODUCE_IMPORT:
				executeIntroduceImport(wb, filePath, startPos, logger, proxy);
				break;
			case INTRODUCE_RECORD:
				executeIntroduceRecord(wb, filePath, startPos, endPos, logger, proxy);
				break;
			case MERGE_EXPRESSION:
				executeMergeExpression(wb, filePath, startPos, endPos, logger, proxy);
				break;

			case REORDER_FUNCTION_PARAMETERS:
				executeReorderFunctionParameters(wb, filePath, startPos, logger, proxy);
				break;
			case TUPLE_FUNCTION_PARAMETERS:
				executeTupleFunctionParameters(wb, filePath, startPos, endPos, logger, proxy);
				break;
			case MOVE_FUNCTION:

				executeMoveFunction(wb, filePath, startPos, logger, proxy);
				break;
			case MOVE_MACRO:
				executeMoveMacro(wb, filePath, startPos, logger, proxy);
				break;
			case MOVE_RECORD:
				executeMoveRecord(wb, filePath, startPos, logger, proxy);
				break;
			default:
				MessageDialog.openInformation(wb.getShell(), Messages.RefactoringHandler_5,
						Messages.RefactoringHandler_6);

			}

		} catch (ReferlException e) {
			Activator.showErrorDialog(e, wb.getShell());
		}

		return null;
	}

	private String showInputDialog(IWorkbenchWindow wb, String dialogTitle, String dialogMessage, String defaultInput) {
		InputDialog dialog = new InputDialog(wb.getShell(), dialogTitle, dialogMessage, defaultInput, null);
		dialog.open();
		String newName = dialog.getValue();
		return newName;
	}

	private String showFileSelectionDialog(IWorkbenchWindow wb, Logger logger, ReferlProxy proxy, String title,
			String message) {
		ElementListSelectionDialog dialog = new ElementListSelectionDialog(wb.getShell(), new LabelProvider());

		dialog.setTitle(title);

		dialog.setMessage(message);

		List<String> files = Activator.executeRequest(new FileListRequest(proxy, logger), wb.getShell());
		if (files != null) {
			dialog.setElements(files.toArray());
			dialog.open();
			String targetFilePath = dialog.getFirstResult().toString();
			return targetFilePath;
		}
		return null;
	}

	private String queryName(String query, String filePath, int startPos, Logger logger, ReferlProxy proxy, IWorkbenchWindow wb)
			throws ReferlException {
		SortedMap<String, List<QueryResultElement>> queryResults = Activator.executeRequest(new QueryRequest(filePath, startPos, query, false,
				proxy, logger), wb.getShell());

		String name = queryResults.get(queryResults.firstKey()).get(0).getValue().replaceAll("^\"|\"$", ""); //$NON-NLS-1$ //$NON-NLS-2$
		return name;
	}

	private List<String> query(String query, String filePath, int startPos, Logger logger, ReferlProxy proxy, IWorkbenchWindow wb)
			throws ReferlException {
		SortedMap<String, List<QueryResultElement>> queryResults = Activator.executeRequest(new QueryRequest(filePath, startPos, query, false,
				proxy, logger), wb.getShell());

		List<String> results = new ArrayList<>();
		if (!queryResults.isEmpty())
			for (QueryResultElement el : queryResults.get(queryResults.firstKey())) {
				results.add(el.getValue());
			}
		return results;
	}

	private void executeRenameFunction(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String funFullName = queryName("@fun", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$
		String[] sp = funFullName.substring(funFullName.indexOf(":") + 1).split("/"); //$NON-NLS-1$ //$NON-NLS-2$

		String oldName = sp[0];
		int arity = Integer.parseInt(sp[1]);
		String newName = showInputDialog(wb, Messages.RefactoringHandler_12, DEFAULT_DIALOG_MESSAGE + oldName + "/" + arity, oldName); //$NON-NLS-2$
		if (newName == null || newName.isEmpty() || newName.equals(oldName))
			return;
		runRefactoringRequest(
				RefactoringRequestFactory.createRenameFunctionRequest(oldName, arity, newName, filePath, proxy, logger),
				Messages.RefactoringHandler_14, wb);
	}

	private void executeRenameMacro(IWorkbenchWindow wb, String filePath, int startPos, Logger logger, ReferlProxy proxy)
			throws ReferlException {

		String oldName = queryName("@macro", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$

		String newName = showInputDialog(wb, Messages.RefactoringHandler_16, DEFAULT_DIALOG_MESSAGE + oldName, oldName);
		if (newName == null || newName.isEmpty() || newName.equals(oldName))
			return;
		runRefactoringRequest(
				RefactoringRequestFactory.createRenameMacroRequest(oldName, newName, filePath, proxy, logger),
				Messages.RefactoringHandler_17, wb);
	}

	// NOTE structurally same as executeRenameQuery
	private void executeRenameRecord(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String oldName = queryName("@record", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$

		String newName = showInputDialog(wb, Messages.RefactoringHandler_19, DEFAULT_DIALOG_MESSAGE + oldName, oldName);
		if (newName == null || newName.isEmpty() || newName.equals(oldName))
			return;
		runRefactoringRequest(
				RefactoringRequestFactory.createRenameRecordRequest(oldName, newName, filePath, proxy, logger),
				Messages.RefactoringHandler_20, wb);
	}

	private void executeRenameRecordField(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String recordName = queryName("@record", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$
		String oldFieldName = queryName("@recfield", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$

		String newFieldName = showInputDialog(wb, Messages.RefactoringHandler_23, DEFAULT_DIALOG_MESSAGE + oldFieldName + Messages.RefactoringHandler_1
				+ recordName, oldFieldName);
		if (newFieldName == null || newFieldName.isEmpty() || newFieldName.equals(oldFieldName))
			return;
		runRefactoringRequest(RefactoringRequestFactory.createRenameRecordFieldRequest(recordName, oldFieldName,
				newFieldName, filePath, proxy, logger), Messages.RefactoringHandler_25, wb);
	}

	private void executeRenameVariable(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String oldName = queryName("@var", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$

		String newName = showInputDialog(wb, Messages.RefactoringHandler_27, DEFAULT_DIALOG_MESSAGE + oldName, oldName);
		if (newName == null || newName.isEmpty() || newName.equals(oldName))
			return;
		runRefactoringRequest(
				RefactoringRequestFactory.createRenameVariableRequest(startPos, newName, filePath, proxy, logger),
				Messages.RefactoringHandler_28, wb);
	}

	private void executeRenameUnusedVariables(IWorkbenchWindow wb, String filePath, Logger logger, ReferlProxy proxy)
			throws ReferlException {
		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_29, null,
				Messages.RefactoringHandler_30 + Messages.RefactoringHandler_31,
				MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_32, Messages.RefactoringHandler_33 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;
		runRefactoringRequest(RefactoringRequestFactory.createRenameUnusedVariablesRequest(filePath, proxy, logger),
				Messages.RefactoringHandler_34, wb);
	}

	private void executeRenameHeader(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String oldHeaderName = new Path(filePath).lastSegment();

		String newHeaderName = showInputDialog(wb, Messages.RefactoringHandler_35, DEFAULT_DIALOG_MESSAGE + oldHeaderName,
				oldHeaderName);
		if (newHeaderName == null || newHeaderName.isEmpty() || newHeaderName.equals(oldHeaderName))
			return;
		runRefactoringRequest(
				RefactoringRequestFactory.createRenameHeaderRequest(newHeaderName, filePath, proxy, logger),
				Messages.RefactoringHandler_36, wb);
	}

	private void executeRenameModule(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {
		String oldModuleName = new Path(filePath).removeFileExtension().lastSegment();

		String newModuleName = showInputDialog(wb, Messages.RefactoringHandler_37, DEFAULT_DIALOG_MESSAGE + oldModuleName,
				oldModuleName);
		if (newModuleName == null || newModuleName.isEmpty() || newModuleName.equals(oldModuleName))
			return;
		runRefactoringRequest(
				RefactoringRequestFactory.createRenameModuleRequest(newModuleName, filePath, proxy, logger),
				Messages.RefactoringHandler_38, wb);
	}

	private void executeRenameOverloadedFunctions(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String funFullName = queryName("@fun", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$
		String[] sp = funFullName.substring(funFullName.indexOf(":") + 1).split("/"); //$NON-NLS-1$ //$NON-NLS-2$

		String oldName = sp[0];

		String newName = showInputDialog(wb, Messages.RefactoringHandler_42, DEFAULT_DIALOG_MESSAGE
				+ Messages.RefactoringHandler_43 + oldName, oldName);
		if (newName == null || newName.isEmpty() || newName.equals(oldName))
			return;
		runRefactoringRequest(RefactoringRequestFactory.createRenameOverloadedFunctionsRequest(oldName, newName,
				filePath, proxy, logger), Messages.RefactoringHandler_44, wb);
	}

	private void executeFunAppToProc(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {
		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_45, null,
				Messages.RefactoringHandler_46 + Messages.RefactoringHandler_47,
				MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_48, Messages.RefactoringHandler_49 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;
		runRefactoringRequest(RefactoringRequestFactory.createFunAppToProceRequest(startPos, filePath, proxy, logger),
				Messages.RefactoringHandler_50, wb);
	}

	private void executeUpgradeRegexp(IWorkbenchWindow wb, String filePath, Logger logger, ReferlProxy proxy)
			throws ReferlException {
		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_51, null,
				Messages.RefactoringHandler_52
						+ Messages.RefactoringHandler_53 + Messages.RefactoringHandler_54, MessageDialog.QUESTION,
				new String[] { Messages.RefactoringHandler_55, Messages.RefactoringHandler_56 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;
		runRefactoringRequest(RefactoringRequestFactory.createUpgradeRegExpSyntaxRequest(filePath, proxy, logger),
				Messages.RefactoringHandler_57, wb);
	}

	private void executeInlineFunction(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {
		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_58, null,
				Messages.RefactoringHandler_59
						+ Messages.RefactoringHandler_60 + Messages.RefactoringHandler_61, MessageDialog.QUESTION,
				new String[] { Messages.RefactoringHandler_62, Messages.RefactoringHandler_63 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;
		runRefactoringRequest(RefactoringRequestFactory.createInlineFunctionRequest(startPos, filePath, proxy, logger),
				Messages.RefactoringHandler_64, wb);
	}

	private void executeExtractFunction(IWorkbenchWindow wb, String filePath, int startPos, int endPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {
		String newName = showInputDialog(wb, Messages.RefactoringHandler_65, Messages.RefactoringHandler_66,
				Messages.RefactoringHandler_67);
		if (newName == null || newName.isEmpty())
			return;
		runRefactoringRequest(RefactoringRequestFactory.createExtractFunctionRequest(startPos, endPos, newName,
				filePath, proxy, logger), Messages.RefactoringHandler_68, wb);
	}

	private void executeGeneralizeFunction(IWorkbenchWindow wb, String filePath, int startPos, int endPos,
			Logger logger, ReferlProxy proxy) throws ReferlException {
		String newName = showInputDialog(wb, Messages.RefactoringHandler_69, Messages.RefactoringHandler_70, Messages.RefactoringHandler_71);
		if (newName == null || newName.isEmpty())
			return;
		runRefactoringRequest(RefactoringRequestFactory.createGeneraliseFunctionRequest(startPos, endPos, newName,
				filePath, proxy, logger), Messages.RefactoringHandler_72, wb);
	}

	private void executeTupleFunctionParameters(IWorkbenchWindow wb, String filePath, int startPos, int endPos,
			Logger logger, ReferlProxy proxy) throws ReferlException {

		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_73, null,
				Messages.RefactoringHandler_74 + Messages.RefactoringHandler_75,
				MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_76, Messages.RefactoringHandler_77 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;
		runRefactoringRequest(RefactoringRequestFactory.createTupleFunctionParametersRequest(startPos, endPos,
				filePath, proxy, logger), Messages.RefactoringHandler_78, wb);
	}

	private void executeReorderFunctionParameters(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String funFullName = queryName("@fun", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$
		String[] sp = funFullName.substring(funFullName.indexOf(":") + 1).split("/"); //$NON-NLS-1$ //$NON-NLS-2$
		String funName = sp[0];
		int arity = Integer.parseInt(sp[1]);

		List<String> args = query("@clause.args", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$

		if (args.isEmpty())
			return;

		List<String> defs = new ArrayList<>();
		for (Integer i = 1; i <= arity; ++i) {
			defs.add(i.toString());
		}

		ListInputDialog dialog = new ListInputDialog(wb.getShell(), Messages.RefactoringHandler_83,
				Messages.RefactoringHandler_84 + funName + "/" + arity, args, defs); //$NON-NLS-2$
		dialog.open();
		dialog.create();

		List<String> newOrderStr = dialog.getValues();

		if (newOrderStr == null || newOrderStr.isEmpty() || newOrderStr.equals(defs))
			return;

		Integer[] newOrder = new Integer[newOrderStr.size()];
		int i = 0;
		for (String s : newOrderStr) {
			newOrder[i] = Integer.parseInt(s);
			++i;
		}
		runRefactoringRequest(RefactoringRequestFactory.createReorderFunctionParametersRequest(funName, arity,
				newOrder, filePath, proxy, logger), Messages.RefactoringHandler_86, wb);
	}

	private void executeEliminateVariable(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String varName = queryName("@var", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$

		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_88, null, Messages.RefactoringHandler_89 + varName
				+ Messages.RefactoringHandler_90, MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_91, Messages.RefactoringHandler_92 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;
		runRefactoringRequest(
				RefactoringRequestFactory.createEliminateVariableRequest(startPos, filePath, proxy, logger),
				Messages.RefactoringHandler_93, wb);
	}

	private void executeMergeExpression(IWorkbenchWindow wb, String filePath, int startPos, int endPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String newName = showInputDialog(wb, Messages.RefactoringHandler_94,
				Messages.RefactoringHandler_95 + Messages.RefactoringHandler_96, Messages.RefactoringHandler_97);
		if (newName == null || newName.isEmpty())
			return;
		runRefactoringRequest(RefactoringRequestFactory.createMergeExpressionsRequest(startPos, endPos, newName,
				filePath, proxy, logger), Messages.RefactoringHandler_98, wb);
	}

	private void executeExpandFunctionExpression(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_99, null,
				Messages.RefactoringHandler_100 + Messages.RefactoringHandler_101,
				MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_102, Messages.RefactoringHandler_103 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;
		runRefactoringRequest(
				RefactoringRequestFactory.createExpandFunctionExpressionRequest(startPos, filePath, proxy, logger),
				Messages.RefactoringHandler_104, wb);
	}

	private void executeToggleListComprehension(IWorkbenchWindow wb, String filePath, int startPos, int endPos,
			Logger logger, ReferlProxy proxy) throws ReferlException {

		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_105, null,
				Messages.RefactoringHandler_106
						+ Messages.RefactoringHandler_107 + Messages.RefactoringHandler_108,
				MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_109, Messages.RefactoringHandler_110 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;
		runRefactoringRequest(RefactoringRequestFactory.createToggleListComprehensionRequest(startPos, endPos,
				filePath, proxy, logger), Messages.RefactoringHandler_111, wb);
	}

	private void executeInlineMacro(IWorkbenchWindow wb, String filePath, int startPos, Logger logger, ReferlProxy proxy)
			throws ReferlException {

		String macroName = queryName("@macro", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$

		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_113, null, Messages.RefactoringHandler_114 + macroName
				+ Messages.RefactoringHandler_115, MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_116, Messages.RefactoringHandler_117 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;

		runRefactoringRequest(RefactoringRequestFactory.createInlineMacroRequest(startPos, filePath, proxy, logger),
				Messages.RefactoringHandler_118, wb);
	}

	private void executeIntroduceRecord(IWorkbenchWindow wb, String filePath, int startPos, int endPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		List<String> labels = Arrays.asList(Messages.RefactoringHandler_119, Messages.RefactoringHandler_120);
		List<String> defaults = Arrays.asList("new_record", "a b c"); //$NON-NLS-1$ //$NON-NLS-2$

		ListInputDialog dialog = new ListInputDialog(wb.getShell(), Messages.RefactoringHandler_123,
				Messages.RefactoringHandler_124 + Messages.RefactoringHandler_125,
				labels, defaults);
		dialog.open();
		dialog.create();

		List<String> values = dialog.getValues();

		if (values == null || values.isEmpty())
			return;

		String recordName = values.get(0);

		if (recordName.isEmpty())
			return;

		String[] fieldNames = values.get(1).split(" "); //$NON-NLS-1$

		runRefactoringRequest(RefactoringRequestFactory.createIntroduceRecordRequest(startPos, endPos, recordName,
				fieldNames, filePath, proxy, logger), Messages.RefactoringHandler_127, wb);
	}

	private void executeIntroduceImport(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String moduleName = queryName("@fun.mod", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$

		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_129, null,
				Messages.RefactoringHandler_130 + moduleName + Messages.RefactoringHandler_131,
				MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_132, Messages.RefactoringHandler_133 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;

		runRefactoringRequest(
				RefactoringRequestFactory.createIntroduceImportRequest(moduleName, filePath, proxy, logger),
				Messages.RefactoringHandler_134, wb);
	}

	private void executeEliminateImport(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		MessageDialog dialog = new MessageDialog(null, Messages.RefactoringHandler_135, null,
				Messages.RefactoringHandler_136
						+ Messages.RefactoringHandler_137 + Messages.RefactoringHandler_138,
				MessageDialog.QUESTION, new String[] { Messages.RefactoringHandler_139, Messages.RefactoringHandler_140 }, 1);
		int result = dialog.open();
		if (result == 1)
			return;

		runRefactoringRequest(
				RefactoringRequestFactory.createEliminateImportRequest(startPos, filePath, proxy, logger),
				Messages.RefactoringHandler_141, wb);
	}

	private void executeMoveFunction(IWorkbenchWindow wb, String filePath, int startPos, Logger logger,
			ReferlProxy proxy) throws ReferlException {

		String funFullName = queryName("@fun", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$
		String[] sp = funFullName.substring(funFullName.indexOf(":") + 1).split("/"); //$NON-NLS-1$ //$NON-NLS-2$

		String funName = sp[0];
		int arity = Integer.parseInt(sp[1]);

		List<Pair<String, Integer>> funArityPairList = new ArrayList<Pair<String, Integer>>();
		funArityPairList.add(new Pair<String, Integer>(funName, arity));

		String message = Messages.RefactoringHandler_145 + funName + "/" + arity + "'"; //$NON-NLS-2$ //$NON-NLS-3$
		String targetFilePath = showFileSelectionDialog(wb, logger, proxy, Messages.RefactoringHandler_148, message);

		runRefactoringRequest(RefactoringRequestFactory.createMoveFunctionRequest(targetFilePath, funArityPairList,
				filePath, proxy, logger), Messages.RefactoringHandler_149, wb);
	}

	private void executeMoveMacro(IWorkbenchWindow wb, String filePath, int startPos, Logger logger, ReferlProxy proxy)
			throws ReferlException {

		String macroName = queryName("@macro", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$
		String message = Messages.RefactoringHandler_151 + macroName + "'"; //$NON-NLS-2$

		String targetFilePath = showFileSelectionDialog(wb, logger, proxy, Messages.RefactoringHandler_153, message);

		List<String> macroList = new ArrayList<String>();
		macroList.add(macroName);

		runRefactoringRequest(
				RefactoringRequestFactory.createMoveMacroRequest(targetFilePath, macroList, filePath, proxy, logger),
				Messages.RefactoringHandler_154, wb);
	}

	private void executeMoveRecord(IWorkbenchWindow wb, String filePath, int startPos, Logger logger, ReferlProxy proxy)
			throws ReferlException {

		String recordName = queryName("@record", filePath, startPos, logger, proxy, wb); //$NON-NLS-1$
		String message = Messages.RefactoringHandler_156 + recordName + "'"; //$NON-NLS-2$

		String targetFilePath = showFileSelectionDialog(wb, logger, proxy, Messages.RefactoringHandler_158, message);

		List<String> recordList = new ArrayList<String>();
		recordList.add(recordName);

		runRefactoringRequest(
				RefactoringRequestFactory.createMoveRecordRequest(targetFilePath, recordList, filePath, proxy, logger),
				Messages.RefactoringHandler_159, wb);

	}

	/** This is here in case the Activator interface changes */
	private void runRefactoringRequest(RefactoringRequest req, String name, IWorkbenchWindow wb) {
		Activator.executeRequest(req, wb.getShell());
	}

}
