/* *##%
 * Copyright (C) 2006
 *     Code Lutin, Cédric Pineau, Benjamin Poussin
 *
 * 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.
 *##%*/

/* *
 * GravityModel.java
 *
 * Created: 4 sept. 06 15:49:08
 *
 * @author poussin
 * @version $Revision: 1.9 $
 *
 * Last update: $Date: 2007-03-01 17:16:12 $
 * by : $Author: bpoussin $
 */

package scripts;

import static org.codelutin.i18n.I18n._;
import static org.codelutin.i18n.I18n.n_;

import java.util.Collection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codelutin.math.matrix.MatrixFactory;
import org.codelutin.math.matrix.MatrixND;
import org.codelutin.topia.TopiaContext;
import org.codelutin.topia.TopiaException;

import fr.ifremer.isisfish.datastore.ResultStorage;
import fr.ifremer.isisfish.datastore.StorageException;
import fr.ifremer.isisfish.entities.EffortDescription;
import fr.ifremer.isisfish.entities.Metier;
import fr.ifremer.isisfish.entities.Population;
import fr.ifremer.isisfish.entities.PopulationGroup;
import fr.ifremer.isisfish.entities.SetOfVessels;
import fr.ifremer.isisfish.entities.Strategy;
import fr.ifremer.isisfish.entities.Zone;
import fr.ifremer.isisfish.simulator.SimulationContext;
import fr.ifremer.isisfish.types.Date;
import fr.ifremer.isisfish.types.Month;
import fr.ifremer.isisfish.types.TimeUnit;


/**
 * @author poussin
 *
 */

public class GravityModel {

    /** to use log facility, just put in your code: log.info("..."); */
    static private Log log = LogFactory.getLog(GravityModel.class);
    
    protected SimulationContext context = null;
    protected TopiaContext db = null;
    protected SiMatrix siMatrix = null;
    protected ResultStorage resultManager = null;

    /**
     * Method used to get GravityModel used for simulation
     * @param context context simulation
     * @return GravityModel or null if no GravityModel created for simulation
     */
    public static GravityModel getGravityModel(SimulationContext context) {
        GravityModel result = (GravityModel)context.getValue(GravityModel.class.getName());
        return result;
    }
    
    private static void setGravityModel(SimulationContext context, GravityModel gravityModel) {
        context.setValue(GravityModel.class.getName(), gravityModel);
    }
    
    
    public GravityModel(SimulationContext context, SiMatrix siMatrix) throws TopiaException, StorageException{
        this.context = context;
        this.db = context.getDB();
        this.resultManager = context.getSimulationStorage().getResultStorage();
        this.siMatrix = siMatrix;
        setGravityModel(context, this);
    }

    //////////////////////////////////////////////////////////////////////
    // Matrice de Revenue et Cout
    //////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////
    // MatrixFishingTimePerMonthPerVessel
    //////////////////////////////////////////////////////////////////////

    public MatrixND matrixFishingTimePerMonthPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_FISHING_TIME_PER_MONTH_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = fishingTimePerMonthPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
        
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = fishingTimePerMonthPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * FishingTimePerMonthPerVessel[str,met,month] = FishingTimePerTrip[str,met,month]NbTripsPerMonth[str,month]

     * @param str
     * @param metier
     * @param date
     * @return
     */
    private double fishingTimePerMonthPerVessel(Strategy str, Metier metier, Date date) {
         Month month = date.getMonth();
         double timePerTrip = siMatrix.fishingTimePerTrip(str, metier, date);
         int nbTrip = str.getStrategyMonthInfo(month).getNumberOfTrips();
         return timePerTrip * nbTrip;
     }


    //////////////////////////////////////////////////////////////////////
    // matrixFuelCostsOfTravelPerVessel
    //////////////////////////////////////////////////////////////////////

