/* ###
 * 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.program.database.map;

import java.util.List;

import ghidra.program.model.address.*;

/**
 * Address map interface add methods need by the program database implementation to manage its address map.
 * NOTE: Objects implementing this interface are not intended for use outside of the
 * <code>ghidra.program.database</code> packages.
 */
public interface AddressMap {

	/**
	 * Reserved key for an invalid key.
	 */
	public static final long INVALID_ADDRESS_KEY = -1;

	/**
	 * Get the database key associated with the given relative address.
	 * This key uniquely identifies a relative location within the program.
	 * If the program's image base is moved to another address, this key will map to a new
	 * address that is the same distance to the new base as the old address was to the old base.
	 * If the requested key does not exist and create is false, INVALID_ADDRESS_KEY
	 * will be returned.  Note that nothing should ever be stored using the returned key unless
	 * create is true.
	 * @param addr the address for which to get a database key.
	 * @param create true if a new key may be generated
	 * @return the database key for the given address or INVALID_ADDRESS_KEY if 
	 * create is false and one does not exist for the specified addr.
	 */
	public long getKey(Address addr, boolean create);

	/**
	 * Get the database key associated with the given absolute address.
	 * This key uniquely identifies an absolute location within the program.
	 * If the requested key does not exist and create is false, INVALID_ADDRESS_KEY
	 * will be returned.  Note that nothing should ever be stored using the returned key unless
	 * create is true.
	 * @param addr the address for which to get a database key.
	 * @param create true if a new key may be generated
	 * @return the database key for the given address or INVALID_ADDRESS_KEY if 
	 * create is false and one does not exist for the specified addr.
	 */
	public long getAbsoluteEncoding(Address addr, boolean create);

	/**
	 * Search for addr within the "sorted" keyRangeList and return the index of the
	 * keyRange which contains the specified addr.
	 * @param keyRangeList key range list to search
	 * @param addr address or null
	 * @return index of the keyRange within the keyRangeList which contains addr 
	 * if it is contained in the list; otherwise, <code>(-(<i>insertion point</i>) - 1)</code>. 
	 * The <i>insertion point</i> is defined as the point at which the
	 * addr would be inserted into the list: the index of the first keyRange
	 * greater than addr, or <code>keyRangeList.size()</code>, if all
	 * keyRanges in the list are less than the specified addr.  Note
	 * that this guarantees that the return value will be &gt;= 0 if
	 * and only if the addr is found within a keyRange.  
	 * An addr of null will always result in a returned index of -1.
	 */
	public int findKeyRange(List<KeyRange> keyRangeList, Address addr);

	/**
	 * Generates a properly ordered list of database key ranges for a
	 * a specified address range.  If absolute encodings are requested, 
	 * only memory addresses will be included.  Returned key ranges are 
	 * generally intended for read-only operations since new keys will 
	 * never be generated.  The returned key ranges will correspond 
	 * to those key ranges which have previously been created within 
	 * the specified address range and may represent a much smaller subset 
	 * of addresses within the specified range. 
	 * NOTE: if the create parameter is true, the given range must not extend in the upper 32 bits 
	 * by more than 1 segment. For example, range(0x0000000000000000 - 0x0000000100000000) 
	 * is acceptable, but the range (0x0000000000000000 - 0x0000000200000000) is not because the
	 * upper 32 bits differ by 2.
	 * @param start the start address of the range
	 * @param end maximum address of range
	 * @param create true if a new keys may be generated, otherwise returned 
	 * key-ranges will be limited to those already defined. And if true, the range will be limited
	 * to a size of 2^32 so that at most it creates two new address bases
	 * @return "sorted" list of KeyRange objects
	 * @throws UnsupportedOperationException if the given range is so large that the upper 32 bit
	 * segments differ by more than 1.
	 */
	public List<KeyRange> getKeyRanges(Address start, Address end, boolean create);

	/**
	 * Generates a properly ordered list of database key ranges for a
	 * a specified address set.  If absolute encodings are requested, 
	 * only memory addresses will be included.
	 * @param set address set or null for all addresses.  May not be null if <code>create</code> is true.
	 * @param create true if a new keys may be generated, otherwise returned 
	 * key-ranges will be limited to those already defined.
	 * @return "sorted" list of KeyRange objects
	 */
	public List<KeyRange> getKeyRanges(AddressSetView set, boolean create);

	/**
	 * Returns the address that was used to generate the given long key. (If the image base was
	 * moved, then a different address is returned unless the value was encoded using the
	 * "absoluteEncoding" method.  If the program's default address space is segmented (i.e., SegmentedAddressSpace).
	 * the address returned will be always be normalized to defined segmented memory blocks if possible.
	 * @param value the long value to convert to an address.
	 * @return address decoded from long 
	 */
	public Address decodeAddress(long value);

	/**
	 * Returns the address factory associated with this map.
	 * Null may be returned if map not associated with a specific address factory.
	 * @return associated {@link AddressFactory} or null
	 */
	public AddressFactory getAddressFactory();

	/**
	 * Generates a properly ordered list of database key ranges for a
	 * a specified address range.  If absolute encodings are requested, 
	 * only memory addresses will be included.
	 * @param start minimum address of range
	 * @param end maximum address of range
	 * @param absolute if true, absolute key encodings are returned, otherwise 
	 * standard/relocatable address key encodings are returned.
	 * @param create true if a new keys may be generated, otherwise returned 
	 * key-ranges will be limited to those already defined.
	 * @return "sorted" list of KeyRange objects
	 */
	public List<KeyRange> getKeyRanges(Address start, Address end, boolean absolute,
			boolean create);

	/**
	 * Generates a properly ordered list of database key ranges for a
	 * a specified address set.  If absolute encodings are requested, 
	 * only memory addresses will be included.
	 * @param set address set or null for all addresses.  May not be null if <code>create</code> is true.
	 * @param absolute if true, absolute key encodings are returned, otherwise 
	 * standard/relocatable address key encodings are returned.
	 * @param create true if a new keys may be generated, otherwise returned 
	 * key-ranges will be limited to those already defined.
	 * @return "sorted" list of KeyRange objects
	 */
	public List<KeyRange> getKeyRanges(AddressSetView set, boolean absolute, boolean create);

	/**
	 * Returns an address map capable of decoding old address encodings.
	 */
	public AddressMap getOldAddressMap();

	/**
	 * Returns true if this address map has been upgraded.
	 */
	public boolean isUpgraded();

	/**
	 * Returns the current image base setting.
	 */
	public Address getImageBase();

}
