package rules;

import static org.nuiton.i18n.I18n._;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import scripts.GravityModel;
//import scripts.ResultName;
import scripts.SiMatrix;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.io.File;
import java.io.Writer;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.FileReader;

import org.nuiton.math.matrix.*;

import fr.ifremer.isisfish.IsisFishDAOHelper;
import fr.ifremer.isisfish.simulator.MetierMonitor;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.TimeStep;
import fr.ifremer.isisfish.types.Month;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.rule.AbstractRule;
import fr.ifremer.isisfish.datastore.ResultStorage;

import org.nuiton.util.FileUtil;

/**
 * effortObs_MultiSp
 *
 * Created: 26 aout 2008
 *
 * @author anonymous <anonymous@labs.libre-entreprise.org>
 * @version $Revision: 1.2 $
 *
 * Last update: $Date: 2013-06-12 08:59:38 $
 * by : $Author: 2SY- Sigrid $
 */
public class Effort_2008_2014_MixChannel extends AbstractRule {
    /** to use log facility, just put in your code: log.info("..."); */
    static private Log log = LogFactory.getLog(Effort_2008_2014_MixChannel.class);
	
	protected File Inactivity;
	protected File Effort;
	protected File nbVess;
	//public String param_cheminFichierHistoric ="/home1/caparmor/slehuta/InputMixChannel/HistoricStrategies_2008-2010/" ;
	public String param_cheminFichierHistoric ="InputMixChannel/HistoricStrategies_2008-2014/" ;
	public int param_startDate = 0;
	
	protected List<Metier> metiers;
	protected List<Strategy> allStrategies ;
	
	protected MatrixND matInactivity;
	protected MatrixND matEffort;
	protected MatrixND matNbVess;
	protected Map<Strategy, MatrixND> strMat;

    public String [] necessaryResult = {
    };

    public String[] getNecessaryResult() {
        return this.necessaryResult;
    }

    /**
     * Permet d'afficher a l'utilisateur une aide sur la regle.
     * @return L'aide ou la description de la regle
     */
    public String getDescription() throws Exception {
        return ("Chaque annee et mois les efforts % et inactivity observ");
		 
    }
     