    public MatrixND matrixFuelCostsOfTravelPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_FUEL_COSTS_OF_TRAVEL_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = fuelCostsOfTravelPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = fuelCostsOfTravelPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * FuelCostsOfTravelPerVessel[sov,met,month] = NbTripsPerMonth[str,month]*TravelTimePerTrip[sov,met,month]*UnitFuelCostsOfTravel[vt]
     *
     * @param str
     * @param metier
     * @param date
     * @return
     */
    private double fuelCostsOfTravelPerVessel(Strategy str, Metier metier, Date date) {
        Month month = date.getMonth();
        int nbTrip = str.getStrategyMonthInfo(month).getNumberOfTrips();

        Collection<Zone> zone = metier.getMetierSeasonInfo(month).getZone();
        // TODO: verifier que travelTime est bien en heure, car le unitFuelCost est l'unite par heure
        double travelTime = siMatrix.travelTimePerTrip(str.getSetOfVessels(), zone);
        double unitFuelCost = str.getSetOfVessels().getVesselType().getUnitFuelCostOfTravel();

        return nbTrip * travelTime * unitFuelCost;
    }

    //////////////////////////////////////////////////////////////////////
    // matrixCostsOfFishingPerVessel
    //////////////////////////////////////////////////////////////////////

    public MatrixND matrixCostsOfFishingPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_COSTS_OF_FISHING_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = costsOfFishingPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = costsOfFishingPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * CostsOfFishingPerVessel[str,met,month]= FishingTimePerMonthPerVessel [str,met,month] {NbFishingOperationsPerDay[sov,met] UnitCostsOfFishing[sov,met] / 24}
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     */
    private double costsOfFishingPerVessel(Strategy str, Metier metier, Date date) {
        double fishingTime = fishingTimePerMonthPerVessel(str, metier, date);

        EffortDescription effort = str.getSetOfVessels().getPossibleMetiers(metier);
        int nbOperation = 0;
        double unitCostOfFishing = 0;
        if(effort != null){
            nbOperation = effort.getFishingOperation();
            unitCostOfFishing = effort.getUnitCostOfFishing();
        }

        return fishingTime * ( nbOperation * unitCostOfFishing / TimeUnit.HOUR_PER_DAY);
    }

    //////////////////////////////////////////////////////////////////////
    // matrixFuelCostsPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixFuelCostsPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_FUEL_COSTS_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = fuelCostsPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = fuelCostsPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * FuelCostsPerVessel[str,met,month] = FuelCostsOfTravelPerVessel [sov,met,month] + CostsOfFishingPerVessel [str,met,month]
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     */
    private double fuelCostsPerVessel(Strategy str, Metier metier, Date date) {
        double fuelCosts = fuelCostsOfTravelPerVessel(str, metier, date);
        double costsOfFishing = costsOfFishingPerVessel(str, metier, date);

        return fuelCosts + costsOfFishing;
    }

    //////////////////////////////////////////////////////////////////////
    // matrixRepairAndMaintenanceGearCostsPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixRepairAndMaintenanceGearCostsPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_REPAIR_AND_MAINTENANCE_GEAR_COSTS_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = repairAndMaintenanceGearCostsPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = repairAndMaintenanceGearCostsPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * RepairAndMaintenanceGearCostsPerVessel[str,met,month] = FishingTimePerMonthPerVessel[str,met,month] *RepairAndMaintenanceGearCostsPerDay[sov,met]/NbHoursPerDay
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     */
    private double repairAndMaintenanceGearCostsPerVessel(Strategy str, Metier metier, Date date) {
        double fishingTime = fishingTimePerMonthPerVessel(str, metier, date);

        EffortDescription effort = str.getSetOfVessels().getPossibleMetiers(metier);

        double repair = 0;
        if(effort != null){
            repair = effort.getRepairAndMaintenanceGearCost();
        }
        // FIXME verifier qu'il faut bien retourner 0, si pas d'effort
        return fishingTime * repair / TimeUnit.HOUR_PER_DAY;
    }

    //////////////////////////////////////////////////////////////////////
    // matrixOtherRunningCostsPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixOtherRunningCostsPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_OTHER_RUNNING_COSTS_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = otherRunningCostsPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = otherRunningCostsPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * OtherRunningCostsPerVessel[str,met,month]= FishingTimePerMonthPerVessel[str,met,month]*OtherRunningCostsPerDay[sov,met]/ NbHoursPerDay
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     */
    private double otherRunningCostsPerVessel(Strategy str, Metier metier, Date date) {
        double fishingTime = fishingTimePerMonthPerVessel(str, metier, date);

        EffortDescription effort = str.getSetOfVessels().getPossibleMetiers(metier);

        double otherCosts = 0;
        if(effort != null){
            otherCosts = effort.getOtherRunningCost();
        }
        // FIXME verifier qu'il faut bien retourner 0, si pas d'effort
        return fishingTime * otherCosts / TimeUnit.HOUR_PER_DAY;
    }

