package ui.controller; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; import classes.AbstractCanvasObject; import classes.GroupNode; import classes.Flexibility; import classes.HolonElement; import classes.HolonObject; import ui.model.Model; /** * Class to Manage to flexibilities. * To order, view Flexibilities. * @author tom * */ public class FlexManager { private int timeStep; private List allFlexModels; private List allFlexesOrderedThisTimeStep = new ArrayList(); private HashMap> accessOtherFlex = new HashMap>(); private HashMap accessFlexMap = new HashMap(); public FlexManager(Model model, int timeStep, FlexManager timestepBefore){ //Thread.dumpStack(); this.timeStep = timeStep; allFlexModels = getAllFlexFromModel(model); //fill accessFlexMap allFlexModels.stream().map(flex -> new FlexWrapper(flex, timeStep, (timestepBefore != null)?timestepBefore.getFlexWrapper(flex):null)).forEach(flexWrapper -> { accessFlexMap.put(flexWrapper.getFlex(), flexWrapper); HolonElement ele = flexWrapper.getFlex().getElement(); if(accessOtherFlex.containsKey(ele)) { accessOtherFlex.get(ele).add(flexWrapper); }else { ArrayList toAdd = new ArrayList(); toAdd.add(flexWrapper); accessOtherFlex.put(ele, new ArrayList(toAdd)); } }); //because when added not all flexes can see others accessFlexMap.values().stream().forEach(flexWrapper -> flexWrapper.revalidateState()); } private FlexWrapper getFlexWrapper(Flexibility flex) { return accessFlexMap.getOrDefault(flex, null); } public List getAllFlexWrapper() { return accessFlexMap.values().stream().collect(Collectors.toList()); } public List getAllFlexWrapperWithState(FlexState state) { return accessFlexMap.values().stream().filter(flexWrapper -> (flexWrapper.getState() == state)).collect(Collectors.toList()); } private List getAllFlexFromModel(Model model) { return createListOfHolonObjects(model.getObjectsOnCanvas()).stream().flatMap(hObject -> hObject.getElements().stream()).flatMap(hElement -> hElement.flexList.stream()).collect(Collectors.toList()); } private List createListOfHolonObjects(List objectsOnCanvas) { List list = new ArrayList(); for(AbstractCanvasObject aCps : objectsOnCanvas) { if(aCps instanceof HolonObject) list.add((HolonObject) aCps); else if(aCps instanceof GroupNode)list.addAll(createListOfHolonObjects(((GroupNode)aCps).getNodes())); } return list; } public int getTimeStep() { return timeStep; } public List getAllFlexesOrderedThisTimeStep() { return allFlexesOrderedThisTimeStep; } public void orderFlexFromList(List flexList) { flexList.stream().forEach(flex -> { FlexWrapper flexToOrder = accessFlexMap.get(flex); if(flexToOrder!=null)flexToOrder.order(); }); } public void orderFlex(Flexibility flex) { FlexWrapper flexToOrder = accessFlexMap.get(flex); if(flexToOrder!=null)flexToOrder.order(); } public boolean isAFlexInUseOfHolonElement(HolonElement ele) { return ele.flexList.stream().filter(flex -> this.accessFlexMap.containsKey(flex)).anyMatch(flex -> (this.accessFlexMap.get(flex).getState() == FlexState.IN_USE)); } /** * Or Return null * @param flex * @return */ public FlexWrapper getFlexWrapperFromFlexibility(Flexibility flex) { return accessFlexMap.get(flex); } public static enum FlexState{ IN_USE, ON_COOLDOWN, OFFERED, NOT_OFFERED, UNAVAILABLE } //Classes public class FlexWrapper{ private Flexibility flex; private FlexState state; int timeStep; int durationEndTime = -1; int coolDownEndTime = -1; public FlexWrapper(Flexibility flex, int timeStep, FlexWrapper old) { this.flex = flex; this.timeStep = timeStep; if(old == null) { state = flex.fulfillsConstrains()?(flex.offered?FlexState.OFFERED:FlexState.NOT_OFFERED):FlexState.UNAVAILABLE; }else { durationEndTime = old.durationEndTime; coolDownEndTime = old.coolDownEndTime; revalidateState(); } } public void revalidateState() { if(remainingTimeTillActivation() == 0) state = (flex.fulfillsConstrains() && !otherFlexInUseOrOnCooldown())?(flex.offered?FlexState.OFFERED:FlexState.NOT_OFFERED):FlexState.UNAVAILABLE; else if(remainingDuration()== 0) state = FlexState.ON_COOLDOWN; else state = FlexState.IN_USE; } public Flexibility getFlex() { return flex; } public FlexState getState() { return state; } public boolean canOrder() { return (state == FlexState.OFFERED) && //Right state !otherFlexInUseOrOnCooldown(); //No other flex of this ele in use } private boolean otherFlexInUseOrOnCooldown() { if(accessOtherFlex.get(this.getFlex().getElement()) == null) return false; return accessOtherFlex.get(this.getFlex().getElement()).stream().anyMatch(flexWrapper -> flexWrapper != this && (flexWrapper.getState() == FlexState.IN_USE || flexWrapper.getState() == FlexState.ON_COOLDOWN)); } public boolean order() { if(canOrder()) { state=FlexState.IN_USE; allFlexesOrderedThisTimeStep.add(flex); durationEndTime = timeStep + flex.getDuration(); coolDownEndTime = durationEndTime + flex.getCooldown(); //accessFlexMap.values().stream().filter(flexWrapper -> (flexWrapper.getFlex().getElement() == flex.getElement() && flexWrapper != this)).forEach(otherFlex -> otherFlex.revalidateState()); accessOtherFlex.get(this.getFlex().getElement()).stream().filter(flexWrapper -> (flexWrapper != this)).forEach(otherFlex -> otherFlex.revalidateState()); return true; } return false; } public boolean cancel() { if(allFlexesOrderedThisTimeStep.contains(flex)) { state=FlexState.OFFERED; durationEndTime = -1; coolDownEndTime = -1; allFlexesOrderedThisTimeStep.remove(flex); accessOtherFlex.get(this.getFlex().getElement()).stream().filter(flexWrapper -> (flexWrapper != this)).forEach(otherFlex -> otherFlex.revalidateState()); return true; } return false; } public int remainingTimeTillActivation() { return Math.max(0, coolDownEndTime - timeStep); } public int remainingDuration() { return Math.max(0, durationEndTime - timeStep); } } public void reset() { getAllFlexWrapper().forEach(flexWrapper -> flexWrapper.cancel()); } }