package com.xcompwiz.lookingglass.apiimpl;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.xcompwiz.lookingglass.api.APIInstanceProvider;
import com.xcompwiz.lookingglass.api.APIUndefined;
import com.xcompwiz.lookingglass.api.APIVersionRemoved;
import com.xcompwiz.lookingglass.api.APIVersionUndefined;
import com.xcompwiz.lookingglass.log.LoggerUtils;
/**
* The implementation of the API provider interface. Instances of this class are given to mods requesting an API provider and bound to that mod's name. The
* class also functions as the registration manager for what APIs we have available.
*/
public class APIProviderImpl implements APIInstanceProvider {
private String modname;
public APIProviderImpl(String modname) {
this.modname = modname;
}
public String getOwnerMod() {
return modname;
}
private HashMap<String, Object> instances = new HashMap<String, Object>();
// See parent/javadoc for doc
@Override
public Object getAPIInstance(String api) throws APIUndefined, APIVersionUndefined, APIVersionRemoved {
Object ret = instances.get(api);
// First, we check if the API has already been constructed up for this provider
if (ret != null) return ret;
// Get the id and version from the passed in arg
String[] splitName = api.split("-");
// If we can't get a name and version then we throw APIUndefined.
if (splitName.length != 2) throw new APIUndefined(api);
String apiname = splitName[0];
int version = Integer.parseInt(splitName[1]);
// Ask the magical constructor to provide us an instance of the API for the specified version.
ret = constructAPIWrapper(modname, apiname, version);
instances.put(api, ret);
return ret;
}
private static Map<String, Map<Integer, WrapperBuilder>> apiCtors;
private static Map<String, Set<Integer>> apiVersions;
private static Map<String, Set<Integer>> apiVersions_immutable_sets;
private static Map<String, Set<Integer>> apiVersions_immutable;
/**
* This init function sets up the wrapper constructors for the different APIs and versions of APIs we support.
*/
public static void init() {
// Skip if already initialized
if (apiCtors != null) return;
apiCtors = new HashMap<String, Map<Integer, WrapperBuilder>>();
apiVersions = new HashMap<String, Set<Integer>>();
// Immutable views to the internal stuff to allow for the getAvailableAPIs functionality without breaking containment
apiVersions_immutable_sets = new HashMap<String, Set<Integer>>();
apiVersions_immutable = Collections.unmodifiableMap(apiVersions_immutable_sets);
// Register the APIs we support
registerAPI("view", 1, new WrapperBuilder(LookingGlassAPIWrapper.class));
registerAPI("view", 2, new WrapperBuilder(LookingGlassAPI2Wrapper.class));
// Note that removed API versions should be registered as null.
}
private static void registerAPI(String apiname, int version, WrapperBuilder builder) {
getVersions(apiname).add(version);
getCtors(apiname).put(version, builder);
}
private static Map<Integer, WrapperBuilder> getCtors(String apiname) {
Map<Integer, WrapperBuilder> ctors = apiCtors.get(apiname);
if (ctors == null) {
ctors = new HashMap<Integer, WrapperBuilder>();
apiCtors.put(apiname, ctors);
}
return ctors;
}
private static Set<Integer> getVersions(String apiname) {
Set<Integer> versions = apiVersions.get(apiname);
if (versions == null) {
versions = new HashSet<Integer>();
apiVersions.put(apiname, versions);
apiVersions_immutable_sets.put(apiname, Collections.unmodifiableSet(versions));
}
return versions;
}
/**
* ** This function is voodoo.** <br/> This is the function which actually calls the builders to produce the wrappers which implement the version of the requested API.
* @param owner The name of the mod wanting the API
* @param apiname The name of the API wanted
* @param version The version of the API wanted
* @return An object which is an instance of the interface matching the API version
* @throws APIUndefined The API requested doesn't exist
* @throws APIVersionUndefined The API requested exists, but the version requested is missing in the local environment
* @throws APIVersionRemoved The API requested exists, but the version requested has been removed and is no longer supported
*/
private static Object constructAPIWrapper(String owner, String apiname, int version) throws APIUndefined, APIVersionUndefined, APIVersionRemoved {
// First, check to make sure we initialized before
if (apiCtors == null) throw new RuntimeException("Something is broken. The LookingGlass API Provider hasn't constructed properly.");
// Get the builders for the API we want
Map<Integer, WrapperBuilder> ctors = apiCtors.get(apiname);
// If there are no builders, then the API doesn't exist
if (ctors == null) throw new APIUndefined(apiname);
// If the builders collection doesn't have an entry for the version we wanted, it never existed
if (!ctors.containsKey(version)) throw new APIVersionUndefined(apiname + "-" + version);
// Get the builder entry
WrapperBuilder ctor = ctors.get(version);
// If the builder is null, then the API has been removed.
if (ctor == null) throw new APIVersionRemoved(apiname + "-" + version);
// Now, the magic itself. Use the builder to produce an instance of the API
try {
return ctor.newInstance(owner); // Poof!
} catch (Exception e) {
// If there are any problems then we need to report them. Theoretically there shouldn't be, but one never knows.
LoggerUtils.error("Caught an exception while building an API wrapper. Go kick XCompWiz.");
throw new RuntimeException("Caught an exception while building an API wrapper. Go kick XCompWiz.", e);
}
}
@Override
public Map<String, Set<Integer>> getAvailableAPIs() {
return apiVersions_immutable;
}
}