/*
 * #%L
 * IsisFish data
 * %%
 * Copyright (C) 2006 - 2015 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 3 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-3.0.html>.
 * #L%
 */
package rules;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import scripts.SiMatrix;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.nuiton.math.matrix.*;

import fr.ifremer.isisfish.simulator.MetierMonitor;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.TimeStep;
import fr.ifremer.isisfish.types.Month;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.rule.AbstractRule;

import fr.ifremer.isisfish.annotations.Doc;
import resultinfos.MatrixNoActivity;

/**
 * InterdictionEngin.java
 *
 * Created: 30 novembre 2006
 *
 * @author anonymous &lt;anonymous@labs.libre-entreprise.org&gt;
 * @version $Revision: 1.1 $
 *
 * Last update: $Date: 2007-01-24 18:25:34 $
 * by : $Author: bpoussin $
 */
public class InterdictionEngin extends AbstractRule {

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

    @Doc(value="Prohibited gear")
    public Gear param_gear = null;
    @Doc(value="Begin date")
    public TimeStep param_beginStep = new TimeStep(0);
    @Doc(value="End date")
    public TimeStep param_endStep = new TimeStep(119);
    @Doc(value="Begin month")
    public Month param_beginMonth = Month.JANUARY;
    @Doc(value="do the doc of param endMonth")
    public Month param_endMonth = Month.DECEMBER;

    protected String [] necessaryResult = {
        // put here all necessary result for this rule
        // example: 
        // MatrixBiomass.NAME,
        // MatrixNetValueOfLandingsPerStrategyMet.NAME
    };

    @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 {
        // interdiction des metiers utilisant cet engin
        return "Prohibited gear";
    }
 
    /**
     * 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 {
        // nothing
    }

    /**
     * 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("condition fermeture zone");
        boolean result = true;
        Month mois = step.getMonth();
        log.info("mois:" + mois);
        if (!(param_beginMonth.getMonthNumber() <= mois.getMonthNumber() 
                && mois.getMonthNumber() <= param_endMonth.getMonthNumber())) {
          result = false;
        } else {
            log.info("on est dans l'espace des mois possible");
            if (step.before(param_beginStep)) {
                result = false;
            } else if (step.after(param_endStep)) {
                result = false;
            } else if (!metier.getGear().equals(param_gear)) { 
                result = false;
            }
        }

        return result;
        // fin condition
    }
 
    /**
     * 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 {
        log.info("le metier vise par l'interdiction : " + metier);

        MetierMonitor metierMon = context.getMetierMonitor();
        metierMon.addforbiddenMetier(metier);
        
        // récupère toutes les stratégies pratiquant le métier et pour lesquelles la proportion !=0
        SiMatrix siMatrix = SiMatrix.getSiMatrix(context);
        List<Strategy> strs = siMatrix.getStrategies(step);
        List<Strategy> ListeStrat = new ArrayList<>();
        
        for (Strategy str : strs) {
            double prop = str.getStrategyMonthInfo(step.getMonth()).getProportionMetier(metier);
            if (prop != 0) {
                ListeStrat.add(str);
            }
        }
        
        for (Strategy Strat : ListeStrat) {
            StrategyMonthInfo StratMonthInfo = Strat.getStrategyMonthInfo(step.getMonth());
            
            // 1er cas:l'effort est reporte sur un metier de la meme strategie,
            // n'ayant pas l'espece comme capture principale et pechant avec le meme engin
            List<EffortDescription> MetiersPossibles = new ArrayList<>(Strat.getSetOfVessels().getPossibleMetiers());
          
            // on verifie que les metiers sont bien pratiques au mois courant, 
            // qu'ils n'ont pas le meme engin et qu'ils ne sont pas
            // interdits par ailleurs
            for (Iterator<EffortDescription> effort = MetiersPossibles.iterator();effort.hasNext();) {
                Metier met = effort.next().getPossibleMetiers();
                if (StratMonthInfo.getProportionMetier(met) == 0 
                        || met.getGear().equals(metier.getGear())
                        || met.getName().equalsIgnoreCase("nonActivite") 
                        || metierMon.isForbidden(metier, step.getMonth())){
                    effort.remove();
                }
            }   
          
            // on repartit maintenant l'effort entre les differents metiers
            // possibles dans la meme strategie si un metier possible existe bien
            if (MetiersPossibles.size() != 0) {
                int NbMetier=MetiersPossibles.size();
                for (EffortDescription effort : MetiersPossibles) {
                    Metier met = effort.getPossibleMetiers();
                    double NouvelleProportion = 
                        StratMonthInfo.getProportionMetier(met)
                        + (StratMonthInfo.getProportionMetier(metier) / NbMetier);
                    StratMonthInfo.setProportionMetier(met, NouvelleProportion);
                }
                StratMonthInfo.setProportionMetier(metier, 0); //le metier vise a alors une proportion nulle
            }
            // s'il n'y a pas de metier alternatif, on passe a nonActivite
            else {
                MatrixND matNonActivite = metierMon.getOrCreateNoActivity(step,
                        MatrixNoActivity.NAME,
                        siMatrix.getStrategies(step),
                        siMatrix.getMetiers(step));                                            
                matNonActivite.setValue(Strat, metier,
                        StratMonthInfo.getProportionMetier(metier));
                StratMonthInfo.setProportionMetier(metier, 0);
            }
        }

        // fin methode
    }
 
    /**
     * 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 {
        // nothing
    }

}
