package rules;

import java.util.*;
import java.io.*;
import java.util.regex.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


import org.nuiton.math.matrix.*;

import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.rule.AbstractRule;
import fr.ifremer.isisfish.annotations.Doc;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.types.*;

import scripts.SiMatrix;
import static scripts.PTAtoolbox.expandEnvirVar;

/**
 * Inspir�� du forcage nb vessels, prop_vessels, inactivity et prop_str_met_month
 * 2015-2022
 * Forcage prop_str_met_month
 * 2015-2018
 *
 *  projet Macco
 *
 * doit s'appliquer avec le forcage des parametres annuels calibr��s
 *
 *  Stephanie Mahevas 2023
 * -
 *     lecture d'un fichier par annee
 *
 *  
 *     
 */
 
public class ForcageEffort extends AbstractRule {
    
    /** to use log facility, just put in your code: log.info("..."); */
    private static Log log = LogFactory.getLog(ForcageEffort.class);
    
    public String param_README = String.join(" ��������� ",
                    "adaptation For��age Nb Navires "
            
    );
    

    /*public static String param_cheminFichierAverage = "${PBS_O_WORKDIR}/forcage/" ;*/
    public static String param_cheminFichierAverage = "C:/Users/Dedah/Desktop/TheThesis/Works/2024/ISIS_paper/Ressources/forcage/";
    public static String param_cheminFichierPropNbVess = "nb_prop_vessels/years/";  
    
    @Doc(value = "simulation starting year compared to estimation starting year (0: 2015; 1: 2016; 2: 2017; 3: 2018; 4:2019; 5:2020; 6:2021; 7:2022; 8 average 2010-22 or 2022)")
    public int param_startDate = 0;
    
    @Doc(value = "After 2018: true = mean effort 2010-22, false = effort 2022)")
    public boolean param_averagefrom2010 = false;
 
    private int param_year = param_startDate; //annee de debut

    private List<Strategy> allStrategies;
    private MatrixND matPropVess; //anneexmoisxstr
 
    Pattern ForeignPattern = Pattern.compile("^(ES|UK|BE)"); //pour les flottilles/str etrangeres on ne change pas nb_vessels=1 et prop_vessells=1
    private boolean first = true; // ne boucler que sur un seul m��tier dans la pr��action :
 
    public String[] necessaryResult = {}; // must be initialized, error if not
    public String[] getNecessaryResult() { return this.necessaryResult; }

    /** Permet d���afficher �� l���utilisateur une aide sur la r��gle */
    public String getDescription() {
        return "Forcage nb vessels, prop_vessels, inactivity et prop_str_met_month sur 2015-2022 et Forcage prop_str_met_month 2015-2018, puis valeurs de la derni��re annee disponible ou moyenne";
    }

    /**
     * Appel��e au d��marrage de la simulation, cette m��thode permet d���initialiser des valeurs.
     *
     * @param context la simulation pour lequel on utilise cette r��gle
     */
    public void init(SimulationContext context) throws Exception {
           log.info("------Init------");
           log.info("------Init------");
           log.info("------Init------");

      
           
        // r��cup��ration des set of vessels, strat��gies
        SiMatrix siMatrix = SiMatrix.getSiMatrix(context);
                   log.info("------SiMatrix------");

                   
        TimeStep step = new TimeStep(0);

        // r��cup��ration des strat��gies
        allStrategies = siMatrix.getStrategies(step);
        log.info("allStrategies ======= " + allStrategies);
        //allMetiers = siMatrix.getMetiers(step);
        //allSetOfVessels = getSetOfVessels(allStrategies);
        List<Month>allMonths=Arrays.asList(Month.MONTH);
        

        List<Integer> annees = List.of(0);
        List<Integer> allMonth = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);



        matPropVess = MatrixFactory.getInstance().create(
                "matPropVess", new List[] { annees, allMonth, allStrategies },
                new String[] { "Annee", "Mois" , "Strategies" });
           log.info("---------------------- Entree --------------------------------------  ");
        String param_StringYear;
        //chargement dans l'init des matrices pour toutes les annnees 
        // Boucle sur les annees (year) de startDate a endDate  pour remplir les matrices
        // Import des matrices 2015,2016,2017,2018,moyenne2010-2020

       param_cheminFichierAverage = expandEnvirVar.replace(param_cheminFichierAverage);
  
