package rules;

import static org.nuiton.i18n.I18n._;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
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 org.nuiton.math.matrix.*;
import scripts.ResultName;
import scripts.SiMatrix;

import fr.ifremer.isisfish.simulator.MetierMonitor;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.Date;
import fr.ifremer.isisfish.types.Month;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.rule.AbstractRule;
import scripts.ResultName;
import scripts.SiMatrix;
import fr.ifremer.isisfish.entities.Metier;
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.simulator.PopulationMonitor;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.simulator.ResultManager;
import fr.ifremer.isisfish.types.Date;
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 : $Camille de la Vega $
 */
public class Ogive_de_Rejet extends AbstractRule {

    /** to use log facility, just put in your code: log.info("..."); */
    static private Log log = LogFactory.getLog(Ogive_de_Rejet.class);

    @Doc(value = "Begin date")
    public Date param_beginDate = new Date(0);

    @Doc(value = "End date")
    public Date param_endDate = new Date(119);

    @Doc(value = "Affected species")
    public Species param_species = null;

    @Doc(value = "param_Retention_L50")
    public double param_Retention_L50 = 29.4307;

    @Doc(value = "param_Retention_slope")
    public double param_Retention_slope = 2.02485;

    @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;
    }
    
	boolean flagBouclePostAction = false;
    /**
     * 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 _("l'abondance de poissons captur" + " ne seront pas captur"
                + " suivant la proportion de survie.");
    }

    /**
      * 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(Date date, Species species, Metier metier) {
    ///        MetierSeasonInfo info = metier.getMetierSeasonInfo(date.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
     * @return vrai si on souhaite que les actions soit faites
     */
    @Override
    public boolean condition(SimulationContext context, Date date, Metier metier)
            throws Exception {
        //log.info("Recherche si la taille Minimale s'applique");
        boolean result = true;
        if (date.before(param_beginDate)) {
            result = false;
        } else if (date.after(param_endDate)) {
            result = false;
        }
        ////else if (isCaptureDate(date, param_species, metier) != true) {
        ////result = false;
        ////}

        log.info("fin de condition TailleMin:" + result);
        return result;

        // fin
    }

    /**
     * Si la condition est vrai alors cette action est execut
          * temps de la simulation.
     * 
     * @param context La simulation pour lequel on utilise cette regle
     */
    @Override
    public void preAction(SimulationContext context, Date date, Metier metier)
            throws Exception {
        flagBouclePostAction = false; // remise false pour pouvoir passer dans postaction
    }

    /**
     * Si la condition est vrai alors cette action est execut
          * temps de la simulation.
     * @param context La simulation pour lequel on utilise cette regle
     */
    @Override
    public void postAction(SimulationContext context, Date date, Metier metier)
            throws Exception {
        //log.info("*$*$*$* TailleMin.actionApres:" + date + " metapop:"
        //        + param_species + " metier:" + metier);

        // 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)
        //////
		if (flagBouclePostAction == false) {
		 // pour faire le travail que pour le premier metier
        log.info("deb de affecterCaptureREJETOgive");
        
            PopulationMonitor popMon = context.getPopulationMonitor();
            SiMatrix siMatrix = SiMatrix.getSiMatrix(context);
            List<Population> pops = siMatrix.getPopulations(date);
            
            for (Population pop : pops) { 
                if (pop.getSpecies().equals(param_species)) {
                       MatrixND discard = popMon.getCatch(pop).copy(); // initialisation de discard au bon format
                       for (MatrixIterator i = discard.iterator(); i.next();) {
							//i.setValue(0); //initialisation 0 des rejets
                            Object[] coordonnees = i.getSemanticsCoordinates();
                            // log.info("coordonnees[0]" + coordonnees[0]);
                             //log.info("coordonnees[1]" + coordonnees[1]);
                             // log.info("coordonnees[2]" + coordonnees[2]);
                              //log.info("coordonnees[3]" + coordonnees[3]);
                             // log.info("coordonnees[4]" + coordonnees[4]);
                            PopulationGroup group =
                                    (PopulationGroup) coordonnees[2];
                            Metier met = (Metier) coordonnees[1];
                            //log.info("coordonnees[1]" + coordonnees[1]);
                             //log.info("met.getName()" + met.getName());
                            // calcul de l'ogive de rejet en fonction des metier
                            if ( met.getName().equals("metier lang simp Sud") || 
							     met.getName().equals("metier lang simp Nord") || 
								 met.getName().equals("metier lang simple") || 
								 met.getName().equals("metier lang jum Nord") || 
								 met.getName().equals("metier lang jum Sud") || 
								 met.getName().equals("metier lang jum")) {
                              double trie = 1 / (1 + Math.exp(-(group.getLength() - param_Retention_L50)/ param_Retention_slope));
                              double rejet = 1 - trie;
                              log.info("REJETS" + rejet);
							  double catchValue = i.getValue();
							  //log.info("catchValue" + catchValue);
							  double value = catchValue * rejet;
							  //log.info("VALUE" + value);
							  i.setValue(value);
                            }else{
                            	i.setValue(0); //initialisation ÃƒÂ  0 des rejets
                          }	
							//si ce n'est pas un metier qui genere des rejets, on ne fait rien rejet=0
							
                       } 
				// ajout de la matrice rejet au populationMonitor
				discard.setName(
                    ResultName.MATRIX_DISCARDS_PER_STR_MET_PER_ZONE_POP);
				popMon.addDiscard(date, pop, discard);						  
			    }
            }

            log.info("fin de affecterCaptureREJETOgive");
		   flagBouclePostAction = true; // pour ne pas repasser dans postaction au prochain metier de la boucle
		}
    }
}
