/*
 * Copyright (C) 2010
 *
 * 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 rules;

import static org.nuiton.i18n.I18n._;
import org.nuiton.j2r.REngine;
import org.nuiton.j2r.RException;
import org.nuiton.j2r.RProxy;
import org.nuiton.j2r.types.RDataFrame;
import scripts.ResultName;
import scripts.SiMatrix;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import fr.ifremer.isisfish.types.TimeStep;
import fr.ifremer.isisfish.types.Month;
import scripts.ResultName;
import java.io.Writer;
import fr.ifremer.isisfish.export.Export;
import java.io.File;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import org.nuiton.util.FileUtil;
import org.nuiton.math.matrix.*;
import fr.ifremer.isisfish.entities.Population;
import fr.ifremer.isisfish.util.Doc;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.TimeStep;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.rule.AbstractRule;
import fr.ifremer.isisfish.datastore.SimulationStorage;
import fr.ifremer.isisfish.datastore.ResultStorage;
import org.nuiton.math.matrix.MatrixIterator;
import org.nuiton.topia.TopiaContext;
import fr.ifremer.isisfish.simulator.SimulationControl;
import fr.ifremer.isisfish.simulator.SimulationProperties;



/**
 * XSA.java
 *
 * Created: 11 mars 2010
 *
 * @author ben <user.name@vcs.hostName>
 * @version $Revision: 1545 $
 * Last update: $Date: 2 
 * by : $Author: Paul et Youen $
 */
public class XSA extends AbstractRule {

	/** to use log facility, just put in your code: log.info("..."); */
	private static Log log = LogFactory.getLog(XSA.class);

	protected TopiaContext db = null;

	private MatrixND catchYear0;
	private MatrixND effortS1Met0;
	private MatrixND catchS1Met0;
	public MatrixND matrixCpue;
	public static MatrixND matrixNageExport;
	public static MatrixND matrixFageExport;
	public static double ssbExport, fbarExport;

	RDataFrame FauxAges;
	RDataFrame NauxAges;
	// Configuration

	@Doc("Mois de l'evaluation")
	public Month param_month = Month.JANUARY;
    
	// Matrices necessaires
	public String [] necessaryResult = {
		ResultName.MATRIX_ABUNDANCE,
		ResultName.MATRIX_BIOMASS,
		ResultName.MATRIX_CATCH_PER_STRATEGY_MET_PER_ZONE_POP,
		ResultName.MATRIX_DISCARDS_PER_STR_MET_PER_ZONE_POP,
		ResultName.MATRIX_DISCARDS_WEIGHT_PER_STR_MET_PER_ZONE_POP 
    };

    public String[] getNecessaryResult() {
		return this.necessaryResult;
	}

	public String getDescription() throws Exception {
		return _("Fait une XSA");
	}


