17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/*
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 1996-2012, Google, International Business Machines Corporation and    *
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved.                                                *
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.dev.util;
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Comparator;
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashMap;
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.List;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.dev.util.UnicodeProperty.PatternMatcher;
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.UnicodeRegex;
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.UTF16;
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.UnicodeSet;
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Allows for overriding the parsing of UnicodeSet property patterns.
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * WARNING: If this UnicodePropertySymbolTable is used with {@code UnicodeSet.setDefaultXSymbolTable}, and the
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Unassigned characters (gc=Cn) are different than in ICU other than in ICU, you MUST call
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@code UnicodeProperty.ResetCacheProperties} afterwards. If you then call {@code UnicodeSet.setDefaultXSymbolTable}
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * with null to clear the value, you MUST also call {@code UnicodeProperty.ResetCacheProperties}.
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author markdavis
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class UnicodePropertySymbolTable extends UnicodeSet.XSymbolTable {
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    UnicodeRegex unicodeRegex;
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    final UnicodeProperty.Factory factory;
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public UnicodePropertySymbolTable(UnicodeProperty.Factory factory) {
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      unicodeRegex = new UnicodeRegex().setSymbolTable(this);
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      this.factory = factory;
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //    public boolean applyPropertyAlias0(String propertyName,
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //            String propertyValue, UnicodeSet result) {
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //      if (!propertyName.contains("*")) {
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //        return applyPropertyAlias(propertyName, propertyValue, result);
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //      }
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //      String[] propertyNames = propertyName.split("[*]");
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //      for (int i = propertyNames.length - 1; i >= 0; ++i) {
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //        String pname = propertyNames[i];
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //      }
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //      return null;
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //    }
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean applyPropertyAlias(String propertyName,
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String propertyValue, UnicodeSet result) {
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      boolean status = false;
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      boolean invert = false;
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      int posNotEqual = propertyName.indexOf('\u2260');
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      int posColon = propertyName.indexOf(':');
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      if (posNotEqual >= 0 || posColon >= 0) {
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          if (posNotEqual < 0) posNotEqual = propertyName.length();
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          if (posColon < 0) posColon = propertyName.length();
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          int opPos = posNotEqual < posColon ? posNotEqual : posColon;
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          propertyValue = propertyValue.length() == 0 ? propertyName.substring(opPos+1)
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  : propertyName.substring(opPos+1) + "=" + propertyValue;
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          propertyName = propertyName.substring(0,opPos);
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          if (posNotEqual < posColon) {
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              invert = true;
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      if (propertyName.endsWith("!")) {
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        propertyName = propertyName.substring(0, propertyName.length() - 1);
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        invert = !invert;
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      propertyValue = propertyValue.trim();
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      if (propertyValue.length() != 0) {
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        status = applyPropertyAlias0(propertyName, propertyValue, result);
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      } else {
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          status = applyPropertyAlias0("gc", propertyName, result);
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } catch (Exception e) {};
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!status) {
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          try {
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            status = applyPropertyAlias0("sc", propertyName, result);
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          } catch (Exception e) {};
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          if (!status) {
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            try {
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              status = applyPropertyAlias0(propertyName, "Yes", result);
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } catch (Exception e) {};
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (!status) {
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              status = applyPropertyAlias0(propertyName, "", result);
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      if (status && invert) {
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        result.complement();
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      return status;
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final HashMap<String,String[]> GC_REMAP = new HashMap();
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("c", "Cc Cf Cn Co Cs".split(" "));
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("other", GC_REMAP.get("c"));
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("l", "Ll Lm Lo Lt Lu".split(" "));
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("letter", GC_REMAP.get("l"));
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("lc", "Ll Lt Lu".split(" "));
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("casedletter", GC_REMAP.get("lc"));
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("m", "Mc Me Mn".split(" "));
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("mark", GC_REMAP.get("m"));
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("n", "Nd Nl No".split(" "));
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("number", GC_REMAP.get("n"));
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("p", "Pc Pd Pe Pf Pi Po Ps".split(" "));
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("punctuation", GC_REMAP.get("p"));
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("punct", GC_REMAP.get("p"));
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("s", "Sc Sk Sm So".split(" "));
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("symbol", GC_REMAP.get("s"));
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("z", "Zl Zp Zs".split(" "));
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        GC_REMAP.put("separator", GC_REMAP.get("z"));
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean applyPropertyAlias0(String propertyName,
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String propertyValue, UnicodeSet result) {
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      result.clear();
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      UnicodeProperty prop = factory.getProperty(propertyName);
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      String canonicalName = prop.getName();
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      boolean isAge = UnicodeProperty.equalNames("Age", canonicalName);
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      // Hack for special GC values
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      if (canonicalName.equals("General_Category")) {
1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          String[] parts = GC_REMAP.get(UnicodeProperty.toSkeleton(propertyValue));
1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          if (parts != null) {
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              for (String part : parts) {
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  prop.getSet(part, result);
1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              }
1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              return true;
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      PatternMatcher patternMatcher = null;
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      if (propertyValue.length() > 1 && propertyValue.startsWith("/") && propertyValue.endsWith("/")) {
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String fixedRegex = unicodeRegex.transform(propertyValue.substring(1, propertyValue.length() - 1));
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        patternMatcher = new UnicodeProperty.RegexMatcher().set(fixedRegex);
1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      UnicodeProperty otherProperty = null;
1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      boolean testCp = false;
1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      if (propertyValue.length() > 1 && propertyValue.startsWith("@") && propertyValue.endsWith("@")) {
1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String otherPropName = propertyValue.substring(1, propertyValue.length() - 1).trim();
1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ("cp".equalsIgnoreCase(otherPropName)) {
1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          testCp = true;
1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          otherProperty = factory.getProperty(otherPropName);
1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      if (prop != null) {
1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        UnicodeSet set;
1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (testCp) {
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          set = new UnicodeSet();
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          for (int i = 0; i <= 0x10FFFF; ++i) {
1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (UnicodeProperty.equals(i, prop.getValue(i))) {
1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              set.add(i);
1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else if (otherProperty != null) {
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          set = new UnicodeSet();
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          for (int i = 0; i <= 0x10FFFF; ++i) {
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String v1 = prop.getValue(i);
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String v2 = otherProperty.getValue(i);
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (UnicodeProperty.equals(v1, v2)) {
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              set.add(i);
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else if (patternMatcher == null) {
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          if (!isValid(prop, propertyValue)) {
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("The value '" + propertyValue + "' is illegal. Values for " + propertyName
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    + " must be in "
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    + prop.getAvailableValues() + " or in " + prop.getValueAliases());
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          if (isAge) {
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            set = prop.getSet(new ComparisonMatcher(propertyValue, Relation.geq));
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          } else {
1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            set = prop.getSet(propertyValue);
1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else if (isAge) {
1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          set = new UnicodeSet();
1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          List<String> values = prop.getAvailableValues();
1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          for (String value : values) {
1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (patternMatcher.matches(value)) {
1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              for (String other : values) {
1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (other.compareTo(value) <= 0) {
1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  set.addAll(prop.getSet(other));
1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              }
1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          set = prop.getSet(patternMatcher);
2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        result.addAll(set);
2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return true;
2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      throw new IllegalArgumentException("Illegal property: " + propertyName);
2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private boolean isValid(UnicodeProperty prop, String propertyValue) {
2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//      if (prop.getName().equals("General_Category")) {
2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//        if (propertyValue)
2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//      }
2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      return prop.isValidValue(propertyValue);
2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public enum Relation {less, leq, equal, geq, greater}
2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static class ComparisonMatcher implements PatternMatcher {
2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Relation relation;
2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        static Comparator comparator = new UTF16.StringComparator(true, false,0);
2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String pattern;
2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public ComparisonMatcher(String pattern, Relation comparator) {
2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          this.relation = comparator;
2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          this.pattern = pattern;
2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public boolean matches(Object value) {
2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          int comp = comparator.compare(pattern, value.toString());
2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          switch (relation) {
2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          case less: return comp < 0;
2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          case leq: return comp <= 0;
2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          default: return comp == 0;
2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          case geq: return comp >= 0;
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          case greater: return comp > 0;
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        public PatternMatcher set(String pattern) {
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          this.pattern = pattern;
2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          return this;
2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      }
2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
249