package tools;

import java.io.File;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.google.gwt.user.client.rpc.IsSerializable;

import authoritymanager.client.DataSerial;
import authoritymanager.client.DataPair;
import authoritymanager.client.Duplicate;
import authoritymanager.client.Path;
import authoritymanager.client.SearchQuery;
import authoritymanager.client.Utilities;

/*
 * @author      (classes and interfaces only, required)
 * @version     (classes and interfaces only, required. See footnote 1)
 * @param       (methods and constructors only)
 * @return      (methods only)
 * @exception   (@throws is a synonym added in Javadoc 1.2)
 * @see         
 * @since       
 * @serial      (or @serialField or @serialData)
 * @deprecated  (see How and When To Deprecate APIs)
 */
/**
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * @author Dejan Kolundzija
 * @version 1.0
 */
public class Authority implements IsSerializable {
	public static final String	PATH			=	new File("").getAbsolutePath() + File.separatorChar + "data" + File.separatorChar  ;
	public static final String	DEFAULT_NAME	=	"DEFAULT_NAME";
	public static final int		DEFAULT_ID		=	0;

	public static final Random 	generator		=	new Random(System.currentTimeMillis());

	private String authorityType ;
	private Configuration configuration;
	private DuplicatesSet duplicatesSet ;
	private Map<String, ElementData> data;
	
	private Path sortingPath ;
	private int numFiles, numProcessed, currentPercent ;
	private static Map<String, Authority> typeToAuthority = new HashMap<String, Authority>() ;
	private boolean isLoaded, isChanged ;
	
	public Authority() {
		this.data = new HashMap<String, ElementData>();
		this.configuration = null;
		this.authorityType = "" ;
		
		setLoaded(false) ;
		setChanged(false) ;
	}

	public Authority(Configuration configuration) {
		this() ;
		this.configuration = configuration;
	}

	public Authority(String authorityType, String configurationURL) {
		this(configurationURL) ;
		this.setType(authorityType) ;
	}
	public Authority(String configurationURL) {
		this();
		this.loadConfiguration(configurationURL) ;
		this.configuration.setURL(configuration.getURL()) ;
		this.loadData() ;
		
	}
	public Authority(Map<String, ElementData> data, Configuration configuration) {
		this.data = data;
		this.configuration = configuration;
	}
	public static ElementData getByID(String itemID) {
		Collection<Authority> authorities = typeToAuthority.values() ;
		for (Iterator<Authority> itAuthority = authorities.iterator() ; itAuthority.hasNext() ; ) {
			Authority authority = itAuthority.next() ;
			ElementData result = authority.data.get(itemID) ;
			if (result != null) {
				return result ;
			}
		}
		return null ;
	}
	
	
	public String getType() {
		return authorityType ;
	}
	public void setType(String authorityType) {
		this.authorityType = authorityType ;
		Authority.typeToAuthority.put(authorityType, this) ;		
	}
	
	
	public boolean isLoaded() {
		return this.isLoaded ;
	}
	public void setLoaded(boolean isLoaded) {
		this.isLoaded = isLoaded ;
	}
	public boolean isChanged() {
		return this.isChanged ;
	}
	
	
	
	public void setChanged(boolean isChanged) {
		this.isChanged = isChanged ;
	}
	
	public static Collection<Authority> getAuthorities() {
		return typeToAuthority.values() ;
	}
	
	public void loadData() {
		long initTime = System.currentTimeMillis();
		String URL = configuration.getURL() ;
		numFiles = countFiles(new File(URL)) ;
		numProcessed = 0 ;
		currentPercent = 0 ;
		System.out.println("__________") ;
		processURL(new File(URL));
		System.out.println();
		setLoaded(true) ;
		System.out.println("Total time reading " + 1.000
				* (System.currentTimeMillis() - initTime) + "ms");
	}
	
	private void loadConfiguration(String configurationURL) {
		configuration = new Configuration(configurationURL);
		configuration.compile();
	}
	
	public static Authority fromDump(String dumpDir, String confURL) {
		Authority authority = new Authority() ;
		authority.loadConfiguration(confURL) ;
		authority.configuration.setURL(dumpDir) ;
		authority.loadData() ;
		return authority ;
	}
	
	public static Authority byType(String type) {
		return typeToAuthority.get(type) ;
	}
	
