/* ** 2012 Februar 24 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. */ package info.ata4.bsplib.app; import info.ata4.log.LogUtils; import java.net.URI; import java.net.URISyntaxException; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; /** * Source engine application identifier. * * @author Nico Bergemann <barracuda415 at yahoo.de> */ public class SourceApp { private static final Logger L = LogUtils.getLogger(); public static final SourceApp UNKNOWN = new SourceApp("Unknown", SourceAppID.UNKNOWN); private final String name; private final int appID; private int versionMin = -1; private int versionMax = -1; private String filePattern; private Pattern filePatternCompiled; private Set<String> entities = new HashSet<>(); private float pointsEntities = 20; private float pointsFilePattern = 3; public SourceApp(String name, int appID) { this.name = name; this.appID = appID; } float getPointsEntities() { return pointsEntities; } void setPointsEntities(float pointsEntities) { this.pointsEntities = pointsEntities; } float getPointsFilePattern() { return pointsFilePattern; } void setPointsFilePattern(float pointsFilePattern) { this.pointsFilePattern = pointsFilePattern; } public String getName() { return name; } public int getAppID() { return appID; } public URI getSteamStoreURI() { // don't return the URI for unknown or custom appIDs if (this == SourceApp.UNKNOWN || appID < 0) { return null; } try { return new URI(String.format("http://store.steampowered.com/app/%d/", appID)); } catch (URISyntaxException ex) { // this really shouldn't happen... return null; } } public String getFilePattern() { return filePattern; } public void setFilePattern(String filePattern) { try { this.filePatternCompiled = Pattern.compile(filePattern); this.filePattern = filePattern; } catch (PatternSyntaxException ex) { L.log(Level.WARNING, "Invalid file name pattern", ex); } } public Set<String> getEntities() { return entities; } public int getVersionMin() { return versionMin; } public void setVersionMin(int versionMin) { this.versionMin = versionMin; } public int getVersionMax() { return versionMax; } public void setVersionMax(int versionMax) { this.versionMax = versionMax; } public boolean canCheckName() { return filePatternCompiled != null; } /** * Returns the absolute heuristic score for a BSP file name. If the name * matches the pattern of this app, a score of {@link #getPointsFilePattern()} * will be returned. * * @param name BSP file name to check * @return name match score */ public float checkName(String name) { if (!canCheckName()) { throw new UnsupportedOperationException(); } if (filePatternCompiled.matcher(name.toLowerCase()).find()) { L.log(Level.FINER, "File pattern match: {0} on {1}", new Object[]{filePattern, name}); return pointsFilePattern; } else { return 0; } } /** * Checks if the version can be checked. * * @return true if the version can be checked */ public boolean canCheckVersion() { return versionMin != -1 || versionMax != -1; } /** * Checks if a BSP version number is valid for this app. * * @param bspVersion BSP version number to check * @return true if the version is valid for this app */ public boolean checkVersion(int bspVersion) { if (!canCheckVersion()) { throw new UnsupportedOperationException(); } // check exact BSP version if (versionMin != -1 && versionMax == -1) { return bspVersion == versionMin; } if (versionMax != -1 && versionMin == -1) { return bspVersion == versionMax; } // check BSP version range if (bspVersion > versionMax || bspVersion < versionMin) { return false; } return true; } /** * Checks if the entities can be checked. * * @return true if the entities can be checked */ public boolean canCheckEntities() { return entities != null && !entities.isEmpty(); } /** * Returns the absolute heuristic score for a set of entity class names. * The more entity classes are found for this app, the higher is the resulting * score. The maximum score can be set with {@link #setPointsEntities(float)}. * * @param classNames * @return entity match score */ public float checkEntities(Set<String> classNames) { if (!canCheckEntities()) { throw new UnsupportedOperationException(); } int matches = 0; for (String className : classNames) { if (entities.contains(className)) { L.log(Level.FINER, "Entity match: {0}", className); matches++; } } // weight the points by entity matches relative to all entity entries return (matches / (float) entities.size()) * pointsEntities; } @Override public String toString() { return name; } }