package ac.essex.ooechs.lcs;

import ac.essex.ooechs.lcs.Classifier;
import ac.essex.ooechs.lcs.util.ProportionalSelection;

import java.util.Vector;

/**
 * A match set represents a bunch of classifiers which have been chosen for one
 * reason or another. It basically wraps around a vector of classifiers, but also
 * offers a couple of utility methods (such as the classifiers' average age) so
 * the code is easier to understand and read.
 *
 * @author Olly Oechsle, University of Essex, Date: 18-Jan-2008
 * @version 1.0
 */
public class ClassifierSet {

    /**
     * A vector which stores all the rules in the match set
     */
    protected Vector<Classifier> classifiers;

    /**
     * The total strength of the match set
     */
    protected double totalMatchStrength;

    /**
     * Initialises an empty match set.
     */
    public ClassifierSet() {
        this.classifiers = new Vector<Classifier>();
        this.totalMatchStrength = 0;
    }

    /**
     * Adds a rule to the match set
     */
    public void add(Classifier classifier) {
        classifiers.add(classifier);
        totalMatchStrength += classifier.p * classifier.numerosity;
    }

    /**
     * Returns the rule at a particular index.
     */
    public Classifier elementAt(int index) {
        return classifiers.elementAt(index);
    }

    /**
     * Returns the number of rules in the match set
     */
    public int getSize() {
        return classifiers.size();
    }

    /**
     * Returns the total numerosity of members of the set. This
     * will be equal to or higher than the value returned by getSize();
     * @return
     */
    public int getNumerosity() {
        int numerosity = 0;
        for (int i = 0; i < classifiers.size(); i++) {
            numerosity +=  classifiers.elementAt(i).numerosity;
        }
        return numerosity;
    }

    /**
     * Returns all the rules in this match set.
     */
    public Vector<Classifier> getClassifiers() {
        return classifiers;
    }

    /**
     * Returns whether the selected classifier is a member of the set
     */
    public boolean contains(Classifier classifier) {
        return classifiers.contains(classifier);
    }

    /**
     * Returns the total strength of the match set
     */
    public double getTotalStrength() {
        return totalMatchStrength;
    }

    /**
     * Selects a random rule from the match set. This implementation
     * returns rules with equal probability and is numerosity safe.
     */
    public Classifier getRandomRule() {
        ProportionalSelection selector = new ProportionalSelection(classifiers.size());
        for (int i = 0; i < classifiers.size(); i++) {
            Classifier classifier = classifiers.elementAt(i);
            selector.addWeight(classifier.numerosity);
        }
        return classifiers.elementAt(selector.chooseIndex());
    }

    /**
     * Gets the average time stamp for all rules in the set.
     */
    public double getAverageTimeStamp() {
        double total = 0;
        int totalRules = 0;
        for (int i = 0; i < classifiers.size(); i++) {
            Classifier classifier = classifiers.elementAt(i);
            total += (classifier.timestamp * classifier.numerosity);
            totalRules += classifier.numerosity;
        }
        return total / totalRules;
    }

    /**
     * Sets the time stamp of all the rules in the match set to
     * a given value.
     */
    public void setTimeStamp(int time) {
        //  reset the clocks on the match set
        for (int i = 0; i < classifiers.size(); i++) {
            Classifier classifier = classifiers.elementAt(i);
            classifier.timestamp = time;
        }
    }

}
