/*
 * #%L
 * IsisFish data
 * %%
 * Copyright (C) 2006 - 2011 Ifremer, CodeLutin
 * %%
 * 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.
 * 
 * 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.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-2.0.html>.
 * #L%
 */
package rules;

import static org.nuiton.i18n.I18n._;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.math.matrix.MatrixIterator;
import org.nuiton.math.matrix.MatrixND;

import scripts.ResultName;
import scripts.SiMatrix;
import fr.ifremer.isisfish.entities.Metier;
import fr.ifremer.isisfish.entities.MetierSeasonInfo;
import fr.ifremer.isisfish.entities.Population;
import fr.ifremer.isisfish.entities.PopulationGroup;
import fr.ifremer.isisfish.entities.Species;
import fr.ifremer.isisfish.entities.TargetSpecies;
import fr.ifremer.isisfish.rule.AbstractRule;
import fr.ifremer.isisfish.simulator.PopulationMonitor;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.TimeStep;
import fr.ifremer.isisfish.util.Doc;

/**
 * Cette methode remplace aussi TailleMinSurvieRejet si propSurvie est > 0
 * 
 * Created: 30 novembre 2006
 *
 * @author anonymous <anonymous@labs.libre-entreprise.org>
 * @version $Revision: 1.1 $
 *
 * Last update: $Date: 2007-01-24 18:25:34 $
 * by : $Author: bpoussin $
 */
public class TailleMin extends AbstractRule {

    /** to use log facility, just put in your code: log.info("..."); */
    static private Log log = LogFactory.getLog(TailleMin.class);

    @Doc(value = "Begin step")
    public TimeStep param_beginStep = new TimeStep(0);

    @Doc(value = "End date")
    public TimeStep param_endStep = new TimeStep(119);

    @Doc(value = "Affected species")
    public Species param_species = null;

    @Doc(value = "Taille minimale")
    public double param_TailleMin = 27;

    @Doc(value = "Proportion de survie")
    public double param_propSurvie = 0;
    
    public String[] necessaryResult = {
    // put here all necessary result for this rule
    // example: 
    // ResultName.MATRIX_BIOMASS,
    // ResultName.MATRIX_NET_VALUE_OF_LANDINGS_PER_STRATEGY_MET,
    };

    @Override
    public String[] getNecessaryResult() {
        return this.necessaryResult;
    }

    /**
     * Permet d'afficher a l'utilisateur une aide sur la regle.
     * 
     * @return L'aide ou la description de la regle
     */
    @Override
    public String getDescription() throws Exception {
        return _("Tous les poissons dont la taille est inf��rieure �� TailleMin" +
                " ne seront pas captur��s. Ils sont plac��s en rejets et rejet��s" +
                " suivant la proportion de survie.");
    }

    /**
     * Appel�� au d��marrage de la simulation, cette m��thode permet d'initialiser
     * des valeurs
     * 
     * @param context La simulation pour lequel on utilise cette regle
     */
    @Override
    public void init(SimulationContext context) throws Exception {
    }

    /**
     * @param context
     * @param date
     * @param param_species
     * @param metier
     * @return
     */
    private boolean isCaptureDate(TimeStep step, Species species, Metier metier) {
        MetierSeasonInfo info = metier.getMetierSeasonInfo(step.getMonth());
        TargetSpecies target = info.getSpeciesTargetSpecies(species);

        boolean result;
        if (target != null) {
            result = true;
        } else {
            result = false;
        }

        return result;
    }

    /**
     * La condition qui doit etre vrai pour faire les actions.
     * 
     * @param context la simulation pour lequel on utilise cette regle
     * @param step le pas de temps courant
     * @param metier le metier concern��
     * @return vrai si on souhaite que les actions soit faites
     */
    @Override
    public boolean condition(SimulationContext context, TimeStep step, Metier metier)
            throws Exception {
        log.info("Recherche si la taille Minimale s'applique");
        boolean result = true;
        if (step.before(param_beginStep)) {
            result = false;
        } else if (step.after(param_endStep)) {
            result = false;
        } else if (isCaptureDate(step, param_species, metier) != true) {
            result = false;
        }

        log.info("fin de condition TailleMin:" + result);
        return result;
    }

    /**
     * Si la condition est vrai alors cette action est executee avant le pas
     * de temps de la simulation.
     * 
     * @param context la simulation pour lequel on utilise cette regle
     * @param step le pas de temps courant
     * @param metier le metier concern��
     */
    @Override
    public void preAction(SimulationContext context, TimeStep step, Metier metier)
            throws Exception {
        // nothing
    }

    /**
     * Si la condition est vrai alors cette action est execut��e apres le pas
     * de temps de la simulation.
     * 
     * @param context La simulation pour lequel on utilise cette regle
     * @param step le pas de temps courant
     * @param metier le metier concern��
     */
    @Override
    public void postAction(SimulationContext context, TimeStep step, Metier metier)
            throws Exception {
        log.info("*$*$*$* TailleMin.actionApres:" + step + " metapop:" +
                param_species + " metier:" + metier);

        if (isCaptureDate(step, param_species, metier)) {
            log.info(
                    "*$*$*$* ok affecte capture inf��?rieure ��? TailleMin au rejet");
            // ATTENTION        
            // les captures pour cette metapop ne sont plus du qu'au metier pour qui 
            // l'espece est secondaire: elles sont affectees aux rejets

            //pb : ne se fait pas par metier
            //il faut une matrice pour chaques pas de temps qui stocke les rejets 
            //par metier, par metapop et par classes d'age (comme pour les captures)
            //////
            log.info("deb de affecterCaptureREJETTailleMin");

            PopulationMonitor popMon = context.getPopulationMonitor();
            SiMatrix siMatrix = SiMatrix.getSiMatrix(context);
            List<Population> pops = siMatrix.getPopulations(step);

            for (Population pop : pops) {
                if (pop.getSpecies().equals(param_species)) {
                    if (popMon.getDiscard(step, pop) == null) {
                        MatrixND discard = popMon.getCatch(pop).copy();
                        MatrixND eff = popMon.getN(pop);

                        for (MatrixIterator i = discard.iterator(); i.next();) {
                            Object[] coordonnees = i.getSemanticsCoordinates();
                            PopulationGroup group =
                                    (PopulationGroup) coordonnees[2];
                            if (group.getLength() >= param_TailleMin) {
                                i.setValue(0);
                            } else if (param_propSurvie > 0) {
                                eff.setValue(coordonnees[2], coordonnees[3],
                                        eff.getValue(coordonnees[2],
                                        coordonnees[3]) + i.getValue() *
                                        param_propSurvie);
                            }
                        }
                        discard.setName(
                                ResultName.MATRIX_DISCARDS_PER_STR_MET_PER_ZONE_POP);
                        popMon.addDiscard(step, pop, discard);
                    }
                }
            }

            log.info("fin de affecterCaptureRejetTailleMin");

            //on a affecte une fois cette meta pop au rejet il ne faut pas le refaire
        }
    }
}
