package com.yoursway.model.repository;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import com.yoursway.model.timeline.PointInTime;
import com.yoursway.model.timeline.Timeline;
import com.yoursway.utils.collections.HashSetMultiMap;
import com.yoursway.utils.collections.MultiMap;
public class Scheduler implements IRepository, ConsumerTrackerMaster, ModelTrackerMaster,
CalculatedModelTrackerMaster {
private final ExecutorService executorService;
private final Timeline timeline;
private final Collection<ConsumerTracker> consumers = new ArrayList<ConsumerTracker>();
private final Map<Class<?>, CalculatedModelTracker> calculatedModels = new HashMap<Class<?>, CalculatedModelTracker>();
private final Map<Class<?>, BasicModelTracker> basicModels = new HashMap<Class<?>, BasicModelTracker>();
private final MultiMap<IHandle<?>, IDependant> dependencies = new HashSetMultiMap<IHandle<?>, IDependant>();
private final MultiMap<IDependant, IHandle<?>> invertedDependencies = new HashSetMultiMap<IDependant, IHandle<?>>();
private final SimpleSnapshotStorage snapshotStorage;
public Scheduler(Timeline timeline, ExecutorService executorService) {
this.timeline = timeline;
this.executorService = executorService;
this.snapshotStorage = new SimpleSnapshotStorage();
}
public <T> IBasicModelChangesRequestor addBasicModel(Class<T> rootHandleInterface, T rootHandle) {
BasicModelTracker tracker = new BasicModelTracker(rootHandleInterface, rootHandle, this,
executorService);
basicModels.put(rootHandleInterface, tracker);
return tracker;
}
public void addConsumer(IConsumer consumer) {
ConsumerTracker consumerTracker = new ConsumerTracker(consumer, this, executorService,
snapshotStorage);
consumers.add(consumerTracker);
consumerTracker.call(timeline.now(), ModelDelta.EMPTY_DELTA);
}
public <T> void registerModel(Class<T> rootHandleInterface, T rootHandle,
ICalculatedModelUpdater modelUpdater) {
CalculatedModelTracker tracker = new CalculatedModelTracker(rootHandleInterface, rootHandle, this,
modelUpdater, executorService, snapshotStorage);
calculatedModels.put(rootHandleInterface, tracker);
tracker.call(timeline.now(), ModelDelta.EMPTY_DELTA);
}
@SuppressWarnings("unchecked")
public <V extends IModelRoot> V obtainRoot(Class<V> rootInterface) {
BasicModelTracker tracker = basicModels.get(rootInterface);
V result = (V) tracker.getRootHandle();
if (result != null)
return result;
CalculatedModelTracker tracker2 = calculatedModels.get(rootInterface);
result = (V) tracker2.getRootHandle();
if (result != null)
return result;
throw new AssertionError("No model provides a root of type " + rootInterface);
}
public void addDependency(IDependant tracker, IHandle<?> handle) {
dependencies.put(handle, tracker);
invertedDependencies.put(tracker, handle);
}
public void handlesChanged(PointInTime moment, ModelDelta delta) {
Set<IDependant> trackersToUpdate = new HashSet<IDependant>();
for (IHandle<?> handle : delta.getChangedHandles())
trackersToUpdate.addAll(dependencies.get(handle));
update(moment, trackersToUpdate, delta);
}
private void update(PointInTime moment, Set<IDependant> trackersToUpdate, ModelDelta delta) {
for (IDependant tracker : trackersToUpdate) {
tracker.call(moment, delta);
}
}
public PointInTime createPointInTime() {
return timeline.advanceThisCrazyWorldToTheNextMomentInTime();
}
public ISnapshotStorage getSnapshotStorage() {
return snapshotStorage;
}
public void clearDependencies(IDependant dependant) {
Collection<IHandle<?>> list = invertedDependencies.get(dependant);
for (IHandle<?> h : list) {
dependencies.get(h).remove(dependant);
}
list.clear();
}
public IResolver addBackgroundConsumer(IConsumer consumer) {
// TODO: implement
return null;
}
}