content: // This file is part of AceWiki.
  // Copyright 2008-2013, AceWiki developers.
  // 
  // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
  // Lesser General Public License as published by the Free Software Foundation, either version 3 of
  // the License, or (at your option) any later version.
  // 
  // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
  // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  // Lesser General Public License for more details.
  // 
  // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
  // not, see http://www.gnu.org/licenses/.
  
  package ch.uzh.ifi.attempto.chartparser;
  
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Set;
  
  import ch.uzh.ifi.attempto.base.NextTokenOptions;
  
  /**
   * This class represents a set of options that describe how a partial text can be continued
   * according to a given grammar, and contains specific code for its use in the chart parser.
   * 
   * @author Tobias Kuhn
   */
  public class CPNextTokenOptions implements NextTokenOptions {
  	
  	private Set<CPAbstractOption> aOptions;
  	private Set<CPConcreteOption> cOptions;
  	private Map<String,Set<CPAbstractOption>> categoryMap;
  	private Set<String> tokens;
  	
  	/**
  	 * Generates a new object with the given abstract and concrete options.
  	 * 
  	 * @param aOptions The set of abstract options.
  	 * @param cOptions The set of concrete options.
  	 */
  	CPNextTokenOptions(Set<CPAbstractOption> aOptions, Set<CPConcreteOption> cOptions) {
  		this.aOptions = aOptions;
  		this.cOptions = cOptions;
  	}
  	
  	public Set<CPAbstractOption> getAbstractOptions() {
  		return aOptions;
  	}
  	
  	/**
  	 * Returns the abstract options that have a pre-terminal category with the specified name.
  	 * 
  	 * @param categoryName The name of the category.
  	 * @return The set of abstract options with the respective category name.
  	 */
  	public Set<CPAbstractOption> getAbstractOptions(String categoryName) {
  		createCategoryCache();
  		Set<CPAbstractOption> s = categoryMap.get(categoryName);
  		if (s == null) {
  			s = new HashSet<CPAbstractOption>();
  			categoryMap.put(categoryName, s);
  		}
  		return s;
  	}
  	
  	public Set<CPConcreteOption> getConcreteOptions() {
  		return cOptions;
  	}
  	
  	public boolean containsToken(String token) {
  		createTokenCache();
  		return tokens.contains(token);
  	}
  	
  	public boolean containsCategory(String categoryName) {
  		createCategoryCache();
  		return categoryMap.containsKey(categoryName);
  	}
  	
  	/**
  	 * Returns true if the given pre-terminal category represents a possible next token.
  	 * 
  	 * @param c The pre-terminal category.
  	 * @return true if it represents a possible next token.
  	 */
  	public boolean containsCategory(Preterminal c) {
  		createCategoryCache();
  		if (!categoryMap.containsKey(c.getName())) return false;
  		for (CPAbstractOption o : getAbstractOptions(c.getName())) {
  			if (o.isFulfilledBy(c)) {
  				return true;
  			}
  		}
  		return false;
  	}
  	
  	private void createTokenCache() {
  		if (tokens != null) return;
  		
  		tokens = new HashSet<String>();
  		for (CPConcreteOption o : cOptions) {
  			tokens.add(o.getWord());
  		}
  	}
  	
  	private void createCategoryCache() {
  		if (categoryMap != null) return;
  		
  		categoryMap = new HashMap<String, Set<CPAbstractOption>>();
  		for (CPAbstractOption o : aOptions) {
  			if (o.getCategory() instanceof Preterminal) {
  				String n = o.getCategory().getName();
  				Set<CPAbstractOption> s = categoryMap.get(n);
  				if (s == null) {
  					s = new HashSet<CPAbstractOption>();
  					categoryMap.put(n, s);
  				}
  				s.add(o);
  			}
  		}
  	}
  
  }
  