package com.onaro.util.jfc.tables.filter.matcher; import com.onaro.sanscreen.client.view.tabular.value.NumberValue; import com.onaro.util.jfc.tables.filter.*; import java.util.*; public class NumberFilterMatcher implements FilterMatcher { /** * Lower bound of a range matching or null if no lower bound is set. */ private Double min; /** * Upper bound of a range matching or null if no upper bound is set. */ private Double max; /** * An exact value to search for or null if not set. Must be null if {@link #min} or {@link #max} * is are set. */ protected Double exact; /** * Tells if the pattern requires a range search or an exact match. */ private boolean range; public NumberFilterMatcher(String patternStr) throws FilterException { try { char first = patternStr.charAt(0); if ('<' == first) { max = new Double(patternStr.substring(1)); } else if ('>' == first) { min = new Double(patternStr.substring(1)); } else if (patternStr.contains("..")) { //$NON-NLS-1$ String rangeTokens[] = patternStr.split("\\.\\."); //$NON-NLS-1$ if (rangeTokens.length != 2) { throw new FilterException("2 range tokens are needed"); //$NON-NLS-1$ } else { range = true; min = new Double(rangeTokens[0]); max = new Double(rangeTokens[1]); } } else { exact = new Double(patternStr); } } catch (NumberFormatException e) { throw new FilterException("Failed to parse number from ",e); //$NON-NLS-1$ } catch (IndexOutOfBoundsException e) { throw new FilterException("Failed to parse number from ", e); //$NON-NLS-1$ } } /** * Tests if a value matches the "filter by" expression. Expects a {@link Number} value. * Subclasses should be used with other value types. The actual test is delegated to {@link #isAccepted(double)}. * * @param value a {@link Number} * @return true if the value matches the filter */ public boolean isAccepted(Object value) { if (value == null) { return false; } if (value instanceof NumberValue) { return isAccepted(((NumberValue)value).getNumber()); } else { return isAccepted(((Number)value).doubleValue()); } } /** * Tests if a value matches the filter. * * @param doubleValue the value to test * @return true if the value matches the pattern */ protected boolean isAccepted(double doubleValue) { if (exact != null){ // Check tolerance to avoid the decimal comparison between the value // entered by the User and the raw numeric value (usually 15 digits after the period) float lowerBound = (float) (doubleValue - 0.01); float upperBound = (float) (doubleValue + 0.01); if ((lowerBound <= exact) && (exact <= upperBound)) return true; else return false; } if (!range) { if (min != null && doubleValue <= min.doubleValue()) return false; if (max != null && doubleValue >= max.doubleValue()) return false; } else { if (min != null && doubleValue < min.doubleValue()) return false; if (max != null && doubleValue > max.doubleValue()) return false; } return true; } public List getAcceptedRange(Object value) { //not supported return Collections.emptyList(); } }