package simulationplans;

//import static org.nuiton.i18n.I18n._;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.*;
import java.io.File;
import java.io.FileReader;
import org.nuiton.util.FileUtil;
import org.nuiton.util.StringUtil;
import org.nuiton.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Collection;
import org.nuiton.math.matrix.*;
import org.nuiton.util.*;
import org.nuiton.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.entities.*;
import fr.ifremer.isisfish.simulator.SimulationPlanIndependent;

import fr.ifremer.isisfish.simulator.SimulationPlanContext;
import fr.ifremer.isisfish.simulator.SimulationPlan;
import fr.ifremer.isisfish.datastore.ResultStorage;
import fr.ifremer.isisfish.datastore.RuleStorage;
import fr.ifremer.isisfish.datastore.SimulationStorage;
import fr.ifremer.isisfish.util.Doc;
//import scripts.ResultName;
import org.apache.commons.io.FileUtils;
import resultinfos.MatrixCatchWeightPerStrategyMetPerZonePop;
/*
 * SensitivityCapturabilite10param.java
 *
 * Created: 10/09/09
 *
 * @author slehuta
 * @version $Revision: version 3.2.
 *
 * Last update: $Date:  $
 * by : $Author:sigrid $
 */

public class Sensitivity_QeqTF_GD_SansObjectif implements SimulationPlanIndependent {

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

   static private final String MATRIX = "tableLHS_seuil_5.4_optim_30";
    private MatrixND matrix = null;
	
	
	
    @Doc("Population which parameters are calibrated")
    public Population param_Population = null;
    int param_parameterNumber = 8;
    public int param_first = 0;
    public int param_simulationNumber = 1000;
    public String param_directory = "F:/CDD_Ifremer_Nantes/Galion/MathieuGenu/Data/Matrice_Observation_ISIS/LHS/";
   /* public String param_exportPath = "Output_essai_recuit/ExportLHS8Param.csv";
    protected String exportHisto = "";
    public String param_nomfichier_debarquements2015 = "Input_essai_recuit/Inputlandings10param10ans10FO.csv";
    public String param_nomfichier_debarquements2016 = "Input_essai_recuit/Inputlandings10param10ans10FO.csv";
	protected File debarquementsObserves2015;
    protected File debarquementsObserves2016;
    protected MatrixND matrixDebarquement2015;
    protected MatrixND matrixDebarquement2016;
	
	File exportHistoric = new File(param_exportPath);
	*/
    int compteurSimus;
    public String [] necessaryResult = {
    };
    public String[] getNecessaryResult() {
        return this.necessaryResult;
    }
	
	protected Strategy espStr;


    /**
     * Permet d'afficher a l'utilisateur une aide sur le plan.
     * @return L'aide ou la description du plan
     */
    public String getDescription() throws Exception {
        // TODO
        return ("fait experiences d'une maytrice pour x parametres");
    }
 