     /**
     * Appel
     * des valeurs
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    public void init(SimulationContext context) throws Exception {
        
		// reccuperation des metiers et strategies
		SiMatrix siMatrix = SiMatrix.getSiMatrix(context);
		
		TimeStep date = new TimeStep(0);
        List<TimeStep> dates = new ArrayList <TimeStep>();
		for (int i=0; i < 84; i++) {
		dates.add(new TimeStep (i));
		}
		Integer[] yearTab = {0,1,2,3,4,5,6}; 
		
 		// reccuperation des metiers et strategies
		metiers = siMatrix.getMetiers(date);		
		allStrategies = siMatrix.getStrategies(date);	
		List<Month> months = Arrays.asList(Month.MONTH);
		List<Integer> year = Arrays.asList(yearTab);
		
		// vecteur des noms des strategies
		String[] strategyNames = new String[]{"4_Norm_12-18","4_North_12-18","4_Norm_Inf10","4_Norm_10-12","4_Norm_18-24","4_North_10-12","1_Norm_Inf12",    
		"13_Norm_Inf10","13_North_Inf10","13_North_10-12","13_Norm_10-12","13_North_12-18","1_Norm_18-40","2_North_18-24","1_North_18-40" ,
		"2_North_24-40","2_Norm_18-40"};
		// vecteur des noms des fichiers csv de chaque strategy
		String[] strategyFileNames = new String[]{"HistStr1-Nord-[18-40[ m.csv","HistStr1-Norm-[18-40[ m.csv" ,"HistStr1-Norm-Inf 12 m.csv","HistStr13-Nord-[10-12[ m.csv",
		 "HistStr13-Nord-[12-18[ m.csv","HistStr13-Nord-Inf 10 m.csv", "HistStr13-Norm-[10-12[ m.csv","HistStr13-Norm-Inf 10 m.csv" ,
		 "HistStr2-Nord-[18-24[ m.csv","HistStr2-Nord-[24-40[ m.csv" , "HistStr2-Norm-[18-40[ m.csv","HistStr4-Nord-[10-12[ m.csv", 
		 "HistStr4-Nord-[12-18[ m.csv","HistStr4-Norm-[10-12[ m.csv", "HistStr4-Norm-[12-18[ m.csv","HistStr4-Norm-[18-24[ m.csv" ,
		 "HistStr4-Norm-Inf 10 m.csv"};
        
		 String InactivityFileName = "";
		if(context.getSimulationStorage().getParameter().getTagValue().get("FileInactivityName") == null){
			String tmp = new String ("InactivityHistoric2008-2014_strategy2_240514.csv");	
			InactivityFileName = param_cheminFichierHistoric + tmp;
			//InactivityFileName = new String("InputMixChannel/EffortMatrices/InactivityHistoric2008-2010_saisine_12.csv");
		}else {
			String fin = context.getSimulationStorage().getParameter().getTagValue().get("FileInactivityName");
            log.info("Dans rule : "+fin);
			InactivityFileName = "InputMixChannel/EffortMatrices/" + fin;
		}
		
		String nbVessFileName = param_cheminFichierHistoric +"HistNbVess_2008-2014_020516.csv";
		
		
		// pour chaque strategy vecteur des noms des metiers dans l'ordre du fichier		
		// "4-Norm-[12-18[ m"
		 String[] metNamesStr1 = {"DRB_27E9","DRB_28E8","DRB_28E9","DRB_28F0","DRB_29F0","DRB_29F1","DRB_VIId_Nm","OTB_27E9","OTB_28E8","OTB_28E9","OTB_28F0","OTB_29F0","OTB_29F1","OTB_VIId_Nm",
		"OTH-OTH","OTH-VIId","TBB_27E9","TBB_28E8","TBB_28E9","TBB_28F0","TBB_29F0","TBB_29F1","TBB_VIId_Nm"};
		// "4_Nord_[12_18[ m"
		 String[] metNamesStr2 = {"DRB_28E9","DRB_29F0","DRB_29F1","DRB_30F0","DRB_30F1","DRB_VIId_Nd","OTB_29F0","OTB_29F1","OTB_30F1","OTB_VIId_Nd","OTH-OTH","OTH-VIId","TBB_29F0","TBB_29F1",
		"TBB_30F0","TBB_30F1"};
		// "4_Norm_< 10 m"
		 String[] metNamesStr3 = {"DRB_27E9","DRB_28E8","DRB_28E9","DRB_29F0","DRB_29F1","DRB_VIId_Nm","OTB_27E9","OTB_28E8","OTB_28E9","OTB_28F0","OTB_29F1","OTB_VIId_Nm","OTH-OTH","OTH-VIId",
		 "TBB_29F1","TBB_VIId_Nm"};
		// "4_Norm_[10_12[ m"
		 String[] metNamesStr4 = {"DRB_27E9","DRB_28E8","DRB_28E9","DRB_28F0","DRB_29F0","DRB_29F1","DRB_VIId_Nm","OTB_27E9","OTB_28E8","OTB_28E9","OTB_28F0","OTB_29F0","OTB_29F1","OTB_VIId_Nm",
		"OTH-OTH","OTH-VIId","TBB_27E9","TBB_28E8","TBB_28E9","TBB_28F0","TBB_29F0","TBB_29F1","TBB_VIId_Nm"};
		// "4_Norm_[18_24[ m"
		 String[] metNamesStr5 = {"DRB_27E9","DRB_28E9","DRB_28F0","DRB_29F0","DRB_29F1","DRB_VIId_Nm","OTB_28E8","OTB_28E9","OTB_28F0","OTB_29F0","OTB_29F1","OTB_VIId_Nm","OTH-OTH","OTH-VIId"};
		// "4_Nord_[10_12[ m"
		 String[] metNamesStr6 =  {"DRB_28E9","DRB_29F0","DRB_29F1","DRB_30F0","DRB_30F1","DRB_VIId_Nd","OTB_29F0","OTB_29F1","OTB_30F1","OTB_VIId_Nd","OTH-OTH","OTH-VIId","TBB_29F1","TBB_30F1"};
		// "1_Norm_< 12 m"
		 String[] metNamesStr7 = {"OTB_27E9","OTB_28E8","OTB_28E9","OTB_28F0","OTB_29F0","OTB_29F1","OTB_VIId_Nm","OTH-OTH","OTH-VIId","TBB_27E9","TBB_28E8","TBB_28F0","TBB_29F1","TBB_VIId_Nm"};
		// "13_Norm_< 10 m"
		 String[] metNamesStr8 = {"GNS_27E9","GNS_28E8","GNS_28F0","GNS_29F1","GNS_VIId_Nm","GTR_27E9","GTR_28E8","GTR_28E9","GTR_28F0","GTR_29F0","GTR_29F1","GTR_VIId_Nm","OTH-OTH","OTH-VIId"};
		// "13_Nord_< 10 m"
		String[] metNamesStr9 = {"GNS_30F1","GNS_VIId_Nd","GTR_30F1","GTR_VIId_Nd","OTH-OTH","OTH-VIId"};
		// "13_Nord_[10_12[ m"
		String[] metNamesStr10 = {"GNS_30F1","GNS_VIId_Nd","GTR_30F1","GTR_VIId_Nd","OTH-OTH","OTH-VIId"};
		// "13_Norm_[10_12[ m"
		 String[] metNamesStr11 =  {"GNS_27E9","GNS_28E8","GNS_28E9","GNS_28F0","GNS_29F0","GNS_VIId_Nm","GTR_27E9","GTR_28E8","GTR_28E9","GTR_28F0","GTR_29F0","GTR_29F1","GTR_VIId_Nm","OTH-OTH" ,
		 "OTH-VIId"};
		// "13_Nord_[12_18[ m"
		String[] metNamesStr12 =  {"GNS_30F1","GNS_VIId_Nd","GTR_30F1","GTR_VIId_Nd","OTH-OTH","OTH-VIId"};
		// "1_Norm_[18_40[ m"
		String[] metNamesStr13 =  {"OTB_27E9","OTB_28E8","OTB_28E9","OTB_28F0","OTB_29F0","OTB_29F1","OTB_VIId_Nm","OTH-OTH","OTH-VIId"};
		// "2_Nord_[18_24[ m"
		String[] metNamesStr14 =  {"OTB_29E9","OTB_29F0","OTB_29F1","OTB_30F0","OTB_30F1","OTB_VIId_Nd","OTH-OTH","OTH-VIId"};
		// "1_Nord_[18_40[ m"
		String[] metNamesStr15 =  {"OTB_29E9","OTB_29F0","OTB_29F1","OTB_30F0","OTB_30F1","OTB_VIId_Nd","OTH-OTH","OTH-VIId"};
		// "2_Nord_[24_40[ m"
		String[] metNamesStr16 = {"OTB_29E9","OTB_29F0","OTB_29F1","OTB_30F0","OTB_30F1","OTB_VIId_Nd","OTH-OTH","OTH-VIId"};
		// "2_Norm_[18_40[ m"
		String[] metNamesStr17 =  {"OTB_27E9","OTB_28E9","OTB_28F0","OTB_29E9","OTB_29F0","OTB_29F1","OTB_VIId_Nm","OTH-OTH","OTH-VIId"};

				
		// map qui associe chaque strategy a son nom dans l'ordre du fichier inactivite
		List<Strategy> mesStrOrder = new ArrayList<Strategy>();
		Map<String , Strategy> mesStrategies = new HashMap<String, Strategy>();
		for (String curStrNam:strategyNames){
			for(Strategy curStr : allStrategies ){
				if(curStr.getName().equals(curStrNam)){
					mesStrategies.put(curStrNam,curStr);
					mesStrOrder.add(curStr);
				}
			}
		}
		
		//reccupere la liste des strategies dans l ordre
		//List <Strategy> mesStrOrder = mesStrategies.values();
		
		
		// creation d'un map <Strategy, String> qui associe chaque strategie au nom du fichier csv correspondant
		Map<Strategy,String> strFileName = new HashMap<Strategy,String>();
		// creation d'un map<Strategy, String[]> (si c'est possible) qui associe chaque strategie au vecteur des noms des metiers dans l'ordre du fichier
		Map<Strategy,Integer> metStrNum = new HashMap<Strategy,Integer>();
		List<String[]> listMetStr = new ArrayList<String[]>();
		int cpt = -1;
		for(Strategy str : allStrategies) {
			cpt = cpt +1;
			mesStrategies.put(str.getName(), str);
			if(str.getName().equals("4_Norm_12-18")){
				listMetStr.add(metNamesStr1);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[14]);
			}else if(str.getName().equals("4_North_12-18")){
				listMetStr.add(metNamesStr2);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[12]);
			}else if(str.getName().equals("4_Norm_Inf10")){
				listMetStr.add(metNamesStr3);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[16]);
			}else if(str.getName().equals("4_Norm_10-12")){
				listMetStr.add(metNamesStr4);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[13]);
			}else if(str.getName().equals("4_Norm_18-24")){
				listMetStr.add(metNamesStr5);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[15]);
			}else if(str.getName().equals("4_North_10-12")){
				listMetStr.add(metNamesStr6);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[11]);
			}else if(str.getName().equals("1_Norm_Inf12")){
				listMetStr.add(metNamesStr7);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[2]);
			}else if(str.getName().equals("13_Norm_Inf10")){
				listMetStr.add(metNamesStr8);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[7]);
			}else if(str.getName().equals("13_North_Inf10")){
				listMetStr.add(metNamesStr9);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[5]);
			}else if(str.getName().equals("13_North_10-12")){
				listMetStr.add(metNamesStr10);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[3]);
			}else if(str.getName().equals("13_Norm_10-12")){
				listMetStr.add(metNamesStr11);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[6]);
			}else if(str.getName().equals("13_North_12-18")){
				listMetStr.add(metNamesStr12);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[4]);
			}else if(str.getName().equals("1_Norm_18-40")){
				listMetStr.add(metNamesStr13);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[1]);
			}else if(str.getName().equals("2_North_18-24")){
				listMetStr.add(metNamesStr14);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[8]);
			}else if(str.getName().equals("1_North_18-40")){
				listMetStr.add(metNamesStr15);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[0]);
			}else if(str.getName().equals("2_North_24-40")){
				listMetStr.add(metNamesStr16);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[9]);
			}else if(str.getName().equals("2_Norm_18-40")){
				listMetStr.add(metNamesStr17);
				metStrNum.put(str,cpt);
				strFileName.put(str,strategyFileNames[10]);
			}
				
		/*1"HistStr1-Nord-[18-40[ m.csv",2"HistStr1-Norm-[18-40[ m.csv" ,3"HistStr1-Norm-Inf 12 m.csv",4"HistStr13-Nord-[10-12[ m.csv",
		 5"HistStr13-Nord-[12-18[ m.csv",6"HistStr13-Nord-Inf 10 m.csv", 7"HistStr13-Norm-[10-12[ m.csv",8"HistStr13-Norm-Inf 10 m.csv" ,
		 9"HistStr2-Nord-[18-24[ m.csv",10"HistStr2-Nord-[24-40[ m.csv" , 11"HistStr2-Norm-[18-40[ m.csv",12"HistStr4-Nord-[10-12[ m.csv", 
		 13"HistStr4-Nord-[12-18[ m.csv",14"HistStr4-Norm-[10-12[ m.csv", 15"HistStr4-Norm-[12-18[ m.csv",16"HistStr4-Norm-[18-24[ m.csv" ,
		 17"HistStr4-Norm-Inf 10 m.csv"};*/
		
		}
								
		// load files for each str
		Map <Strategy, File> strFile = new HashMap <Strategy,File>();
		for(Strategy str:allStrategies){
			String chemin = param_cheminFichierHistoric + strFileName.get(str);
			File Effort = new File(chemin);
			strFile.put(str,Effort);
		}
		
		Inactivity = new File(InactivityFileName);

		// create matrix for each strategy
		strMat = new HashMap <Strategy, MatrixND>();
		for(Strategy str : allStrategies){
		//ArrayList <String> metNameList = new ArrayList(Arrays.asList(vecNames));	
		List <String> metNameList = new ArrayList<String>();
		int num = metStrNum.get(str);
			for(String n : listMetStr.get(num)){
				metNameList.add(n);
			}
			matEffort = MatrixFactory.getInstance().create(
				"matEffort",
				new List[]{metNameList,dates},
                new String[]{"Metiers","Date"});
			strMat.put(str,matEffort);
		}
				
		matInactivity = MatrixFactory.getInstance().create(
				"matInactivity",
				new List[]{mesStrOrder,dates},
                new String[]{"Strategies","Date"});
        
		for(Strategy str : allStrategies){
			try (FileReader in = new FileReader(strFile.get(str))){
				strMat.get(str).importCSV(in,new int []{0,0});
			}
			//strMat.get(str).importCSV(new FileReader(strFile.get(str)),new int []{0,0});
		}
		
		try (FileReader in = new FileReader(Inactivity)){
            matInactivity.importCSV(in,new int []{0,0});
        }
		//matInactivity.importCSV(new FileReader(Inactivity),new int []{0,0});
        
		//System.out.println("matInactivity: "+ matInactivity);
	

		nbVess = new File(nbVessFileName);		
		matNbVess = MatrixFactory.getInstance().create(
				"matNbVess",
				new List[]{mesStrOrder,year},
                new String[]{"Strategies","Year"});
		try (FileReader in = new FileReader(nbVess)){
            matNbVess.importCSV(in,new int []{0,0});
        }		
		//matNbVess.importCSV(new FileReader(nbVess),new int []{0,0});	
        
    }// fin de init
	
	
    /**
     * La condition qui doit etre vrai pour faire les actions
     * @param simulation La simulation pour lequel on utilise cette regle
     * @return vrai si on souhaite que les actions soit faites
     */ 
    public boolean condition(SimulationContext context, TimeStep step, Metier metier) throws Exception {
		return (step.getYear()<(7-param_startDate));
	
    }
 
    /**
     * Si la condition est vrai alors cette action est execute avant le pas
     * de temps de la simulation.
     * @param simulation La simulation pour lequel on utilise cette regle
     */
	// Booleen permettant que ne boucler que sur un seul metier dans la preaction :
	boolean first = true;
    public void preAction(SimulationContext context, TimeStep step, Metier metier) throws Exception {        
			if (log.isDebugEnabled()) {
             	log.debug("first = "+ first + "date:"+ step);
   			}
			//System.out.println("first = " + first+ " ,on passe dans la preaction ?");
			if (first){ // on passe dans preaction pour la premiere fois
				//System.out.println("Oui, preaction : ");
				double newProp=0;
				int newInactivity = 0;
				
				// Boucle sur les strategies 
				//System.out.println("strs dans preaction : " + strs);
				//System.out.println("mesStrategies : " + mesStrategies);
				
				//List<Strategy> mStr = new ArrayList(mesStrategies.values());
				for(Strategy strIndex : allStrategies){
				//for(Strategy strIndex : mStr){
					// interdit de faire des set sur les strategies de la semantique de la matrice, il faut recuperer les strategies de la date courante
					Strategy str = (Strategy)context.getDB().findByTopiaId(strIndex.getTopiaId());
					StrategyMonthInfo smi = str.getStrategyMonthInfo(step.getMonth());
					
					//System.out.println("pour str="+str.getName());
					
					int start = param_startDate*12;
					if(context.getSimulationStorage().getParameter().getTagValue().get("year") != null){
						String tmp1 = context.getSimulationStorage().getParameter().getTagValue().get("year");
						start = Integer.parseInt(tmp1)*12;//(int)StringUtil.toArrayDouble(tmp1.split(";"))[0]*12;
					}

					TimeStep s = step.add(start);
					
					newInactivity = (int) matInactivity.getValue(str,s);
					smi.setMinInactivityDays(newInactivity);
					//System.out.println("pour la strategy=" + str.getName() +", l'ann: "+ date.getYear() + " et le mois = "+date.getMonth()+": newInactivity= "+ newInactivity);
					
					// on boucle sur les metiers de la strategie pour initialiser les efforts avec matEffort
					Collection<EffortDescription> strMet = str.getSetOfVessels().getPossibleMetiers() ;
					for (EffortDescription ed : strMet){ 
						Metier strMetier = ed.getPossibleMetiers();
						/*System.out.println("pour le strat=" + str.getName());
       				    System.out.println("pour le metier=" + strMetier.getName());
       				    System.out.println("dim strMat=" + strMat.get(str).getSemantic(0));*/
       				    	newProp = strMat.get(str).getValue(strMetier.getName(),s);
						//System.out.println("pour le metier=" + strMetier +" l'anne : "+ step.getYear() + "et le mois = "+step.getMonth()+" newProp= "+ newProp);*/
					    smi.setProportionMetier(strMetier,newProp);
						
					}
					
					// change le nb de navires pour la flottille
					int nbv = (int) matNbVess.getValue(str, s.getYear());
					str.getSetOfVessels().setNumberOfVessels(nbv);
					
					
				}//fin de boucle sur strategies
				first = false;	 
			}// fin de first= true
 	        if (log.isDebugEnabled()) {
        	    log.debug("fin Effort Anchois Action avant");
       		 }
    }// fin de pre action
 
    /**
     * Si la condition est vrai alors cette action est strategy=" + str.getName() +", l'anne : "+ date.getYear() + " et le mois = "+date.getMonth()+": newInactivity= "+ newInactivity);
					
					// on boucle sur les metiers de la strategie pour initialiser les efforts avec matEffort
					Collection<EffortDescription> strMet = str.getSetOfVessels().getPossibleMetiers() ;
					for (EffortDescription ed : strMet){ 
						Metier strMetier = ed.getPossibleMetiers();
       				    System.out.println("pour le metier=" + strMetier);
execut
     * de temps de la simulation.
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    public void postAction(SimulationContext context, TimeStep step, Metier metier) throws Exception {
    first = true ;   
    }

}
