package com.mobilesorcery.sdk.capabilities.devices.internal;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import com.mobilesorcery.sdk.core.Capabilities;
import com.mobilesorcery.sdk.core.Capability;
import com.mobilesorcery.sdk.core.CapabilityState;
import com.mobilesorcery.sdk.core.CoreMoSyncPlugin;
import com.mobilesorcery.sdk.core.ICapabilities;
import com.mobilesorcery.sdk.core.MergeCapabilities;
import com.mobilesorcery.sdk.core.MoSyncTool;
import com.mobilesorcery.sdk.core.Pair;
import com.mobilesorcery.sdk.core.SectionedPropertiesFile;
import com.mobilesorcery.sdk.core.SectionedPropertiesFile.Section;
import com.mobilesorcery.sdk.core.SectionedPropertiesFile.Section.Entry;
import com.mobilesorcery.sdk.core.Util;
import com.mobilesorcery.sdk.profiles.IProfile;
import com.mobilesorcery.sdk.profiles.Profile;
public class DeviceCapabilitiesParser {
class CapabilitiesMap {
List<Pair<Pattern, Capabilities>> runtimes = new ArrayList<Pair<Pattern,Capabilities>>();
List<Pair<Pattern, Capabilities>> profiles = new ArrayList<Pair<Pattern,Capabilities>>();
public void addRuntimeCapability(Pattern pattern, Capabilities capabilites) {
if (pattern != null && capabilites != null) {
runtimes.add(new Pair<Pattern, Capabilities>(pattern, capabilites));
}
}
public void addProfileCapability(Pattern pattern, Capabilities capabilites) {
if (pattern != null && capabilites != null) {
profiles.add(new Pair<Pattern, Capabilities>(pattern, capabilites));
}
}
public ICapabilities getCapabilities(IProfile requestProfile) {
String profileName = MoSyncTool.toString(requestProfile);
String runtimeName = Profile.getAbbreviatedPlatform(requestProfile);
ArrayList<Capabilities> result = new ArrayList<Capabilities>();
for (Pair<Pattern, Capabilities> runtime : runtimes) {
if (runtime.first.matcher(runtimeName).matches()) {
result.add(runtime.second);
}
}
for (Pair<Pattern, Capabilities> profile : profiles) {
if (profile.first.matcher(profileName).matches()) {
result.add(profile.second);
}
}
// Correct inheritance
Collections.reverse(result);
if (result.isEmpty()) {
return null;
} else {
return new MergeCapabilities(result.toArray(new ICapabilities[0]));
}
}
}
private static final String CAPABILITIES_FILENAME = "runtime-capabilities.map";
private final HashMap<IProfile, ICapabilities> capabilities = new HashMap<IProfile, ICapabilities>();
private final HashMap<IProfile, CapabilitiesMap> profileCapabilities = new HashMap<IProfile, CapabilitiesMap>();
private final HashMap<String, CapabilitiesMap> runtimeCapabilities = new HashMap<String, CapabilitiesMap>();
private CapabilitiesMap defaultCapabilities;
public DeviceCapabilitiesParser() {
}
private CapabilitiesMap parse(File file) throws IOException {
FileReader input = null;
try {
if (!file.exists()) {
return null;
}
input = new FileReader(file);
return parse(input);
} finally {
Util.safeClose(input);
}
}
private CapabilitiesMap parse(Reader input) throws IOException {
SectionedPropertiesFile capabilitesMap = SectionedPropertiesFile.parse(input);
CapabilitiesMap result = new CapabilitiesMap();
for (Section section : capabilitesMap.getSections()) {
Capabilities capabilities = null;
List<Entry> entries = section.getEntries();
for (Entry entry : entries) {
String capability = entry.getKey();
String capabilityStateStr = entry.getValue();
if (capabilities == null) {
capabilities = new Capabilities();
}
CapabilityState capabilityState = CapabilityState.SUPPORTED;
try {
capabilityState = CapabilityState.valueOf(capabilityStateStr);
} catch (Exception e) {
// Fallback to default: SUPPORTED
}
capabilities.setCapability(new Capability(capability, capabilityState));
}
addCapabilites(result, section.getName(), capabilities);
}
return result;
}
private void addCapabilites(CapabilitiesMap capabilitiesMap, String matchingCriteria, Capabilities capabilities) {
if (matchingCriteria == null) {
return;
}
try {
if (matchingCriteria.startsWith("profile:")) {
capabilitiesMap.addProfileCapability(Pattern.compile(matchingCriteria.substring("profile:".length())), capabilities);
} else if (matchingCriteria.startsWith("runtime:")) {
capabilitiesMap.addRuntimeCapability(Pattern.compile(matchingCriteria.substring("runtime:".length())), capabilities);
} else {
capabilitiesMap.addRuntimeCapability(Pattern.compile(matchingCriteria), capabilities);
}
} catch (PatternSyntaxException e) {
// Just log & ignore
CoreMoSyncPlugin.getDefault().log(e);
}
}
public ICapabilities getCapabilitiesForProfile(IProfile profile) {
if (capabilities.get(profile) == null) {
try {
capabilities.put(profile, createCapabilities(profile));
} catch (IOException e) {
CoreMoSyncPlugin.getDefault().log(e);
}
}
return capabilities.get(profile);
}
private ICapabilities createCapabilities(IProfile profile) throws IOException {
CapabilitiesMap defaultMap = getDefaultCapabilitiesMap();
CapabilitiesMap runtimeMap = getCapabilitiesMapForRuntime(profile.getRuntime());
CapabilitiesMap profileMap = getCapabilitiesMapForProfile(profile);
return assembleCapabilities(profile, defaultMap, runtimeMap, profileMap);
}
private ICapabilities assembleCapabilities(IProfile profile, CapabilitiesMap... maps) {
ArrayList<ICapabilities> result = new ArrayList<ICapabilities>();
for (CapabilitiesMap map : maps) {
ICapabilities partialCapabilities = map == null ? null : map.getCapabilities(profile);
if (partialCapabilities != null) {
result.add(partialCapabilities);
}
}
return new MergeCapabilities(result.toArray(new ICapabilities[0]));
}
private CapabilitiesMap getCapabilitiesMapForProfile(IProfile profile) throws IOException {
if (profileCapabilities.get(profile) == null) {
profileCapabilities.put(profile, createCapabilitiesMap(profile));
}
return profileCapabilities.get(profile);
}
private CapabilitiesMap getCapabilitiesMapForRuntime(String platform) throws IOException {
if (runtimeCapabilities.get(platform) == null) {
runtimeCapabilities.put(platform, createCapabilitiesMap(platform));
}
return runtimeCapabilities.get(platform);
}
private CapabilitiesMap getDefaultCapabilitiesMap() throws IOException {
if (defaultCapabilities == null) {
defaultCapabilities = createDefaultCapabilitiesMap();
}
return defaultCapabilities;
}
private CapabilitiesMap createCapabilitiesMap(IProfile profile) throws IOException {
File profileFile = MoSyncTool.getDefault().getProfilePath(profile).append(CAPABILITIES_FILENAME).toFile();
return parse(profileFile);
}
private CapabilitiesMap createCapabilitiesMap(String platform) throws IOException {
File runtimeFile = MoSyncTool.getDefault().getRuntimePath(platform).append(CAPABILITIES_FILENAME).toFile();
CapabilitiesMap runtimeCapabilites = parse(runtimeFile);
return runtimeCapabilites;
}
private CapabilitiesMap createDefaultCapabilitiesMap() throws IOException {
File defaultFile = MoSyncTool.getDefault().getProfilesPath().append(CAPABILITIES_FILENAME).toFile();
return parse(defaultFile);
}
}