        for (Integer annee : annees) {
            //param_year = 2015 + annee;
            param_year = annee;
           log.info("---------------------- Annee ------------- =  " + param_year);
            System.out.println("---------------------- Annee --------------  =  " + param_year);
            // NEW : nb vessels de set of vessels :fichier avec semantic des setof vessels et annee de 0 =2015 �� ...

            // propVess ?
            File propVessFile = new File(param_cheminFichierAverage + param_cheminFichierPropNbVess + param_year + "_allMonthStrategy.txt"); //double nbv = matNbVess.getValue(str, ts.getYear()); donc fichier avec semantic des strat��gies et annee de 0 =2015 �� ...

            MatrixND matPropVessForYear = MatrixFactory.getInstance().create(propVessFile);
    for (Integer mois : allMonth) {
            for (Strategy str : allStrategies) {
                String strName = str.getName();
                Matcher ForeignMatch = ForeignPattern.matcher(strName);
                if (!ForeignMatch.find()) {
                    log.info("strategie = " +strName);
                    log.info("matPropVessForYear.getSemantic(0).contains(str) ========"+matPropVessForYear.getSemantic(0).contains(str));

                  if (matPropVessForYear.getSemantic(0).contains(str)) {  
                   matPropVess.setValue(annee, mois, str, matPropVessForYear.getValue(mois, str));
                   log.info("Valeur _______________________"+ matPropVessForYear.getValue(mois, str));
                  } 
                  else {
                   matPropVess.setValue(annee, mois, str, 2);  
                   }
                }
            }
    }
            log.info("matrice prop navires Set of Vessels " + matPropVess);
      }
    }

    /**
     * La condition qui doit ��tre vraie pour faire les actions.
     *
     * @param context la simulation pour laquelle on utilise cette r��gle
     * @param step le pas de temps courant
     * @param metier le m��tier concern��
     * @return vrai si on souhaite que les actions soit faites
     */
    public boolean condition(SimulationContext context, TimeStep step, Metier metier) { 
       
        int start = param_startDate * 12; // If startDate != 0 si debut en 2013 8*12 = 96 par rapport �� 2015
        TimeStep ts = step.add(start);
        boolean beforeEndYearForcage = (ts.getStep() < 84); //84 si forcage jqu'en 2022
        if (beforeEndYearForcage){ // before  do preaction
             return true; 
        } else {
           if (param_averagefrom2010) { 
            return false; // Do not change prop_str : on utlise la moyenne2010-2020 qui est par defaut dans la base
           } else {
            return true; // do preaction and use 2022 values
           }
        }

    }

    /** Si la condition est vraie alors cette action est ex��cut��e avant le pas de temps de la simulation. */
    public void preAction(SimulationContext context, TimeStep step, Metier metier) {

        if (first) {
            log.info("Oui, preaction");
            
            System.out.println("Oui, preaction : ");

            // If startDate != 0
            int start = param_startDate * 12; // si on demarre en 2023 start = 8*12 = 96
            TimeStep ts = step.add(start); //time step relative to 2015
            TimeStep ts_str = step.add(start); //time step relative to 2015
         
            //if (step.getStep() + 12 > 47) ts_str = new TimeStep(ts.getMonth().getMonthNumber() + 36); // prop effort dans str �� partir de 2019 = 2018
            // time step de 2018 par rapport �� 2015 = 3*12 = 36, 2019 : 4*12 = 48
            if (ts.getStep() > 47) ts_str = new TimeStep(ts.getMonth().getMonthNumber() + 36); //  �� partir de 2019, on simule avec valeur de prop effort dans str de  2018

            //if (step.getStep() + 12 > 59) ts = new TimeStep(ts.getMonth().getMonthNumber() + 48); // une annee de plus - ne marchera que quand on aura une moyenne
            //84 si forcage jqu'en 2022
            //72 si forcage jqu'en 2021
            //time step de 2023 par rapport �� 2015 = 8*12 = 96, 2022 : 7*12 = 84
            if (ts.getStep() > 95) ts = new TimeStep(ts.getMonth().getMonthNumber() + 84); // ie �� partir de 2023, on simule avec valeur de 2022
           log.info("Timestep : " + ts);


            // Boucle sur les strat��gies
            for (Strategy strIndex : allStrategies) {
                log.info("---------------------- Strategie -----------------");
                String strName = strIndex.getName();
                log.info("Strategie : " + strName);

                // interdit de faire des set sur les strat��gies de la s��mantique de la matrice, il faut r��cup��rer les strat��gies de la date courante
                Strategy str = (Strategy) context.getDB().findByTopiaId(strIndex.getTopiaId());

                // Change prop_vessel number
                Matcher ForeignMatch = ForeignPattern.matcher(strName);
                if (ForeignMatch.find()) {
                   log.info("    foreign, don���t change prop vessells");
                } else {
                    double nbv = matPropVess.getValue(ts.getYear(),ts.getMonth().getMonthNumber(), str);
                    str.setProportionSetOfVessels(nbv);
                    log.info("Year: " + ts.getYear());
                    log.info("Mois : " + ts.getMonth().getMonthNumber());
                    log.info("Strategie : " + str);
                    log.info("Nb bateaux : " + nbv);
                    
                }

                // Change Inactivity ��quation
                //double newInactivity = matInactivity.getValue(ts.getYear(), str, ts.getMonth());
                //double newInactivity = 20;
                //System.out.println("newInactivity :" + newInactivity);
                Equation eqInac = str.getInactivityEquation();
                //eqInac.setContent("return " + newInactivity + " ;");
                str.setInactivityEquationUsed(true) ;
                System.out.println("Inactivity :" + eqInac.getContent());

                log.info("Inactivity :" + eqInac.getContent());
                
            }
            first = false;
        }

    }

    /** Si la condition est vraie alors cette action est ex��cut��e apr��s le pas de temps de la simulation. */
    public void postAction(SimulationContext context, TimeStep step, Metier metier) { first = true; }

}
