//   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;
import java.util.List;

import de.ugoe.cs.autoquest.eventcore.Event;

/**
 * <p>
 * This interface defines the functionalities provided by stochastic processes.
 * </p>
 * 
 * @author Steffen Herbold
 * @version 1.0
 */
public interface IStochasticProcess extends Serializable {

    /**
     * <p>
     * Returns the probability, that the next event is {@code symbol} given the last events are
     * {@code context}. The last element of {@code context} is the most recent in the history, the
     * first element is the oldest.
     * </p>
     * 
     * @param context
     *            recently observed symbols
     * @param symbol
     *            event for which the probability is calculated
     * @return probabilty the {@code symbol} is the next event, given the last events
     *         {@code context}
     * @throws IllegalArgumentException
     *             thrown if context or symbol is null
     */
    double getProbability(List<Event> context, Event symbol);

    /**
     * <p>
     * Returns the probability that a given sequence is generated by the stochastic process.
     * </p>
     * 
     * @param sequence
     *            sequences of which the probability is calculated
     * @return probability of the sequences; 1.0 if sequence is empty
     * @throws IllegalArgumentException
     *             thrown if sequence is null
     */
    double getProbability(List<Event> sequence);

    /**
     * <p>
     * Returns the sum of the negative logarithm of the probabilities.
     * </p>
     * 
     * @param sequence
     *            sequences of which the logsum is calculated
     * @return logsum of the sequences; 0.0 if sequence is empty
     * @throws IllegalArgumentException
     *             thrown if sequence is null
     */
    public double getLogSum(List<Event> sequence);

    /**
     * <p>
     * Generates a random sequence of events. The sequence starts with {@link Event#STARTEVENT} and
     * finishes with {@link Event#ENDEVENT}.
     * </p>
     * 
     * @return randomly generated sequence
     */
    public List<Event> randomSequence();

    /**
     * <p>
     * Generates a random sequence of events. The sequence starts with {@link Event#STARTEVENT} and
     * finishes with
     * <ul>
     * <li>{@link Event#ENDEVENT} if validEnd==true.</li>
     * <li>b) if a generated sequences reaches {@link Event#ENDEVENT} before maxLength, the sequence
     * finishes and is shorter than maxLenght. Otherwise, the sequence finishes as soon as maxLength
     * is reached and the final event of the sequence must not be {@link Event#ENDEVENT}.</li>
     * </ul>
     * </p>
     * 
     * @param maxLength
     *            maximum length of the generated sequence
     * @param validEnd
     *            if true, only sequences that finish with {@link Event#ENDEVENT} are generated
     * @param maxIter
     *            maximum number of attempts for the generation of the sequence; in case of failure
     *            and empty sequence is returned
     * @return randomly generated sequence
     * 
     */
    public List<Event> randomSequence(int maxLength, boolean validEnd, long maxIter);

    /**
     * <p>
     * Generates all sequences of a given length are possible, i.e., have a positive probability.<br>
     * All states are used as possible starting states.
     * </p>
     * 
     * @param length
     *            length of the generated sequences
     * @return generated sequences
     * @see #generateSequences(int, boolean)
     * @throws IllegalArgumentException
     *             thrown if length is less than or equal to 0
     */
    public Collection<List<Event>> generateSequences(int length);

    /**
     * <p>
     * Generates all sequences of given length that can are possible, i.e., have positive
     * probability.<br>
     * If {@code fromStart==true}, all generated sequences start in {@link Event#STARTEVENT}.
     * Otherwise this method is the same as {@link #generateSequences(int)}.
     * </p>
     * 
     * @param length
     *            length of the generated sequences
     * @param fromStart
     *            if true, all generated sequences start with {@link Event#STARTEVENT}
     * @return generated sequences
     * @throws IllegalArgumentException
     *             thrown if length is less than or equal to 0
     */
    public Collection<List<Event>> generateSequences(int length, boolean fromStart);

    /**
     * <p>
     * Generates all sequences starting with {@link Event#STARTEVENT} and finishing with
     * {@link Event#ENDEVENT} of a given length. It is possible that no such sequence exists with
     * the defined length and the returned set is empty. If {@code length} is less than 2 the
     * returned set is always empty.
     * </p>
     * 
     * @param length
     * @return generated sequences
     * @throws IllegalArgumentException
     *             thrown if length is less than or equal to 0
     */
    public Collection<List<Event>> generateValidSequences(int length);

    /**
     * <p>
     * Returns the number of states known by the stochastic process, i.e., the size of its alphabet.
     * </p>
     * 
     * @return number of states
     */
    public int getNumSymbols();

    /**
     * <p>
     * Returns a string representation of all known states.
     * </p>
     * 
     * @return string representation for all known states
     */
    public String[] getSymbolStrings();

    /**
     * <p>
     * Returns the number of states the process would have if it would be flattened through
     * state-splitting to a first-order Markov model.
     * </p>
     * <p>
     * If it is not possible to flatten the model, -1 is returned.
     * </p>
     * 
     * @return number of states an equivalent FOM would have; -1 if not available
     */
    public int getNumFOMStates();

    /**
     * <p>
     * Returns the number of transitions the process would have if it would be flattened through
     * state-splitting to a first-order Markov model.
     * </p>
     * 
     * @return number of transitions an equivalent FOM would have; -1 if not available
     */
    public int getNumTransitions();

    /**
     * <p>
     * Returns all states known by the stochastic process, i.e., its {@link Event}s.
     * </p>
     * 
     * @return events known by the process
     */
    public Collection<Event> getEvents();

}