    //////////////////////////////////////////////////////////////////////
    // matrixSharedNotFixedCostsPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixSharedNotFixedCostsPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_SHARED_NOT_FIXED_COSTS_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = sharedNotFixedCostsPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = sharedNotFixedCostsPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * SharedNotFixedCostsPerVessel[str,met,month]= FuelCostsPerVessel[str,met,month] + OtherRunningCostsPerVessel[str,met,month]
     *
     * @param str
     * @param metier
     * @param date
     * @return
     */
    private double sharedNotFixedCostsPerVessel(Strategy str, Metier metier, Date date) {
        double fuelCostsPerVessel = fuelCostsPerVessel(str, metier, date);
        double otherRunningCostsPerVessel = otherRunningCostsPerVessel(str, metier, date);

        return fuelCostsPerVessel + otherRunningCostsPerVessel;
   }

    //////////////////////////////////////////////////////////////////////
    // matrixSharedFixedCostsPerVesselPerMet
    //////////////////////////////////////////////////////////////////////
// Supprime avec Steph le 20070227 
//    public MatrixND matrixSharedFixedCostsPerVesselPerMet(Date date) throws TopiaException{
//        List<Strategy> strategies = siMatrix.getStrategies(date);
//
//        MatrixND result = MatrixFactory.getInstance().create(
//                ResultName.MATRIX_SHARED_FIXED_COSTS_PER_VESSEL_PER_MET,
//                new List[]{strategies},
//                new String[]{n_("Strategies")});
//
//        for (int s=0; s < strategies.size(); s++) {
//            Strategy str = strategies.get(s);
//            double value = sharedFixedCostsPerVesselPerMet(str, date);
//            result.setValue(s, value);
//        }
////        for(Strategy str : strategies){
////            double value = sharedFixedCostsPerVesselPerMet(str, date);
////            result.setValue(str, value);
////        }
//
//        return result;
//    }
//
//    /**
//     * implanté suivant document ModifTable3PourBP25-07-2006.doc
//     * SharedFixedCostsPerVesselPerMet [str,month]=FixedCostsPerMonth[sov]/NbMet[sov]
//     * 
//     * @param str
//     * @param date
//     * @return
//     */
//    private double sharedFixedCostsPerVesselPerMet(Strategy str, Date date) {       
//        SetOfVessels sov = str.getSetOfVessels();
//        double fixedCosts = sov.getFixedCosts();
//        int nbMet = sov.sizePossibleMetiers();
//
//        return fixedCosts / (double)nbMet;
//    }

    //////////////////////////////////////////////////////////////////////
    // matrixGrossValueOfLandingsPerSpeciesPerStrategyMet
    //////////////////////////////////////////////////////////////////////
 

    public MatrixND matrixGrossValueOfLandingsPerSpeciesPerStrategyMet(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);
        List<Population> pops = siMatrix.getPopulations(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_GROSS_VALUE_OF_LANDINGS_PER_SPECIES_PER_STRATEGY_MET,
                new List[]{strategies, metiers, pops},
                new String[]{n_("Strategies"), n_("Metiers"), n_("Populations")});

