package com.graphhopper.jsprit.core.algorithm.recreate;

import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobInsertedListener;
import com.graphhopper.jsprit.core.algorithm.ruin.listener.RuinListener;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.job.Break;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;

import java.util.*;

/**
 * Created by schroeder on 07/04/16.
 */
public class BreakScheduling implements JobInsertedListener, RuinListener {

    private final StateManager stateManager;

    private final BreakInsertionCalculator breakInsertionCalculator;

    private final EventListeners eventListeners;

    private Set<VehicleRoute> modifiedRoutes = new HashSet<VehicleRoute>();

    public BreakScheduling(VehicleRoutingProblem vrp, StateManager stateManager, ConstraintManager constraintManager) {
        this.stateManager = stateManager;
        this.breakInsertionCalculator = new BreakInsertionCalculator(vrp.getTransportCosts(),vrp.getActivityCosts(),new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(),vrp.getActivityCosts(),stateManager),constraintManager);
        this.breakInsertionCalculator.setJobActivityFactory(vrp.getJobActivityFactory());
        eventListeners = new EventListeners();
    }

    @Override
    public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
        Break aBreak = inRoute.getVehicle().getBreak();
        if(aBreak != null){
            boolean removed = inRoute.getTourActivities().removeJob(aBreak);
            if(removed){
                stateManager.removed(aBreak,inRoute);
                stateManager.reCalculateStates(inRoute);
            }
            if(inRoute.getEnd().getArrTime() > aBreak.getTimeWindow().getEnd()){
                InsertionData iData = breakInsertionCalculator.getInsertionData(inRoute, aBreak, inRoute.getVehicle(), inRoute.getDepartureTime(), inRoute.getDriver(), Double.MAX_VALUE);
                if(!(iData instanceof InsertionData.NoInsertionFound)){
                    for(Event e : iData.getEvents()){
                        eventListeners.inform(e);
                    }
                    stateManager.informJobInserted(aBreak,inRoute,0,0);
                }
            }
        }
    }

    @Override
    public void ruinStarts(Collection<VehicleRoute> routes) {

    }

    @Override
    public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
        for(VehicleRoute route : modifiedRoutes){
            Break aBreak = route.getVehicle().getBreak();
            route.getTourActivities().removeJob(aBreak);
        }
        List<Break> breaks = new ArrayList<Break>();
        if(!modifiedRoutes.isEmpty()) {
            for (Job j : unassignedJobs) {
                if (j instanceof Break) {
                    breaks.add((Break) j);
                }
            }
        }
        for(Break b : breaks){ unassignedJobs.remove(b); }
        modifiedRoutes.clear();
    }

    @Override
    public void removed(Job job, VehicleRoute fromRoute) {
        if(fromRoute.getVehicle().getBreak() != null) modifiedRoutes.add(fromRoute);
    }
}

@@ -588,16 +588,100 @@
 leRoute;
+%0Aimport org.apache.logging.log4j.LogManager;%0Aimport org.apache.logging.log4j.Logger;
 %0A%0Aimport
@@ -813,24 +813,90 @@
 Listener %7B%0A%0A
+    private final static Logger logger = LogManager.getLogger();%0A%0A
     private 
@@ -1122,24 +1122,63 @@
 eRoute%3E();%0A%0A
+    private boolean firstRuin = true;%0A%0A
     public B
@@ -2031,16 +2031,74 @@
 moved)%7B%0A
+                logger.trace(%22ruin: %7B%7D%22, aBreak.getId());%0A
         
@@ -2550,24 +2550,105 @@
 ionFound))%7B%0A
+                    logger.trace(%22insert: %5BjobId=%7B%7D%5D%7B%7D%22, aBreak.getId(), iData);%0A
             
@@ -2972,32 +2972,32 @@
 %0A%0A    @Override%0A
-
     public void 
@@ -3064,32 +3064,175 @@
 assignedJobs) %7B%0A
+        if(firstRuin)%7B%0A            firstRuin = false;%0A            modifiedRoutes.clear();%0A            modifiedRoutes.addAll(routes);%0A        %7D%0A
         for(Vehi

improve break-scheduling