package com.j256.ormlite.field;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.j256.ormlite.field.types.EnumStringType;

/**
 * Class used to manage the various data types used by the system. The bulk of the data types come from the
 * {@link DataType} enumerated fields although you can also register your own here using the
 * {@link #registerDataPersisters(DataPersister...)} method.
 * 
 * @author graywatson
 */
public class DataPersisterManager {

	private static final DataPersister DEFAULT_ENUM_PERSISTER = EnumStringType.getSingleton();

	private static Map<Class<?>, DataPersister> classMap = null;
	private static List<DataPersister> registeredPersisters = null;

	/**
	 * Register a data type with the manager.
	 */
	public static void registerDataPersisters(DataPersister... dataPersisters) {
		// we build the map and replace it to lower the chance of concurrency issues
		List<DataPersister> newList = new ArrayList<DataPersister>();
		if (registeredPersisters != null) {
			newList.addAll(registeredPersisters);
		}
		for (DataPersister persister : dataPersisters) {
			newList.add(persister);
		}
		registeredPersisters = newList;
	}

	/**
	 * Remove any previously persisters that were registered with {@link #registerDataPersisters(DataPersister...)}.
	 */
	public static void clear() {
		registeredPersisters = null;
	}

	/**
	 * Lookup the data-type associated with the class.
	 * 
	 * @return The associated data-type interface or null if none found.
	 */
	public static DataPersister lookupForField(Field field) {

		if (classMap == null) {
			// add our built-in persisters the first time around
			HashMap<Class<?>, DataPersister> newMap = new HashMap<Class<?>, DataPersister>();
			for (DataType dataType : DataType.values()) {
				addPersisterToMap(newMap, dataType.getDataPersister());
			}
			classMap = newMap;
		}

		// first look it up in our map
		DataPersister dataPersister = classMap.get(field.getType());
		if (dataPersister != null) {
			return dataPersister;
		}

		// see if the any of the registered persisters are valid
		if (registeredPersisters != null) {
			for (DataPersister persister : registeredPersisters) {
				if (persister.isValidForField(field)) {
					return persister;
				}
			}
		}

		/*
		 * Special case for enum types. We can't put this in the registered persisters because we want people to be able
		 * to override it.
		 */
		if (field.getType().isEnum()) {
			return DEFAULT_ENUM_PERSISTER;
		} else {
			/*
			 * Serializable classes return null here because we don't want them to be automatically configured for
			 * forwards compatibility with future field types that happen to be Serializable.
			 */
			return null;
		}
	}

	private static void addPersisterToMap(HashMap<Class<?>, DataPersister> newMap, DataPersister persister) {
		if (persister != null) {
			for (Class<?> clazz : persister.getAssociatedClasses()) {
				newMap.put(clazz, persister);
			}
		}
	}
}

@@ -682,21 +682,23 @@
 sister%3E 
-class
+builtIn
 Map = nu
@@ -1636,17 +1636,263 @@
 %0A%0A%09%09
-if (class
+// see if the any of the registered persisters are valid first%0A%09%09if (registeredPersisters != null) %7B%0A%09%09%09for (DataPersister persister : registeredPersisters) %7B%0A%09%09%09%09if (persister.isValidForField(field)) %7B%0A%09%09%09%09%09return persister;%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%0A%09%09if (builtIn
 Map 
@@ -1957,16 +1957,29 @@
 e around
+ if necessary
 %0A%09%09%09Hash
@@ -2109,19 +2109,20 @@
 ) %7B%0A%09%09%09%09
-add
+Data
 Persiste
@@ -2126,21 +2126,20 @@
 ster
-ToMap(newMap,
+ persister =
  dat
@@ -2166,24 +2166,166 @@
 er()
-)
 ;%0A%09%09%09
-%7D%0A%09%09%09class
+%09if (persister != null) %7B%0A%09%09%09%09%09for (Class%3C?%3E clazz : persister.getAssociatedClasses()) %7B%0A%09%09%09%09%09%09newMap.put(clazz, persister);%0A%09%09%09%09%09%7D%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%09builtIn
 Map 
@@ -2343,22 +2343,16 @@
 %09%7D%0A%0A%09%09//
- first
  look it
@@ -2362,19 +2362,37 @@
  in our 
-map
+built-in map by class
 %0A%09%09DataP
@@ -2416,21 +2416,23 @@
 ister = 
-class
+builtIn
 Map.get(
@@ -2514,246 +2514,8 @@
 %09%7D%0A%0A
-%09%09// see if the any of the registered persisters are valid%0A%09%09if (registeredPersisters != null) %7B%0A%09%09%09for (DataPersister persister : registeredPersisters) %7B%0A%09%09%09%09if (persister.isValidForField(field)) %7B%0A%09%09%09%09%09return persister;%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%0A
 %09%09/*
@@ -2966,249 +2966,7 @@
 %7D%0A%09%7D
-%0A%0A%09private static void addPersisterToMap(HashMap%3CClass%3C?%3E, DataPersister%3E newMap, DataPersister persister) %7B%0A%09%09if (persister != null) %7B%0A%09%09%09for (Class%3C?%3E clazz : persister.getAssociatedClasses()) %7B%0A%09%09%09%09newMap.put(clazz, persister);%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D
 %0A%7D%0A

Allow users to be able to override the built-in persisters.