// Path: src/main/java/com/rolfje/anonimatron/synonyms/HashedFromSynonym.java
// public class HashedFromSynonym implements Synonym {
// 
// 	private String from;
// 	private Object to;
// 	private String type;
// 	private boolean shortLived = false;
// 
// 	public HashedFromSynonym() {
// 	}
// 
// 	public HashedFromSynonym(Hasher hasher, Synonym synonym) {
// 		from = hasher.base64Hash(synonym.getFrom());
// 		to = synonym.getTo();
// 		type = synonym.getType();
// 	}
// 
// 	@Override
// 	public String getType() {
// 		return type;
// 	}
// 
// 	@Override
// 	public Object getFrom() {
// 		return from;
// 	}
// 
// 	@Override
// 	public Object getTo() {
// 		return to;
// 	}
// 
// 	@Override
// 	public boolean isShortLived() {
// 		return shortLived;
// 	}
// 
// 	public void setFrom(String from) {
// 		this.from = from;
// 	}
// 
// 	public void setTo(Object to) {
// 		this.to = to;
// 	}
// 
// 	public void setType(String type) {
// 		this.type = type;
// 	}
// }
// 
// Path: src/main/java/com/rolfje/anonimatron/synonyms/Synonym.java
// public interface Synonym {
// 
// 	/**
// 	 * Indicates if this Synonym is short-lived or transient, meaning that
//      * it should not be stored in the synonyms file. Transient Synonyms
//      * are not stored, need to be calculated each run time.
// 	 *
// 	 * Transient synonyms are:
// 	 *
// 	 * <ol>
// 	 *     <li>Not stored in memory.</li>
// 	 *     <li>Not stored in the synonym file.</li>
// 	 * </ol>
// 	 *
// 	 * @return <code>true</code> if the synonym should be thrown away
// 	 * after use (not stored in the synonym file).
// 	 */
// 	boolean isShortLived();
// 
// 	/**
// 	 * @return The semantic data type of this Synonym, usually something
// 	 *         descriptive as "NAME" or "STREET".
// 	 */
// 	String getType();
// 
// 	/**
// 	 * @return The data which was in the original database for this Synonym
// 	 */
// 	Object getFrom();
// 
// 	/**
// 	 * 
// 	 * @return The data with which the original data in the database will be or
// 	 *         is replaced when the Anonymizer runs.
// 	 */
// 	Object getTo();
// }
// 
// Path: src/main/java/com/rolfje/anonimatron/synonyms/SynonymMapper.java
// public class SynonymMapper {
// 
// 	@SuppressWarnings("unchecked")
// 	public static List<Synonym> readFromFile(String filename) throws IOException, XMLException, MappingException {
// 		Mapping mapping = getMapping();
// 		Unmarshaller unmarshaller = new Unmarshaller(ArrayList.class);
// 		unmarshaller.setMapping(mapping);
// 
// 		File file = new File(filename);
// 
//         if (file.exists() && !file.isFile()) {
//             throw new IOException("File " + file.getAbsolutePath() + " exists but is not a file.");
//         }
// 
// 		if (!file.exists() || file.length() == 0) {
// 			return Collections.emptyList();
// 		}
// 
// 		Reader reader = new FileReader(file);
// 		return (List<Synonym>) unmarshaller.unmarshal(reader);
// 	}
// 
// 	public static void writeToFile(List<Synonym> synonyms, String filename) throws IOException, MappingException, XMLException {
// 		Mapping mapping = getMapping();
// 
// 		Writer writer = new FileWriter(new File(filename));
// 		Marshaller marshaller = new Marshaller(writer);
// 
// 		// I have no idea why this does not work, so I added a castor.propeties
// 		// file in the root as workaround.
// 		// marshaller.setProperty("org.exolab.castor.indent", "true");
// 
// 		marshaller.setRootElement("synonyms");
// 		marshaller.setMapping(mapping);
// 		marshaller.setSuppressXSIType(true);
// 		marshaller.marshal(synonyms);
// 		writer.close();
// 	}
// 
// 	private static Mapping getMapping() throws IOException, MappingException {
// 		URL url = SynonymMapper.class.getResource("castor-synonym-mapping.xml");
// 		Mapping mapping = new Mapping();
// 		mapping.loadMapping(url);
// 		return mapping;
// 	}
// }


import com.rolfje.anonimatron.synonyms.HashedFromSynonym;
import com.rolfje.anonimatron.synonyms.Synonym;
import com.rolfje.anonimatron.synonyms.SynonymMapper;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.XMLException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
package com.rolfje.anonimatron.anonymizer;



public class SynonymCache {

    private Map<String, Map<Object, Synonym>> synonymCache = new HashMap<>();
    private Hasher hasher;
    private long size = 0;

    public SynonymCache() {
    }

