/*
 *  BSD License (http://lemurproject.org/galago-license)
 */
package org.lemurproject.galago.core.util;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;

/**
 * This is a utility class to hold word lists in memory.
 *  - This class is meant to ensure that traversals don't 
 *    need to read word lists from files each time a query is run.
 *
 * @author sjh
 */
public class WordLists {

  private static Map<String, Set<String>> wordLists;

  public static HashSet<String> readStreamIgnoringComments(InputStream stream) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
    HashSet<String> set = new HashSet<>();
    String line;

    while ((line = reader.readLine()) != null) {
      if(line.startsWith("#")) continue;
      set.add(line.trim());
    }

    reader.close();
    return set;
  }

  @Nullable
  public static Set<String> getWordList(String name) throws IOException {
    if (wordLists == null) {
      wordLists = new HashMap<>();
    }
    if (!wordLists.containsKey(name)) {
      Set<String> list;
      File f = new File(name);
      if (f.exists()) {
        list = readStreamIgnoringComments(new BufferedInputStream(new FileInputStream(f)));
      } else {
        // try to find word list in "/stopwords/"
        InputStream resourceStream = WordLists.class.getResourceAsStream("/stopwords/" + name);
        if (resourceStream == null) {
          // try to find word list in specified folder...
          resourceStream = WordLists.class.getResourceAsStream(name);

          if (resourceStream == null) {
            // give up
            Logger.getLogger("WordList").warning(String.format("Unable to create resource file."));
            return null;
          }
        }
        // found a stream -- read it.
        list = readStreamIgnoringComments(resourceStream);
      }
      // ensure we keep the wordlist (also ensure unmodifiable).
      wordLists.put(name, Collections.unmodifiableSet(list));
    }

    // otherwise we've already read this list.
    return wordLists.get(name);
  }

  @Nonnull
  public static Set<String> getWordListOrDie(String name) {
    try {
      Set<String> list = getWordList(name);
      if(list == null) {
        throw new IllegalArgumentException("Couldn't find wordlist: "+name);
      }
      return list;
    } catch (IOException e) {
      throw new IllegalArgumentException("Couldn't find wordlist: "+name, e);
    }
  }
}

@@ -430,16 +430,77 @@
 run.%0A *%0A
+ *    14 July 2016 - this file is now threadsafe - jfoley%0A *%0A
  * @auth
@@ -553,16 +553,26 @@
  static 
+final Hash
 Map%3CStri
@@ -597,16 +597,34 @@
 ordLists
+ = new HashMap%3C%3E()
 ;%0A%0A  pub
@@ -1123,18 +1123,28 @@
 n %7B%0A    
-if
+synchronized
  (wordLi
@@ -1150,61 +1150,14 @@
 ists
- == null
 ) %7B%0A  
-    wordLists = new HashMap%3C%3E();%0A    %7D%0A
     
@@ -1190,32 +1190,34 @@
 (name)) %7B%0A      
+  
 Set%3CString%3E list
@@ -1224,16 +1224,18 @@
 ;%0A      
+ 
+ 
 File f =
@@ -1253,24 +1253,26 @@
 ame);%0A      
+  
 if (f.exists
@@ -1273,24 +1273,26 @@
 exists()) %7B%0A
+  
         list
@@ -1367,24 +1367,26 @@
 tream(f)));%0A
+  
       %7D else
@@ -1388,32 +1388,34 @@
  else %7B%0A        
+  
 // try to find w
@@ -1440,16 +1440,18 @@
 words/%22%0A
+  
         
@@ -1538,32 +1538,34 @@
  name);%0A        
+  
 if (resourceStre
@@ -1580,32 +1580,34 @@
 ll) %7B%0A          
+ 
+ 
 // try to find w
@@ -1638,16 +1638,18 @@
 lder...%0A
+  
         
@@ -1713,32 +1713,34 @@
 me);%0A%0A          
+  
 if (resourceStre
@@ -1765,16 +1765,18 @@
         
+ 
+ 
 // give 
@@ -1778,16 +1778,18 @@
 give up%0A
+  
         
@@ -1888,24 +1888,26 @@
             
+  
 return null;
@@ -1907,16 +1907,18 @@
 n null;%0A
+  
         
@@ -1921,34 +1921,38 @@
       %7D%0A        
-%7D%0A
+  %7D%0A  
         // found
@@ -1973,16 +1973,18 @@
 ead it.%0A
+  
         
@@ -2036,26 +2036,30 @@
 eam);%0A      
+ 
+ 
 %7D%0A
+  
       // ens
@@ -2117,16 +2117,18 @@
 .%0A      
+  
 wordList
@@ -2171,24 +2171,32 @@
 Set(list));%0A
+      %7D%0A
     %7D%0A%0A    /

Make WordLists threadsafe