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