package analyseplans;

import static org.codelutin.i18n.I18n._;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import scripts.ResultName;

import java.io.*;
import java.io.File;
import java.io.FileReader;
import java.io.Writer;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.codelutin.math.matrix.*;
import org.codelutin.util.*;
import org.codelutin.topia.*;

import fr.ifremer.isisfish.*;
import fr.ifremer.isisfish.types.*;
import fr.ifremer.isisfish.rule.Rule;
import fr.ifremer.isisfish.rule.RuleHelper;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.Date;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.simulator.AnalysePlan;
import fr.ifremer.isisfish.simulator.AnalysePlanContext;
import fr.ifremer.isisfish.simulator.SimulationParameter;
import fr.ifremer.isisfish.datastore.RegionStorage;
import fr.ifremer.isisfish.datastore.RuleStorage;
import fr.ifremer.isisfish.datastore.SimulationStorage;
import fr.ifremer.isisfish.datastore.ResultStorage;

/**
 * Sensibility.java
 *
 * Created: 21 décembre 2008
 *
 * @author HUSSEIN chirine <m475chi@yahoo.fr>
 *
 */
public class Sensibility implements AnalysePlan {

    /** to use log facility, just put in your code: log.info("..."); */
    static private Log log = LogFactory.getLog(Sensibility.class);

    static private final String MATRIX = "matrix"; /// Le fichier est donc matrix.txt
    static private final String VBGF = "growth";
    static private final String SELECTIVITY = "selectivity";
    static private final String CATCHABILITY = "capturabilite";
    static private final String MORTALITY = "mortalite";
    static private final String STANDARDISATION = "standardisation";
    static private final String AMP = "amp";

public int param_parameterNumber = 6; /// ce paramètre n'est normalement pas modifié
    public int param_first = 0; /// on utilise ce paramètre pour indiquer à quelle ligne 
		/// de la matrice on doit commencer à faire tourner les simulations au cas où on ait dû interompre le plan
    public int param_simulationNumber = 64;/// ce paramètre n'est normalement pas modifié 
    public String param_directory = "C:/Documents and Settings/hussein/Bureau/isis-fish-3.1.3/isis-fish-3.1.3/fichier paramètres//"; /// Il s'agit du chemin vers le dossier 
	///contenant les fichier de matrice et paramètres, par défaut le repertoire du go.bat 
	/// donc dans ce cas c'est le dossier Exemple_repertory qui est dans le dossier contenant le go.bat
  
/// Déclaration de la matrice d'expérience 

 private MatrixND matrix = null;

/// Non utilisé pour ce script mais à ne pas effacer
    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 le plan.
     * @return L'aide ou la description du plan
     */
    public String getDescription() throws Exception {
       
        return _("réalise les expériences d'un plan complet pour 6 parametres à 2 modalités");
    }
 
    /**
     * 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(AnalysePlanContext context) throws Exception {
/// Création de la matrice d'expérience et chargement :
File dir = new File(param_directory);

File csvFile = new File(dir, MATRIX + ".txt");
log.info("CSV file is : " + csvFile.getAbsolutePath());
if(!csvFile.exists()) {
log.warn("File doesn't exists");
}

matrix = MatrixFactory.getInstance().create(new int[]{param_simulationNumber, param_parameterNumber});
matrix.importCSV(new FileReader(csvFile), new int[]{0,0});
matrix.setSemantics(1, Arrays.asList(new String[]{VBGF,CATCHABILITY,MORTALITY, STANDARDISATION, SELECTIVITY, AMP}));
System.out.println(matrix);
System.out.println("amp 0 : "+ matrix.getValue(0,AMP));
/// ajout des regles qui sont modifiées par le plan
context.getParam().addExtraRules("Cantonnement");
}

         /// Création des méthodes qui réccupère dans la matrice la modalité du paramètre pour l'expérience en cours 
		/// Les arguments des méthodes sont le nom du fichier et le numéro de la simulation
		/// (On détermine l'expérience en cours et donc la ligne de la matrice en sommant le numéro de la simulation et le param_first)
		/// pour un double  

 private double getDouble(String name, int simulation) throws Exception {
        File dir = new File(param_directory);
        Properties prop = new Properties();
        prop.load(new BufferedReader(new FileReader(new File(dir, name + ".txt"))));        
        int ligne = simulation + param_first;
		int mod = (int)matrix.getValue(ligne, name);
System.out.println("mod et ligne : "+ mod+" "+ligne);
        double result = Double.parseDouble(prop.getProperty(""+mod));
System.out.println("result : "+ result);
        return result;
    }
	
		/// pour une liste de doubles

 /**
     * @param name le nom de l'element a recuperer
     * @param simulation le numero de la simulation
     * @return
     */   
  private double [] getList(String name, int simulation) throws Exception {
        File dir = new File(param_directory);
        Properties prop = new Properties();
        prop.load(new BufferedReader(new FileReader(new File(dir, name + ".txt"))));
		int ligne = simulation + param_first;
        int mod = (int)matrix.getValue(ligne, name);
        double [] result = StringUtil.toArrayDouble(prop.getProperty(""+mod).split(";")); // ""+ ca construit une chaine de caractere
        return result;
    }
	
