package rules;

import static org.codelutin.i18n.I18n._;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import scripts.ResultName;
import scripts.SiMatrix;

import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import org.codelutin.math.matrix.*;

import fr.ifremer.isisfish.IsisFishDAOHelper;
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 fr.ifremer.isisfish.datastore.RegionStorage;
import fr.ifremer.isisfish.datastore.SimulationStorage;
import fr.ifremer.isisfish.datastore.ResultStorage;

import fr.ifremer.isisfish.util.Doc; // pour pouvoir afficher une aide contextuelle (BUG#1605)

/**
 * TailleMin.java
 *
 * 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 ChangementParamControlablePresimu_Chirine extends AbstractRule {

    /** to use log facility, just put in your code: log.info("..."); */
    static private Log log = LogFactory.getLog(ChangementParamControlablePresimu_Chirine.class);

    @Doc(value="do the doc of param zone")
    public Zone param_zone = null;
    @Doc(value="do the doc of param gear")
    public Gear param_gear = null;
    @Doc(value="do the doc of param beginMonth")
    public Month param_beginMonth = Month.JANUARY;
    @Doc(value="do the doc of param endMonth")
    public Month param_endMonth = Month.DECEMBER;
    @Doc(value="do the doc of param newParamValue")
    public String param_newParamValue = "80";

    public String [] necessaryResult = {
    // put here all necessary result for this rule
    // example: 
    // 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 {
        return _("Change gear parameter value for all metier with this gear");
    }
 
    /**
     * Appelé au démarrage de la simulation, cette méthode permet d'initialiser
     * des valeurs
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    public void init(SimulationContext context) throws Exception {
        SiMatrix siMatrix = SiMatrix.getSiMatrix(context);
        
        Zone ZoneFermee = param_zone; 
        Month MoisDeb = param_beginMonth;
        Month MoisFin= param_endMonth;
        String nouvelleValeurParam = param_newParamValue;
        Gear EnginInterdit = param_gear;
        
        log.info("nom de l'engin interdit " + EnginInterdit.getName());
        
        FisheryRegion RegionSimu = RegionStorage.getFisheryRegion(context.getDB());
        List<Metier> ListeMetiers = RegionSimu.getMetier();
        List<Month> SaisonFermee = Month.getMonths(MoisDeb, MoisFin);

        for (Metier metier : ListeMetiers) {
            log.info("metier examiné " + metier.getName() + " son engin " + metier.getGear().getName());
            if (!metier.getGear().equals(EnginInterdit)){
                log.info("l engin du métier n est pas concerné");
            } else {
                log.info("l engin du métier est bien concerné");
                if (ZoneFermee == null && Month.JANUARY.equals(MoisDeb) && Month.DECEMBER.equals(MoisFin)){
                    //aucun critère spatio-temporel il suffit donc de mettre
                    //le param controlable à la nouvelle valeur
                    metier.setGearParameterValue(nouvelleValeurParam);
                    log.info("aucune spatialisation ni saisonnalité, on passe le Param Controlable a "+nouvelleValeurParam);
                } else {   
                    List<MetierSeasonInfo> ListeSaisons = metier.getMetierSeasonInfo();
                    for (MetierSeasonInfo saisonmetier : ListeSaisons) {
                        List<Month> saison = saisonmetier.getMonths();
                        int taille=0;
                        if (ZoneFermee != null){
                            taille = siMatrix.nbCellInter(saisonmetier.getZone(), ZoneFermee);
                        } else {
                            log.info ("pas de sélection de zone, toute la zone d'étude est donc concernée");
                        }
                        if (ZoneFermee == null || taille!=0){
                            if (saison.containsAll(SaisonFermee)){
                                log.info ("il y a intersection de la zone metier au cours de la saison" + saison);
                                List<Month> moisconcerne = new ArrayList<Month>(saison);
                                moisconcerne.retainAll(SaisonFermee);
                                
                                MetierDAO metierDao = IsisFishDAOHelper.getMetierDAO(context.getDB());
                                MetierSeasonInfoDAO infoDao = IsisFishDAOHelper.getMetierSeasonInfoDAO(context.getDB());
                                EffortDescriptionDAO effortDao = IsisFishDAOHelper.getEffortDescriptionDAO(context.getDB());
                                
                                Metier NouveauMetier = metierDao.create();
                                NouveauMetier.setName(metier.getName()+" Mois "+moisconcerne.get(0).getMonthNumber()+" a "+moisconcerne.get(moisconcerne.size()-1).getMonthNumber()+" ValeurParam "+nouvelleValeurParam);
                                NouveauMetier.setGear(EnginInterdit);
                                NouveauMetier.setGearParameterValue(nouvelleValeurParam);
                                NouveauMetier.setComment("métier créé pendant la simu pour le changement de paramètre contrôlable");
                                
                                for (MetierSeasonInfo infsais : metier.getMetierSeasonInfo()){
                                    List<Month> sais = infsais.getMonths();
                                    MetierSeasonInfo NouveauInfoSaison = infoDao.create();
                                    NouveauInfoSaison.setMetier(NouveauMetier);
                                    NouveauInfoSaison.setFirstMonth(sais.get(0));
									NouveauInfoSaison.setLastMonth(sais.get(sais.size()-1));
                                    NouveauInfoSaison.setZone(infsais.getZone());
                                    NouveauInfoSaison.setComment("créé durant la simulation");
                                    NouveauMetier.addMetierSeasonInfo(NouveauInfoSaison);
                                }
                                
                                //On ajoute aux strategies qui pratiquent le métier le nouveau métier
                                List<Strategy> listestrategies = RegionSimu.getStrategy();
                                for(Strategy strategie : listestrategies){
                                    SetOfVessels SetOfBateau = strategie.getSetOfVessels();
                                    EffortDescription AncienEffort = SetOfBateau.getPossibleMetiers(metier);
                                    if (AncienEffort != null) {
                                        EffortDescription DescriptionEffort = effortDao.create();
                                        DescriptionEffort.setPossibleMetiers(NouveauMetier);
                                        DescriptionEffort.setSetOfVessels(SetOfBateau);
                                        DescriptionEffort.setFishingOperation(AncienEffort.getFishingOperation());
                                        DescriptionEffort.setFishingOperationDuration(AncienEffort.getFishingOperationDuration());
                                        DescriptionEffort.setGearsNumberPerOperation(AncienEffort.getGearsNumberPerOperation());
                                        DescriptionEffort.setCrewSize(AncienEffort.getCrewSize());
                                        DescriptionEffort.setUnitCostOfFishing(AncienEffort.getUnitCostOfFishing());
                                        DescriptionEffort.setFixedCrewSalary(AncienEffort.getFixedCrewSalary());
                                        DescriptionEffort.setCrewShareRate(AncienEffort.getCrewShareRate());
                                        DescriptionEffort.setCrewFoodCost(AncienEffort.getCrewFoodCost());
                                        DescriptionEffort.setRepairAndMaintenanceGearCost(AncienEffort.getRepairAndMaintenanceGearCost());
                                        DescriptionEffort.setLandingCosts(AncienEffort.getLandingCosts());
                                        DescriptionEffort.setOtherRunningCost(AncienEffort.getOtherRunningCost());
                                        
                                        SetOfBateau.addPossibleMetiers(DescriptionEffort);
                                        
                                        // on a ajouté le nouveau métier au set of vessels,
                                        // maintenant, on va reporté l'effort du métier ancien
                                        // vers le nouveau pour les mois concernés
                                        for (Month mois : Month.MONTH){
                                            StrategyMonthInfo PropStratMois = strategie.getStrategyMonthInfo(mois);
                                            double prop = PropStratMois .getProportionMetier(metier);
                                            if (moisconcerne.contains(mois) && prop != 0){
                                                //on créé un nouveau PropStrMet
                                                log.info ("la stratégie "+strategie.getName()+" pratique bien le metier "+metier.getName()+" au mois " + mois);
                                                PropStratMois.setProportionMetier(NouveauMetier, prop); 
                                                PropStratMois.setProportionMetier(metier, 0);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        // fin de la methode
        
        /*
this.p = new Object();
this.p.paramRegle = this.param;


//attention: cette règle de gestion ne fonctionne que si le changement a lieu pour toutes
//les années de simulation


var zoneselective=this.param.getValue("Zone Tot"); //entrez le nom de la zone concernée, non si pas de sélection sur zone
var moisDeb=this.param.getValue("janiver0"); //entrez le mois debut de fermeture
var moisFin=this.param.getValue("decembre9");//entrez le mois de fin de fermeture
var nouvelleValeurParam=this.param.getValue("90");//entrez la valeur du paramètre contrôlable


if (zoneselective!="non") {
    var ZoneFermee=this.param.getValue("zone");
}
var EnginInterdit=this.param.getValue("engin");
writeln("nom de l'engin interdit "+EnginInterdit.getNom());
var RegionSimu=EnginInterdit.getRegion();
var ListeMetiers=MetierFactory.findAllByRegion(RegionSimu);
var MoisDeb=new Packages.fr.ifremer.nodb.Mois(moisDeb);
var MoisFin=new Packages.fr.ifremer.nodb.Mois(moisFin);
var SaisonFermee= new Packages.fr.ifremer.nodb.Saison(moisDeb,moisFin);




for (var imetier = ListeMetiers.iterator() ; imetier.hasNext();){
    var metier=imetier.next();
    writeln ("metier examiné "+metier.getNom()+"son engin "+metier.getEngin().getNom());
    if (!metier.getEngin().equals(EnginInterdit)){
        writeln("l engin du métier n est pas concerné");
    }
    else {
        writeln("l engin du métier est bien concerné");
        if (zoneselective==false && moisDeb==0 && moisFin==11){
            //aucun critère spatio-temporel il suffit donc de mettre
            //le param controlable à la nouvelle valeur
            metier.setValeurParamControlable(nouvelleValeurParam);
            writeln("aucune spatialisation ni saisonnalité, on passe le Param Controlable a "+nouvelleValeurParam);
        }
        else {   
            var ListeSaisons = metier.getInfoSaison();
            for (var isaisonmetier = ListeSaisons.iterator() ; isaisonmetier.hasNext();){
                var saisonmetier=isaisonmetier.next();
        var saison=saisonmetier.getSaison();
        var taille=0;
                if (zoneselective){
                    var maillefermee=ZoneFermee.getMaille();
                    var MailleMetier=saisonmetier.getSecteur().getMaille().copy();
                    MailleMetier.retainAll(maillefermee);
                    taille=MailleMetier.size();
                }
            else {
            writeln ("pas de sélection de zone, toute la zone d'étude est donc concernée");
        }
                if (zoneselective==false || taille!=0){
                    if (saison.contains(SaisonFermee)){
                        writeln ("il y a intersection de la zone metier au cours de la saison"+saison.toString());
                        var moisconcerne=saison.copy().toListMois();
                        moisconcerne.retainAll(SaisonFermee.toListMois());
                        var NouveauMetier=MetierFactory.create(metier.getNom()+" Mois "+moisconcerne.get(0).getNumMois()+" a "+moisconcerne.get(moisconcerne.size()-1).getNumMois()+" ValeurParam "+nouvelleValeurParam, RegionSimu, EnginInterdit,nouvelleValeurParam, "métier créé pendant la simu pour le changement de paramètre contrôlable");
                        for (var iinfsais=metier.getInfoSaison().iterator();iinfsais.hasNext();){
                var infsais=iinfsais.next();
                var sais=infsais.getSaison();
                var NouveauInfoSaison=InfoSaisonMetierFactory.create(NouveauMetier, sais, infsais.getSecteur(), "créé durant la simulation")
                NouveauMetier.addInfoSaison(NouveauInfoSaison);
            }

                        //On ajoute aux strategies qui pratiquent le métier le nouveau métier
                        var listestrategies=StrategyFactory.findAllByRegion(RegionSimu);
                        for(var i=0; i<listestrategies.size(); i++){
                            var strategie=listestrategies.get(i);
                            var SetOfBateau=strategie.getSetOfVessels();
                            var MetiersPosibles=SetOfBateau.getMetiers();
                            if (MetiersPosibles.contains(metier)){
                                var AncienEffort=SetOfBateau.getEffort(metier);
                                var DescriptionEffort=EffortDescriptionFactory.create(NouveauMetier, SetOfBateau, AncienEffort.getFishingOperation(), AncienEffort.getFishingOperationDuration(), AncienEffort.getGearsNumberPerOperation(), AncienEffort.getCrewSize(), AncienEffort.getUnitCostOfFishing(), AncienEffort.getFixedCrewSalary(), AncienEffort.getCrewShareRate(), AncienEffort.getCrewFoodCost(), AncienEffort.getRepairAndMaintenanceGearCost(), AncienEffort.getLandingCosts(), AncienEffort.getOtherRunningCosts(), "effort description créé durant la simulation");

                SetOfBateau.addPossibleMetiers(DescriptionEffort);

                    //on a ajouté le nouveau métier au set of vessels, maintenant, on va reporté l'effort du métier ancien vers le nouveau pour les mois concernés
                                for (var intmois=0; intmois<=11;intmois++){
                                    var mois=new Packages.fr.ifremer.nodb.Mois(intmois);
                                    var PropStratMois=strategie.getStrategyMonthInfo(mois);
                                    var NouveauStrMet=PropStrMetFactory.create(PropStratMois, NouveauMetier, 0, "créé durant la simulation");
                    PropStratMois.addPropStrMet(NouveauStrMet);
                    if (moisconcerne.contains(mois) && PropStratMois.getProportionMetier(metier)!=0){
                                        //on créé un nouveau PropStrMet
                                        writeln ("la stratégie "+strategie.getName()+" pratique bien le metier "+metier.getNom()+" au mois "+mois.getNumMois());
                                        PropStratMois.setProportionMetier(NouveauMetier,new Packages.java.lang.Float(PropStratMois.getProportionMetier(metier))); 
                                        PropStratMois.setProportionMetier(metier,new Packages.java.lang.Float(0));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
} 
         */
    }
    
    /**
     * La condition qui doit etre vrai pour faire les actions
     * @param simulation La simulation pour lequel on utilise cette regle
     * @return vrai si on souhaite que les actions soit faites
     */
    public boolean condition(SimulationContext context, Date date, Metier metier) throws Exception {
        return false;
    }
 
    /**
     * Si la condition est vrai alors cette action est executée avant le pas
     * de temps de la simulation.
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    public void preAction(SimulationContext context, Date date, 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 simulation La simulation pour lequel on utilise cette regle
     */
    public void postAction(SimulationContext context, Date date, Metier metier) throws Exception {
        // nothing
    }

}