    public void init(SimulationContext context) throws Exception {

		TimeStep date = new TimeStep(0);
		
		List<Strategy> strs = SiMatrix.getSiMatrix(context).getStrategies(date);
		List<Metier> metiers = SiMatrix.getSiMatrix(context).getMetiers(date);
		List<Month> months = Arrays.asList(Month.MONTH);
		List<Population> populations = SiMatrix.getSiMatrix(context).getPopulations(date);
		List<PopulationGroup> agegroupsall = new ArrayList<PopulationGroup>();
		this.db = context.getDB();
		for (Population pop : populations) {
			if (pop.getName().compareTo("BlueLingSouth") == 0){
				for (PopulationGroup age : pop.getPopulationGroup()) {
					PopulationGroup tmp = (PopulationGroup) db.findByTopiaId(age.getTopiaId());
					agegroupsall.add(tmp);
				}
			}	
		}
		catchYear0 = MatrixFactory.getInstance().create(
			"catchYear0",
			new List[]{agegroupsall},
			new String[]{"AgeGroupsAll"});
		catchS1Met0 = MatrixFactory.getInstance().create(
			"catchS1MetYear0",
			new List[]{agegroupsall,metiers},
			new String[]{"AgeGroupsAll","Metiers"});
		effortS1Met0 = MatrixFactory.getInstance().create(
			"effortS1MetYear0",
			new List[]{metiers},
			new String[]{"Metiers"});
		matrixCpue = MatrixFactory.getInstance().create(
			"matrixCpue",
			new List[]{agegroupsall},
			new String[]{"AgeGroupsAll"});
		matrixNageExport = MatrixFactory.getInstance().create(
			"matrixNageExport",
			new List[]{agegroupsall},
			new String[]{"AgeGroupsAll"});
		matrixFageExport = MatrixFactory.getInstance().create(
			"matrixFageExport",
			new List[]{agegroupsall},
			new String[]{"AgeGroupsAll"});
	
		REngine engine = new RProxy();
            
		engine.voidEval("library(FLXSA)");
		engine.voidEval("stock<-readFLStock(\"C:/Paul/2005-2011/DPCP/P6/DEEPFISHMAN/Science/WP5/VPA/bli567ind.txt\")");
		engine.voidEval("indices<-readFLIndices(\"C:/Paul/2005-2011/DPCP/P6/DEEPFISHMAN/Science/WP5/VPA/bli567fl.txt\")");

   		  //engine.voidEval("stock<-readFLStock(\"F:/D/Projets/deepfishman/Blue ling/bli567ind.txt\")");
   		  //
		  //engine.voidEval("indices<-readFLIndices(\"F:/D/Projets/deepfishman/Blue ling/bli567fl.txt\")");

		
		// Parametres XSA		  
		engine.voidEval("tol<-1.e-09");
		engine.voidEval("maxit<-1000");
		engine.voidEval("min.nse<-0.3");
		engine.voidEval("fse<-1.0");
		engine.voidEval("rage<-0");
		engine.voidEval("qage<-14");
		engine.voidEval("shk.n<-TRUE");
		engine.voidEval("shk.f<-TRUE");
		engine.voidEval("shk.yrs<-5");
		engine.voidEval("shk.ages<-5");
		engine.voidEval("window<-100");
		engine.voidEval("tsrange<-20");
		engine.voidEval("tspower<-0");
		// stocke dans FLXSA les parametres
		engine.voidEval("xsa.control<-FLXSA.control(tol=tol,maxit=maxit,min.nse=min.nse,fse=fse,rage=rage,qage=qage,shk.n=shk.n,shk.f=shk.f,shk.yrs=shk.yrs,shk.ages=shk.ages,window=window,tsrange=tsrange,tspower=tspower,vpa=FALSE)");
		engine.voidEval("stock@catch.n <- stock@landings.n"); // recupere les capt aux ages de l annee precedente		  
		engine.voidEval("save.image(file=\"C:/Paul/2005-2011/DPCP/P6/DEEPFISHMAN/Science/WP5/VPA/xsaRes.RData\")"); // sauver l'objet pour pouvoir le rouvrir ensuite pour utilisation
  		  //engine.voidEval("save.image(file=\"F:/D/Projets/deepfishman/Blue ling/xsaRes.RData\")"); // sauver l'objet pour pouvoir le rouvrir ensuite pour utilisation
		engine.voidEval("stock<-setPlusGroup(stock,17)");//yv 200712    		  
    }