		/// pour une chaine de characteres (equation)
    /**
     * @param name le nom de l'element a recuperer
     * @param simulation le numero de la simulation
     * @return
     */
 private String getString(String name, int simulation) throws Exception {
        File dir = new File(param_directory);
        Properties prop = new Properties();
        prop.load(new BufferedReader(new FileReader(new File(dir, name + ".txt"))));
		int ligne = simulation + param_first;
        int mod = (int)matrix.getValue(ligne , name);
        String result = prop.getProperty(""+mod);
        return result;
    }
		/// pour les paramètres d'une règle de gestion
	  /**
     * @param name le nom de l'element a recuperer
     * @param simulation le numero de la simulation
     * @return
     */	
   private Rule getRule(RegionStorage regionStorage, String name, int simulation) throws Exception {
        File dir = new File(param_directory);
        Properties prop = new Properties();
        prop.load(new BufferedReader(new FileReader(new File(dir, name+".txt"))));
		int ligne = simulation + param_first;
        int mod = (int)matrix.getValue(ligne , name);
        String ruleName = prop.getProperty(""+mod);
        RuleStorage ruleStorage = RuleStorage.getRule(ruleName);
        Rule rule = ruleStorage.getNewRuleInstance();
        RuleHelper.populateRule(mod, regionStorage, rule, prop); 
        return rule;
    }
    
	
	
    /**
     * Call before each simulation
     * @param context plan context
     * @param nextSimulation storage used for next simulation
     * @return true if we must do next simulation, false to stop plan
     * @throws Exception
     */
    public boolean beforeSimulation(AnalysePlanContext context, SimulationStorage nextSimulation) throws Exception {
        
		int simNum = context.getNumber()+ param_first; 
        
		if (simNum < param_simulationNumber+1) { /// On vérifie qu'il reste des expériences à faire

			/// On utilise les méthodes crées pour récupérer les valeurs des modalités pour l'expérience en cours
            double [] croissance    = getList (VBGF , simNum);
            double catchability     = getDouble (CATCHABILITY, simNum);
            double [] standerdisation    = getList (STANDARDISATION , simNum);
			String selectivity      = getString (SELECTIVITY, simNum);
            String mortality      = getString (MORTALITY, simNum);
			Rule amp = getRule(context.getParam().getRegion(), AMP, simNum);
			
			/// On peut afficher des informations dans les logs
            nextSimulation.getInformation().addInformation("Growth ("+context.getNumber()+")= " + croissance);
            nextSimulation.getInformation().addInformation("Selectivity ("+context.getNumber()+")= " + selectivity);


			/// Il faut maintenant modifier la valeur des paramètres dans la base de données et les paramètres des règle de la simulation
				/// modif les parametres des regles de gestion :
            
			// on enleve la regle de la simulation passé (elle est stoquée sous le nom LastAMP) 
            List<Rule> paramRules = nextSimulation.getParameter().getRules();
            paramRules.remove(context.getValue("lastAMP"));
            // on nomme la regle que l'on va ajouter LastAMP (pour pouvoir la retrouver a la simulation suivante)
			context.setValue("lastAMP", amp);
            // on ajoute la regle à la simulation
            paramRules.add(amp);
            
				/// modif les parametres dans la base de données :
            TopiaContext tx = nextSimulation.getStorage().beginTransaction();
            /// On récupère les objets ISIS a modifier dans la base de données
			PopulationDAO popDAO = IsisFishDAOHelper.getPopulationDAO(tx);			
			Population pop = popDAO.findByName("CSar");
            List<PopulationGroup> groups = pop.getPopulationGroup();
			GearDAO gearDAO = IsisFishDAOHelper.getGearDAO(tx);
            List<Gear> gears = gearDAO.findAll();

					///modif borne des classes de taille
					/// On remplace les bornes par les éléments de la liste
            for (PopulationGroup group : groups) {
                group.setMinLength(croissance[group.getId()]) ;
                group.setMaxLength(croissance[group.getId()+1]) ;
            }
            
					
					// modif la capturabilité
					/// On modifie la valeur de la base en la multipliant par la valeur contenue dans la modalité
		    MatrixND c = pop.getCapturability();
		    for (MatrixIterator i = c.iterator(); i.hasNext();){
			    i.next();
        		i.setValue(i.getValue()* catchability);
            }
					 

					 // modif la mortalité naturelle
					/// On modifie la valeur de la base en la remplacant par la valeur contenue dans la modalité
		  
		    for (PopulationGroup group : groups) {
                
              mortality  = group.setNaturalDeathRate();
              Equation eq = getPopulation().getNaturalDeathRate();
               eq.setContent(mortality);
            }
         tx.commitTransaction();
           return true;
       } else {
          return false;
        }

		
    
                     // modif les facteurs de standardisation
					/// On modifie la valeur de la base en la remplacant par la valeur contenue dans la modalité

		    for (Gear gear : gears) {
                 gear.getFacteurStandard(pop);
                 

			}

           
			
					/// modif selectivité
					/// On remplace l'equation existante par une autre equation
            for (Gear gear : gears) {
                Selectivity sel = gear.getPopulationSelectivity(pop);
                Equation eq = sel.getEquation();                
				eq.setContent(selectivity);
			}

            tx.commitTransaction();
           return true;
         } else {
        return false;
        }
		
   } 

 
    /**
     * Call before each simulation
     * @param context plan context
     * @param nextSimulation storage used for next simulation
     * @return true if we must do next simulation, false to stop plan
     * @throws Exception
     */
     public boolean afterSimulation(AnalysePlanContext context, SimulationStorage lastSimulation) throws Exception {
        return true;
    }

}
