/*
 * Copyright (C) 2012 jandre
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
package analyseplans;

import static org.nuiton.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.List;
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.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.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;
//import fr.ifremer.isisfish.util.TopiaEntityConverter;


/**
 * Future_Catch_biomass_independantPlan.java
 *
 * Created: 20 juin 2012
 *
 * @author jandre <user.name@vcs.hostName>
 * @version $Revision: 1545 $
 * Last update: $Date: 20 juin 2012 $
 * by : $Author: jandre $
 */
public class Future_Catch_biomass_independantPlan implements AnalysePlan {

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

    static private final String MATRIX = "matrix";
    static private final String RECRUITBMW = "recruitBMW";
    static private final String RECRUITCAL = "recruitCal";
    static private final String RECRUITWRAS = "recruitWras";
    static private final String RECRUITGAR = "recruitGar";

    static private final String RuleRECRUITBMW30Years = "RuleBMWRecruit";
    static private final String RuleRECRUITGAR30Years = "RuleGarRecruit";
    static private final String RuleRECRUITCAL30Years = "RuleCalRecruit";
    static private final String RuleRECRUITWRA30Years = "RuleWraRecruit";
    
    public int param_parameterNumber = 4;//1 list of recruitment for each species
    public int param_first = 0;
    public int param_simulationNumber = 499; //actually, it is 500 but 1st simulation is called 0
    // !!! change the directory folder...
    public String param_directory = "C:/Documents and Settings/slehuta/isis-database-3/analyseplans/SAAnchoisfiles/";
    
    private MatrixND matrix = null;
       
    public String [] necessaryResult = {
	ResultName.MATRIX_DISCARDS_WEIGHT_PER_STR_MET_PER_ZONE_POP,
	ResultName.MATRIX_CATCH_WEIGHT_PER_STRATEGY_MET_PER_ZONE_POP,
	ResultName.MATRIX_BIOMASS,
	ResultName.MATRIX_ABUNDANCE_BEGIN_MONTH
    };

