    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 OR.
    015 * @author Pavel Vlasov.
    016 *
    017 * @param <T>
    018 */
    019public class Or<T, C> extends ExtractorBase<T, Boolean, C> implements CompositePredicate<T, List<Predicate<T, C>>, C, Or<T,C>>, Serializable {
    020
    021        private List<Predicate<T, C>> parts = new ArrayList<Predicate<T, C>>();
    022
    023        public Or(double initialCost, TimeUnit costUnit) {
    024                super(initialCost, costUnit);
    025        }
    026
    027        public Or(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 Or(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 Or) {
    043                        for (Predicate<T, C> pp: ((Or<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 Or && parts.equals(((Or) otherPredicate).parts)) {
    063                        return ComparisonResult.EQUAL_NM;
    064                }
    065
    066                boolean isTrue = false;
    067                boolean isFalse = true;
    068                for (Predicate<T, C> part: getParts()) {
    069                        ComparisonResult pcr = part.compareTo((Predicate<T, C>) True.getInstance());
    070                        if (pcr.getType().equals(ComparisonResult.Type.EQUAL)) {
    071                                isTrue = true;
    072                                isFalse = false;
    073                                break;
    074                        } else if (!pcr.getType().equals(ComparisonResult.Type.OPPOSITE)) {
    075                                isFalse = 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().iterator().next().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 LESS_RESTRICTIVE:
    096                                        return ComparisonResult.LESS_RESTRICTIVE_NM;
    097//                              case OPPOSITE:
    098//                              case OPPOSITE_LESS_RESTRICTIVE:
    099//                                      return ComparisonResult.OPPOSITE_MORE_RESTRICTIVE_NM;
    100                                }
    101                        }
    102                }
    103
    104                return super.compareTo(otherPredicate);
    105        }
    106
    107        protected Boolean extractInternal(
    108                        C context,
    109                        Map<C, Map<Extractor<T, ? super Boolean, C>, ? super Boolean>> cache,
    110                        T... obj) {
    111
    112                for (Predicate<T, C> part: parts) {
    113                        if (part.extract(context, cache, obj)) {
    114                                return true;
    115                        }
    116                }
    117                return false;
    118        }
    119
    120        public Set<Integer> parameterIndices() {
    121                Set<Integer> ret = new TreeSet<Integer>();
    122                for (Predicate<T, C> part: parts) {
    123                        ret.addAll(part.parameterIndices());
    124                }
    125                return ret;
    126        }
    127
    128
    129        @SuppressWarnings("unchecked")
    130        public Predicate<T, C> remove(Predicate<T, C> part) {
    131                if (!parts.contains(part)) {
    132                        return this;
    133                }
    134                try {
    135                        Or<T, C> ret = (Or<T, C>) clone();
    136                        ret.parts.remove(part);
    137                        return ret.parts.size()==1 ? ret.parts.get(0) : ret;
    138                } catch (CloneNotSupportedException e) {
    139                        throw new ExtractorException(e);
    140                }
    141        }
    142
    143        @SuppressWarnings("unchecked")
    144        public Predicate<T, C> normalize() {
    145                if (getParts().isEmpty()) {
    146                        return True.getInstance();
    147                }
    148                if (getParts().size()==1) {
    149                        Predicate<T, C> ret = getParts().get(0);
    150                        if (ret instanceof CompositePredicate) {
    151                                ((CompositePredicate) ret).normalize();
    152                        }
    153                        return ret;
    154                }
    155                ComparisonResult cr = compareTo((Predicate<T, C>) True.getInstance());
    156                if (cr.getType().equals(ComparisonResult.Type.EQUAL)) {
    157                        return True.getInstance();
    158                }
    159                if (cr.getType().equals(ComparisonResult.Type.OPPOSITE)) {
    160                        return False.getInstance();
    161                }
    162                Predicate<T, C>[] pa = getParts().toArray(new Predicate[getParts().size()]);
    163                Z: for (int i=0; i<pa.length; ++i) {
    164                        for (int j=0; j<pa.length; ++j) {
    165                                if (j!=i && pa[i]!=null && pa[j]!=null) {
    166                                        ComparisonResult pcr1 = pa[i].compareTo(pa[j]);
    167                                        if (pcr1.isOneToOneMapping()) {
    168                                                switch (pcr1.getType()) {
    169                                                case EQUAL:
    170                                                case MORE_RESTRICTIVE:
    171                                                        pa[j]=null;
    172                                                        continue;
    173                                                case OPPOSITE:
    174                                                case OPPOSITE_MORE_RESTRICTIVE:
    175                                                        return True.getInstance();
    176                                                }
    177                                        }
    178
    179                                        ComparisonResult pcr2 = pa[j].compareTo(pa[i]);
    180                                        if (pcr2.isOneToOneMapping()) {
    181                                                switch (pcr2.getType()) {
    182                                                case EQUAL:
    183                                                case MORE_RESTRICTIVE:
    184                                                        pa[i]=null;
    185                                                        continue Z;
    186                                                case OPPOSITE:
    187                                                case OPPOSITE_MORE_RESTRICTIVE:
    188                                                        return True.getInstance();
    189                                                }
    190                                        }
    191                                }
    192                        }
    193                }
    194
    195                int pc = 0;
    196                for (Predicate<T, C> part: pa) {
    197                        if (part!=null) {
    198                                ++pc;
    199                        }
    200                }
    201
    202                if (pc==0) {
    203                        return True.getInstance();
    204                }
    205
    206                if (pc==1) {
    207                        for (Predicate<T, C> part: pa) {
    208                                if (part!=null) {
    209                                        if (part instanceof CompositePredicate) {
    210                                                ((CompositePredicate) part).normalize();
    211                                        }
    212                                        return part;
    213                                }
    214                        }
    215                }
    216
    217                if (pc!=pa.length) {
    218                        Or<T, C> ret = new Or<T, C>(cost, costUnit);
    219                        for (Predicate<T, C> part: pa) {
    220                                if (part!=null) {
    221                                        ret.addPart(part);
    222                                }
    223                        }
    224                        return ret;
    225                }
    226
    227                return this;
    228        }
    229
    230        public boolean isContextDependent() {
    231                for (Predicate<T, C> part: getParts()) {
    232                        if (part.isContextDependent()) {
    233                                return true;
    234                        }
    235                }
    236                return false;
    237        }
    238
    239        @Override
    240        public String toString() {
    241                return getClass().getName()+getParts();
    242        }
    243
    244        @Override
    245        public double getCost() {
    246                if (cost==0 && costUnit==null) {
    247                        double ret = 0;
    248                        for (Predicate<T,C> part: parts) {
    249                                ret+=part.getCost();
    250                        }
    251                        return ret;
    252                }
    253                return super.getCost();
    254        }
    255
    256
    257        @Override
    258        public Extractor<T, Boolean, C> map(int[] map) {
    259                Or<T,C> ret = new Or<T, C>(initialCost, costUnit);
    260                for (Predicate<T,C> part: parts) {
    261                        ret.addPart(MappedPredicate.mapPredicate(part, map));
    262                }
    263                return ret;
    264        }
    265
    266        @Override
    267        public Object clone() throws CloneNotSupportedException {
    268                @SuppressWarnings("unchecked")
    269                Or<T,C> ret = (Or<T, C>) super.clone();
    270                ret.parts = new ArrayList<Predicate<T,C>>(parts);
    271                return ret;
    272        }
    273
    274        @Override
    275        public Or<T, C> add(Predicate<T, C> part) {
    276                Or<T, C> ret = new Or<T, C>(initialCost, costUnit, parts);
    277                ret.parts.add(part);
    278                return ret;
    279        }
    280}