    /**
     * Reads the synonyms from the specified file and (re-)initializes the
     * {@link #synonymCache} with it.
     *
     * @param synonymXMLfile the xml file containing the synonyms, as written by
     *                       {@link #toFile(File)}
     * @return Synonyms as the were stored on last run.
     * @throws MappingException When synonyms can not be read from file.
     * @throws IOException      When synonyms can not be read from file.
     * @throws XMLException     When synonyms can not be read from file.
     */
    public static SynonymCache fromFile(File synonymXMLfile) throws MappingException, IOException, XMLException {

        SynonymCache synonymCache = new SynonymCache();
// Path: src/main/java/com/rolfje/anonimatron/synonyms/HashedFromSynonym.java
// public class HashedFromSynonym implements Synonym {
// 
// 	private String from;
// 	private Object to;
// 	private String type;
// 	private boolean shortLived = false;
// 
// 	public HashedFromSynonym() {
// 	}
// 
// 	public HashedFromSynonym(Hasher hasher, Synonym synonym) {
// 		from = hasher.base64Hash(synonym.getFrom());
// 		to = synonym.getTo();
// 		type = synonym.getType();
// 	}
// 
// 	@Override
// 	public String getType() {
// 		return type;
// 	}
// 
// 	@Override
// 	public Object getFrom() {
// 		return from;
// 	}
// 
// 	@Override
// 	public Object getTo() {
// 		return to;
// 	}
// 
// 	@Override
// 	public boolean isShortLived() {
// 		return shortLived;
// 	}
// 
// 	public void setFrom(String from) {
// 		this.from = from;
// 	}
// 
// 	public void setTo(Object to) {
// 		this.to = to;
// 	}
// 
// 	public void setType(String type) {
// 		this.type = type;
// 	}
// }
// 
// Path: src/main/java/com/rolfje/anonimatron/synonyms/Synonym.java
// public interface Synonym {
// 
// 	/**
// 	 * Indicates if this Synonym is short-lived or transient, meaning that
//      * it should not be stored in the synonyms file. Transient Synonyms
//      * are not stored, need to be calculated each run time.
// 	 *
// 	 * Transient synonyms are:
// 	 *
// 	 * <ol>
// 	 *     <li>Not stored in memory.</li>
// 	 *     <li>Not stored in the synonym file.</li>
// 	 * </ol>
// 	 *
// 	 * @return <code>true</code> if the synonym should be thrown away
// 	 * after use (not stored in the synonym file).
// 	 */
// 	boolean isShortLived();
// 
// 	/**
// 	 * @return The semantic data type of this Synonym, usually something
// 	 *         descriptive as "NAME" or "STREET".
// 	 */
// 	String getType();
// 
// 	/**
// 	 * @return The data which was in the original database for this Synonym
// 	 */
// 	Object getFrom();
// 
// 	/**
// 	 * 
// 	 * @return The data with which the original data in the database will be or
// 	 *         is replaced when the Anonymizer runs.
// 	 */
// 	Object getTo();
// }
// 
// Path: src/main/java/com/rolfje/anonimatron/synonyms/SynonymMapper.java
// public class SynonymMapper {
// 
// 	@SuppressWarnings("unchecked")
// 	public static List<Synonym> readFromFile(String filename) throws IOException, XMLException, MappingException {
// 		Mapping mapping = getMapping();
// 		Unmarshaller unmarshaller = new Unmarshaller(ArrayList.class);
// 		unmarshaller.setMapping(mapping);
// 
// 		File file = new File(filename);
// 
//         if (file.exists() && !file.isFile()) {
//             throw new IOException("File " + file.getAbsolutePath() + " exists but is not a file.");
//         }
// 
// 		if (!file.exists() || file.length() == 0) {
// 			return Collections.emptyList();
// 		}
// 
// 		Reader reader = new FileReader(file);
// 		return (List<Synonym>) unmarshaller.unmarshal(reader);
// 	}
// 
// 	public static void writeToFile(List<Synonym> synonyms, String filename) throws IOException, MappingException, XMLException {
// 		Mapping mapping = getMapping();
// 
// 		Writer writer = new FileWriter(new File(filename));
// 		Marshaller marshaller = new Marshaller(writer);
// 
// 		// I have no idea why this does not work, so I added a castor.propeties
// 		// file in the root as workaround.
// 		// marshaller.setProperty("org.exolab.castor.indent", "true");
// 
// 		marshaller.setRootElement("synonyms");
// 		marshaller.setMapping(mapping);
// 		marshaller.setSuppressXSIType(true);
// 		marshaller.marshal(synonyms);
// 		writer.close();
// 	}
// 
// 	private static Mapping getMapping() throws IOException, MappingException {
// 		URL url = SynonymMapper.class.getResource("castor-synonym-mapping.xml");
// 		Mapping mapping = new Mapping();
// 		mapping.loadMapping(url);
// 		return mapping;
// 	}
// }


// Path: src/main/java/com/rolfje/anonimatron/anonymizer/SynonymCache.java
import com.rolfje.anonimatron.synonyms.HashedFromSynonym;
import com.rolfje.anonimatron.synonyms.Synonym;
import com.rolfje.anonimatron.synonyms.SynonymMapper;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.XMLException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

package com.rolfje.anonimatron.anonymizer;



public class SynonymCache {

    private Map<String, Map<Object, Synonym>> synonymCache = new HashMap<>();
    private Hasher hasher;
    private long size = 0;

    public SynonymCache() {
    }

    /**
     * Reads the synonyms from the specified file and (re-)initializes the
     * {@link #synonymCache} with it.
     *
     * @param synonymXMLfile the xml file containing the synonyms, as written by
     *                       {@link #toFile(File)}
     * @return Synonyms as the were stored on last run.
     * @throws MappingException When synonyms can not be read from file.
     * @throws IOException      When synonyms can not be read from file.
     * @throws XMLException     When synonyms can not be read from file.
     */
    public static SynonymCache fromFile(File synonymXMLfile) throws MappingException, IOException, XMLException {

        SynonymCache synonymCache = new SynonymCache();
        List<Synonym> synonymsFromFile = SynonymMapper