/**
   * Encodes an SDO relate
   *
   * @param filter
   * @param property
   * @param geometry
   * @param extraData
   */
  protected void doSDORelate(
      Filter filter, Expression e1, Expression e2, boolean swapped, Object extraData)
      throws IOException {
    // grab the operating mask
    String mask = null;
    for (Class filterClass : SDO_RELATE_MASK_MAP.keySet()) {
      if (filterClass.isAssignableFrom(filter.getClass()))
        mask = SDO_RELATE_MASK_MAP.get(filterClass);
    }
    if (mask == null)
      throw new IllegalArgumentException(
          "Cannot encode filter " + filter.getClass() + " into a SDO_RELATE");
    if (swapped) mask = INVERSE_OPERATOR_MAP.get(mask);

    // ok, ready to write out the SDO_RELATE
    out.write("SDO_RELATE(");
    e1.accept(this, extraData);
    out.write(", ");
    e2.accept(this, extraData);
    // for disjoint we ask for no interaction, anyinteract == false
    if (filter instanceof Disjoint) {
      out.write(", 'mask=ANYINTERACT querytype=WINDOW') <> 'TRUE' ");
    } else {
      out.write(", 'mask=" + mask + " querytype=WINDOW') = 'TRUE' ");
    }
  }
  /**
   * There might be multiple mappings per propery name, like <code>gml:name[1] = att1</code>, <code>
   * gml:name2 = strConcat(att2, att3)</code>, <code>gml:name[3] = "sampleValue</code>.
   *
   * <p>In the BoreHole test mapping used here, the following mappings exist for gml:name:
   *
   * <ul>
   *   <li>gml:name[1] = strConcat( strConcat(QS, strConcat("/", RT)), strConcat(strConcat("/",
   *       NUMB), strConcat("/", BSUFF)) )
   *   <li>gml:name[2] = BGS_ID
   *   <li>gml:name[3] = NAME
   *   <li>gml:name[4] = ORIGINAL_N
   * </ul>
   *
   * This means the "unrolled" filter for <code>gml:name = "SWADLINCOTE"</code> should be <code>
   * strConcat( strConcat(QS, ...) = "SWADLINCOTE"
   *          OR BGS_ID = "SWADLINCOTE"
   *          OR NAME = "SWADLINCOTE"
   *          OR ORIGINAL_N = "SWADLINCOTE"</code>
   *
   * <p>
   *
   * @throws Exception
   */
  @Test
  public void testCompareFilterMultipleMappingsPerPropertyName() throws Exception {
    final String XMMLNS = "http://www.opengis.net/xmml";
    final Name typeName = new NameImpl(XMMLNS, "Borehole");

    AppSchemaDataAccess complexDs = (AppSchemaDataAccess) mappingDataStore;
    mapping = complexDs.getMappingByElement(typeName);

    NamespaceSupport namespaces = new NamespaceSupport();
    namespaces.declarePrefix("gml", GML.NAMESPACE);
    namespaces.declarePrefix("xmml", XMMLNS);

    FilterFactory2 ff = new FilterFactoryImplNamespaceAware(namespaces);
    PropertyIsEqualTo complexFilter = ff.equals(ff.property("gml:name"), ff.literal("SWADLINCOTE"));

    visitor = new UnmappingFilterVisitor(mapping);

    Filter unrolled = (Filter) complexFilter.accept(visitor, null);
    assertNotNull(unrolled);
    assertNotSame(complexFilter, unrolled);

    assertTrue(unrolled.getClass().getName(), unrolled instanceof org.opengis.filter.Or);

    Or oredFilter = (Or) unrolled;
    List children = oredFilter.getChildren();
    assertEquals(4, children.size());

    assertTrue(children.get(0) instanceof PropertyIsEqualTo);
    assertTrue(children.get(1) instanceof PropertyIsEqualTo);
    assertTrue(children.get(2) instanceof PropertyIsEqualTo);
    assertTrue(children.get(3) instanceof PropertyIsEqualTo);

    PropertyIsEqualTo filter1 = (PropertyIsEqualTo) children.get(0);
    PropertyIsEqualTo filter2 = (PropertyIsEqualTo) children.get(1);
    PropertyIsEqualTo filter3 = (PropertyIsEqualTo) children.get(2);
    PropertyIsEqualTo filter4 = (PropertyIsEqualTo) children.get(3);

    assertTrue(filter1.getExpression1() instanceof Function);
    assertTrue(filter2.getExpression1() instanceof PropertyName);
    assertTrue(filter3.getExpression1() instanceof PropertyName);
    assertTrue(filter4.getExpression1() instanceof PropertyName);

    assertTrue(filter1.getExpression2() instanceof Literal);
    assertTrue(filter2.getExpression2() instanceof Literal);
    assertTrue(filter3.getExpression2() instanceof Literal);
    assertTrue(filter4.getExpression2() instanceof Literal);

    assertEquals("BGS_ID", ((PropertyName) filter2.getExpression1()).getPropertyName());
    assertEquals("NAME", ((PropertyName) filter3.getExpression1()).getPropertyName());
    assertEquals("ORIGINAL_N", ((PropertyName) filter4.getExpression1()).getPropertyName());
  }