/*
 * Copyright (C) 2011 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 rules;

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

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

import scripts.ResultName;
import scripts.SiMatrix;
import scripts.RandomNormal_recruitsGarfish;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import java.io.Writer;

import org.nuiton.math.matrix.*;

import fr.ifremer.isisfish.util.Doc;
import fr.ifremer.isisfish.*;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.Date;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.rule.AbstractRule;
import fr.ifremer.isisfish.datastore.SimulationStorage;
import fr.ifremer.isisfish.datastore.ResultStorage;
import fr.ifremer.isisfish.IsisFishDAOHelper;
import fr.ifremer.isisfish.simulator.MetierMonitor;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.Date;
import fr.ifremer.isisfish.types.Month;
import fr.ifremer.isisfish.entities.*;
import fr.ifremer.isisfish.rule.AbstractRule;
import fr.ifremer.isisfish.simulator.PopulationMonitor;

/**
 * Recruit_distribution_garfish.java
 *
 * Created: 29 June 2011
 *
 * @author jandre <user.name@vcs.hostName>
 * @version $Revision: 1545 $
 * Last update: $Date: 29 June 2011 $
 * by : $Author: jandre $
 */
public class Future_recruitment_garfish extends AbstractRule {

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

	@Doc("Mean normal distribution")
	public double param_MeanNormDist = 1439097;//for garfish
	@Doc("Variance normal distribution")
	public double param_StdNormDist = 609814.2; // for garfish

    	@Doc("Month for begining of reproduction")
    	public Month param_beginrepro = Month.OCTOBER;
    	@Doc("Month for end of reproduction")
    	public Month param_endrepro = Month.JANUARY;

    	public Population param_Population = null;
    	boolean dejaFait = false;   //pour ne pas le faire pour chaque metier

	protected Population pop;
	//int index=0;
	private Random fRandom = new Random();
 	private double getGaussian(double aMean, double aStd){
      return aMean + fRandom.nextGaussian() * aStd;
  	}
  
    	protected List<String> namePopList;
    	//protected List<Double> listGarfishRecruits;// = RandomNormal_recruitsGarfish.garfishRecruitsList;
//*************************************************************************************************
    public String [] necessaryResult = {
        // put here all necessary result for this rule
	    // example: 
	    // ResultName.MATRIX_BIOMASS,
	    // ResultName.MATRIX_NET_VALUE_OF_LANDINGS_PER_STRATEGY_MET,
	   ResultName.MATRIX_ABUNDANCE
    };

    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 {
        // TODO
        return _("Picks a random number from the recruitment distribution (normal) for garfish and distributes the recruits"+ 
        "Because reproduction takes place over 4 months, each reproduction month receive 1/4 of recruits");
    }

//*************************************************************************************************
    /**
     * Appele au demarrage de la simulation, cette methode permet d'initialiser
     * des valeurs
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    public void init(SimulationContext context) throws Exception {
    	
    }
    
//*************************************************************************************************
    /**
     * 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, Date date, Metier metier) throws Exception {
       
        log.info("Finds out if the rule applies (i.e. if we are in the reproductive months");
        boolean result = false;
         if (date.getMonth().equals(Month.OCTOBER)||date.getMonth().equals(Month.NOVEMBER)||
         date.getMonth().equals(Month.DECEMBER)||date.getMonth().equals(Month.JANUARY)) {
            return true;
        }
        /*if (date.getMonth().before(param_beginrepro)) {
            return false;
        } else if (date.getMonth().after(param_endrepro)) {
            return false;
        }*/
          
 	return result;
      
    }

//*************************************************************************************************
    /**
     * Si la condition est vrai alors cette action est executee avant le pas
     * de temps de la simulation.
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    public void preAction(SimulationContext context, Date date, Metier metier) throws Exception {
    
    		System.out.println("already done ? "+ dejaFait);
		if (dejaFait == false){
    		log.info("Pre-simulation: applies the rule to the month of reproduction");
    		//int currentYear = context.getSimulationControl().getDate().getYear();
		
		PopulationMonitor popMon = context.getPopulationMonitor();
		MatrixND eff = popMon.getN(param_Population);

		Month month = date.getMonth();
		//recruitment zone for the population - can be a list of zone of presence
		
		List<Population> poplist = popMon.getPopulations();
		log.info("list of population:" + poplist);

		//indexOf only recognise string and the list is a list of Population (not strings...)
		// so create a mirror list in string to find the index of the population that I want
		namePopList = new ArrayList<String>();// Creates an empty list
    	 	
    	 	int size = poplist.size();
    	 	int count = 0;
    	 	   	 	
    	 	while(count<size){
    	 			String namePop = poplist.get(count).getName();
   	 			namePopList.add(namePop);
   	 			log.info("list of population string:" + namePopList);
   	 			count = count+1;
    	 		}
		
		int index = namePopList.indexOf("Garfish_east");
		log.info("Garfish index:" + index);
		pop = poplist.get(index); // gets the population that I want

		// Puts the recruits each year
		List<Zone> zoneRecru = pop.getRecruitmentZone();
		double recruit = getGaussian(param_MeanNormDist,param_StdNormDist);
		
			if (recruit<0) {
				recruit =0; // set recruitment to 0 if the distribution comes out with a negative number
			}
    			for (MatrixIterator i = eff.iterator(); i.hasNext();){
				i.next();
				Object[] sems = i.getSemanticsCoordinates();
				PopulationGroup group = (PopulationGroup) sems[0];
				Zone zone = (Zone) sems[1];
				System.out.println("zone :"+ zone+ " group:"+group.getId());
				//int currentYear = context.getSimulationControl().getDate().getYear();
				if ((zoneRecru.contains(zone) & (group.getId() == 0))){    					
    					i.setValue(recruit/4);
    					log.info("recruit per month: " + month + ": " + recruit);  					
    				}// end if zone recrutment
    		
    		
    			}//end for Matrix iterator
		dejaFait = true ; //pour ne pas le refaire au metier suivant-when running with fishing
		}
		//dejaFait = true ; //pour ne pas le refaire au metier suivant-when doing pop dynamics only
    //return result;		
    }

//*************************************************************************************************
    /**
     * Si la condition est vrai alors cette action est executee apres le pas
     * de temps de la simulation.
     * @param simulation La simulation pour lequel on utilise cette regle
     */
    public void postAction(SimulationContext context, Date date, Metier metier) throws Exception {
    dejaFait = false;    
    }
//*************************************************************************************************
 
}