/*
 * Copyright (C) 2014 slehuta
 *
 * 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>.
 */

package rules;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import scripts.ResultName;

import java.io.Writer;

import org.nuiton.math.matrix.*;

import fr.ifremer.isisfish.util.Doc;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.TimeStep;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.rule.AbstractRule;
import fr.ifremer.isisfish.datastore.SimulationStorage;
import fr.ifremer.isisfish.datastore.ResultStorage;
import fr.ifremer.isisfish.types.Month;
import fr.ifremer.isisfish.simulator.PopulationMonitor;
import java.util.List;

/**
 * TailleMin_LandingsObligation.java
 *
 * Created: 5 septembre 2014
 *
 * @author slehuta <user.name@vcs.hostName>
 * @version $Revision: 1545 $
 * Last update: $Date: 5 septembre 2014 $
 * by : $Author: slehuta $
 */
public class TailleMin_OptionLO extends AbstractRule {

    /** to use log facility, just put in your code: log.info("..."); */
    private static Log log = LogFactory.getLog(TailleMin_OptionLO.class);
    
    public Population param_pop = null;
    public TimeStep param_beginStep = new TimeStep(0);
    public TimeStep param_endStep = new TimeStep (119);
    @Doc(value = "Taille minimale")
    public double param_TailleMin = 27;
	@Doc(value = "Proportion de survie")
    public double param_propSurvie = 0;
    public boolean param_LandingsObligation = false;
    public boolean param_deMinimis = false;
	
    protected boolean affectation = true;
    
    protected String[] necessaryResult = {
        // put here all necessary result for this rule
	   ResultName.MATRIX_DISCARDS_PER_STR_MET_PER_ZONE_POP
	    // ResultName.MATRIX_BIOMASS,
	    // ResultName.MATRIX_NET_VALUE_OF_LANDINGS_PER_STRATEGY_MET,
    };

    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
     */
    public String getDescription() throws Exception {
        // TODO
        return "Tous les poissons dont la taille est inferieure a TailleMin"
                + " ne seront pas debarques. Ils sont places en rejets et survivent"
                + " selon la proportion de survie. Si l'obligation de debarquer est" 
                + " implementee, ils sont debarques mais leur prix est null.";
    }

    /**
     * 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
     */
    public void init(SimulationContext context) throws Exception {
     // TODO
    }

    /**
     * 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
     */
    public boolean condition(SimulationContext context, TimeStep step, Metier metier) throws Exception {
        boolean result = true;
        if(step.before(param_beginStep) || step.after(param_endStep) ){
            result = false;
        } else if(context.getValue("TACatteint"+param_pop.getName()) !=null &&
				(Boolean) context.getValue("TACatteint"+param_pop.getName())){
			result = false; // TAC atteint plus de MLS
		} else { // TAC pas atteint
            if(param_LandingsObligation){
				context.setValue("priceMLS"+param_pop.getName(),1); 
            }else {
				context.setValue("priceMLS"+param_pop.getName(),0);
            }
            context.setValue("MLS"+param_pop.getName(),param_TailleMin);

            result = true;
        }
        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ÃƒÆ’Ã†â€™Ãƒâ€ Ã¢â‚¬â„¢ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â©
     */
    public void preAction(SimulationContext context, TimeStep step, Metier metier) throws Exception {
                    affectation = true;
        
    }

    /**
     * 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ÃƒÆ’Ã†â€™Ãƒâ€ Ã¢â‚¬â„¢ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â©
     */
    public void postAction(SimulationContext context, TimeStep step, Metier metier) throws Exception {
        if (affectation) {
            //log.info("*$*$*$* ok affecte capture inferieure a 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();

            int groupDim = 2;
            int zoneDim = 3;

            //for (Population pop : param_species.getPopulation()) {
                MatrixND discard = popMon.getCatch(param_pop).copy();
                discard.setName(ResultName.MATRIX_DISCARDS_PER_STR_MET_PER_ZONE_POP);

                MatrixND eff = popMon.getN(param_pop);

                // collect les tailles des groupes pour eviter de multiples appels a la methode
                // getLength dans la boucle
                List<PopulationGroup> groups = (List<PopulationGroup>)discard.getSemantic(2);
                double[] length = new double[groups.size()];
                int cpt = 0;
                for (PopulationGroup group : groups) {
                    length[cpt++] = group.getLength();
                }

                // on iter que sur les valeurs != 0, car si deja zero, ca ne
                // sert a rien de le mettre a 0
                for (MatrixIterator i = discard.iteratorNotZero(); i.next();) {
                    int[] pos = i.getCoordinates();
                    int groupIndex = pos[groupDim];
					Object[] coordonnees = i.getSemanticsCoordinates();
					Metier met = (Metier) coordonnees[1];
					// if species is a primary catch de minimis -> right to discard
					//boolean deminimis = met.getMetierSeasonInfo(step.getMonth()).getSpeciesTargetSpecies(param_pop.getSpecies()).isPrimaryCatch() ;
                    boolean deminimis =(context.getValue(met.getName()+param_pop.getName()+"flag")!= null && (int) context.getValue(met.getName()+param_pop.getName()+"flag")==1); // il a le droit de rejeter
					
					if (length[groupIndex] >= param_TailleMin || (param_LandingsObligation && !param_deMinimis) || (param_LandingsObligation && param_deMinimis && !deminimis)) { //pas rejete
                        i.setValue(0);
                    } else if (param_propSurvie > 0) {
                        PopulationGroup group = (PopulationGroup) coordonnees[groupDim];
                        Zone zone = (Zone)coordonnees[zoneDim];
                        eff.setValue(group, zone,
                                eff.getValue(group, zone)
                                        + i.getValue() * param_propSurvie);
                    }
                }
                popMon.addDiscard(step, param_pop, discard);
        //}

            //log.info("fin de affecterCaptureRejetTailleMin");

            // on a affecte une fois cette meta pop au rejet il ne faut pas le
            // refaire pour ce pas de temps
            affectation = false;
        }
    }
}
