/*******************************************************************************
 * Copyright (c) 2006, 2012 Wind River Systems and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Wind River Systems - initial API and implementation
 *     Ericsson           - Update for GDB/MI
 *     Marc Khouzam (Ericsson) - Added expression-groups (bug 394408)
 *******************************************************************************/
package org.eclipse.cdt.dsf.debug.service;

import java.math.BigInteger;
import java.util.Map;

import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.datamodel.IDMData;
import org.eclipse.cdt.dsf.datamodel.IDMEvent;

/**
 * Expressions service provides access to the debugger's expression evaluator. This service has
 * dependencies on the Stack service, as it is be used to provide context for an
 * expression to be evaluated.
 *
 * @since 1.0
 */
@SuppressWarnings("nls")
public interface IExpressions extends IFormattedValues {

	/**
	 * Expression context.
	 */
	public interface IExpressionDMContext extends IFormattedDataDMContext {
		/**
		 * Returns a fully qualified expression string represented by this context.  This
		 * expression string is the same as the string that is sent to the debug engine to be
		 * evaluated in context of a stack frame, thread, or a symbol context.
		 */
		String getExpression();
	}

	/**
	 * To avoid SWT performance issues large arrays are divided into partitions.
	 * This interface represents the context of such a partition.
	 *
	 * @since 2.3
	 */
	public interface IIndexedPartitionDMContext extends IExpressionDMContext {

		/**
		 * Returns the expression string of the parent array.
		 */
		public String getParentExpression();

		/**
		 * Returns the index of the partition's first element in the parent array.
		 */
		public int getIndex();

		/**
		 * Returns the number of array's elements in the partition.
		 */
		public int getLength();
	}

	/**
	 * Represents a group of expressions.  A group of expressions is a list of
	 * possibly unrelated expressions which are somehow described by an
	 * expression-group string.
	 *
	 * Examples of expression-groups that the service could choose to support are:
	 * 	"myVar1; myVar2"
	 *  "=myVar*"
	 *
	 * The sub-expressions of an expression-group are the individual expressions
	 * making up this group.
	 *
	 * @since 2.4
	 */
	public interface IExpressionGroupDMContext extends IExpressionDMContext {
	}

	/**
	 * The address and size of an expression.
	 */
	public interface IExpressionDMAddress {

		/**
		 * Returns the address of the expression.
		 */
		IAddress getAddress();

		/**
		 * Returns the size of the address.
		 */
		int getSize();

		/**
		 * @return The memory space
		 * @since 2.7
		 */
		default String getMemorySpaceID() {
			return "";
		}
	}

	/**
	 * A representation of an expression location that does not correspond to
	 * an address.
	 *
	 * @since 2.1
	 */
	public interface IExpressionDMLocation extends IExpressionDMAddress {

		/**
		 * A constant that can be returned by {@link IExpressionDMAddress#getAddress()}
		 * to represent an invalid address.  Implementations of
		 * <code>IExpressionDMLocation</code> can return this constant if no
		 * valid address can be returned for a given expression location.
		 */
		public static final IAddress INVALID_ADDRESS = new IAddress() {
			@Override
			public IAddress add(BigInteger offset) {
				return this;
			}

			@Override
			public IAddress add(long offset) {
				return this;
			}

			@Override
			public BigInteger getMaxOffset() {
				return BigInteger.ZERO;
			}

			@Override
			public BigInteger distanceTo(IAddress other) {
				return BigInteger.ZERO;
			}

			@Override
			public BigInteger getValue() {
				return BigInteger.ZERO;
			}

			@Override
			public boolean isZero() {
				return false;
			}

			@Override
			public boolean isMax() {
				return false;
			}

			@Override
			public String toString(int radix) {
				return "INVALID";
			}

			@Override
			public String toHexAddressString() {
				return toString();
			}

			@Override
			public String toBinaryAddressString() {
				return toString();
			}

			@Override
			public int getCharsNum() {
				return 0;
			}

			@Override
			public int getSize() {
				return 0;
			}

			@Override
			public int compareTo(Object o) {
				return 0;
			}
		};

