    001package com.hammurapi.extract;
    002
    003import java.io.Serializable;
    004import java.util.Collections;
    005import java.util.HashSet;
    006import java.util.Map;
    007import java.util.Set;
    008import java.util.TreeSet;
    009import java.util.concurrent.TimeUnit;
    010
    011
    012/**
    013 * Commutative AND.
    014 * @author Pavel Vlasov.
    015 *
    016 * @param <T>
    017 */
    018public class CommutativeAnd<T, C> extends ExtractorBase<T, Boolean, C> implements CommutativeCompositePredicate<T, C, CommutativeAnd<T,C>>, Serializable {
    019
    020        private Set<Predicate<T, C>> parts = new HashSet<Predicate<T, C>>();
    021
    022        public CommutativeAnd(double initialCost, TimeUnit costUnit) {
    023                super(initialCost,costUnit);
    024        }
    025
    026        public CommutativeAnd(double initialCost, TimeUnit costUnit, Predicate<T,C>... parts) {
    027                super(initialCost,costUnit);
    028                for (Predicate<T,C> part: parts) {
    029                        addPart(part);
    030                }
    031        }
    032
    033        public CommutativeAnd(double initialCost, TimeUnit costUnit, Iterable<Predicate<T,C>> parts) {
    034                super(initialCost,costUnit);
    035                for (Predicate<T,C> part: parts) {
    036                        addPart(part);
    037                }
    038        }
    039
    040        private void addPart(Predicate<T, C> part) {
    041                if (part instanceof CommutativeAnd) {
    042                        for (Predicate<T, C> pp: ((CommutativeAnd<T, C>) part).getParts()) {
    043                                addPart(pp);
    044                        }
    045                } else {
    046                        parts.add(part);
    047                }
    048        }
    049
    050        public Set<Predicate<T, C>> getParts() {
    051                return Collections.unmodifiableSet(parts);
    052        }
    053
    054        @Override
    055        @SuppressWarnings("unchecked")
    056        public ComparisonResult compareTo(Extractor<T, Boolean, C> otherPredicate) {
    057                if (getParts().isEmpty()) {
    058                        return True.getInstance().compareTo((Extractor<Object, Boolean, Object>) otherPredicate);
    059                }
    060
    061                if (otherPredicate instanceof CommutativeAnd && parts.equals(((CommutativeAnd) otherPredicate).parts)) {
    062                        return ComparisonResult.EQUAL_NM;
    063                }
    064
    065                boolean isTrue = true;
    066                boolean isFalse = false;
    067                for (Predicate<T, C> part: getParts()) {
    068                        ComparisonResult pcr = part.compareTo((Predicate<T, C>) False.getInstance());
    069                        if (pcr.getType().equals(ComparisonResult.Type.EQUAL)) {
    070                                isFalse = true;
    071                                isTrue = false;
    072                                break;
    073                        } else if (!pcr.getType().equals(ComparisonResult.Type.OPPOSITE)) {
    074                                isTrue = false;
    075                        }
    076                }
    077
    078                if (isTrue) {
    079                        return otherPredicate.compareTo((Predicate<T, C>) True.getInstance());
    080                }
    081
    082                if (isFalse) {
    083                        return otherPredicate.compareTo((Predicate<T, C>) False.getInstance());
    084                }
    085
    086                if (getParts().size()==1) {
    087                        return getParts().iterator().next().compareTo(otherPredicate);
    088                }
    089                for (Predicate<T, C> part: getParts()) {
    090                        ComparisonResult pcr = part.compareTo(otherPredicate);
    091                        if (pcr.isOneToOneMapping()) {
    092                                switch (pcr.getType()) {
    093                                case EQUAL:
    094                                case MORE_RESTRICTIVE:
    095                                        return ComparisonResult.MORE_RESTRICTIVE_NM;
    096//                              case OPPOSITE:
    097//                              case OPPOSITE_MORE_RESTRICTIVE:
    098//                                      return ComparisonResult.OPPOSITE_MORE_RESTRICTIVE_NM;
    099                                }
    100                        }
    101                }
    102
    103                return super.compareTo(otherPredicate);
    104        }
    105
    106        protected Boolean extractInternal(C context, Map<C, Map<Extractor<T, ? super Boolean, C>, ? super Boolean>> cache, T... obj) {
    107                for (Predicate<T, C> part: parts) {
    108                        if (!part.extract(context, cache, obj)) {
    109                                return false;
    110                        }
    111                }
    112                return true;
    113        }
    114
    115        public Set<Integer> parameterIndices() {
    116                Set<Integer> ret = new TreeSet<Integer>();
    117                for (Predicate<T, C> part: parts) {
    118                        ret.addAll(part.parameterIndices());
    119                }
    120                return ret;
    121        }
    122
    123
    124        @SuppressWarnings("unchecked")
    125        public Predicate<T, C> remove(Predicate<T, C> part) {
    126                if (!parts.contains(part)) {
    127                        return this;
    128                }
    129                try {
    130                        CommutativeAnd<T, C> ret = (CommutativeAnd<T, C>) clone();
    131                        ret.parts.remove(part);
    132                        return ret.parts.size()==1 ? ret.parts.iterator().next() : ret;
    133                } catch (CloneNotSupportedException e) {
    134                        throw new ExtractorException(e);
    135                }
    136        }
    137
    138        @SuppressWarnings("unchecked")
    139        public Predicate<T, C> normalize() {
    140                if (getParts().isEmpty()) {
    141                        return True.getInstance();
    142                }
    143                if (getParts().size()==1) {
    144                        Predicate<T, C> ret = getParts().iterator().next();
    145                        if (ret instanceof CompositePredicate) {
    146                                ((CompositePredicate) ret).normalize();
    147                        }
    148                        return ret;
    149                }
    150                ComparisonResult cr = compareTo((Predicate<T, C>) True.getInstance());
    151                if (cr.getType().equals(ComparisonResult.Type.EQUAL)) {
    152                        return True.getInstance();
    153                }
    154                if (cr.getType().equals(ComparisonResult.Type.OPPOSITE)) {
    155                        return False.getInstance();
    156                }
    157                Predicate<T, C>[] pa = getParts().toArray(new Predicate[getParts().size()]);
    158                Z: for (int i=0; i<pa.length; ++i) {
    159                        for (int j=0; j<pa.length; ++j) {
    160                                if (j!=i && pa[i]!=null && pa[j]!=null) {
    161                                        ComparisonResult pcr1 = pa[i].compareTo(pa[j]);
    162                                        if (pcr1.isOneToOneMapping()) {
    163                                                switch (pcr1.getType()) {
    164                                                case EQUAL:
    165                                                case LESS_RESTRICTIVE:
    166                                                        pa[j]=null;
    167                                                        continue;
    168                                                case OPPOSITE:
    169                                                case OPPOSITE_LESS_RESTRICTIVE:
    170                                                        return False.getInstance();
    171                                                }
    172                                        }
    173
    174                                        ComparisonResult pcr2 = pa[j].compareTo(pa[i]);
    175                                        if (pcr2.isOneToOneMapping()) {
    176                                                switch (pcr2.getType()) {
    177                                                case EQUAL:
    178                                                case LESS_RESTRICTIVE:
    179                                                        pa[i]=null;
    180                                                        continue Z;
    181                                                case OPPOSITE:
    182                                                case OPPOSITE_LESS_RESTRICTIVE:
    183                                                        return False.getInstance();
    184                                                }
    185                                        }
    186                                }
    187                        }
    188                }
    189
    190                int pc = 0;
    191                for (Predicate<T, C> part: pa) {
    192                        if (part!=null) {
    193                                ++pc;
    194                        }
    195                }
    196
    197                if (pc==0) {
    198                        return True.getInstance();
    199                }
    200
    201                if (pc==1) {
    202                        for (Predicate<T, C> part: pa) {
    203                                if (part!=null) {
    204                                        if (part instanceof CompositePredicate) {
    205                                                ((CompositePredicate) part).normalize();
    206                                        }
    207                                        return part;
    208                                }
    209                        }
    210                }
    211
    212                if (pc!=pa.length) {
    213                        CommutativeAnd<T, C> ret = new CommutativeAnd<T, C>(cost, costUnit);
    214                        for (Predicate<T, C> part: pa) {
    215                                if (part!=null) {
    216                                        ret.addPart(part);
    217                                }
    218                        }
    219                        return ret;
    220                }
    221
    222                return this;
    223        }
    224
    225        public boolean isContextDependent() {
    226                for (Predicate<T, C> part: getParts()) {
    227                        if (part.isContextDependent()) {
    228                                return true;
    229                        }
    230                }
    231                return false;
    232        }
    233
    234        @Override
    235        public String toString() {
    236                return getClass().getName()+getParts();
    237        }
    238
    239        @Override
    240        public double getCost() {
    241                if (cost==0 && costUnit==null) {
    242                        double ret = 0;
    243                        for (Predicate<T,C> part: parts) {
    244                                ret+=part.getCost();
    245                        }
    246                        return ret;
    247                }
    248                return super.getCost();
    249        }
    250
    251
    252        @Override
    253        public Extractor<T, Boolean, C> map(int[] map) {
    254                CommutativeAnd<T,C> ret = new CommutativeAnd<T, C>(initialCost, costUnit);
    255                for (Predicate<T,C> part: parts) {
    256                        ret.addPart(MappedPredicate.mapPredicate(part, map));
    257                }
    258                return ret;
    259        }
    260
    261        @Override
    262        public Object clone() throws CloneNotSupportedException {
    263                @SuppressWarnings("unchecked")
    264                CommutativeAnd<T,C> ret = (CommutativeAnd<T, C>) super.clone();
    265                ret.parts = new HashSet<Predicate<T,C>>(parts);
    266                return ret;
    267        }
    268
    269        @Override
    270        public CommutativeAnd<T, C> add(Predicate<T, C> part) {
    271                CommutativeAnd<T, C> ret = new CommutativeAnd<T, C>(initialCost, costUnit, parts);
    272                ret.parts.add(part);
    273                return ret;
    274        }
    275}