code: /*
   * Carnegie Mellon University
   * Copyright (c) 2004, 2010
   * 
   * This software is distributed under the terms of the GNU Lesser General
   * Public License.  See the included COPYING and COPYING.LESSER files.
   * 
   */
  
  package edu.cmu.meteor.scorer;
  
  import java.io.File;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Properties;
  import java.util.StringTokenizer;
  
  import edu.cmu.meteor.util.Constants;
  
  /**
   * Meteor configuration class which can be instantiated, modified with set()
   * methods, and passed to a new MeteorScorer
   * 
   * Important: setting language also sets default task parameters for that
   * language. Task sets parameters and weights. Make sure to set options in the
   * following order:
   * 
   * 1. language
   * 
   * 2. task
   * 
   * 3. everything else
   */
  public class MeteorConfiguration {
  
  	/* Configuration Instance */
  
  	private String language;
  	private int langID;
  	private String task;
  	private int normalization;
  	private ArrayList<Double> parameters;
  	private ArrayList<Integer> modules;
  	private ArrayList<Double> moduleWeights;
  	private int beamSize;
  	private URL wordFileURL;
  	private URL synDirURL;
  	private URL paraDirURL;
  	private URL embeddingsURL;
  	private int embeddingsType;
  	private boolean charBased;
  	private double embeddingsThreshold;
  
  	/**
  	 * Create configuration with default parameters
  	 */
  	public MeteorConfiguration() {
  		setDefaults();
  	}
  
  	private void setDefaults() {
  		setLanguage("english");
  		setTask("default");
  		setBeamSize(Constants.DEFAULT_BEAM_SIZE);
  		setWordFileURL(Constants.getDefaultWordFileURL(langID));
  		setSynDirURL(Constants.DEFAULT_SYN_DIR_URL);
  		setParaFileURL(Constants.getDefaultParaFileURL(langID));
  		setNormalization(Constants.NO_NORMALIZE);
  		setEmbeddingsThreshold(Constants.DEFAULT_THRESHOLD_EMBEDDINGS);
  		setCharBased(false);
  	}
  
  	/**
  	 * Return the string identifying this Meteor scorer configuration.
  	 */
  	public String getConfigID() {
  		// Format: meteor-version-ch-lang-norm-params-mods-weights
  		return "meteor-" + Constants.VERSION + "-"
  				+ (this.charBased ? "ch-" : "wo-")
  				+ Constants.getLanguageShortName(this.langID) + "-"
  				+ Constants.getNormName(this.normalization) + "-"
  				+ Constants.getWeightListString(this.parameters) + "-"
  				+ Constants.getModuleListString(this.modules) + "-"
  				+ Constants.getWeightListString(this.moduleWeights);
  	}
  
  	public String getLanguage() {
  		return language;
  	}
  
  	public void setLanguage(String language) {
  		this.language = Constants.normLanguageName(language);
  		this.langID = Constants.getLanguageID(this.language);
  		setParaFileURL(Constants.getDefaultParaFileURL(langID));
  		int defaultTask = Constants.getDefaultTask(langID);
  		setTask(defaultTask);
  
  	}
  
  	// No setter for langID since it must correspond to language
  
  	public int getLangID() {
  		return langID;
  	}
  
  	public String getTask() {
  		return task;
  	}
  
  	public String getTaskDesc() {
  		return Constants.getTaskDescription(task);
  	}
  
  	/**
  	 * Sets task by name plus default parameters, modules, and module weights
  	 * for task.
  	 * 
  	 * @param task
  	 */
  	public void setTask(String task) {
  		setTask(Constants.getTaskID(task));
  	}
  
  	public void setTask(int taskID) {
  		setParameters(Constants.getParameters(langID, taskID));
  		setModules(Constants.getModules(langID, taskID));
  		ArrayList<Double> weightList = Constants.getModuleWeights(langID,
  				taskID);
  		ArrayList<Double> sizedWeightList = new ArrayList<Double>();
  		for (int i = 0; i < modules.size(); i++)
  			sizedWeightList.add(weightList.get(i));
  		setModuleWeights(sizedWeightList);
  		setTaskName(Constants.getTaskName(taskID));
  		// Utility task uses character-based evaluation
  		setCharBased(taskID == Constants.TASK_UTIL);
  	}
  
  	// Only used by other methods
  	private void setTaskName(String name) {
  		this.task = name;
  	}
  
  	public int getNormalization() {
  		return normalization;
  	}
  
  	public void setNormalization(int normalization) {
  		this.normalization = normalization;
  	}
  
  	public ArrayList<Double> getParameters() {
  		return new ArrayList<Double>(parameters);
  	}
  
  	public String getParametersString() {
  		StringBuilder sb = new StringBuilder();
  		for (Double param : parameters)
  			sb.append(param + " ");
  		return sb.toString().trim();
  	}
  
  	public void setParameters(ArrayList<Double> parameters) {
  		setTaskName("custom");
  		this.parameters = new ArrayList<Double>(parameters);
  	}
  
  	public void setParameters(String language, String taskName) {
  		setTaskName(taskName);
  		parameters = Constants.getParameters(
  				Constants.getLanguageID(Constants.normLanguageName(language)),
  				Constants.getTaskID(taskName));
  	}
  
  	public ArrayList<Integer> getModules() {
  		return new ArrayList<Integer>(modules);
  	}
  
  	public String getModulesString() {
  		StringBuilder sb = new StringBuilder();
  		for (Integer module : modules)
  			sb.append(Constants.getModuleName(module) + " ");
  		return sb.toString().trim();
  	}
  
  	public void setModules(ArrayList<Integer> modules) {
  		setTaskName("custom");
  		this.modules = new ArrayList<Integer>();
  		for (Integer modID : modules)
  			this.modules.add(modID);
  	}
  
  	public void setModulesByName(ArrayList<String> modules) {
  		setTaskName("custom");
  		this.modules = new ArrayList<Integer>();
  		for (String modName : modules)
  			this.modules.add(Constants.getModuleID(modName));
  	}
  
  	public ArrayList<Double> getModuleWeights() {
  		return new ArrayList<Double>(moduleWeights);
  	}
  
  	public String getModuleWeightsString() {
  		StringBuilder sb = new StringBuilder();
  		for (Double weight : moduleWeights)
  			sb.append(weight + " ");
  		return sb.toString().trim();
  	}
  
  	public void setModuleWeights(ArrayList<Double> moduleScores) {
  		setTaskName("custom");
  		this.moduleWeights = new ArrayList<Double>(moduleScores);
  	}
  
  	public URL getWordFileURL() {
  		return wordFileURL;
  	}
  
  	public void setWordFileURL(URL wordFileURL) {
  		try {
  			// This should not ever throw a malformed url exception
  			this.wordFileURL = new URL(wordFileURL.toString());
  		} catch (MalformedURLException ex) {
  			System.err.println("Error: Word list directory URL NOT set");
  			ex.printStackTrace();
  		}
  	}
  
  	public URL getSynDirURL() {
  		return synDirURL;
  	}
  
  	public void setSynDirURL(URL synDirURL) {
  		try {
  			// This should not ever throw a malformed url exception
  			this.synDirURL = new URL(synDirURL.toString());
  		} catch (MalformedURLException ex) {
  			System.err.println("Error: Synonym directory URL NOT set");
  			ex.printStackTrace();
  		}
  	}
  
  	public URL getParaDirURL() {
  		return paraDirURL;
  	}
  	public URL getEmbeddingsURL() {
  		return embeddingsURL;
  	}
  
  	public void setEmbeddingsType(int embeddingsType) {
  		this.embeddingsType = embeddingsType;
  	}
  	public int getEmbeddingsType() {
  		return embeddingsType;
  	}
  
  	public void setParaFileURL(URL paraDirURL) {
  		try {
  			// This should not ever throw a malformed url exception
  			this.paraDirURL = new URL(paraDirURL.toString());
  		} catch (MalformedURLException ex) {
  			System.err.println("Error: Synonym directory URL NOT set");
  			ex.printStackTrace();
  		}
  	}
  
  	public void setEmbeddingsURL(URL embeddingsURL) {
  		try {
  			// This should not ever throw a malformed url exception
  			this.embeddingsURL = new URL(embeddingsURL.toString());
  		} catch (MalformedURLException ex) {
  			System.err.println("Error: word2vec model URL NOT set");
  			ex.printStackTrace();
  		}
  	}
  
  	public void setEmbeddingsThreshold(double embeddingsThreshold) {
  		this.embeddingsThreshold = embeddingsThreshold;
  	}
  
  	public double getEmbeddingsThreshold() {
  		return embeddingsThreshold;
  	}
  
  	public int getBeamSize() {
  		return beamSize;
  	}
  
  	public void setBeamSize(int beamSize) {
  		this.beamSize = beamSize;
  	}
  
  	public boolean getCharBased() {
  		return charBased;
  	}
  
  	public void setCharBased(boolean charBased) {
  		this.charBased = charBased;
  	}
  
  	public void newLang(String filesDir) {
  		setLanguage("other");
  		setTask("universal");
  		try {
  			setWordFileURL((new File(filesDir, "function.words")).toURI()
  					.toURL());
  			setParaFileURL((new File(filesDir, "paraphrase.gz")).toURI()
  					.toURL());
  		} catch (MalformedURLException ex) {
  			System.err.println("Error: files NOT set");
  			ex.printStackTrace();
  		}
  		setNormalization(Constants.NORMALIZE_LC_ONLY);
  	}
  
  	// Integration with Java properties
  	public MeteorConfiguration(Properties props) {
  
  		setDefaults();
  
  		// Language
  		String language = props.getProperty("language");
  		if (language != null)
  			setLanguage(language);
  
  		// Task
  		String task = props.getProperty("task");
  		if (task != null)
  			setTask(task);
  
  		// Parameters
  		String parameters = props.getProperty("parameters");
  		if (parameters != null) {
  			System.err.println("PARAMETERS: "+parameters);
  			ArrayList<Double> params = new ArrayList<Double>();
  			StringTokenizer p = new StringTokenizer(parameters);
  			while (p.hasMoreTokens())
  				params.add(Double.parseDouble(p.nextToken()));
  			setParameters(params);
  		}
  
  		// Weights
  		String weights = props.getProperty("moduleWeights");
  		if (weights != null) {
  			ArrayList<Double> weightList = new ArrayList<Double>();
  			StringTokenizer wtok = new StringTokenizer(weights);
  			while (wtok.hasMoreTokens())
  				weightList.add(Double.parseDouble(wtok.nextToken()));
  			setModuleWeights(weightList);
  		}
  
  		// Modules
  		String modules = props.getProperty("modules");
  		if (modules != null) {
  			ArrayList<String> modList = new ArrayList<String>();
  			StringTokenizer mods = new StringTokenizer(modules);
  			while (mods.hasMoreTokens())
  				modList.add(mods.nextToken());
  			setModulesByName(modList);
  			// Update weights to match number of modules
  			ArrayList<Double> weightList = getModuleWeights();
  			ArrayList<Double> sizedWeightList = new ArrayList<Double>();
  			for (int i = 0; i < modList.size(); i++) {
  				if (i < weightList.size())
  					sizedWeightList.add(weightList.get(i));
  				else
  					sizedWeightList.add(0.0);
  			}
  			setModuleWeights(sizedWeightList);
  		}
  
  		// Beam size
  		String beamSize = props.getProperty("beamSize");
  		if (beamSize != null)
  			setBeamSize(Integer.parseInt(beamSize));
  
  		// Word list file
  		String wordFile = (props.getProperty("wordFile"));
  		if (wordFile != null)
  			try {
  				// This should not ever throw a malformed url exception
  				setWordFileURL((new File(wordFile)).toURI().toURL());
  			} catch (MalformedURLException ex) {
  				System.err.println("Error: Word list directory URL NOT set");
  				ex.printStackTrace();
  			}
  
  		// Synonym dir
  		String synDir = (props.getProperty("synDir"));
  		if (synDir != null)
  			try {
  				// This should not ever throw a malformed url exception
  				setSynDirURL((new File(synDir)).toURI().toURL());
  			} catch (MalformedURLException ex) {
  				System.err.println("Error: Synonym directory URL NOT set");
  				ex.printStackTrace();
  			}
  
  		// Paraphrase file
  		String paraFile = (props.getProperty("paraFile"));
  		if (paraFile != null)
  			try {
  				// This should not ever throw a malformed url exception
  				setParaFileURL((new File(paraFile)).toURI().toURL());
  			} catch (MalformedURLException ex) {
  				System.err.println("Error: Paraphrase directory URL NOT set");
  				ex.printStackTrace();
  			}
  
  		// Embeddings file
  		String embFile = (props.getProperty("embFile"));
  		if (embFile != null)
  			try {
  				// This should not ever throw a malformed url exception
  				setEmbeddingsURL((new File(embFile)).toURI().toURL());
  			} catch (MalformedURLException ex) {
  				System.err.println("Error: word2vec file URL NOT set");
  				ex.printStackTrace();
  			}
  
  		// Embeddings threshold
  		String embThrString = (props.getProperty("embThreshold"));
  		if (embThrString != null) {
  				setEmbeddingsThreshold(Double.parseDouble(embThrString));
  		}
  
  		// Embeddings Type
  		String embTypeStr = (props.getProperty("embType"));
  		if (embTypeStr != null) {
  				setEmbeddingsType(Integer.parseInt(embTypeStr));
  		}
  
  		// Normalization
  		Boolean norm = Boolean.parseBoolean(props.getProperty("norm"));
  		Boolean lower = Boolean.parseBoolean(props.getProperty("lower"));
  		Boolean noPunct = Boolean.parseBoolean(props.getProperty("noPunct"));
  		Boolean nBest = Boolean.parseBoolean(props.getProperty("nBest"));
  
  		if (nBest) {
  			// NBest scoring handles its own normalization
  			setNormalization(Constants.NO_NORMALIZE);
  		} else if (norm) {
  			if (noPunct)
  				setNormalization(Constants.NORMALIZE_NO_PUNCT);
  			else
  				setNormalization(Constants.NORMALIZE_KEEP_PUNCT);
  		} else if (lower) {
  			setNormalization(Constants.NORMALIZE_LC_ONLY);
  		} else {
  			setNormalization(Constants.NO_NORMALIZE);
  		}
  
  		Boolean charBased = Boolean
  				.parseBoolean(props.getProperty("charBased"));
  		setCharBased(charBased);
  
  		// New language overrides other options
  		Boolean newLang = Boolean.parseBoolean(props.getProperty("newLang"));
  		if (newLang) {
  			newLang(props.getProperty("filesDir"));
  		}
  	}
  }