		/**
		 * Returns a string representation of the expression location.
		 */
		public String getLocation();
	}

	/**
	 * This is the model data interface that corresponds to IExpressionDMContext.
	 */
	public interface IExpressionDMData extends IDMData {
		// These static fields define the possible return values of method getTypeId().

		final static String TYPEID_UNKNOWN = "TYPEID_UNKNOWN";
		final static String TYPEID_INTEGER = "TYPEID_INTEGER";
		final static String TYPEID_CHAR = "TYPEID_CHAR";
		final static String TYPEID_FLOAT = "TYPEID_FLOAT";
		final static String TYPEID_DOUBLE = "TYPEID_DOUBLE";
		final static String TYPEID_OPAQUE = "TYPEID_OPAQUE";

		/**
		 * This enumerates the possible basic types that an expression can have.
		 *
		 * @see getBasicType().
		 */
		enum BasicType {
			unknown, // Unknown type.
			basic, // Scalar type (e.g., int, short, float).
			pointer, // Pointer to anything.
			array, // Array of anything.
			composite, // Struct, union, or class.
			enumeration, // Enumeration.
			function // Function.
		}

		/**
		 * If this expression is a sub-expression of another expression, this method returns
		 * the expression relative to the parent of this expression.  Otherwise this method
		 * will return the same string as {@link #getExpression()}.
		 */
		String getName();

		/**
		 * @return A BasicType enumerator describing the basic type of an expression.
		 */
		BasicType getBasicType();

		/**
		 * @return The source code type of this expression.  This is a string such as "struct Foo", "short",
		 *         "int *", "mytypedef", "(int *)[]", "enum Bar".  If the debugger backend cannot supply
		 *         this information, this method returns "<UNKNOWN>" (the angle brackets are there just in
		 *         case there is a type named "UNKNOWN" in the application).
		 *         <p>
		 *         If you implement {@link IExpressions2}, this should return the casted type name,
		 *         if this expression was generated via {@link IExpressions2#createCastedExpression(IDMContext, String, IExpressions2.ICastedExpressionDMContext)}
		 */
		String getTypeName();

		/**
		 * This method needs to be defined.  For now, this returns the empty string.
		 */
		String getEncoding();

		/**
		 * @return One of the TYPEID_* static field values defined by this interface.
		 */
		String getTypeId();

		/**
		 * @return A Map in which the keys are strings that are the names of enumerators in the enumeration
		 *         that is the value of this expression and the values are the integer values of the
		 *         enumerators.  If the expression type is not an enumeration, this returns an empty Map.
		 */
		Map<String, Integer> getEnumerations();

		/**
		 * This method needs to be defined.
		 */
		IRegisters.IRegisterDMContext getRegister();
	}

	/**
	 * Event indicating that a given expression is changed. If an expression is changed, it's implied that all
	 * the children of that expression are changed too.
	 */
	public interface IExpressionChangedDMEvent extends IDMEvent<IExpressionDMContext> {
	}

	/**
	 * Retrieves the expression DM data object for the given expression context(<tt>dmc</tt>).
	 *
	 * @param dmc
	 *            The ExpressionDMC for the expression to be evaluated.
	 * @param rm
	 *            The data request monitor that will contain the requested data
	 */
	void getExpressionData(IExpressionDMContext dmc, DataRequestMonitor<IExpressionDMData> rm);

	/**
	 * Retrieves the address and size of an expression given by the expression context(<tt>dmc</tt>).
	 * Non-lvalues do not have an addresses (e.g., "x + 5").  When the expression
	-    * has no address, the request monitor will have an error with code
	 * <code>IDsfStatusConstants.REQUEST_FAILED</code> and the data request
	 * monitor will contain null.
	 *
	 * @param dmc
	 *            The ExpressionDMC for the expression
	 * @param rm
	 *            The data request monitor that will contain the requested data
	 */
	void getExpressionAddressData(IExpressionDMContext dmc, DataRequestMonitor<IExpressionDMAddress> rm);