        for (int p=0; p < pops.size(); p++) {
            Population pop = pops.get(p);
            for (int s=0; s < strategies.size(); s++) {
                Strategy str = strategies.get(s);
                metiers = siMatrix.getMetiers(str, date);
                for (int m=0; m < metiers.size(); m++) {
                    Metier metier = metiers.get(m);
                    double value = grossValueOfLandingsPerSpeciesPerStrategyMet(str, metier, pop, date);
                    result.setValue(str, metier, pop, value);
                }
            }
        }

//        for(Population pop : pops){            
//            for(Strategy str : strategies){
//                metiers = siMatrix.getMetiers(str, date);
//                for(Metier metier : metiers) {
//                    double value = grossValueOfLandingsPerSpeciesPerStrategyMet(str, metier, pop, date);
//                    result.setValue(str, metier, pop, value);
//                }
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * GrossValueOfLandingsPerSpeciesPerStrategyMet[str,met,pop,month] = sum over classes_cl of [PricePerKg(pop,cl, t)* (CatchWeightPerStrategyMet [str,met,pop,cl,month] ?DiscardsWeightPerStrategyMet [str,met,pop,cl,mo
nth]
     * GrossValueOfLandingsPerSpeciesPerStrategyMet[str,met,pop,month] = sum over classes_cl of [PricePerKg(pop,cl, t)* (CatchWeightPerStrategyMet [str,met,pop,cl,month] -DiscardsWeightPerStrategyMet [str,met,pop,cl,mo
nth])]
     *
     * @param str
     * @param metier
     * @param pop
     * @param date
     * @return
     */
    private double grossValueOfLandingsPerSpeciesPerStrategyMet(Strategy str, Metier metier, Population pop, Date date) {
        List<PopulationGroup> groups = pop.getPopulationGroup();
        float result = 0;
        for(PopulationGroup group : groups){
            double price = group.getPrice();
            Collection<Zone> zones = pop.getPopulationZone();
            for(Zone zone : zones){
                double catchWeight =  getCatchWeightPerStrMet(str, metier, group, zone, date);
                double discardsWeight = getDiscardsWeightPerStrMet(str, metier, group, zone, date);
                // FIXME demander/verifier que ce le bon calcule
                result += price * (catchWeight - discardsWeight);
            }
        }
        return result;
    }

    /**
     * @param str
     * @param metier
     * @param group
     * @param zone
     * @param date
     * @return
     */
    private double getCatchWeightPerStrMet(Strategy str, Metier metier, PopulationGroup group, Zone zone, Date date) {
        MatrixND mat = resultManager.getMatrix(date, group.getPopulation(), ResultName.MATRIX_CATCH_WEIGHT_PER_STRATEGY_MET);
        double result = 0; 
        if(mat != null){
            result = mat.getValue(str, metier, group, zone);
        }
        return result;
    }

    /**
     * @param str
     * @param metier
     * @param group
     * @param zone
     * @param date
     * @return
     */
    private double getDiscardsWeightPerStrMet(Strategy str, Metier metier, PopulationGroup group, Zone zone, Date date) {
        MatrixND mat = resultManager.getMatrix(date, group.getPopulation(), ResultName.MATRIX_DISCARDS_WEIGHT_PER_STR_MET);
        double result = 0; 
        if(mat != null){
            result = mat.getValue(str, metier, group, zone);
        }
        return result;
    }

    //////////////////////////////////////////////////////////////////////
    // matrixGrossValueOfLandingsPerStrategyMet
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixGrossValueOfLandingsPerStrategyMet(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_GROSS_VALUE_OF_LANDINGS_PER_STRATEGY_MET,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = grossValueOfLandingsPerStrategyMet(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = grossValueOfLandingsPerStrategyMet(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }
        
        return result;
    }

    /**
     * @param str
     * @param metier
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double grossValueOfLandingsPerStrategyMet(Strategy str, Metier metier, Date date) throws TopiaException {
        List<Population> pops = siMatrix.getPopulations(date);
        double result = 0;
        for(int i=0; i<pops.size(); i++){
            Population pop = (Population)pops.get(i);
            result += grossValueOfLandingsPerSpeciesPerStrategyMet(str, metier, pop, date);
        }
        return result;
    }

    //////////////////////////////////////////////////////////////////////
    // matrixGrossValueOfLandingsPerStrategyMetPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixGrossValueOfLandingsPerStrategyMetPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_GROSS_VALUE_OF_LANDINGS_PER_STRATEGY_MET_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = grossValueOfLandingsPerStrategyMetPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = grossValueOfLandingsPerStrategyMetPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * GrossValueOfLandingsPerStrategyMetPerVessel[str,met,month] = GrossValueOfLandingsPerStrategyMet[str,met,month] /[PropNbVessels(str,sov)*NbVesselsSetOfVessels(sov)]
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double grossValueOfLandingsPerStrategyMetPerVessel(Strategy str, Metier metier, Date date) throws TopiaException {
        double grossValueOfLandingsPerStrategyMet = grossValueOfLandingsPerStrategyMet(str, metier, date);
        // FIXME verifier que c bien cette donnée qu'il faut utiliser dans le doc: PropNbVessels(str, sov)
        double proportionSetOfVessels = str.getProportionSetOfVessels();
        double numberOfVessels = str.getSetOfVessels().getNumberOfVessels();

        double grossValueOfLandingsOtherSpeciesPerStrategyMet = grossValueOfLandingsOtherSpeciesPerStrategyMet(str,metier,date);

        
        return (grossValueOfLandingsPerStrategyMet + grossValueOfLandingsOtherSpeciesPerStrategyMet) / (proportionSetOfVessels * numberOfVessels);
    }

    //////////////////////////////////////////////////////////////////////
    // matrixNetValueOfLandingsPerStrategyMet
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixNetValueOfLandingsPerStrategyMet(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_NET_VALUE_OF_LANDINGS_PER_STRATEGY_MET,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = netValueOfLandingsPerStrategyMet(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = netValueOfLandingsPerStrategyMet(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * NetValueOfLandingsPerStrategyMet[str,met,month] = GrossValueOfLandingsPerStrategyMet[str,met,month] (1-LandingCostRate[str,met] )
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double netValueOfLandingsPerStrategyMet(Strategy str, Metier metier, Date date) throws TopiaException {
        double grossValue = grossValueOfLandingsPerStrategyMet(str, metier, date);
        EffortDescription effort = str.getSetOfVessels().getPossibleMetiers(metier);
        double landingCost = 1;
        // FIXME demander si le metier n'a pas d'effort s'il faut que landingCost soit bien a 1
        if(effort != null){
            landingCost -= effort.getLandingCosts();
        }

        double grossValueOfLandingsOtherSpeciesPerStrategyMet = grossValueOfLandingsOtherSpeciesPerStrategyMet(str,metier,date);
        
        double result = (grossValue + grossValueOfLandingsOtherSpeciesPerStrategyMet)* landingCost;
        return result;
   }

    private double grossValueOfLandingsOtherSpeciesPerStrategyMet(Strategy str, Metier metier, Date date) throws TopiaException {
        // FIXME evaluer l'equation dans suivant le doc des equations
        return 0;
    }
    
    //////////////////////////////////////////////////////////////////////
    // matrixNetValueOfLandingsPerStrategyMetPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixNetValueOfLandingsPerStrategyMetPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_NET_VALUE_OF_LANDINGS_PER_STRATEGY_MET_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = netValueOfLandingsPerStrategyMetPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = netValueOfLandingsPerStrategyMetPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }
    

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * NetValueOfLandingsPerStrategyMetPerVessel[str,met,month] = NetValueOfLandingsPerStrategyMet[str,met,month] /[PropNbVessels(str,sov)*NbVesselsSetOfVessels(sov)]
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double netValueOfLandingsPerStrategyMetPerVessel(Strategy str, Metier metier, Date date) throws TopiaException {
        double netValueOfLandingsPerStrategyMet = netValueOfLandingsPerStrategyMet(str, metier, date);
        // FIXME verifier que c bien cette donnée qu'il faut utiliser dans le doc: PropNbVessels(str, sov)
        double proportionSetOfVessels = str.getProportionSetOfVessels();
        double numberOfVessels = str.getSetOfVessels().getNumberOfVessels();

        return netValueOfLandingsPerStrategyMet / (proportionSetOfVessels * numberOfVessels);
    }

    //////////////////////////////////////////////////////////////////////
    // matrixNetRenevueToSharePerStrategyMetPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixNetRenevueToSharePerStrategyMetPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_NET_RENEVUE_TO_SHARE_PER_STRATEGY_MET_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = netRenevueToSharePerStrategyMetPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = netRenevueToSharePerStrategyMetPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * NetRevenueToSharePerStrategyMetPerVessel[str,met,month] = NetValueOfLandingsPerStrategyMetPerVessel[str,met,month] - SharedNotFixedCostsPerVessel [str,met,month]*PropStr(str,met,month) - SharedFixedCostsPerVessel
PerMet[str,month]
     *
     * @param str
     * @param metier
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double netRenevueToSharePerStrategyMetPerVessel(Strategy str, Metier metier, Date date) throws TopiaException {
        double netRenevueToSharePerStrategyMetPerVessel = netValueOfLandingsPerStrategyMetPerVessel(str, metier, date);
        double sharedNotFixedCostsPerVessel = sharedNotFixedCostsPerVessel(str, metier, date);
        double propStr = str.getStrategyMonthInfo(date.getMonth()).getProportionMetier(metier);

        double result = netRenevueToSharePerStrategyMetPerVessel - sharedNotFixedCostsPerVessel * propStr;
        return result;
    }

    //////////////////////////////////////////////////////////////////////
    // matrixCrewSharePerStrategyMetPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixCrewSharePerStrategyMetPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_CREW_SHARE_PER_STRATEGY_MET_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = crewSharePerStrategyMetPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = crewSharePerStrategyMetPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    
    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * CrewSharePerStrategyMetPerVessel[str,met,month] = NetRevenueToSharePerStrategyMetPerVessel[str,met,month]*CrewShareRate[sov,met]
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double crewSharePerStrategyMetPerVessel(Strategy str, Metier metier, Date date) throws TopiaException {
        double netRenevueToShare = netRenevueToSharePerStrategyMetPerVessel(str, metier, date);

        EffortDescription effort = str.getSetOfVessels().getPossibleMetiers(metier);

        double crewShareRate = 0;
        if(effort != null){
            crewShareRate = effort.getCrewShareRate();
        }
        // FIXME verifier qu'il faut bien retourner 0, si pas d'effort
        return netRenevueToShare * crewShareRate;
   }

    //////////////////////////////////////////////////////////////////////
    // matrixOwnerMarginOverVariableCostsPerStrategyMetPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixOwnerMarginOverVariableCostsPerStrategyMetPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_OWNER_MARGIN_OVER_VARIABLE_COSTS_PER_STRATEGY_MET_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = ownerMarginOverVariableCostsPerStrategyMetPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = ownerMarginOverVariableCostsPerStrategyMetPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    
    /**
    * implanté suivant document ModifTable3PourBP25-07-2006.doc
    * OwnerMarginOverVariableCostsPerStrategyMetPerVessel[str,met,month] = NetRevenueToSharePerStrategyMetPerVessel[str,met,month] - CrewSharePerStrategyMetPerVessel[str,met,month] - RepairAndMaintenanceGearCostsPerVes
sel[str,met,month] * PropStr(str,met,month)
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double ownerMarginOverVariableCostsPerStrategyMetPerVessel(Strategy str, Metier metier, Date date) throws TopiaException {
        double netRenevueToShare = netRenevueToSharePerStrategyMetPerVessel(str, metier, date);
        double crewShare = crewSharePerStrategyMetPerVessel(str, metier, date);
        double repair = repairAndMaintenanceGearCostsPerVessel(str, metier, date);
        double propStr = str.getStrategyMonthInfo(date.getMonth()).getProportionMetier(metier);

        return netRenevueToShare - crewShare - repair * propStr;
   }

    
    //////////////////////////////////////////////////////////////////////
    // matrixVesselMarginOverVariableCostsPerStrategyMetPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixVesselMarginOverVariableCostsPerStrategyMetPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);
        List<Metier> metiers = siMatrix.getMetiers(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_VESSEL_MARGIN_OVER_VARIABLE_COSTS_PER_STRATEGY_MET_PER_VESSEL,
                new List[]{strategies, metiers},
                new String[]{n_("Strategies"), n_("Metiers")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            metiers = siMatrix.getMetiers(str, date);
            for (int m=0; m < metiers.size(); m++) {
                Metier metier = metiers.get(m);
                double value = vesselMarginOverVariableCostsPerStrategyMetPerVessel(str, metier, date);
                result.setValue(str, metier, value);
            }
        }
//        for(Strategy str : strategies){
//            metiers = siMatrix.getMetiers(str, date);
//            for(Metier metier : metiers) {
//                double value = vesselMarginOverVariableCostsPerStrategyMetPerVessel(str, metier, date);
//                result.setValue(str, metier, value);
//            }
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * VesselMarginOverVariableCostsPerStrategyMetPerVessel [str,met,month] =NetRevenueToSharePerStrategyMetPerVessel[str,met,month]- RepairAndMaintenanceGearCostsPerVessel [str,met,month] * PropStr(str,met,month)
     * 
     * @param str
     * @param metier
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double vesselMarginOverVariableCostsPerStrategyMetPerVessel(Strategy str, Metier metier, Date date) throws TopiaException {
        double netRenevueToShare = netRenevueToSharePerStrategyMetPerVessel(str, metier, date);
        double repair = repairAndMaintenanceGearCostsPerVessel(str, metier, date);
        double propStr = str.getStrategyMonthInfo(date.getMonth()).getProportionMetier(metier);

        return netRenevueToShare - repair * propStr;
   }
    
    //////////////////////////////////////////////////////////////////////
    // matrixOwnerMarginOverVariableCostsPerStrategyPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixOwnerMarginOverVariableCostsPerStrategyPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_OWNER_MARGIN_OVER_VARIABLE_COSTS_PER_STRATEGY_PER_VESSEL,
                new List[]{strategies},
                new String[]{n_("Strategies")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            double value = ownerMarginOverVariableCostsPerStrategyPerVessel(str, date);
            result.setValue(s, value);
        }
//        for(Strategy str : strategies){
//            double value = ownerMarginOverVariableCostsPerStrategyPerVessel(str, date);
//            result.setValue(str, value);
//        }

        return result;
    }
    
    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * OwnerMarginOverVariableCostsPerStrategyPerVessel[str,month] = somme sur tous les métiers de OwnerMarginOverVariableCostsPerStrategyMetPerVessel [str,met,month]
     * 
     * @param str
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double ownerMarginOverVariableCostsPerStrategyPerVessel(Strategy str, Date date) throws TopiaException {
        SetOfVessels sov = str.getSetOfVessels();
        Collection<EffortDescription> efforts = sov.getPossibleMetiers();

        float result = 0;
        
        for (EffortDescription effort : efforts) {
            Metier metier = effort.getPossibleMetiers();
            result += ownerMarginOverVariableCostsPerStrategyMetPerVessel(str, metier, date);
        }
        return result;
    }

    //////////////////////////////////////////////////////////////////////
    // matrixOwnerMarginOverVariableCostsPerStrategy
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixOwnerMarginOverVariableCostsPerStrategy(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_OWNER_MARGIN_OVER_VARIABLE_COSTS_PER_STRATEGY,
                new List[]{strategies},
                new String[]{n_("Strategies")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            double value = ownerMarginOverVariableCostsPerStrategy(str, date);
            result.setValue(s, value);
        }
//        for(Strategy str : strategies){
//            double value = ownerMarginOverVariableCostsPerStrategy(str, date);
//            result.setValue(str, value);
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * OwnerMarginOverVariableCostsPerStrategy[str,month] = OwnerMarginOverVariableCostsPerStrategyPerVessel[str,month] *[PropNbVessels(str,sov)*NbVesselsSetOfVessels(sov)]
     * 
     * @param str
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double ownerMarginOverVariableCostsPerStrategy(Strategy str, Date date) throws TopiaException {
        double ownerMarginOverVariableCostsPerStrategyPerVessel = ownerMarginOverVariableCostsPerStrategyPerVessel(str, date);
        double proportionSetOfVessels = str.getProportionSetOfVessels();
        double numberOfVessels = str.getSetOfVessels().getNumberOfVessels();

        return ownerMarginOverVariableCostsPerStrategyPerVessel * (proportionSetOfVessels * numberOfVessels);
   }

    //////////////////////////////////////////////////////////////////////
    // matrixVesselMarginOverVariableCostsPerStrategyPerVessel
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixVesselMarginOverVariableCostsPerStrategyPerVessel(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_VESSEL_MARGIN_OVER_VARIABLE_COSTS_PER_STRATEGY_PER_VESSEL,
                new List[]{strategies},
                new String[]{n_("Strategies")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            double value = vesselMarginOverVariableCostsPerStrategyPerVessel(str, date);
            result.setValue(s, value);
        }
//        for(Strategy str : strategies){
//            double value = vesselMarginOverVariableCostsPerStrategyPerVessel(str, date);
//            result.setValue(str, value);
//        }

        return result;
    }
    
    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * VesselMarginOverVariableCostsPerStrategyPerVessel[str,month] = somme sur tous les métiers de VesselMarginOverVariableCostsPerStrategyMetPerVessel  [str,met,month]
     * 
     * @param str
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double vesselMarginOverVariableCostsPerStrategyPerVessel(Strategy str, Date date) throws TopiaException {
        SetOfVessels sov = str.getSetOfVessels();
        Collection<EffortDescription> efforts = sov.getPossibleMetiers();

        float result = 0;

        for (EffortDescription effort : efforts) {
            Metier metier = effort.getPossibleMetiers();
            result += vesselMarginOverVariableCostsPerStrategyMetPerVessel(str, metier, date);
        }
        return result;
   }


    //////////////////////////////////////////////////////////////////////
    // matrixVesselMarginOverVariableCostsPerStrategy
    //////////////////////////////////////////////////////////////////////
 
    public MatrixND matrixVesselMarginOverVariableCostsPerStrategy(Date date) throws TopiaException{
        List<Strategy> strategies = siMatrix.getStrategies(date);

        MatrixND result = MatrixFactory.getInstance().create(
                ResultName.MATRIX_VESSEL_MARGIN_OVER_VARIABLE_COSTS_PER_STRATEGY,
                new List[]{strategies},
                new String[]{n_("Strategies")});

        for (int s=0; s < strategies.size(); s++) {
            Strategy str = strategies.get(s);
            double value = vesselMarginOverVariableCostsPerStrategy(str, date);
            result.setValue(s, value);
        }
//        for(Strategy str : strategies){
//            double value = vesselMarginOverVariableCostsPerStrategy(str, date);
//            result.setValue(str, value);
//        }

        return result;
    }

    /**
     * implanté suivant document ModifTable3PourBP25-07-2006.doc
     * VesselMarginOverVariableCostsPerStrategy[str,month] =VesselMarginOverVariableCostsPerStrategyPerVessel [str,month] *[PropNbVessels(str,sov)*NbVesselsSetOfVessels(sov)]
     * 
     * @param str
     * @param date
     * @return
     * @throws TopiaException 
     */
    private double vesselMarginOverVariableCostsPerStrategy(Strategy str, Date date) throws TopiaException {
        double vesselMarginOverVariableCostsPerStrategyPerVessel = vesselMarginOverVariableCostsPerStrategyPerVessel(str, date);
        double proportionSetOfVessels = str.getProportionSetOfVessels();
        double numberOfVessels = str.getSetOfVessels().getNumberOfVessels();

        return vesselMarginOverVariableCostsPerStrategyPerVessel * (proportionSetOfVessels * numberOfVessels);
    }

    
    ///////////////////////////////////////////////////////////////////////////
    //
    // Methode non utilisée directement dans GravityModel, mais dans les rules
    //
    ///////////////////////////////////////////////////////////////////////////

    public double valuePerUnitFishingEffort(Strategy str, Metier metier, Date date) throws TopiaException{
       List<Population> pops = siMatrix.getPopulations(date);

       double result = 0;

        for(Population pop : pops){
            List<PopulationGroup> groups = pop.getPopulationGroup();
            Collection<Zone> zones = pop.getPopulationZone();
            for(PopulationGroup group : groups){
                double price = group.getPrice();
                for(Zone zone : zones){
                    double catchValue = getCatchWeightPerStrMet(str, metier, group, zone, date);
                    double discards = getDiscardsWeightPerStrMet(str, metier, group, zone, date);
                    result += price * (catchValue - discards);
                }
            }
        }

        double effort = getEffortPerStrategyMet(str, metier, date);

        if(effort == 0){
            result = 0;
        } else {
            result = result / effort;
        }
        // FIXME verifier qu'il faut bien retourner 0, si pas d'effort
        return result;
    }

    /**
     * @param str
     * @param metier
     * @param date
     * @return
     */
    public double getEffortPerStrategyMet(Strategy str, Metier metier, Date date) {
        MatrixND mat = resultManager.getMatrix(date, ResultName.MATRIX_EFFORT_PER_STRATEGY_MET);
        double result = 0;
        if(mat != null){
            result = mat.getValue(str, metier);
        }
        return result;
    }

    public double landingPerUnitFishingEffort(Strategy str, Metier metier, Date date) throws TopiaException{
        List<Population> pops = siMatrix.getPopulations(date);

        double effort = getEffortPerStrategyMet(str, metier, date);
        double result = 0;

        if(effort != 0){ // s'il n'y a pas d'effort on retournera 0
            for(Population pop : pops){
                List<PopulationGroup> groups = pop.getPopulationGroup();
                Collection<Zone> zones = pop.getPopulationZone();
                for(PopulationGroup group : groups){
                    for(Zone zone : zones){
                        double catchValue = getCatchWeightPerStrMet(str, metier, group, zone, date);
                        double discards = getDiscardsWeightPerStrMet(str, metier, group, zone, date);
                        result += catchValue - discards;
                    }
                }
            }
            result = result / effort;
        }

        return result;
    }

}