	/**
	* 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 date, Metier metier) throws Exception {
		Month currentMonth = date.getMonth();
		if (currentMonth.equals(param_month) && (date.getYear() > 0)) { 
			return true;
		}
		else return false;        
    }

	// Booleen permettant que ne boucler que sur un seul metier dans la preaction :
	boolean first = true;

	/**
	* @param simulation La simulation pour lequel on utilise cette regle
	*/
	public void preAction(SimulationContext context, TimeStep date, Metier metier) throws Exception {

		if (first){
			List<Strategy> strs = SiMatrix.getSiMatrix(context).getStrategies(date);
			List<Metier> metiers = SiMatrix.getSiMatrix(context).getMetiers(date);
			List<Month> months = Arrays.asList(Month.MONTH);
			List<Population> populations = SiMatrix.getSiMatrix(context).getPopulations(date);
			ResultStorage resultmanager = context.getSimulationStorage().getResultStorage();
			for (Population pop : populations) {
				if (pop.getName().compareTo("BlueLingSouth") == 0){
					List<PopulationGroup> agegroups = pop.getPopulationGroup();
					for (PopulationGroup age : agegroups){
						catchYear0.setValue(age,0.0);
						for (Strategy str : strs){
							if (str.getName().compareTo("S1") == 0){
								for (Metier met : metiers){
									catchS1Met0.setValue(age,met,0.0);
									effortS1Met0.setValue(met,0.0);
								}	
							}
						}
					} // end of age loop;
					for (TimeStep dat = date.previousYear(); dat.before(date); dat = dat.next()) {
						MatrixND CatchPop = resultmanager.getMatrix(dat,pop,ResultName.MATRIX_CATCH_PER_STRATEGY_MET_PER_ZONE_POP);
						MatrixND EffortS1Met = resultmanager.getMatrix(dat,ResultName.MATRIX_EFFORT_NOMINAL_PER_STRATEGY_MET);
						MatrixND Prov2 = CatchPop.sumOverDim(0); // sum over strategies;
						Prov2 = Prov2.sumOverDim(1); // sum over metiers;
						Prov2 = Prov2.sumOverDim(3); // sum over zones;
						MatrixND Prov3 = CatchPop.sumOverDim(3); // sum over zones;
						for (PopulationGroup age : agegroups){
							System.out.println("pop: "+ pop + " dat: "+ dat + " age: " + age.getId() +
							" Prov2: " + Prov2.getValue(0,0,age.getId(),0) + " catchYear0 : " + catchYear0.getValue(age));
							catchYear0.setValue(age,catchYear0.getValue(age)+Prov2.getValue(0,0,age.getId(),0));
						} //end of age loop;
						for (Strategy str : strs){
							if (str.getName().compareTo("S1") == 0){
								for (Metier met : metiers){
									for (PopulationGroup age : agegroups){
										catchS1Met0.setValue(age,met,catchS1Met0.getValue(age,met)+
											Prov3.reduce().getValue(str,met,age));
									} // end of age loop;
									effortS1Met0.setValue(met,effortS1Met0.getValue(met)+
										EffortS1Met.getValue(str,met));
								} // end of metier loop;
							} // end of str = S1 if-test;
						} // end of str loop;						
					} // end of dat loop;
					for (PopulationGroup age : agegroups){
						double dummyCpue = 0.0;
						int dummyMet = 0;
						for (Metier met : metiers){
							if (effortS1Met0.getValue(met) > 0.0){  
								dummyCpue += catchS1Met0.getValue(age,met)/effortS1Met0.getValue(met);
								dummyMet++;
							}
						} // end of metier loop;
						if (dummyMet > 0){
							//matrixCpue.setValue(age,pop,dummyCpue/dummyMet);
							matrixCpue.setValue(age,dummyCpue/dummyMet);//YV
						}
						else{
							matrixCpue.setValue(age,0.00);
						}
			 		} // end of age loop;
	
					// Si on est au mois de Janvier, avant le pas de temps: 
					// Recuperer les captures aux ages etc du pas de temps precedent
					// realiser la xsa
					//log.info("Avant engine");
					REngine engine = new RProxy();
					//log.info("Avant import");
					
					engine.voidEval("load(file=\"C:/Paul/2005-2011/DPCP/P6/DEEPFISHMAN/Science/WP5/VPA/xsaRes.RData\")");
					//engine.voidEval("load(file=\"F:/D/Projets/deepfishman/Blue ling/xsaRes.RData\")");
					
					// etendre l'objet FLR
					// Objet Stock
					engine.voidEval("stock<-window(stock,end=range(stock)[5]+1)"); // On agrandit la fenetre temporelle du stock de 1 YV
					
					log.info("catchYear0" + catchYear0);
					MatrixND caaAexprter = catchYear0.getSubMatrix(0,7,11) ;
					log.info("caaAexporter" + caaAexprter);
					//
					int j=0;
					String essaimatrix = "test <- c(";
						for(MatrixIterator i = caaAexprter.iterator();i.hasNext();){
						i.next();
						j = j+1;
						if (j < 11) {
                            essaimatrix += i.getValue() + ",";
                        } else {
                            essaimatrix += i.getValue();
                        }
						}
						essaimatrix = essaimatrix + ")";
                    engine.voidEval(essaimatrix);
                    //log.info("essaimatrix=" + essaimatrix);
					//engine.voidEval("save.image(file=\"F:/D/Projets/deepfishman/Blue ling/xsaRes.RData\")");
						
					//engine.voidEval("test<-as.vector(" + caaAexprter + ")");
					engine.voidEval("stock@catch.n[,dim(stock@catch.n)[2],,,] <-test/1000" ); // recupere les capt aux ages de l annee precedente
					engine.voidEval("stock@catch.wt[,dim(stock@catch.n)[2],,,]<-as.vector(rowMeans(stock@catch.wt[,c((dim(stock@catch.wt)[2] - 1):(dim(stock@catch.wt)[2] - 3)),,,]))"); // calcule la moyenne des poids aux ages sur les 3 dernieres annees
					engine.voidEval("stock@landings.n[,dim(stock@landings.n)[2],,,]<-stock@catch.n[,dim(stock@catch.n)[2],,,] "); // pas de rejets les capt==debarquements
					engine.voidEval("stock@landings.wt[,dim(stock@landings.wt)[2],,,]<-as.vector(rowMeans(stock@landings.wt[,c((dim(stock@landings.wt)[2] - 1):(dim(stock@landings.wt)[2] - 3)),,,]))"); // calcule la moyenne des poids aux ages sur les 3 dernieres annees
					engine.voidEval("stock@stock.wt[,dim(stock@stock.wt)[2],,,]<-as.vector(rowMeans(stock@stock.wt[,c((dim(stock@stock.wt)[2] - 1):(dim(stock@stock.wt)[2] - 3)),,,]))"); // calcule la moyenne des poids aux ages sur les 3 dernieres annees
					engine.voidEval("stock@m[,dim(stock@m)[2],,,]<-stock@m[,dim(stock@m)[2] - 1,,,] "); // copie la M de l'anne precedente
					engine.voidEval("stock@mat[,dim(stock@mat)[2],,,]<-stock@mat[,dim(stock@mat)[2] - 1,,,] "); // copie la Maturite de l'anne precedente
					engine.voidEval("stock@harvest.spwn[,dim(stock@harvest.spwn)[2],,,]<-stock@harvest.spwn[,dim(stock@harvest.spwn)[2] - 1,,,] "); // 
					engine.voidEval("stock@m.spwn[,dim(stock@m.spwn)[2],,,]<-stock@m.spwn[,dim(stock@m.spwn)[2] - 1,,,] "); // 
		
					// Objet fleet
					engine.voidEval("indices<-window(indices,end=range(indices)[4]+1)"); // On agrandit la fenetre temporelle de fleet de 1 YV

					MatrixND iaAexprter = matrixCpue.getSubMatrix(0,7,11) ;
					
					//
					int j2=0;
					String essaimatrix2 = "test <- c(";
						for(MatrixIterator i = iaAexprter.iterator();i.hasNext();){
						i.next();
						j2 = j2+1;
						if (j2 < 11) {
                            essaimatrix2 += i.getValue() + ",";
                        } else {
                            essaimatrix2 += i.getValue();
                        }
						}
						essaimatrix2 = essaimatrix2 + ")";
                    engine.voidEval(essaimatrix2);
					
					engine.voidEval("indices@.Data[[1]]@catch.n[,dim(indices@.Data[[1]]@catch.n)[2],,,]<-test/1000");// recupere les indices aux ages de l annee precedente
					engine.voidEval("indices@.Data[[1]]@effort[,dim(indices@.Data[[1]]@effort)[2],,,]<-1");// recupere les indices aux ages de l annee precedente
					 log.info("Avant XSA"); 
					// Faire la xsa
					engine.voidEval("xsa<-FLXSA(stock,indices,xsa.control)");
					log.info("Apres XSA");
					//engine.voidEval("save.image(file=\"C:/Paul/2005-2011/DPCP/P6/DEEPFISHMAN/Science/WP5/VPA/xsaRes.RData\")");
					
					//engine.voidEval("save.image(file=\"F:/D/Projets/deepfishman/Blue ling/xsaRes.RData\")");
					
					// retourner ssb et f de la derniere annee
					//engine.voidEval("range(stock)[3]<-range(xsa)[3]");
					//engine.voidEval("stock<-stock+xsa");
					engine.voidEval("stock@harvest<-xsa@harvest"); // yv 200712
					log.info("J suis passe la");
					engine.voidEval("stock@stock.n<-xsa@stock.n");// yv 200712
					Double ssb = ((Double) engine.eval("ssb<-as.numeric(as.data.frame(ssb(stock)[1,ncol(ssb(stock))]))[7]")).doubleValue();
					Double fbar = ((Double) engine.eval("fbar<-as.numeric(as.data.frame(fbar(stock)[1,ncol(fbar(stock))]))[7]")).doubleValue();
					
				
					FauxAges = (RDataFrame) engine.eval("FauxAges <- as.data.frame(as.data.frame(harvest(stock)[,ncol(harvest(stock))])$data)");
					NauxAges = (RDataFrame) engine.eval("NauxAges<- as.data.frame(as.data.frame(stock.n(stock)[,ncol(stock.n(stock))])$data)");
					NauxAges.setVariable("NauxAges");
                                        FauxAges.setVariable("FauxAges");
					//MatrixND FauxAges = ((MatrixND) engine.eval("FauxAges <- as.data.frame(harvest(xsa.stock)[,ncol(harvest(xsa.stock))])$data")).doubleValue();
					//MatrixND NauxAges = ((MatrixND) engine.eval("NauxAges <- as.data.frame(stock.n(xsa.stock)[,ncol(stock.n(xsa.stock))])$data")).doubleValue();
					ssbExport = ssb;
					fbarExport = fbar;
					
					engine.voidEval("save.image(file=\"C:/Paul/2005-2011/DPCP/P6/DEEPFISHMAN/Science/WP5/VPA/xsaRes.RData\")");

					//log.info("agegroups = " + agegroups);
					
					for (int iage=0; iage <= pop.sizePopulationGroup()-1; iage++){
						PopulationGroup age = pop.getPopulationGroup().get(iage);
						if (iage < 7){
							matrixNageExport.setValue(age,0.0);
							matrixFageExport.setValue(age,0.0);
						} // end of iage if-test;
						else{
						log.info("age = " + iage);
						log.info("NauxAges = " + NauxAges);
						//log.info("NauxAges = " + NauxAges.get(0,iage-7) + "iage= " + iage);
							matrixNageExport.setValue(age,(Double)  NauxAges.get(0,iage-7));
							matrixFageExport.setValue(age,(Double)  FauxAges.get(0,iage-7));
						} // end of iage else-test;
					} // end of age for loop;
					
					engine.voidEval("save.image(file=\"C:/Paul/2005-2011/DPCP/P6/DEEPFISHMAN/Science/WP5/VPA/xsaRes.RData\")");
					//engine.voidEval("save.image(file=\"F:/D/Projets/deepfishman/Blue ling/xsaRes.RData\")");
					
				} // end of pop=bli if-test;	
			} // end of pop loop;
			first = false;
		} // end of (first) if-test;

	}

	/**
	* @param simulation La simulation pour lequel on utilise cette regle
	*/
    public void postAction(SimulationContext context, TimeStep date, Metier metier) throws Exception {
		first = true;
	}

}