001package gu.dtalk;
002
003import com.google.common.base.Predicate;
004import com.google.common.base.Predicates;
005import com.google.common.collect.Iterables;
006import com.google.common.collect.Sets;
007
008import static com.google.common.base.Preconditions.*;
009
010import java.util.Arrays;
011import java.util.Collection;
012import java.util.Comparator;
013import java.util.Iterator;
014import java.util.LinkedHashSet;
015
016/**
017 * 数值验证器
018 * @author guyadong
019 *
020 * @param <T> 数据类型,必须{@link Number}的子类
021 */
022public class NumberValidator<T> implements Predicate<T> {
023        public static final NumberValidator<Object> DEFAULT_VALIDATOR = new NumberValidator<Object>();
024        public static final NumberValidator<Object> NORMALIZATION_VALIDATOR = new NumberValidator<Object>((Double)0.0,true,(Double)1.0,true);
025        private T min = null, max = null;
026        private LinkedHashSet<T> values = null;
027        
028        private Comparator<T> numCcomparator = new Comparator<T>(){
029
030                @Override
031                public int compare(T o1, T o2) {
032                        if((o1 instanceof Integer) && (o2 instanceof Integer) ){
033                                return ((Integer)o1).compareTo((Integer)o2);
034                        }
035                        if((o1 instanceof Short) && (o2 instanceof Short) ){
036                                return ((Short)o1).compareTo((Short)o2);
037                        }
038                        if((o1 instanceof Byte) && (o2 instanceof Byte) ){
039                                return ((Byte)o1).compareTo((Byte)o2);
040                        }
041                        if((o1 instanceof Float) && (o2 instanceof Float) ){
042                                return ((Float)o1).compareTo((Float)o2);
043                        }
044                        if((o1 instanceof Float) && (o2 instanceof Float) ){
045                                return ((Float)o1).compareTo((Float)o2);
046                        }
047                        if((o1 instanceof Double) && (o2 instanceof Double) ){
048                                return ((Double)o1).compareTo((Double)o2);
049                        }
050                        throw new IllegalArgumentException("UNSUPPORTED TYPE");
051                }};
052        private boolean mineq;
053        private boolean maxeq;
054        public NumberValidator() {
055                this(null,true,null,true);
056        }
057        public NumberValidator(T min,boolean mineq,T max,boolean maxeq) {
058                this.min = min;
059                this.max = max;
060                this.mineq = mineq;
061                this.maxeq = maxeq;
062                checkArgument(min == null || Number.class.isAssignableFrom(min.getClass()));
063                checkArgument(max == null || Number.class.isAssignableFrom(max.getClass()));
064                if(min != null && max !=null){
065                        checkArgument(numCcomparator.compare(min, max) < 0,"value of max must less than min");
066                }
067        }
068        @SafeVarargs
069        public NumberValidator(T ... values) {
070                this.values = Sets.newLinkedHashSet(Iterables.filter(Arrays.asList(checkNotNull(values)),Predicates.notNull()));
071                checkArgument(!this.values.isEmpty(),"EMPTY LIST FOR values");
072                Iterables.any(this.values, new Predicate<T>() {
073                        @Override
074                        public boolean apply(T input) {
075                                checkArgument(input instanceof Number,"INVALID type of values");
076                                return true;
077                        }
078                });
079        }
080        @Override
081        public boolean apply(T input) {
082                if(input == null){
083                        return false;
084                }
085                if(values != null){
086                        return values.contains(input);
087                }else{
088                        boolean check = true;
089                        if(min != null){
090                                int comp = numCcomparator.compare(min, input);
091                                check = check && ((mineq && comp <= 0 ) || comp <0);
092                        }
093                        if(max != null){
094                                int comp = numCcomparator.compare(input,max);
095                                check = check && ((maxeq && comp >= 0 ) || comp >0);
096                        }
097                        return check;
098                }
099        }
100        @Override
101        public String toString() {
102                final int maxLen = 10;
103                StringBuilder builder = new StringBuilder();
104                builder.append("NumberValidator [");
105                if (min != null) {
106                        builder.append("min=");
107                        builder.append(min);
108                        builder.append(", ");
109                }
110                if (max != null) {
111                        builder.append("max=");
112                        builder.append(max);
113                        builder.append(", ");
114                }
115                if (values != null) {
116                        builder.append("values=");
117                        builder.append(toString(values, maxLen));
118                        builder.append(", ");
119                }
120                if (numCcomparator != null) {
121                        builder.append("numCcomparator=");
122                        builder.append(numCcomparator);
123                }
124                builder.append("]");
125                return builder.toString();
126        }
127        private String toString(Collection<?> collection, int maxLen) {
128                StringBuilder builder = new StringBuilder();
129                builder.append("[");
130                int i = 0;
131                for (Iterator<?> iterator = collection.iterator(); iterator.hasNext() && i < maxLen; i++) {
132                        if (i > 0)
133                                builder.append(", ");
134                        builder.append(iterator.next());
135                }
136                builder.append("]");
137                return builder.toString();
138        }
139        @SuppressWarnings({ "rawtypes", "unchecked" })
140        @SafeVarargs
141        public static final <T>Predicate<Object> makeValidator(T ...values){
142                checkArgument(values != null && values.length >1);
143                return new NumberValidator(values);
144        }
145        @SuppressWarnings({ "rawtypes", "unchecked" })
146        public static final <T>Predicate<Object> makeValidator( T min,boolean mineq,T max,boolean maxeq){
147                return new NumberValidator(min,mineq,max,maxeq);
148        }
149}