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;

/*
 * PlanAnalyse.java
 *
 * Created: 6 juin 2007
 *
 * @author sl
 * @version $Revision: 3.1.3 $
 *
 * Last update: $Date: 2008/12/01 09:29:18 $
 * by : $Author: sl $
 */

/**
 * Le principe est d'avoir dans un repertoire un fichier matrix.txt et un 
 * fichier par parametre. Si le parametre s'appelle tac, le fichier sera tac.txt
 * 
 * Les fichiers pour les parametres de type double sont de la forme
 * <pre>
 * -1=0.8
 * 1=1.2
 * </pre> 
 * 
 * Les fichiers pour les parametres de type String sont de la forme
 * <pre>
 * -1=L'equation ecrite sur une seul ligne
 * 1=une autre equation toujours sur une ligne
 * </pre> 
 * 
 * Les fichiers pour les parametres de type Rule sont de la forme
 * <pre>
-1=Cantonnement
rule.-1.parameter.gear=fr.ifremer.isisfish.entities.Gear\#11690286646709\#0.5814158398678262 
rule.-1.parameter.zone=fr.ifremer.isisfish.entities.Zone\#11690286645767\#0.37798185123822536
rule.-1.parameter.beginDate=0                                                                
rule.-1.parameter.endDate=119
rule.-1.parameter.enginSelectivite=false
rule.-1.parameter.beginMonth=8          
rule.-1.parameter.endMonth=11
1=Cantonnement
rule.1.parameter.gear=fr.ifremer.isisfish.entities.Gear\#11690286646709\#0.5814158398678262 
rule.1.parameter.zone=fr.ifremer.isisfish.entities.Zone\#11690286645767\#0.37798185123822536
rule.1.parameter.beginDate=0                                                                
rule.1.parameter.endDate=119
rule.1.parameter.enginSelectivite=false
rule.1.parameter.beginMonth=3          
rule.1.parameter.endMonth=11
 * </pre> 
 */

public class PlanAnalyse implements AnalysePlan {

    /** to use log facility, just put in your code: log.info("..."); */
    
static private Log log = LogFactory.getLog(PlanAnalyse.class);

	/// On rentre ici le nom des fichiers ��� lire c'est ��� dire ceux contenant la matrice d'exp���rience et 
	/// pour chaque param���tre les valeurs du param���tres correspondant ��� chaque modalit���
	/// Les param���tres ��� modifier sont ici les bornes des classes de longueur (growth),  ///la capturabilit���, la selectivit��� et les param���tres de l'AMP.
    
    static private final String MATRIX = "matrix"; /// Le fichier est donc matrix.txt
    static private final String CATCHABILITY = "capturabilite";
    static private final String NATURALDEATHRATE = "mortalitenaturelle";

    
	/// Ici figure les param���tres du plan qui apparaitront dans l'interface de lancement de simulation et 
	/// qu on peut ���ventuellement modifier avant de lancer le plan :
    
	public int param_parameterNumber = 4; /// 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 = 16;/// ce param���tre n'est normalement pas modifi��� 
    public String param_directory = "Analyse_sensibilite"; /// 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 2 parametres et 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 ce plan
     */
    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[]{CATCHABILITY, NATURALDEATHRATE}));
        System.out.println("matrice d exp :"+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     
    /**
     * @param name le nom de l'element a recuperer
     * @param simulation le numero de la simulation
     * @return
     */
    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("double : 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);
		System.out.println("list : mod et ligne : "+ mod+" "+ligne);
        double [] result = StringUtil.toArrayDouble(prop.getProperty(""+mod).split(";")); // ""+ ca construit une chaine de caractere
        return result;
		System.out.println("result : "+ 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(); 
        
		if (simNum + param_first < param_simulationNumber) { /// 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 capturabilite     = getDouble (CATCHABILITY, simNum);
			//String selectivity      = getString (SELECTIVITY, simNum);
                        String mortalitenaturelle  = getString(NATURALDEATHRATE, 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("test population");
            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) {
// System.out.println("group:"+group.getId());
               // group.setMinLength(croissance[group.getId()]) ;
               // group.setMaxLength(croissance[group.getId()+1]) ;
 // System.out.println("min:"+croissance[group.getId()]+" max:"+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()* capturabilite);
System.out.println("cat "+capturabilite);
            }


/// modif la mortalit�� naturelle
				
					/// On remplace l'equation existante par une autre equation
           
MatrixND mn = pop.getNaturalDeathRate();
for (MatrixIterator i = mn.iterator(); i.hasNext();) {
i.next();
i.setValue(i.getValue()*mortalitenaturelle);
System.out.println("cat" +mortalitenaturelle);
}


			//	 for (Gear gear : gears) {
            //   NaturalDeathRate sel = gear.getPopulationNaturalDeathRate(pop);
          //    Equation eq = sel.getEquation();                
			//	eq.setContent(mortalitenaturelle);
//System.out.println(mortalitenaturelle);
	//	}
            
			
					/// 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);
//System.out.println(selectivity);
	//		}

            tx.commitTransaction();
            return true;
        } else {
            return false;
        }
		
    }

    /**
     * Call after 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;
    }

}