	public void setConfiguration(String configurationURL) {
		this.loadConfiguration(configurationURL) ;
	}
	
	private int countFiles(File file) {
		int count = 0 ;
		if (file.isFile()) {
			count ++;
		}
		if (file.isDirectory()) {
			File[] fileChildren = file.listFiles();
			for (int iFile = 0; iFile < fileChildren.length; iFile++) {
				count += countFiles(fileChildren[iFile]);
			}
		}
		return count ;
	}
	private void processURL(File file) {
		if (file.isFile()) {
			fromFile(file);
			numProcessed ++ ;
			while (100.0 * numProcessed / numFiles > 10 * currentPercent - 1e-8) {
				currentPercent ++ ;
				System.out.print("*") ;
			}
		}
		if (file.isDirectory()) {
			File[] fileChildren = file.listFiles();
			for (int iFile = 0; iFile < fileChildren.length; iFile++) {
				processURL(fileChildren[iFile]);
			}
		}
	}

	
	public boolean addElement(ElementData element) {
		return this.data.put((String) element.getField("uid").iterator().next(), element) != null;
	}

	private char dec2hex(int value) {
		if (value < 10)
			return (char) ('0' + value);
		else
			return (char) ('A' + (value - 10));
	}

	public String genID(int length) {
		String id = "";
		for (int i = 0; i < length; i++) {
			id += dec2hex(generator.nextInt() % 16);
		}
		return id;
	}

	public ElementData getElement(long id) {
		return this.data.get("" + id);
	}

	public Object[] getAllData() {
		return data.values().toArray();
	}

	public static String readField(Element element, String tagName) {
		try {
			NodeList nodeList = element.getElementsByTagName(tagName);
			Element tagElement = (Element) nodeList.item(0);
			NodeList textList = tagElement.getChildNodes();
			return ((Node) textList.item(0)).getNodeValue().trim();
		} catch (Exception e) {
			return null;
		}
	}