	/**
	 * Returns the data model context object for the specified expression in the context
	 * specified by <b>ctx</b>.
	 *
	 * @param ctx: Context in which to evaluate the expression.  This context could include the
	 * PC location, stack frame, thread, or just a symbol context.
	 *
	 * @param expression: The expression to evaluate.
	 *
	 * @return  An expression data model context object that must be passed to the appropriate
	 *          data retrieval routine to obtain the value of the expression.
	 */
	IExpressionDMContext createExpression(IDMContext ctx, String expression);

	/**
	 * Retrieves the sub-expressions of the given expression.  Sub-expressions are fields of a struct, union,
	 * or class, the enumerators of an enumeration, and the element of an array.
	 * <br>
	 * Note: Clients may call this method on any valid expression context, and before calling any other
	 * method to evaluate the expression value.  It is up to the implementation to internally evaluate the
	 * expression if needed, in order to calculate sub expressions.
	 *
	 * @param exprCtx: The data model context representing an expression.
	 *
	 * @param rm: Request completion monitor containing an array of all sub-expressions
	 */
	void getSubExpressions(IExpressionDMContext exprCtx, DataRequestMonitor<IExpressionDMContext[]> rm);

	/**
	 * Retrieves a particular range of sub-expressions of the given expression.
	 * Sub-expressions are fields of a struct, union, or class, the enumerators
	 * of an enumeration, and the element of an array.
	 * <br>
	 * Note: Clients may call this method on any valid expression context, and before calling any other
	 * method to evaluate the expression value.  It is up to the implementation to internally evaluate the
	 * expression if needed, in order to calculate sub expressions.
	 *
	 * @param exprCtx: The data model context representing an expression.
	 *        startIndex: Index of the first sub-expression to retrieve
	 *        length: Total number of sub-expressions to retrieve
	 *
	 * @param rm: Request completion monitor containing an array of the requested
	 *            range of sub-expressions
	 */
	void getSubExpressions(IExpressionDMContext exprCtx, int startIndex, int length,
			DataRequestMonitor<IExpressionDMContext[]> rm);

	/**
	 * Retrieves the number of sub-expressions of the given expression.  Sub-expressions are fields of a struct, union,
	 * or class, the enumerators of an enumeration, and the element of an array.
	 * <br>
	 * Note: Clients may call this method on any valid expression context, and before calling any other
	 * method to evaluate the expression value.  It is up to the implementation to internally evaluate the
	 * expression if needed, in order to calculate sub expressions.
	 *
	 * @param exprCtx: The data model context representing an expression.
	 *
	 * @param rm: Request completion monitor containing the number of sub-expressions
	 *            of the specified expression
	 */
	void getSubExpressionCount(IExpressionDMContext exprCtx, DataRequestMonitor<Integer> rm);

	/**
	 * For object oriented languages, this method returns the expressions representing base types of
	 * the given expression type.
	 * <br>
	 * Note: Clients may call this method on any valid expression context, and before calling any other
	 * method to evaluate the expression value.  It is up to the implementation to internally evaluate the
	 * expression if needed, in order to calculate sub expressions.
	 *
	 * @param exprContext: The data model context representing an expression.
	 *
	 * @param rm: Request completion monitor.
	 */
	void getBaseExpressions(IExpressionDMContext exprContext, DataRequestMonitor<IExpressionDMContext[]> rm);

	/**
	 * This method indicates if an expression can be written to.
	 *
	 * @param expressionContext: The data model context representing an expression.
	 *
	 * @param rm: Data Request monitor containing True if this expression's value can be edited.  False otherwise.
	 */
	void canWriteExpression(IExpressionDMContext expressionContext, DataRequestMonitor<Boolean> rm);

	/**
	 * This method supports the writing/modifying the value of the expression.
	 *
	 * @param expressionContext: The data model context representing an expression.
	 *
	 * @param expressionValue: The new value of the expression as a String.
	 *
	 * @param formatId: The format ID specifying the format of parameter <b>expressionValue</b>.
	 *
	 * @param rm: Request completion monitor.
	 */
	void writeExpression(IExpressionDMContext expressionContext, String expressionValue, String formatId,
			RequestMonitor rm);
}
