/* 
-*- 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.logic.refactoring;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangBoolean;
import com.ericsson.otp.erlang.OtpErlangInt;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.refactorerl.ui.common.OtpErlangHelper;
import com.refactorerl.ui.common.Pair;
import com.refactorerl.ui.communication.ReferlProxy;

/**
 * This class holds all the factory methods to construct specific requests for refactorings.
 * 
 * @author Daniel Lukacs, 2014 ELTE IK
 *
 */
public class RefactoringRequestFactory {

	static public RefactoringRequest createEliminateDupcodeRequest(String cloneName, int groupIdx, String functionName, ReferlProxy proxy, Logger logger) {
		Map<String, OtpErlangObject> map = createPropertyMap();
		map.put("clone_name", new OtpErlangAtom(cloneName));
		map.put("group", new OtpErlangInt(groupIdx));
		map.put("name", new OtpErlangAtom(functionName));
		
		return new RefactoringRequest(proxy, logger, "dupcode", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));	
	}
	
	static public RefactoringRequest createRenameFunctionRequest(
			String oldName, int arity, String newName, String filePath,
			ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		map.put("function", new OtpErlangAtom(oldName)); //$NON-NLS-1$
		map.put("arity", new OtpErlangInt(arity)); //$NON-NLS-1$
		map.put("name", new OtpErlangAtom(newName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "rename_fun", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createRenameMacroRequest(String oldName,
			String newName, String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		map.put("macro", new OtpErlangString(oldName)); //$NON-NLS-1$
		map.put("macname", new OtpErlangString(newName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "rename_mac", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	static public RefactoringRequest createRenameRecordRequest(String oldName,
			String newName, String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		map.put("record", new OtpErlangAtom(oldName)); //$NON-NLS-1$
		map.put("name", new OtpErlangAtom(newName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "rename_rec", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	static public RefactoringRequest createRenameRecordFieldRequest(
			String recordName, String oldFieldName, String newFieldName,
			String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		map.put("record", new OtpErlangAtom(recordName)); //$NON-NLS-1$
		map.put("recfield", new OtpErlangAtom(oldFieldName)); //$NON-NLS-1$
		map.put("name", new OtpErlangAtom(newFieldName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "rename_recfield", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createRenameModuleRequest(
			String newModuleName, String filePath, ReferlProxy proxy,
			Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		map.put("name", new OtpErlangAtom(newModuleName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "rename_mod", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	static public RefactoringRequest createRenameHeaderRequest(
			String newHeaderName, String filePath, ReferlProxy proxy,
			Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);
		map.put("filename", new OtpErlangString(newHeaderName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "rename_header", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createRenameUnusedVariablesRequest(
			String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		return new RefactoringRequest(proxy, logger, "rename_unused_vars", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	static public RefactoringRequest createRenameOverloadedFunctionsRequest(
			String oldName, String newName, String filePath, ReferlProxy proxy,
			Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);
		map.put("funname", new OtpErlangAtom(oldName)); //$NON-NLS-1$
		map.put("name", new OtpErlangAtom(newName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "rename_overloaded_funs", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	static public RefactoringRequest createUpgradeRegExpSyntaxRequest(
			String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		return new RefactoringRequest(proxy, logger, "upgrade_regexp", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	static public RefactoringRequest createFunAppToProceRequest(int position, String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath, position);
		
		return new RefactoringRequest(proxy, logger, "funapp_to_proc", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}
	
	static public RefactoringRequest createRenameVariableRequest(int position,
			String newName, String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath, position);

		map.put("varname", new OtpErlangString(newName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "rename_var", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	static public RefactoringRequest createInlineFunctionRequest(int position,
			String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath, position);

		return new RefactoringRequest(proxy, logger, "inline_fun", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	static public RefactoringRequest createExtractFunctionRequest(int startPos,
			int endPos, String newName, String filePath, ReferlProxy proxy,
			Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath,
				startPos, endPos);
		map.put("name", new OtpErlangString(newName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "extract_fun", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}

	// introduce parameter
	static public RefactoringRequest createGeneraliseFunctionRequest(
			int startPos, int endPos, String varName, String filePath,
			ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath,
				startPos, endPos);
		map.put("varname", new OtpErlangString(varName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "gen", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createTupleFunctionParametersRequest(
			int startPos, int endPos, String filePath, ReferlProxy proxy,
			Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath,
				startPos, endPos);

		return new RefactoringRequest(proxy, logger, "tuple_funpar", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createReorderFunctionParametersRequest(
			String funName, int arity, Integer[] newOrder, String filePath,
			ReferlProxy proxy, Logger logger) {

		if (newOrder.length != arity)
			throw new IllegalArgumentException(
					Messages.RefactoringRequestFactory_32);

		OtpErlangObject[] newOrderOtp = new OtpErlangObject[newOrder.length];
		for (int i = 0; i < newOrder.length; ++i) {
			newOrderOtp[i] = new OtpErlangInt(newOrder[i]);
		}
		
		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		map.put("function", new OtpErlangAtom(funName)); //$NON-NLS-1$
		map.put("arity", new OtpErlangInt(arity)); //$NON-NLS-1$
		map.put("order", new OtpErlangList(newOrderOtp)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "reorder_funpar", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createEliminateVariableRequest(
			int position, String filePath, ReferlProxy proxy, Logger logger) {
		Map<String, OtpErlangObject> map = createPropertyMap(filePath, position);

		return new RefactoringRequest(proxy, logger, "elim_var", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	// introduce variable
	static public RefactoringRequest createMergeExpressionsRequest(int startPos,
			int endPos, String varName, String filePath, ReferlProxy proxy,
			Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath,
				startPos, endPos);
		map.put("varname", new OtpErlangString(varName)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "merge", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createExpandFunctionExpressionRequest(
			int position, String filePath, ReferlProxy proxy, Logger logger) {
		Map<String, OtpErlangObject> map = createPropertyMap(filePath, position);

		return new RefactoringRequest(proxy, logger, "expand_funexpr", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createToggleListComprehensionRequest(
			int startPos, int endPos, String filePath, ReferlProxy proxy,
			Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath,
				startPos, endPos);

		return new RefactoringRequest(proxy, logger, "list_comp", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createInlineMacroRequest(int position,
			String filePath, ReferlProxy proxy, Logger logger) {
		Map<String, OtpErlangObject> map = createPropertyMap(filePath, position);

		return new RefactoringRequest(proxy, logger, "inline_mac", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createIntroduceRecordRequest(int startPos,
			int endPos, String recordName, String[] fieldNames,
			String filePath, ReferlProxy proxy, Logger logger) {

		String fieldNamesStr = ""; //$NON-NLS-1$
		if (fieldNames.length > 0) {
			StringBuilder sb = new StringBuilder(fieldNamesStr);
			sb.append(fieldNames[0]);
			for (int i = 1; i < fieldNames.length; ++i) {
				sb.append(" " + fieldNames[i]); //$NON-NLS-1$
			}
			
			fieldNamesStr = sb.toString();
		}

		Map<String, OtpErlangObject> map = createPropertyMap(filePath,
				startPos, endPos);
		map.put("name", new OtpErlangAtom(recordName)); //$NON-NLS-1$
		map.put("text", new OtpErlangString(fieldNamesStr)); //$NON-NLS-1$
		return new RefactoringRequest(proxy, logger, "introduce_rec", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}

	static public RefactoringRequest createIntroduceImportRequest(
			String moduleName, String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);
		map.put("module", new OtpErlangAtom(moduleName)); // replaces the old value //$NON-NLS-1$
		
		return new RefactoringRequest(proxy, logger, "introduce_import", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));

	}
	
	static public RefactoringRequest createEliminateImportRequest(int position,
			String filePath, ReferlProxy proxy, Logger logger) {
		Map<String, OtpErlangObject> map = createPropertyMap(filePath, position);

		return new RefactoringRequest(proxy, logger, "eliminate_import", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}
	
	static public RefactoringRequest createMoveFunctionRequest(String targetFilePath,
			List<Pair<String, Integer>> functionArityList, String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		String moduleName = filePathToModuleName(targetFilePath);
		Map<String, OtpErlangObject> functionArityMap = new HashMap<>();
		for (Pair<String, Integer> pair : functionArityList) {
			functionArityMap.put(pair.key, new OtpErlangInt(pair.value));
		}
		OtpErlangList functionArityPropList = OtpErlangHelper.createPropList(functionArityMap);
		map.put("name", new OtpErlangString(moduleName)); //$NON-NLS-1$
		map.put("funlist", functionArityPropList	); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "move_fun", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}
	
	static public RefactoringRequest createMoveMacroRequest(String targetFilePath,
			List<String> macroList, String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		OtpErlangObject[] macroListOtp = new OtpErlangObject[macroList.size()];
		int i = 0;
		for (String string : macroList) {
			macroListOtp[i] = new OtpErlangString(string);
			++i;
		}
		
		map.put("filename", new OtpErlangString(targetFilePath)); //$NON-NLS-1$
		map.put("maclist", new OtpErlangList(macroListOtp)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "move_mac", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}
	
	static public RefactoringRequest createMoveRecordRequest(String targetFilePath,
			List<String> recordList, String filePath, ReferlProxy proxy, Logger logger) {

		Map<String, OtpErlangObject> map = createPropertyMap(filePath);

		OtpErlangObject[] recordListOtp = new OtpErlangObject[recordList.size()];
		int i = 0;
		for (String string : recordList) {
			recordListOtp[i] = new OtpErlangString(string);
			++i;
		}
		
		map.put("filename", new OtpErlangString(targetFilePath)); //$NON-NLS-1$
		map.put("reclist", new OtpErlangList(recordListOtp)); //$NON-NLS-1$

		return new RefactoringRequest(proxy, logger, "move_rec", //$NON-NLS-1$
				OtpErlangHelper.createPropList(map));
	}
	
	static private Map<String, OtpErlangObject> createPropertyMap() {
		Map<String, OtpErlangObject> map = new HashMap<>();
		map.put("ask_missing", new OtpErlangBoolean(false)); //$NON-NLS-1$
		return map;
	}
	
	static private Map<String, OtpErlangObject> createPropertyMap(
			String filePath) {
		Map<String, OtpErlangObject> map = createPropertyMap(); 
		map.put("file", new OtpErlangString(filePath)); //$NON-NLS-1$

		String moduleName = filePathToModuleName(filePath);

		map.put("module", new OtpErlangAtom(moduleName)); //$NON-NLS-1$

		return map;
	}

	private static String filePathToModuleName(String filePath) {
		String fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
		int idx = fileName.lastIndexOf('.');
		String moduleName = fileName.substring(0, idx < 0 ? fileName.length()
				: idx);
		return moduleName;
	}

	static private Map<String, OtpErlangObject> createPropertyMap(
			String filePath, int position) {
		Map<String, OtpErlangObject> map = createPropertyMap(filePath);
		map.put("position", new OtpErlangInt(position)); //$NON-NLS-1$
		return map;
	}

	static private Map<String, OtpErlangObject> createPropertyMap(
			String filePath, int startPos, int endPos) {
		Map<String, OtpErlangObject> map = createPropertyMap(filePath);
		map.put("posrange", OtpErlangHelper.createTuple(new OtpErlangInt( //$NON-NLS-1$
				startPos), new OtpErlangInt(endPos)));
		return map;
	}

}
