package info.opencards.core; import info.opencards.Utils; import java.util.*; import java.util.logging.Level; /** * An approach to create a common API for the processing of one or several card-sets using some kind of learning method. * Because not all learning methods (leitner, SM-type, etc.) can be generalized to use one single processing API, this * class intends to encapsulate the most common level, and shifting approach-dependent parts into some abstract methods * to be implemented by inheritors. * <p/> * The learning method used by the learning method, beomces factored by an instance of <code>LearnMethodFactoru</code>. * The big difference beween the method and the process is that learn-processes are able to process several files * whereas <code>LearnMethod</code>s are restricted to a single card-set only. The <code>LearnMethods</code> factored by * the factory selects which kind of <code>ItemCollection</code> should be learnt. * <p/> * This class is completely independent of the used serialization- and presetnation-backend. The serializers are * internal properties of <code>CardFile</code>s to be learnt. The presentation backend is provided in terms of an * <code>ItemValuater</code> which provides the necessary API to show cards (or parts of them to the user). * * @author Holger Brandl * @see CardFile * @see ItemValuater * @see LearnMethod * @see LearnMethodFactory */ public abstract class LearnProcessManager implements LearnMethodListener { protected final LinkedHashMap<CardFile, List<Item>> scheduler = new LinkedHashMap<CardFile, List<Item>>(); protected Iterator<CardFile> procIt; protected ItemValuater itemValuater; protected CardFile curFile; private final List<LearnProcListener> learnProcListeners = new ArrayList<LearnProcListener>(); protected LearnMethodFactory lmFactory; protected LearnProcessManager(ItemValuater itemValuater, LearnMethodFactory factory) { assert lmFactory != null : "learn method factory must not be null"; assert itemValuater != null : "item valuter must not be null"; this.lmFactory = factory; this.itemValuater = itemValuater; } public abstract void processStatusInfo(String statusMsg, double completeness); public abstract void setupSchedule(Collection<CardFile> curFiles); protected abstract ItemCollection getItemCollection(CardFile cardFile); public void startProcessing() { startProcessing(null); } private void startProcessing(CardFile cardFile) { Utils.log(Level.FINE, "processing next card-file: " + cardFile); assert procIt != null; if (cardFile == null) { if (!procIt.hasNext()) { terminateProcess(false); return; } // this is should only be the case if the learn-process is started from outside cardFile = procIt.next(); itemValuater.prepareLearnSession(); } List<Item> scheduledFileItems = scheduler.get(cardFile); Utils.log(Level.FINEST, "scheduled items are : " + scheduledFileItems.toString()); if (scheduledFileItems.size() > 0) { LearnMethod learnMethod = lmFactory.createLearner(itemValuater); learnMethod.addLearnProcessListener(this); curFile = cardFile; itemValuater.prepareFileSession(cardFile); cardFile.synchronize(); ItemCollection cardItemCollection = getItemCollection(cardFile); itemValuater.startFileSession(cardFile, cardItemCollection); learnMethod.run(cardItemCollection, scheduledFileItems); learnMethod.fireStatusInfo(); // cardFile.flush(CardFileBackend.getInstance().getSerializer(), true); } else { if (procIt.hasNext()) startProcessing(procIt.next()); else terminateProcess(false); } } public void cardFileProcessingFinished(boolean wasInterrupted) { Utils.log(Level.FINER, "cardFile processing finished"); // flush to ensure that new sesstion state becomes persistent curFile.flush(); itemValuater.finishedFileSession(curFile); if (wasInterrupted) { terminateProcess(true); return; } if (procIt.hasNext()) { startProcessing(procIt.next()); } else { terminateProcess(wasInterrupted); } } private void terminateProcess(boolean wasInterrupted) { Utils.log(Level.FINER, "terminating session..."); itemValuater.finishedLearnSession(); for (LearnProcListener learnProcListener : learnProcListeners) learnProcListener.processFinished(wasInterrupted); } /** * Adds a new listener. */ public void addLearnProcessManagerProcessListener(LearnProcListener l) { if (l == null || learnProcListeners.contains(l)) return; learnProcListeners.add(l); } /** * Removes a listener. */ public void removeLearnProcessManagerProcessListener(LearnProcListener l) { if (l == null) return; learnProcListeners.remove(l); } /** * Returns <code>true</code> if this schedules has scheduled some items for today. */ public boolean hasScheduledItems() { int numScheduledCards = 0; for (List<Item> items : scheduler.values()) { numScheduledCards += items.size(); } return numScheduledCards > 0; } public List<Item> getScheduledItems(CardFile file) { return scheduler.get(file); } }