001    package com.thaiopensource.relaxng.impl;
002    
003    import java.util.Hashtable;
004    
005    public class ValidatorPatternBuilder extends PatternBuilder {
006      private final Hashtable patternMemoMap = new Hashtable();
007      private final PatternFunction endAttributesFunction;
008      private final PatternFunction ignoreMissingAttributesFunction;
009      private final PatternFunction endTagDerivFunction;
010      private final PatternFunction mixedTextDerivFunction;
011      private final PatternFunction textOnlyFunction;
012      private final PatternFunction recoverAfterFunction;
013      private final PatternFunction dataDerivTypeFunction;
014    
015      private final Hashtable choiceMap = new Hashtable();
016      private final PatternFunction removeChoicesFunction = new RemoveChoicesFunction();
017      private final PatternFunction noteChoicesFunction = new NoteChoicesFunction();
018    
019      private class NoteChoicesFunction extends AbstractPatternFunction {
020        public Object caseOther(Pattern p) {
021          choiceMap.put(p, p);
022          return null;
023        }
024    
025        public Object caseChoice(ChoicePattern p) {
026          p.getOperand1().apply(this);
027          p.getOperand2().apply(this);
028          return null;
029        }
030      }
031    
032      private class RemoveChoicesFunction extends AbstractPatternFunction {
033        public Object caseOther(Pattern p) {
034          if (choiceMap.get(p) != null)
035            return notAllowed;
036          return p;
037        }
038    
039        public Object caseChoice(ChoicePattern p) {
040          Pattern p1 = p.getOperand1().applyForPattern(this);
041          Pattern p2 = p.getOperand2().applyForPattern(this);
042          if (p1 == p.getOperand1() && p2 == p.getOperand2())
043            return p;
044          if (p1 == notAllowed)
045            return p2;
046          if (p2 == notAllowed)
047            return p1;
048          Pattern p3 = new ChoicePattern(p1, p2);
049          return interner.intern(p3);
050        }
051      }
052    
053      public ValidatorPatternBuilder(PatternBuilder builder) {
054        super(builder);
055        endAttributesFunction = new EndAttributesFunction(this);
056        ignoreMissingAttributesFunction = new IgnoreMissingAttributesFunction(this);
057        endTagDerivFunction = new EndTagDerivFunction(this);
058        mixedTextDerivFunction = new MixedTextDerivFunction(this);
059        textOnlyFunction = new TextOnlyFunction(this);
060        recoverAfterFunction = new RecoverAfterFunction(this);
061        dataDerivTypeFunction = new DataDerivTypeFunction(this);
062      }
063    
064      PatternMemo getPatternMemo(Pattern p) {
065        PatternMemo memo = (PatternMemo)patternMemoMap.get(p);
066        if (memo == null) {
067          memo = new PatternMemo(p, this);
068          patternMemoMap.put(p, memo);
069        }
070        return memo;
071      }
072    
073      PatternFunction getEndAttributesFunction() {
074        return endAttributesFunction;
075      }
076    
077      PatternFunction getIgnoreMissingAttributesFunction() {
078        return ignoreMissingAttributesFunction;
079      }
080    
081      PatternFunction getEndTagDerivFunction() {
082        return endTagDerivFunction;
083      }
084    
085      PatternFunction getMixedTextDerivFunction() {
086        return mixedTextDerivFunction;
087      }
088    
089      PatternFunction getTextOnlyFunction() {
090        return textOnlyFunction;
091      }
092    
093      PatternFunction getRecoverAfterFunction() {
094        return recoverAfterFunction;
095      }
096    
097      PatternFunction getDataDerivTypeFunction() {
098        return dataDerivTypeFunction;
099      }
100    
101      Pattern makeAfter(Pattern p1, Pattern p2) {
102        Pattern p = new AfterPattern(p1, p2);
103        return interner.intern(p);
104      }
105    
106      Pattern makeChoice(Pattern p1, Pattern p2) {
107        if (p1 == p2)
108          return p1;
109        if (p1 == notAllowed)
110          return p2;
111        if (p2 == notAllowed)
112          return p1;
113        if (!(p1 instanceof ChoicePattern)) {
114          if (p2.containsChoice(p1))
115            return p2;
116        }
117        else if (!(p2 instanceof ChoicePattern)) {
118          if (p1.containsChoice(p2))
119            return p1;
120        }
121        else {
122          p1.apply(noteChoicesFunction);
123          p2 = p2.applyForPattern(removeChoicesFunction);
124          if (choiceMap.size() > 0)
125            choiceMap.clear();
126        }
127        if (p1 instanceof AfterPattern && p2 instanceof AfterPattern) {
128          AfterPattern ap1 = (AfterPattern)p1;
129          AfterPattern ap2 = (AfterPattern)p2;
130          if (ap1.getOperand1() == ap2.getOperand1())
131            return makeAfter(ap1.getOperand1(), makeChoice(ap1.getOperand2(), ap2.getOperand2()));
132          if (ap1.getOperand1() == notAllowed)
133            return ap2;
134          if (ap2.getOperand1() == notAllowed)
135            return ap1;
136          if (ap1.getOperand2() == ap2.getOperand2())
137            return makeAfter(makeChoice(ap1.getOperand1(), ap2.getOperand1()), ap1.getOperand2());
138        }
139        return super.makeChoice(p1, p2);
140      }
141    }