	public void dump(String dumpDir) {
		File f = new File(dumpDir) ;
		if (!f.exists()) {
			f.mkdir() ;
		}
		Collection<ElementData> values = data.values() ;
		String dumpFile = "d_" + authorityType.replace(" ", "") ;
		int countXML = 0, xmlPerFile = 10, countFile = 0;
		try {
			PrintWriter curFile = new PrintWriter(new File(dumpDir + dumpFile + "_" + countFile + ".xml")) ;
			curFile.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") ;
			curFile.println("<record>");
			curFile.println("<efg:efgEntity xmlns:efg=\"http://www.europeanfilmgateway.eu/efg\" xmlns=\"http://www.openarchives.org/OAI/2.0/\">") ;
			for (Iterator<ElementData> itValue = values.iterator() ; itValue.hasNext() ; ) {
				ElementData curValue = itValue.next() ;
				curFile.println(curValue.toXML()) ;
				countXML ++ ;
				if (countXML >= xmlPerFile) {
					countXML = 0 ;
					curFile.println("</record>") ;
					curFile.println("</efg:efgEntity>") ;
					curFile.flush() ;
					curFile.close() ;
					countFile ++ ;
					curFile = new PrintWriter(new File(dumpDir + dumpFile + countFile + ".xml")) ;
					curFile.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") ;
					curFile.println("<record>");
					curFile.println("<efg:efgEntity xmlns:efg=\"http://www.europeanfilmgateway.eu/efg\" xmlns=\"http://www.openarchives.org/OAI/2.0/\">") ;
				}
			}
			curFile.println("</record>") ;
			curFile.println("</efg:efgEntity>") ;
			curFile.flush() ;
			curFile.close() ;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
	}
	

	public void fromFile(File file) {
		try {
			DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
			domFactory.setNamespaceAware(true);
			DocumentBuilder builder = domFactory.newDocumentBuilder();
			Document doc = builder.parse(file);
			doc.getDocumentElement().normalize();
			
			StringTokenizer st = new StringTokenizer(configuration.getRootPath(), "/") ;
			Element element = doc.getDocumentElement() ;
			NodeList elements = null ;
			
			while (st.hasMoreTokens()) {
				String path = st.nextToken().trim();
				elements = element.getElementsByTagName(path) ;
				element = (Element) elements.item(0) ;
			}
			
			for (int iElement = 0; iElement < elements.getLength(); iElement++) {
				Node curNode = (Node) elements.item(iElement);
				if (curNode.getNodeType() == Node.ELEMENT_NODE) {
					Element curElement = (Element) curNode;
					ElementData record = new ElementData(this);
					readData(curElement, record, configuration.getRoot());

					addElement(record);	
					record.fileName = file.getAbsolutePath() ;
				}
			}
		} catch (Exception e) {
			System.out.println("Exception: " + e);
		}
	}

	public void createFromFile(String fileName) {
		fromFile(new File(fileName));
	}

	public void toFile(String fileName) {
		try {
			PrintWriter out = new PrintWriter(fileName);
			Collection<ElementData> records = data.values();
			out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") ;
			out.println("<record>");
			out.println("<efg:efgEntity xmlns:efg=\"http://www.europeanfilmgateway.eu/efg\" xmlns=\"http://www.openarchives.org/OAI/2.0/\">") ;
			for (ElementData record: records) {
				out.println(record.toXML());
				
			}
			out.println("</efg:efgEntity>") ;
			out.println("</record>") ;
			out.flush();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

	}
	
	private void readData(Element element, ElementData record, ConfigTree tree) {
		String name = tree.name;
		if (name != null) {
			if (satisfy(element, tree.conditions)) {
				if (tree.isComplex()) {
					ElementData recordComplex = new ElementData(this) ;
					record.addData(name, recordComplex) ;
					record = recordComplex ;
				}
				else {
					record.addData(name, getValue(element, tree.path));
				}
			}
		}
		Collection<ConfigTree> children = tree.children.values();
		for (java.util.Iterator<ConfigTree> it = children.iterator(); it
				.hasNext();) {
			ConfigTree child = it.next();

			if (isAttribute(child)) {
				readData(element, record, child);
			} else {
				if (child.path.equals("/") || child.path.length() == 0) {
					readData(element, record, child) ;
				}
				else {
					NodeList nextElements = element.getElementsByTagName(child.path);
					for (int i = 0; i < nextElements.getLength(); i++) {
						Element nextElement = (Element) nextElements.item(i);
						if (nextElement.getParentNode() == element && satisfy(nextElement, child.conditions)) {
							readData(nextElement, record, child);
						}
					}
				}
			}
		}
	}

	private boolean satisfy(Element nextElement, Collection<Condition> conditions) {
		for (Iterator<Condition> it = conditions.iterator(); it.hasNext();) {
			Condition curCondition = (Condition) it.next();
			String fieldName = curCondition.fieldName.substring(1);
			String attr = nextElement.getAttribute(fieldName);
			if (!attr.equals(curCondition.fieldValue)) {
				return false;
			}
		}
		return true;
	}

	private boolean isAttribute(ConfigTree child) {
		return child.path.length() > 0 && child.path.charAt(0) == '@';
	}

	private String getValue(Element element, String path) {
		try {
			if (path.length() > 0 && path.charAt(0) == '@') {
				return element.getAttribute(path.substring(1));
			} else {
				return element.getChildNodes().item(0).getNodeValue();
			}
		} catch (Exception e) {
			return "";
		}
	}

	
	public DuplicatesSet getDuplicates() {
		Object[] records = ((Collection<ElementData>) data.values()).toArray();
		Collection<Path> sortingPaths = configuration.getSortingPaths() ;
		
		DuplicatesSet result = new DuplicatesSet(this.getType()) ;
		HashMap<String, Boolean> duplicatesCache = new HashMap<String, Boolean>() ;
		PrintWriter tmp = null ;
		try {
			tmp = new PrintWriter("tmp.txt") ;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		long initTime = System.currentTimeMillis(), calcDis = 0, count = 0 ;
		for (Path path: sortingPaths) {
			this.sortingPath = path ;
			System.out.println("Sorting by " + path) ;
			Arrays.sort(records) ;
			
			int percent = 0;
			for (int iRecord = 0 ; iRecord < records.length ; iRecord ++) {
				ElementData curRecord = (ElementData) records [iRecord] ;
				String curID = (String) curRecord.getField("uid").iterator().next() ;
				for (int iNext = iRecord + 1 ; iNext < Math.min(records.length, iRecord + configuration.getDelta() + 1) ; iNext ++) {
					ElementData nextRecord = (ElementData) records [iNext] ;
					String nextID = (String) nextRecord.getField("uid").iterator().next() ;
					if (!duplicatesCache.containsKey(curID + nextID) && !duplicatesCache.containsKey(nextID + curID)) {
						long initCalcDis = System.currentTimeMillis() ;
						 count ++;
						double distance = curRecord.similarity(nextRecord) ;
						calcDis += System.currentTimeMillis() - initCalcDis ;
						if (distance > configuration.getThreshold()) {
							duplicatesCache.put(curID + nextID, Boolean.TRUE) ;
							result.addDuplicate(new Duplicate(curID, nextID, distance)) ;
							
							tmp.println("***********************************") ;
							tmp.println("DISTANCE: " + distance) ;
							tmp.println(curRecord.toXML()) ;
							tmp.println(nextRecord.toXML()) ;
						}
						else {
							if (duplicatesCache.size() < 2000000) {
								duplicatesCache.put(curID + nextID, Boolean.FALSE) ;
								if (duplicatesCache.size() % 100000 == 0) {
									//System.out.println(duplicatesCache.size() + " " + iRecord + "/" + records.length) ;
								}
							}
						}
					}
				}
				
				if (100.0 * (iRecord + 1) / records.length >= (percent + 10)) {
					if (percent == 10) {
						System.out.println("Time estimated: " + 0.001 * records.length / (iRecord + 1) * (System.currentTimeMillis() - initTime) + "s") ;
						System.out.println("__________") ;
					}
					percent += 10;
					System.out.print("*") ;
					if (percent == 100) {
						System.out.println();
						percent = 0 ;
						System.out.println("All " + 0.001 * (System.currentTimeMillis() - initTime) + "s.") ;
						System.out.println("calc dis() " + calcDis) ;
						System.out.println("count = " + count) ;
						initTime = System.currentTimeMillis() ;
						calcDis = 0 ;
						count = 0 ;
					}					
				}
			}
		}
		
		
		tmp.flush() ;
		tmp.close() ;
		return result ;
	}
	
	public Vector<DataPair> findDuplicates() {
		Object[] records = ((Collection<ElementData>) data.values()).toArray();
		Collection<Field> fields = configuration.getField().values();

		Vector<DataPair> duplicates = new Vector<DataPair>();
		HashMap<String, Boolean> control = new HashMap<String, Boolean>();
		int total = records.length;
		System.out.println("Number of records: " + records.length);
		Stack<String> path = new Stack<String>() ;
		
		try {
			PrintWriter out = new PrintWriter("distances.txt");
			for (int iRecord1 = 0 ; iRecord1 < records.length ; iRecord1 ++) {
				ElementData record1 = (ElementData) records [iRecord1] ;
				System.out.println(iRecord1 + "/" + records.length) ;
				for (int iRecord2 = iRecord1 + 1 ; iRecord2 < records.length ; iRecord2 ++) {
					ElementData record2 = (ElementData) records [iRecord2] ;
					double distance = record1.similarity(record2) ;
					if (distance > configuration.getThreshold()) {
						System.out.println("found " + distance) ;
						out.println("DISTANCE: " + distance) ;
						out.println("$") ;
						out.println("RECORD 1: ") ;
						out.println(record1) ;
						out.println("$") ;
						out.println("RECORD 2: ") ;
						out.println(record2) ;
						out.println("$") ;				
					}
					
				}
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		/*
		for (Iterator<Field> it = fields.iterator(); it.hasNext();) {

			Field field = it.next();
			if (field.isSortable()) {
				int count = 0, percent = 0;
				sortingField = field.name;
				System.out.println("Sorting: " + sortingField);
				Arrays.sort(records);

				System.out.println("Finding duplicates...");
				System.out.println("__________");
				for (int iRecord = configuration.getDelta(); iRecord < records.length; iRecord++) {
					// if (iRecord % 100 == 0)
					// System.out.println("iRecord = " + iRecord + "/" +
					// records.length) ;
					ElementData curRecord = (ElementData) records[iRecord];
					for (int iPrevRecord = iRecord - configuration.getDelta(); iPrevRecord < iRecord; iPrevRecord++) {
						ElementData prevRecord = (ElementData) records[iPrevRecord];
						// System.out.println("Distance: " +
						// curRecord.distance(prevRecord)) ;

						double curDis = curRecord.similarity(prevRecord);
						if (curDis > configuration.getThreshold()) {
							if (!control.containsKey(prevRecord.id
									+ curRecord.id)) {
								control.put(prevRecord.id + curRecord.id,
										Boolean.TRUE);
								control.put(curRecord.id + prevRecord.id,
										Boolean.TRUE);
								Pair pair = new Pair(curDis, curRecord.data,
										prevRecord.data);
								duplicates.add(pair);
							}

							// if (duplicates.size() % 10 == 0)
							// System.out.println("pairs: " + duplicates.size())
							// ;
						}
					}
					count++;
					if ((percent + 1) * 10 < 100.0 * count / total + 5.0) {
						percent++;
						System.out.print("*");
					}
				}
				System.out.println();
			}
		}
		*/
		return duplicates;
	}

	/*
	public Vector<DataSerial> search(String searchField, String searchValue) {
		System.out.println("Searching for: " + searchValue + " in "
				+ searchField + " ...");
		Collection<ElementData> records = data.values();
		Vector<DataSerial> results = new Vector<DataSerial>();
		for (Iterator<ElementData> it = records.iterator(); it.hasNext();) {
			ElementData curData = it.next();
			if (((String) curData.data.get(searchField)).contains(searchValue)) {
				results.add(curData.toDataSerial());
			}
		}
		return results;
	}
	*/
	public Vector<DataSerial> search(String query) {
		System.out.println("Searching for: " + query + " ...");
		Collection<ElementData> records = data.values();
		Vector<DataSerial> results = new Vector<DataSerial>(1);
		// tring [] fields = query.split("$") ;
		StringTokenizer sq = new StringTokenizer(query, "" + Utilities.DELIMITER);
		String[] fields = new String[sq.countTokens()];
		for (int iField = 0; sq.hasMoreTokens(); iField++) {
			fields[iField] = sq.nextToken();
		}
		Vector<String> fieldName = new Vector<String>(1);
		Vector<String> relationship = new Vector<String>(1);
		Vector<String> fieldValue = new Vector<String>(1);

		for (int iField = 0; iField < fields.length; iField++) {
			String[] field = fields[iField].split(":");
			// String [] field = st.nextToken().split(":") ;
			String name = field[0].trim();
			if (!name.contains("relationship")) {
				String value = field[1].trim();
				fieldName.add(name);
				fieldValue.add(value.toUpperCase());
				boolean found = false;
				for (int iRel = 0; iRel < fields.length && !found; iRel++) {
					String[] rel = fields[iRel].split(":");
					String nameRel = rel[0].trim();
					if (nameRel.contains("relationship")) {
						String[] st = nameRel.split("-");
						if (st[1].trim().equals(name)) {
							found = true;
							relationship.add(rel[1].trim());
						}
					}
				}
				if (!found) {
					relationship.add(null);
				}
			}
		}
		// int size = records.size(), cur = 0 ;
		for (Iterator<ElementData> it = records.iterator(); it.hasNext();) {
			ElementData curData = it.next();
			// System.out.println((cur ++) + "/" + size) ;
			boolean found = false;
			for (Iterator<String> itField = fieldName.iterator(), itRel = relationship
					.iterator(), itValue = fieldValue.iterator(); itField
					.hasNext()
					&& !found;) {
				String valuePath = itField.next();
				String rel = itRel.next();
				String value = itValue.next();
				Object valueCol = curData.getValue(valuePath);
				if (valueCol == null) {
					continue;
				}
				Collection colValues = null ;
				if (valueCol instanceof String) {
					colValues = new Vector(1) ;
					colValues.add((String) valueCol) ;
				}
				if (valueCol instanceof Collection) {
					colValues = (Collection) valueCol ;
				}
				for (Iterator<String> itValueCol = colValues.iterator() ; itValueCol.hasNext() && !found ; ) {
					String dataValue = ((String) itValueCol.next()).toUpperCase() ;
					if (rel == null) {
						if (dataValue.equals(value)) {
							found = true;
						}
					} else {
						if (rel.equals("begins with")) {
							if (!dataValue.startsWith(value)) {
								found = true;
							}
						}
						if (rel.equals("contains")) {
							if (!dataValue.contains(value)) {
								found = true;
							}
						}
					}
				}
			}
			if (found) {
		//		System.out.println(curData.toDataSerial()) ;
				results.add(curData.toDataSerial());
			}
		}
		return results;
	}
	
	public Vector<DataSerial> search(SearchQuery query) {
		System.out.println("Searching for: " + query + " ...");
		Collection<ElementData> records = data.values();
		Vector<DataSerial> results = new Vector<DataSerial>(1);
		long time = 0, timeSatisfy = 0, timeToSerial = 0 ;
		for (Iterator<ElementData> it = records.iterator(); it.hasNext();) {
			ElementData curData = it.next();
			long cur1 = System.currentTimeMillis() ;
			if (curData.satisfy(query)) {
				long cur2 = System.currentTimeMillis() ;
				DataSerial ds = curData.toDataSerial(query.getResultFields()) ;
				ds.setType(this.getType()) ;
				results.add(ds);
				timeToSerial += System.currentTimeMillis() - cur2 ;
				//DataSerial ds = new DataSerial() ;
				//ds.put("title", "some title") ;
				//results.add(ds) ;
			}
			timeSatisfy += System.currentTimeMillis() - cur1 ;
		}
		System.out.println("timeSatify = " + (timeSatisfy - timeToSerial) + ", toSerial = " + timeToSerial) ;
		
		return results;
	}

	public DataSerial getItem(String itemID) {
		ElementData item = data.get(itemID) ;
		if (item != null) {
			return item.toDataSerial() ;
		}
		return null;
	}

	public Configuration getConfiguration() {
		return this.configuration ;
	}

	public Path getSortingPath() {
		return this.sortingPath ;
	}

	public Map<String, ElementData> getData() {
		return this.data ;
	}
}

/*
 * configuration = new Configuration("eac:eac") ; configuration.addField("id",
 * "@uid", "string", 0.0) ; configuration.addField("uid", "ExtIDs/extid/",
 * "integer", 0.0) ; configuration.addField("title", "IDTitel", "string", 1.9,
 * CompareUtilities.JARO_DISTANCE_REFERENCE |
 * CompareUtilities.TITLE_DISTANCE_REFERENCE) ;
 * configuration.addField("sortval", "IDTitel/@sortval", "string", 3.5,
 * CompareUtilities.EDIT_DISTANCE_REFERENCE) ; configuration.addField("year",
 * "ProdJahr/", "string", 3.8, CompareUtilities.YEAR_DISTANCE_REFERENCE) ;
 * configuration.addField("region", "Ursprungsland/Region/RegionCode/",
 * "string", 0.7, CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 * configuration.compile() ;
 */
/*
 * configuration = new Configuration("Filmwerk") ; configuration.addField("id",
 * "@uid", "string", 0.0) ; configuration.addField("uid", "ExtIDs/extid/",
 * "integer", 0.0) ; configuration.addField("title", "IDTitel", "string", 1.9,
 * CompareUtilities.JARO_DISTANCE_REFERENCE |
 * CompareUtilities.TITLE_DISTANCE_REFERENCE) ;
 * configuration.addField("sortval", "IDTitel/@sortval", "string", 3.5,
 * CompareUtilities.EDIT_DISTANCE_REFERENCE) ; configuration.addField("year",
 * "ProdJahr/", "string", 3.8, CompareUtilities.YEAR_DISTANCE_REFERENCE) ;
 * configuration.addField("region", "Ursprungsland/Region/RegionCode/",
 * "string", 0.7, CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 * configuration.compile() ;
 * 
 * confManifestation = new Configuration("FilmManifestation") ;
 * confManifestation.addField("workRelation", "WerkRelation", "string", 0.6,
 * CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 * confManifestation.addField("gaugeFormat", "Traegerformat", "string", 0.2,
 * CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 * confManifestation.addField("aspectRatioFormat", "Bildformat", "string", 0.4,
 * CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 * confManifestation.addField("sound", "Ton", "string", 1.5,
 * CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 * confManifestation.addField("colour", "Farbe", "string", 2.5,
 * CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 * confManifestation.addField("duration", "Dauer", "string", 8.6,
 * CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 * confManifestation.addField("dimension", "Laenge", "string", 3.0,
 * CompareUtilities.JARO_DISTANCE_REFERENCE) ;
 */
