package ac.essex.ooechs.problems.classification;

import ac.essex.ooechs.lcs.Environment;
import ac.essex.ooechs.lcs.InputVector;
import ac.essex.ooechs.lcs.Payoff;
import ac.essex.ooechs.lcs.Action;
import ac.essex.ooechs.lcs.zcs.ZCSSingleStep;
import ac.essex.ooechs.lcs.representation.Condition;
import ac.essex.ooechs.lcs.representation.messy.MessyCondition;

import java.util.Vector;

/**
 * <p/>
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version,
 * provided that any use properly credits the author.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details at http://www.gnu.org
 * </p>
 *
 * @author Olly Oechsle, University of Essex, Date: 27-Feb-2008
 * @version 1.0
 */
public class ClassificationEnvironment extends Environment {

    public int NUM_GENES = 2;

    protected Vector<FeatureInput> data;
    protected FeatureInput currentFeature;
    protected int cursor = 0;

    /**
     * Returns the name of the environment
     */
    public String getName() {
        return "Basic Classification Environment";
    }

    public boolean isMultiStep() {
        return false;
    }

    /**
     * Initialises (or resets) the environment
     */
    public void initialise() {
        // create some inputs
        data = new Vector<FeatureInput>();

        data.add(new FeatureInput(new double[]{2, 3}, 1));
        data.add(new FeatureInput(new double[]{7, 6}, 2));
        data.add(new FeatureInput(new double[]{3, 4}, 1));
        data.add(new FeatureInput(new double[]{5, 7}, 2));
        data.add(new FeatureInput(new double[]{2, 4}, 1));
        data.add(new FeatureInput(new double[]{5, 4}, 2));

    }

    public int test(ZCSSingleStep zcs) {

        int mistakes =0;

        for (int i = 0; i < data.size(); i++) {
            FeatureInput featureInput = data.elementAt(i);
            Action a = zcs.classify(featureInput);
            if (a == null || a.getId() != featureInput.getClassID()) {
                mistakes++;
            }
        }

        return mistakes;

    }

    public double getMin(int featureIndex) {
        switch (featureIndex) {
            case 0:
                return 2;
            case 1:
                return 3;
        }
        return -1;
    }

    public double getRange(int featureIndex) {
        switch (featureIndex) {
            case 0:
                // between 2 and 7
                return 5;
            case 1:
                // between 3 and 7
                return 4;
        }
        return -1;
    }

    /**
     * Returns the current state of the environment as an input vector
     */
    public InputVector getInput() {
        currentFeature = data.elementAt(cursor);
        cursor++;
        if (cursor >= data.size()) cursor = 0;
        return currentFeature;
    }


    /**
     * Returns the number of inputs that make up each input vector
     */
    public int getFeatureCount() {
        // todo automate
        return 2;
    }

    /**
     * Updates the environment with a certain action
     *
     * @param a The action to takeAction the environment with
     * @return Any payoff that is recieved as a result of updating the environment.
     */
    public Payoff takeAction(Action a) {

        if (a.getId() == currentFeature.getClassID()) {
            return new Payoff(100, true);
        } else {
            return new Payoff(0, true);
        }
    }

    /**
     * Gets all the available actions that may be performed on this environment.
     */
    public Vector<Action> getActions() {
        Vector<Action> actions = new Vector<Action>(10);
        actions.add(new Action(1));
        actions.add(new Action(2));
        return actions;
    }

    /**
     * Gets a condition from the environment
     */
    public Condition getRandomCondition() {
        return new MessyCondition(this);
    }

    /**
     * Gets a condition which matches a given input vector
     */
    public Condition getConditionToCover(InputVector i) {
        return new MessyCondition(this, i);
    }

}
