//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   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 de.ugoe.cs.autoquest.usageprofiles;

import java.io.Serializable;
import java.util.Collection;

/**
 * <p>
 * This interface defines a data structure for holding symbols. Its implementations can be used to
 * improve the performance of a trie by tuning its internal symbol storage management.
 * </p>
 * <p>
 * The interface is called a map, although it is not necessarily. It may contain the same element
 * as separate keys. This is allowed for performance improvements. If it is required to really
 * assure, that a key exists only once, then each call to the {@link #addSymbol(Object, Object)}
 * method should be done only, if the {@link #containsSymbol(Object)} method for the same symbol
 * returns false.
 * </p>
 * <p>
 * Mapping a symbol to the value null is possible. In this case {@link #getValue(Object)} returns
 * null for the symbol. But {@link #containsSymbol(Object)} returns true.
 * </p>
 * 
 * @author Patrick Harms
 * 
 * @param <T>
 *            Type of the symbols that are stored
 * @param <V>
 *            Type of the values associated with the symbols
 *            
 * @see SymbolStrategy
 */
public interface SymbolMap<K, V> extends Serializable {

    /**
     * <p>
     * Returns the size of the map, i.e. the number of symbol entries
     * </p>
     * 
     * @return as described
     */
    public int size();

    /**
     * <p>
     * Returns true if this map is empty, i.e. if {@link #size()} returns 0
     * </p>
     * 
     * @return as described
     */
    public boolean isEmpty();

    /**
     * <p>
     * Returns true if the provided symbol was stored in this map.
     * </p>
     * 
     * @param symbol the symbol to check if it was stored in this map
     * 
     * @return as described
     * 
     * @throws IllegalArgumentException if the provided symbol is null
     */
    public boolean containsSymbol(K symbol);

    /**
     * <p>
     * Returns the value associated to the provided symbol in this map. If there is no value
     * associated to the given symbol or if the symbol is not stored in this map, the method
     * returns null.
     * </p>
     * 
     * @param symbol the symbol to return the value for
     * 
     * @return as described
     * 
     * @throws IllegalArgumentException if the provided symbol is null
     */
    public V getValue(K symbol);

    /**
     * <p>
     * Adds a symbol and an associated value to the map. If the value is null, the symbol is added,
     * anyway and {@link #containsSymbol(Object)} will return true for that symbol. Adding the
     * same symbol twice may produce two entries. This is contradictory to typical map
     * implementations. To prevent this, the {@link #containsSymbol(Object)} and
     * {@link #removeSymbol(Object)} methods should be used to ensure map behavior.
     * </p>
     * 
     * @param symbol the symbol to add to the map
     * @param value  the value to associate to the symbol in this map
     * 
     * @return as described
     * 
     * @throws IllegalArgumentException if the provided symbol is null
     */
    public void addSymbol(K symbol, V value);

    /**
     * <p>
     * Removes a symbol and its associated value from the map. If the symbol is stored several
     * times, the first of its occurrences is removed. 
     * </p>
     * 
     * @param symbol the symbol to be removed from the map
     * 
     * @return as described
     * 
     * @throws IllegalArgumentException if the provided symbol is null
     */
    public V removeSymbol(K symbol);

    /**
     * <p>
     * Returns a collection of all symbols in this map.
     * </p>
     *
     * @return as described
     */
    public Collection<K> getSymbols();
    
    /**
     * <p>
     * Returns a collection of all values associated to symbols in this map. May contain null
     * values, if some of the symbols are mapped to null. The length of the returned collection
     * is in any case the same as the size of the map.
     * </p>
     *
     * @return as described
     */
    public Collection<V> getValues();
    
    /**
     * <p>
     * Removes all symbols and associated values from the map.
     * </p>
     */
    public void clear();

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode();

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj);

}
