package com.mobilesorcery.sdk.profiles.filter;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.ui.IMemento;
import com.mobilesorcery.sdk.core.Cache;
import com.mobilesorcery.sdk.core.MoSyncProject;
import com.mobilesorcery.sdk.core.MoSyncTool;
import com.mobilesorcery.sdk.core.ProfileManager;
import com.mobilesorcery.sdk.core.PropertyUtil;
import com.mobilesorcery.sdk.core.Util;
import com.mobilesorcery.sdk.profiles.ICompositeDeviceFilter;
import com.mobilesorcery.sdk.profiles.IDeviceFilter;
import com.mobilesorcery.sdk.profiles.IProfile;
import com.mobilesorcery.sdk.profiles.ProfileDBManager;
import com.mobilesorcery.sdk.profiles.ProfileDBManager.ProfileDBResult;
import com.mobilesorcery.sdk.profiles.filter.elementfactories.DeviceCapabilitiesFilterFactory;
public class DeviceCapabilitiesFilter extends AbstractDeviceFilter {
private final static String FACTORY_ID = DeviceCapabilitiesFilterFactory.ID;
private static DeviceCapabilitiesFilter EMPTY = new DeviceCapabilitiesFilter(new String[0], new String[0]);
private final String[] requiredCapabilities;
private final String[] optionalCapabilities;
private HashSet<IProfile> profiles;
private Map<String, String> profileMappings;
private HashMap<String, List<IProfile>> profilesForRuntime;
private static Cache<String, DeviceCapabilitiesFilter> cachedFilters = new Cache<String, DeviceCapabilitiesFilter>(32);
public static DeviceCapabilitiesFilter create(String[] requiredCapabilities, String[] optionalCapabilities) {
DeviceCapabilitiesFilter uninited = new DeviceCapabilitiesFilter(requiredCapabilities, optionalCapabilities);
String token = uninited.toString();
DeviceCapabilitiesFilter filter = cachedFilters.get(token);
if (filter == null) {
filter = uninited;
cachedFilters.put(token, uninited);
}
return filter;
}
private DeviceCapabilitiesFilter(String[] requiredCapabilities, String[] optionalCapabilities) {
this.requiredCapabilities = requiredCapabilities;
this.optionalCapabilities = optionalCapabilities;
}
public Set<String> getRequiredCapabilities() {
return new HashSet<String>(Arrays.asList(requiredCapabilities));
}
public Set<String> getOptionalCapabilities() {
return new HashSet<String>(Arrays.asList(optionalCapabilities));
}
@Override
public String getFactoryId() {
return FACTORY_ID;
}
@Override
public void saveState(IMemento memento) {
IMemento capabilities = memento.createChild("capabilities");
capabilities.putString("required", PropertyUtil.fromStrings(requiredCapabilities));
capabilities.putString("optional", PropertyUtil.fromStrings(optionalCapabilities));
}
@Override
public boolean acceptProfile(IProfile profile) {
initProfiles();
return profiles.contains(profile);
}
private void initProfiles() {
if (profiles == null) {
profiles = new HashSet<IProfile>();
ProfileDBManager mgr = (ProfileDBManager) MoSyncTool.getDefault()
.getProfileManager(MoSyncTool.DEFAULT_PROFILE_TYPE);
ProfileDBResult matchResult = mgr.match("+", requiredCapabilities, optionalCapabilities);
profiles.addAll(matchResult.profiles);
profileMappings = matchResult.profileMappings;
profilesForRuntime = matchResult.profilesForRuntime;
}
}
public static DeviceCapabilitiesFilter extractFilterFromProject(MoSyncProject project) {
return replaceFilter(project, null);
}
public static void setFilter(MoSyncProject project, DeviceCapabilitiesFilter newFilter) {
replaceFilter(project, newFilter);
}
private static DeviceCapabilitiesFilter replaceFilter(MoSyncProject project, DeviceCapabilitiesFilter newFilter) {
ICompositeDeviceFilter compositeFilter = project.getDeviceFilter();
IDeviceFilter[] filters = compositeFilter.getFilters();
DeviceCapabilitiesFilter result = null;
for (int i = 0; result == null && i < filters.length; i++) {
IDeviceFilter filter = filters[i];
if (filter instanceof DeviceCapabilitiesFilter) {
result = (DeviceCapabilitiesFilter) filter;
result.initProfiles();
}
}
if (newFilter != null) {
if (result != null) {
compositeFilter.removeFilter(result);
}
compositeFilter.addFilter(newFilter);
}
return result;
}
@Override
public String toString() {
String reqStr = requiredCapabilities.length == 0 ?
"" :
MessageFormat.format("Required capabilities: {0}", Util.join(requiredCapabilities, ","));
String optStr = optionalCapabilities.length == 0 ?
"" :
MessageFormat.format("Optional capabilities: {0}", Util.join(optionalCapabilities, ","));
String delim = reqStr.isEmpty() || optStr.isEmpty() ? "" : "; ";
String result = reqStr + delim + optStr;
if (result.isEmpty()) {
result = "<No required/optional capabilities>";
}
return result;
}
public IProfile mapProfile(IProfile profile) {
if (profile == null) {
return null;
}
if (acceptProfile(profile)) {
return profile;
}
String mapped = profileMappings.get(MoSyncTool.toString(profile));
return MoSyncTool.getDefault().getProfileManager(MoSyncTool.DEFAULT_PROFILE_TYPE).getProfile(mapped);
}
/**
* Given a profile of the {@code MoSyncTool#LEGACY_PROFILE_TYPE} type,
* returns the closest matching profile of
* {@code MoSyncTool#DEFAULT_PROFILE_TYPE} for a project that does not
* filter out any profiles.
* @param profile
* @return {@code null} If no match can be found.
*/
public static IProfile matchLegacyProfile(IProfile profile) {
return matchLegacyProfile(null, profile);
}
/**
* Given a profile of the {@code MoSyncTool#LEGACY_PROFILE_TYPE} type,
* returns the closest matching profile of
* {@code MoSyncTool#DEFAULT_PROFILE_TYPE} for a project
* @param profile
* @return {@code null} If the profile would be filtered out by the project
*/
public static IProfile matchLegacyProfile(MoSyncProject project, IProfile profile) {
DeviceCapabilitiesFilter dcf = project == null ? null : extractFilterFromProject(project);
if (dcf == null) {
dcf = EMPTY;
}
String runtime = ProfileManager
.toCanonicalRuntime(profile.getRuntime());
dcf.initProfiles();
List<IProfile> profiles = dcf.profilesForRuntime.get(runtime);
IProfile firstMatch = profiles == null ? null : profiles.get(0);
IProfile mappedProfile = dcf.mapProfile(firstMatch);
return mappedProfile;
}
}