    @Override
    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
     */
    @Override
    public String getDescription() throws Exception {
        return _("Tries various combinations of recruitment for the 4 species over 30 years");
    }
//**********************************************************************************************
    /**
     * Appele au demarrage de la simulation, cette methode permet d''initialiser
     * des valeurs
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    @Override
    public void init(AnalysePlanContext 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 + ".txt")), new int[]{0,0});
        matrix.setSemantic(1, Arrays.asList(new String[]{RECRUITBMW,RECRUITCAL,RECRUITWRAS,RECRUITGAR}));
        log.info("Matrix: " + matrix);
    }  
//**********************************************************************************************    
    /**
     * @param name the name of the element to get
     * @param simulation the simulation number
     * @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"))));
        
	   // Go and gets in the matrix which modality is defined for the factor (-1,0,1...) 
        int ligne = simulation + param_first;
	   int mod = (int)matrix.getValue(ligne, name);
        double result = Double.parseDouble(prop.getProperty(""+mod));
        return result;
    }

    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(";"));
        return result;

    }
//**********************************************************************************************  
    /**
     * @param name the name of the element to get
     * @param simulation the simulation number
     * @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;
    }

    private Rule getRule(RegionStorage regionStorage, String name, int simulation) throws Exception {
    //private Rule getRule(TopiaContext topiacontext, 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);
	   System.out.println("ruleName : "+ ruleName);
        RuleStorage ruleStorage = RuleStorage.getRule(ruleName);
        Rule rule = ruleStorage.getNewRuleInstance();
        RuleHelper.populateRule(mod, regionStorage.getStorage(), rule, prop);//!!!! check that OK
        
        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
     */
    @Override
    public boolean beforeSimulation(AnalysePlanContext context,
        	SimulationStorage nextSimulation) throws Exception {
           
           
     	 int simNum = nextSimulation.getParameter().getAnalysePlanNumber();//!!!! Why is that not working?!
        	 if (simNum < param_simulationNumber) {
/*/
            double [] BMWrecruits    = getList (RECRUITBMW , simNum);
            double [] Calrecruits    = getList (RECRUITCAL , simNum);
            double [] Wrasrecruits   = getList (RECRUITWRAS , simNum);
            double [] Garrecruits    = getList (RECRUITGAR , simNum);

            log.info("BMWRecruits ("+simNum+")= " + BMWrecruits[0] + " ; " + BMWrecruits[6]);// just to check that it is taking different recruitment
            log.info("CalRecruits ("+simNum+")= " + Calrecruits[0] + " ; " + Calrecruits[6]);
            log.info("WrasRecruits ("+simNum+")= " + Wrasrecruits[0] + " ; " + Wrasrecruits[6]);
            log.info("GarRecruits ("+simNum+")= " + Garrecruits[0] + " ; " + Garrecruits[6]);
/*/
            Rule RuleBMWRecruit = getRule(context.getParam().getRegion(), RuleRECRUITBMW30Years, simNum);// Je vois le mismatch mais j'arrive pas a corriger...
            Rule RuleGarRecruit = getRule(context.getParam().getRegion(), RuleRECRUITGAR30Years, simNum);
		  Rule RuleCalRecruit = getRule(context.getParam().getRegion(), RuleRECRUITCAL30Years, simNum);
            Rule RuleWraRecruit = getRule(context.getParam().getRegion(), RuleRECRUITWRA30Years, simNum);
            
/*/          double reproductionRate = getDouble (FECONDITY, simNum);
            //double spawningFraction = getDouble (SPAWNINGF, simNum);
			double migration = getDouble (MIGRATION,simNum);
            String adultMortality   = getString (MORTALITYA, simNum);
            String juvMortality     = getString (MORTALITYJ, simNum);
            double catchability     = getDouble (CATCHABILITY, simNum);
            double standardisation  = getDouble (FSTD, simNum);
            String selectivityEquation = getString(SELECTIVITY, simNum);
            double targetFactor     = getDouble (TARGET, simNum);
            double effort           = getDouble (EFFORT, simNum);

            Rule tacE = getRule(context.getParam().getRegion(), TACe, simNum);
            Rule tacF = getRule(context.getParam().getRegion(), TACf, simNum);
			Rule apm = getRule(context.getParam().getRegion(), APM, simNum);
            Rule Paita = getRule(context.getParam().getRegion(), PAITA, simNum);


            //log.info("Fecondites ("+simNum+")= " + reproductionRate);
            //log.info("Selectivites ("+simNum+")= " + selectivityEquation);
            //log.info("spawningFraction ("+simNum+")= " + spawningFraction);
			//log.info("Migration ("+simNum+")= "+ migration);
            //log.info("catchability ("+simNum+")= " + catchability);
            //log.info("Fstd ("+simNum+")= " + standardisation);
            //log.info("Ftarget("+simNum+")= " + targetFactor);
            //log.info("effort ("+simNum+")= " + effort);
            //log.info("croissance ("+simNum+")= " + croissance[0] + " ; " + croissance[6]);
            
            nextSimulation.getInformation().addInformation("Fecondites ("+context.getNumber()+")= " + reproductionRate);
            nextSimulation.getInformation().addInformation("Selectivites ("+context.getNumber()+")= " + selectivityEquation);
/*/
		  // Modification of the recruitment rules for the 4 species
		  // !!! Careful, you need to load the rules in the simulation interface but with such parameters
		  // that the rule doesn't actually apply!!!
		  //
		  // We remove the rules from the previous simulation
		  List<Rule> paramRules = nextSimulation.getParameter().getRules();
            paramRules.remove(context.getValue("lastRuleBMWRecruit"));
		  paramRules.remove(context.getValue("lastRuleGarRecruit"));
            paramRules.remove(context.getValue("lastRuleWraRecruit"));
		  paramRules.remove(context.getValue("lastRuleCalRecruit"));   
	       //
  		  // We keep the rules that we want to add
  		  context.setValue("lastRuleBMWRecruit", RuleBMWRecruit);
		  context.setValue("lastRuleGarRecruit", RuleGarRecruit);
		  context.setValue("lastRuleWraRecruit", RuleWraRecruit);
		  context.setValue("lastRuleCalRecruit", RuleCalRecruit);
		  //
            // We add the rules
            paramRules.add(RuleBMWRecruit);
		  paramRules.add(RuleGarRecruit);
            paramRules.add(RuleWraRecruit);
            paramRules.add(RuleCalRecruit);

            TopiaContext tx = nextSimulation.getStorage().beginTransaction();
            
/*/                                    
            // modif le nb de jours d inactivit����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
            //log.info("INACTIVITY");
            StrategyDAO strategyDAO = IsisFishDAOHelper.getStrategyDAO(tx) ;
            List<Strategy> strategies = strategyDAO.findAll();
            for (Strategy strategy : strategies) {
            List <StrategyMonthInfo>  monthInfos = strategy.getStrategyMonthInfo();
              for (StrategyMonthInfo month : monthInfos) {
			  double days = month.getMinInactivityDays()*effort;
				int Days = (int) days ; 
            //log.info("nb j inact = " + Days) ;
				month.setMinInactivityDays(Days);
			  }               
            }
/*/


            tx.commitTransaction();
            return true;
        } else {
            return false;
        } 
     	     
    }
//**********************************************************************************************
    /**
     * Call after each simulation.
     * 
     * @param context plan context
     * @param lastSimulation storage used for simulation
     * @return true if we must do next simulation, false to stop plan
     * @throws Exception
     */
    @Override
    public boolean afterSimulation(AnalysePlanContext context,
            SimulationStorage lastSimulation) throws Exception {
        
        return true;
    }
}