import java.util.Hashtable; /** * This class takes comments from the CommentaryProducer * approximately every 100ms and adds them to a Hashtable. * Every MIN_INTERVAL period, the thread wakes and passes * the highest priority comment in commentPool to voice for output. * It also marks up the speech with different levels of excitement * depending on event taking place. */ public class CommentScheduler extends Thread { private static final int MIN_INTERVAL = 3000; // longest comment length private Hashtable commentPool; // Hashtable is synchronized private int highestPriority = 12; // highest priority comment in pool private long timeStampLowest; private long lastSpoken = 0; private Output commentator; // Constructor public CommentScheduler(Output output) { // 11 or 17. 11 will grow at 7 or 8, 17 at 12 - Prime numbers for efficiency commentPool = new Hashtable(17); // overhead for optimization commentator = output; } public void run() { while(true) { //try { synchronized(commentPool) { // wake up, select highest priority comment, // pass to commentator, and reset proposistion pool if ( (!commentPool.isEmpty() ) && readyToSpeak() ) { switch(highestPriority) { case 1: commentator.out( commentPool.get(highestPriority), OutputVocal.GOAL_VOICE ); lastSpoken = System.currentTimeMillis(); // NEW break; case 2: case 3: commentator.out( commentPool.get(highestPriority), OutputVocal.EXCITED_VOICE ); lastSpoken = System.currentTimeMillis(); // NEW break; case 4: commentator.out( commentPool.get(highestPriority), true ); // uses stats voice lastSpoken = System.currentTimeMillis(); // NEW break; case 5: commentator.out( commentPool.get(highestPriority), OutputVocal.EXCITED_VOICE ); lastSpoken = System.currentTimeMillis(); // NEW break; case 6: commentator.out( commentPool.get(highestPriority), OutputVocal.BEFORE_MATCH_VOICE ); lastSpoken = System.currentTimeMillis(); // NEW break; case 7: commentator.out( commentPool.get(highestPriority), OutputVocal.SLIGHTLY_EXCITED_VOICE ); lastSpoken = System.currentTimeMillis(); // NEW break; case 8: case 9: case 10: case 11: commentator.out( commentPool.get(highestPriority), OutputVocal.EXCITED_VOICE ); lastSpoken = System.currentTimeMillis(); // NEW break; default: if (System.currentTimeMillis() - timeStampLowest < 100) // NEW - is comment fresh? { commentator.out( commentPool.get(highestPriority), OutputVocal.SLIGHTLY_EXCITED_VOICE ); lastSpoken = System.currentTimeMillis(); // NEW } break; } commentPool.clear(); // reset pool - selection made, all others redundant highestPriority = 12; // reset for addToPool } } } } /** * * Method that adds marked up comment text from CP to commentPool * * @param priority int priority value of comment text to be added to pool * @param markedUpCommentText String comment text including any variables e.g. player numbers */ public void addToPool(int priority, String markedUpCommentText) { // http://mindprod.com/jgloss/synchronized.html synchronized(commentPool) { // may throw nullPointerException if key or value is null // will overwrite previous comments of same type // - only latest comment of each type is stored i.e. spoken // - only ever 1 goal per MIN_INTERVAL period // pointless adding lower pri to pool than already contained if (priority <= highestPriority) { // Java 5 uses autoboxing - int (priority) -> Integer conversion commentPool.put(priority, markedUpCommentText ); if(priority == 12) // NEW timeStampLowest = System.currentTimeMillis(); // NEW - Record time added. highestPriority = priority; } } } private boolean readyToSpeak() { return System.currentTimeMillis()- lastSpoken > MIN_INTERVAL; } } /* -You cannot have hashtable elements with duplicate keys. If you add a new element that duplicates the key of an existing element, it will replace it - perfect - can be used to overwrite outdated comments Hashtables work fastest if the capacity is a prime number since it reduces collisions, see: http://mindprod.com/jgloss/hashtable.html */