/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ghidra.pcode.exec.trace.data;

import java.nio.ByteBuffer;

import ghidra.program.model.address.*;
import ghidra.program.model.lang.Language;
import ghidra.trace.model.memory.TraceMemoryState;

/**
 * A data-access shim for a trace
 *
 * @see PcodeTraceAccess
 */
public interface PcodeTraceDataAccess {
	/**
	 * Get the language of the associated platform
	 * 
	 * @return the language
	 */
	Language getLanguage();

	/**
	 * Set the memory state of an address range
	 * 
	 * <p>
	 * The state is set only for the destination snapshot. It is <em>not</em> effective for the
	 * indefinite future.
	 * 
	 * @param range the range
	 * @param state the desired state
	 */
	void setState(AddressRange range, TraceMemoryState state);

	/**
	 * Get the composite state of an address range, using the snapshot's viewport
	 * 
	 * <p>
	 * Typically, the viewport is at most 2 snapshots deep. When reading from a captured snapshot,
	 * the viewport includes only the source snapshot. When reading from scratch snapshot (usually
	 * generated by emulation), the viewport includes that scratch snapshot and the original source
	 * snapshot. The {@link TraceMemoryState#KNOWN} address set is the union of known address sets
	 * among all snapshots in the viewport. If all addresses in the given range are
	 * {@link TraceMemoryState#KNOWN}, then the composite state is known. Otherwise, the composite
	 * state is {@link TraceMemoryState#UNKNOWN}.
	 * 
	 * @param range the range to check
	 * @return the composite state of the range
	 */
	TraceMemoryState getViewportState(AddressRange range);

	/**
	 * Compute the intersection of the given address set and the set of
	 * {@link TraceMemoryState#KNOWN} or (@link {@link TraceMemoryState#ERROR} memory
	 * 
	 * @param view the address set
	 * @param useFullSpans how to treat the viewport; true for ever known, false for known now.
	 * @return the intersection
	 */
	AddressSetView intersectViewKnown(AddressSetView view, boolean useFullSpans);

	/**
	 * Compute the intersection of the given address set and the set of
	 * {@link TraceMemoryState#UNKNOWN} memory
	 * 
	 * @param view the address set
	 * @return the intersection
	 */
	AddressSetView intersectUnknown(AddressSetView view);

	/**
	 * Write bytes into the trace
	 * 
	 * <p>
	 * Each written byte is effective for future snapshots up to but excluding the next snapshot
	 * where another byte is written at the same address.
	 * 
	 * @param start the address of the first byte to write
	 * @param buf a buffer of bytes to write
	 * @return the number of bytes written
	 */
	int putBytes(Address start, ByteBuffer buf);

	/**
	 * Read bytes from the trace
	 * 
	 * @param start the address of the first byte to read
	 * @param buf a buffer to receive the bytes
	 * @return the number of bytes read
	 */
	int getBytes(Address start, ByteBuffer buf);

	/**
	 * Translate the given emulator address to a host/overlay address
	 * 
	 * @param address the emulator address
	 * @return the host/overlay address
	 */
	Address translate(Address address);

	/**
	 * Get a property-access shim for the named property
	 * 
	 * @param <T> the type of the property's values
	 * @param name the name of the property
	 * @param type the class of the property's values
	 * @return the access shim
	 */
	<T> PcodeTracePropertyAccess<T> getPropertyAccess(String name, Class<T> type);
}
