package IRPact_modellierung.needs;

import IRPact_modellierung.agents.consumerAgents.ConsumerAgent;
import IRPact_modellierung.events.NeedEvent;
import IRPact_modellierung.products.Product;
import IRPact_modellierung.simulation.SimulationContainer;

import java.util.*;

/**
 * This NeedDevelopmentScheme is designed to simulate the need & adoption dynamics of "Umweltinnovationen und Lebensstile" (Schwarz, 2007),
 * a model that does not consider the lifetime of products and features a constant need / adoption decision per timestep ratio.
 * This ratio is given by the need indicator, which is interpreted as the probability that a new product adoption decision is triggered,
 * by removing the respective product and scheduling a need event (for every need the product group fulfills).
 * The needs are scheduled for immediate satisfaction.
 * This scheme doesn't differentiate between different needs and considers all needs being part of the simulation.
 *
 * @author Simon Johanning
 */
public class SchwarzNeedDevelopmentScheme extends NeedDevelopmentScheme{

    public SchwarzNeedDevelopmentScheme(Map<Need, Double> needIndicatorMap) {
        super(needIndicatorMap);
    }

    /**
     * Method that checks all product groups in the simulation for product readoption by surging need.
     * For every product group, the needs it fulfills are checked for reevaluation by interpreting the needIndicatorMap
     * as a probability for readoption.
     * For all respective needs that have surged like this, the adopted products of this product group are removed
     * from the adopted products of the agent, and new NeedEvents corresponding to this are scheduled for immediate evaluation.
     *
     * @param simulationContainer The container the consumer agent is part of
     * @param consumerAgent The consumerAgent whos needs are to be created
     * @return A list of all needs of the consumerAgent not yet covered
     */
    public List<NeedEvent> createNeedEvents(SimulationContainer simulationContainer, ConsumerAgent consumerAgent) {
        List<NeedEvent> correspondingNeedEvents = new ArrayList<>();
        Set<Need> surgedNeeds = new HashSet<Need>();
        //Check product groups for readoption
        for(ProductGroup currentProductGroup : simulationContainer.getSimulationConfiguration().getProductConfiguration().getProductGroups()){
          //check if any of the covered needs surges
          for(Need currentNeed : currentProductGroup.getNeedsSatisfied()){
            //check single needs according to the needIndicatorMap
            if(Math.rand() < needIndicatorMap.get(currentNeed)){
              //respective need surges, needs to be added to the list
              surgedNeeds.add(currentNeed);
              //remove the products from the adoption map, so need will not be interpreted as already covered
              //TODO WARNING: following line is pseudo-code / probably needs to be implemented, or at least implemented properly!!!
              consumerAgent.removeAdoptedProducts(currentProductGroup);
            }
          }
        }
        //create the respective need events
        for(Need currentNeed : surgedNeeds){
            correspondingNeedEvents.add(new NeedEvent(simulationContainer.getTimeModel().getSimulationTime(), consumerAgent, currentNeed, consumerAgent.getAssociatedSimulationContainer()));
        }
        return correspondingNeedEvents;
    }

    /**
     * Since the model this class is based upon does not treat product lifetime, 
     * product expiration should not feature in this simulation, and the method is empty
     * (i.e. returns the empty ArrayList)
     *
     * @param expiredProduct The product that expired
     * @param associatedConsumer The consumer that formerly adopted the product
     * @param systemTime The current time (time when the product expired
     * @return A list of NeedEvents based on the expiration of said product
     */
    public List<NeedEvent> productExpiration(Product expiredProduct, ConsumerAgent associatedConsumer, double systemTime) {
        return needEvents = new ArrayList<NeedEvent>();
    }
}