    /**
     * Appelmarrage de la simulation, cette methode permet d'initialiser
     * des valeurs
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    public void init(SimulationPlanContext context) throws Exception {
        File dir = new File(param_directory);
        
        matrix = MatrixFactory.getInstance().create(new int[]{param_simulationNumber, param_parameterNumber});
        matrix.importCSV(new FileReader(new File(dir, MATRIX + ".csv")), new int[]{0,0});
        
	   /* debarquementsObserves2015 = new File(param_nomfichier_debarquements2015);
        debarquementsObserves2016 = new File(param_nomfichier_debarquements2016);
       
		matrixDebarquement2015 = MatrixFactory.getInstance().create(debarquementsObserves2015);
        matrixDebarquement2016 = MatrixFactory.getInstance().create(debarquementsObserves2016);
	 */	
		
	   
	 }
     

    
    /**
     * 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(SimulationPlanContext context, SimulationStorage nextSimulation) throws Exception {
        int simNum = nextSimulation.getParameter().getSimulationPlanNumber();
        //int simNum = context.getNumber();
        if (simNum + param_first < param_simulationNumber) {
            
      List<Strategy> allStrategies = nextSimulation.getParameter().getStrategies();
      for( Strategy str: allStrategies){
            if(str.getName().equals("Strategie_espagnol")){
                espStr = str;
            } 
        }

           
            
            ///////////////////////////////////////////////////////////////////////////////////////////
            // Modif database
		TopiaContext db = nextSimulation.getStorage().beginTransaction();//ouvrir un context pour modifier les donnees
        Population pop = (Population) db.findByTopiaId(param_Population.getTopiaId());			
        MetierDAO metierDAO = IsisFishDAOHelper.getMetierDAO(db);
		List<Metier> metiers = metierDAO.findAll();   

             int ligne = simNum + param_first;
	


            // modif la capturabilite
            Equation eqq = pop.getCapturabilityEquation() ;
			String eqqs  = eqq.getContent();
			String[] eqqsSplit = eqqs.split("q = {1,1,1,1,1,1");
			String eqqNew = eqqsSplit[0] + "q = {" ;
			MatrixND matLigne = matrix.getSubMatrix(0,ligne).reduceDims();
			for(MatrixIterator i=matLigne.iterator(); i.hasNext();){
				i.next();
				eqqNew = eqqNew + i.getValue() + ",";
			}
			eqqNew = eqqNew + "0"+ eqqsSplit[1];
			eqq.setContent(eqqNew);
			System.out.println("Nouvelle eq de capturabilite pour : "+ simNum+" captureabilit = " + eqqNew);
            
			
			/*MatrixND c = pop.getCapturability();
            System.out.println("Ancienne mat de capturabilite pour : "+ simNum+" captureabilit = " + c);
            for (MatrixIterator i = c.iterator(); i.hasNext();){
					i.next() ;
                    Object [] sem = i.getSemanticsCoordinates();
                    PopulationGroup group = (PopulationGroup)sem[0];
					PopulationSeasonInfo season = (PopulationSeasonInfo)sem[1];
                    int monthNumber = season.getFirstMonth().getMonthNumber();
					double q = (double)matrix.getValue(ligne,group.getId());
					//log.info("Parametre " + q);
                    double[] coefAccess = {0.561683153996181,0.620863222959103,0.80371411358396,0.601854406649302,0.527621671697003,0.711320969033697,0.75200188672828,0.934271262394382,0.873357769044904,0.812805691611056,1.0,0.991592837566978};
					if(group.getAge() >= 1){
					    i.setValue(q*coefAccess[monthNumber]);
					}else {
                        i.setValue(q);
					}
            }
            System.out.println("Nouvelle mat de capturabilite pour : "+ simNum+" captureabilit = " + c);
			*/
			
			// modif Target factor of Spanish fleets
			for(Metier met : metiers){
				if(met.getName().equals("OTB_ESP") || met.getName().equals("LLS_ESP")){ 
					double TF =0;
					if(met.getName().equals("OTB_ESP")){
						TF = (double)matrix.getValue(ligne,6);;
					}else if(met.getName().equals("LLS_ESP")){
						TF = (double)matrix.getValue(ligne,7);;
					}
					List<MetierSeasonInfo> 	msis = met.getMetierSeasonInfo();
					for(MetierSeasonInfo msi : msis){
						Collection<TargetSpecies> tss =	msi.getSpeciesTargetSpecies() ;
						for(TargetSpecies ts : tss){
							String tsn = ts.getSpecies().getName();						
							String TFeq = "return " + TF + ";";
							Equation targetFactorEquation = ts.getTargetFactorEquation() ;
							targetFactorEquation.setContent(TFeq);
						}
					}
				}
				
			}


			
            db.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(SimulationPlanContext context,
            SimulationStorage lastSimulation) throws Exception{
    		//File exportHistoric = new File(param_exportPath);
		ResultStorage result = lastSimulation.getResultStorage();
		boolean bool=true;
		compteurSimus=getIteration(lastSimulation); //numero de la simulation qui vient de se terminer
		export(result,compteurSimus);
		return true;
    }
	
	/**
	*Calcule la valeur de la fonction d'objectif de la parametrisation utilisee pour la simulation qui vient de s'achever.
	*@param result le numero de la simulation venant de s'achever
	*@return la valeur de fonction d'objectif
	*/
	    public void export(ResultStorage result, int compteurSimus) throws java.io.IOException{
		/*	
			//Inclut l'import des donnees, des resultats de la simulation et le calcul de la fonction d'objectif;
        /////***import the matrix of simulated data (here landings) from the simulation result
        MatrixND L = result.getMatrix(param_Population,
                MatrixCatchWeightPerStrategyMetPerZonePop.NAME);
        /////*** extract, sum, etc to obtain the same format/data as your observation matrix
        // useful methods to work on matrix : sumOverDim(), getSubMatrix(), reduce()
        //Somme sur les strategies, metiers, pas les  groupes et zones
		L = L.sumOverDim(2);// sum over met
		L = L.sumOverDim(4);// sum over zones
		MatrixND L2015 = L.copy().getSubMatrix(0,0,12).reduce();
		MatrixND L2016 = L.copy().getSubMatrix(0,12,12);
		
		MatrixND L2016esp = L2016.getSubMatrix(1,espStr,1);
		MatrixND L2016fr = L2016.minus(L2016esp);
		L2016fr = L2016fr.sumOverDim(3).reduce();// sum over age group

		
        ///////////////////Calcul du critere//////////////////
        log.info("calcul de la fonction objectif");
        double obj = 0;
		// 2015
		for (MatrixIterator g = L2015.iterator(); g.hasNext();) {
            g.next();
            Object[] sem = g.getSemanticsCoordinates();
			TimeStep step = (TimeStep)sem[0];
			Strategy str = (Strategy) sem[1];
            PopulationGroup group = (PopulationGroup) sem[2];
            double obs = matrixDebarquement2015.getValue(step,str,group);
            if(obs ==0) obs=1;
            double simules = g.getValue();
            obj += Math.pow((obs - simules)/obs, 2);
        }
		
		// 2016
		for (MatrixIterator h = L2016fr.iterator(); h.hasNext();) {
            h.next();
            Object[] sem = h.getSemanticsCoordinates();
			TimeStep step = (TimeStep)sem[0];
			Strategy str = (Strategy) sem[1];
            if(! str.getName().equals("Strategie_espagnol")){
                double obs = matrixDebarquement2016.getValue(step,str);
                if(obs ==0) obs=1;
                double simules = h.getValue();
                obj += Math.pow((obs - simules)/obs, 2);
            }
        }
		
	exportHisto+= compteurSimus+";"+obj+";\n";
	FileUtils.writeStringToFile(exportHistoric,exportHisto);
	*/
	}
	
	/*public String toCSV10FO(MatrixND obj) {
		String sep = ";";
		String saut = "\n";
		String result = "";
		for (MatrixIterator g = obj.iterator(); g.hasNext();){
			g.next();
			result += g.getValue() + sep;
		}
		result += saut;
		return result;
	}*/
	
	/**
	*Recupere le numero de la simulation renseignee
	*@param simulation storage de la simulationr enseignee
	*@return numero de la simulation renseignee
	*/
	public int getIteration(SimulationStorage simulation){			//Il n'y a pas de setIteration
		return simulation.getParameter().getSimulationPlanNumber();
	}
}
