001    package com.thaiopensource.relaxng.impl;
002    
003    import com.thaiopensource.xml.util.Name;
004    
005    import java.util.Hashtable;
006    
007    class FindElementFunction extends AbstractPatternFunction {
008      private final ValidatorPatternBuilder builder;
009      private final Name name;
010      private final Hashtable processed = new Hashtable();
011      private int specificity = NameClass.SPECIFICITY_NONE;
012      private Pattern pattern = null;
013    
014      static public Pattern findElement(ValidatorPatternBuilder builder, Name name, Pattern start) {
015        FindElementFunction f = new FindElementFunction(builder, name);
016        start.apply(f);
017        if (f.pattern == null)
018          return builder.makeNotAllowed();
019        return f.pattern;
020      }
021    
022      private FindElementFunction(ValidatorPatternBuilder builder, Name name) {
023        this.builder = builder;
024        this.name = name;
025      }
026    
027      private boolean haveProcessed(Pattern p) {
028        if (processed.get(p) != null)
029          return true;
030        processed.put(p, p);
031        return false;
032      }
033    
034      private Object caseBinary(BinaryPattern p) {
035        if (!haveProcessed(p)) {
036          p.getOperand1().apply(this);
037          p.getOperand2().apply(this);
038        }
039        return null;
040    
041     }
042    
043      public Object caseGroup(GroupPattern p) {
044        return caseBinary(p);
045      }
046    
047      public Object caseInterleave(InterleavePattern p) {
048        return caseBinary(p);
049      }
050    
051      public Object caseChoice(ChoicePattern p) {
052        return caseBinary(p);
053      }
054    
055      public Object caseOneOrMore(OneOrMorePattern p) {
056        if (!haveProcessed(p))
057          p.getOperand().apply(this);
058        return null;
059      }
060    
061      public Object caseElement(ElementPattern p) {
062        if (!haveProcessed(p)) {
063          int s = p.getNameClass().containsSpecificity(name);
064          if (s > specificity) {
065            specificity = s;
066            pattern = p.getContent();
067          }
068          else if (s == specificity && s != NameClass.SPECIFICITY_NONE)
069            pattern = builder.makeChoice(pattern, p.getContent());
070          p.getContent().apply(this);
071        }
072        return null;
073      }
074    
075      public Object caseOther(Pattern p) {
076        return null;
077      }
078    }