tim@101: package de.intevation.gnv.utils;
tim@101: 
sascha@779: import com.vividsolutions.jts.geom.Coordinate;
sascha@779: import com.vividsolutions.jts.geom.GeometryFactory;
sascha@779: import com.vividsolutions.jts.geom.Point;
sascha@779: 
sascha@779: import com.vividsolutions.jts.io.ParseException;
sascha@779: import com.vividsolutions.jts.io.WKTReader;
sascha@779: 
sascha@779: import de.intevation.gnv.geobackend.util.DateUtils;
sascha@779: 
sascha@779: import de.intevation.gnv.utils.exception.ValidationException;
sascha@779: 
tim@252: import java.util.Date;
tim@252: 
tim@116: import org.apache.commons.validator.GenericValidator;
tim@101: 
sascha@779: import org.apache.log4j.Logger;
tim@101: 
tim@101: /**
sascha@780:  * @author <a href="mailto:tim.englich@intevation.de">Tim Englich</a>
ingo@785:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
sascha@778:  *
tim@101:  */
tim@101: public class InputValidator {
tim@101:     /**
tim@101:      * the logger, used to log exceptions and additonaly information
tim@101:      */
tim@101:     private static Logger log = Logger.getLogger(InputValidator.class);
sascha@778: 
ingo@1051:     /**
ingo@1051:      * Epsilon for handling unprecise date objects (in ms).
ingo@1051:      */
ingo@1051:     public final static long DATE_EPSILON = 750;
ingo@1051: 
sascha@778: 
tim@222:     public final static String NODATASELECTEDVALUE = "n/n";
tim@101: 
tim@101:     /**
tim@101:      * Constructor
tim@101:      */
tim@101:     public InputValidator() {
tim@101:         super();
tim@101:     }
tim@171: 
ingo@806:     /**
ingo@806:      * Validates the input of a range of double or date values. The input values
ingo@806:      * need to be valid double or date values. <i>minInput</i> needs to be
ingo@806:      * smaller or equal <i>maxInput</i>.
ingo@806:      *
ingo@806:      * @param minInput The lower bound.
ingo@806:      * @param maxInput The upper bound.
ingo@806:      * @param type One of 'Date' or 'Double'.
ingo@806:      * @return true, if the input is valid, otherwise false.
ingo@806:      */
ingo@785:     public static boolean isInputValid(String minInput, String maxInput, String type) {
tim@252:         log.debug("InputValidator.isInputValid " + minInput + " " + maxInput + " " +type);
tim@252:         boolean returnValue = false;
tim@252:         if ("Date".equalsIgnoreCase(type)) {
tim@252:             try {
tim@252:                 Date min = DateUtils.getDateFromString(minInput,DateUtils.DATE_PATTERN);
tim@252:                 Date max = DateUtils.getDateFromString(maxInput,DateUtils.DATE_PATTERN);
tim@252:                 int value = max.compareTo(min);
tim@252:                 returnValue = value >= 0;
tim@252:             } catch (Exception e) {
tim@252:                 log.error(e,e);
tim@252:             }
tim@252:         } else if ("Double".equalsIgnoreCase(type)) {
tim@252:             try {
tim@252:                 double min = Double.parseDouble(minInput);
tim@252:                 double max = Double.parseDouble(maxInput);
tim@252:                 returnValue = max >= min;
tim@252:             } catch (Exception e) {
tim@252:                 log.error(e,e);
tim@252:             }
tim@252:         }
tim@252:         log.debug("Is valid? " + returnValue);
tim@252:         return returnValue;
tim@252:     }
sascha@778: 
ingo@806:     /**
ingo@806:      * Validates an input.
ingo@806:      *
ingo@806:      * @param input The input value.
ingo@806:      * @param type The input value type.
ingo@806:      * @return true if the input is valid, otherwise false.
ingo@806:      */
ingo@785:     public static boolean isInputValid(String input, String type) {
ingo@860:         if (input.length() == 0 || input.equals("")) {
ingo@860:             return false;
ingo@860:         }
ingo@860: 
tim@171:         log.debug("InputValidator.isInputValid " + input + " " + type);
ingo@787: 
sascha@803:         // Let's check polygons and linestrings first, because they might
ingo@787:         // contain comma. A splitting at comma characters wouldn't be good here.
ingo@787:         if ("Polygon".equalsIgnoreCase(type) || "Linestring".equalsIgnoreCase(type))
ingo@787:         {
ingo@787:             try {
ingo@787:                 WKTReader reader = new WKTReader();
ingo@787:                 reader.read(input);
ingo@787: 
ingo@787:                 return true;
ingo@787:             }
ingo@787:             catch (ParseException pe) {
ingo@787:                 log.warn(pe, pe);
ingo@787:                 return false;
ingo@787:             }
ingo@787:         }
ingo@787: 
ingo@787:         // Check all the other input here
tim@101:         boolean returnValue = false;
tim@101:         String[] values = input.split(",");
ingo@787: 
tim@171:         for (int i = 0; i < values.length; i++) {
tim@101:             boolean valid;
sascha@778: 
tim@222:             if (NODATASELECTEDVALUE.equals(values[i].trim())){
tim@222:                 valid = true;
tim@222:             } else if ("Integer".equalsIgnoreCase(type)) {
sascha@115:                 valid = GenericValidator.isInt(values[i].trim());
tim@171:             } else if ("Double".equalsIgnoreCase(type)) {
tim@171:                 valid = GenericValidator.isDouble(values[i].trim());
tim@171:             } else if ("String".equalsIgnoreCase(type)) {
tim@171:                 valid = GenericValidator.matchRegexp(values[i], "[a-zA-Z0-9]"); // TODO:
tim@171:                                                                                 // FIXME:
tim@171:                                                                                 // VALIDATE
tim@171:                                                                                 // REGEXP
tim@171:             } else if ("Date".equalsIgnoreCase(type)) {
tim@171:                 valid = GenericValidator.isDate(values[i].trim(),
tim@171:                         DateUtils.DATE_PATTERN, true);
tim@731:             } else if ("Point".equalsIgnoreCase(type) || "Geometry".equals(type)) {
tim@171:                 valid = GenericValidator.matchRegexp(values[i], "[0-9]"); // TODO:
tim@171:                                                                           // FIXME:
tim@171:                                                                           // VALIDATE
tim@171:                                                                           // REGEXP
tim@171:             } else if ("AttributeName".equalsIgnoreCase(type)) {
tim@171:                 valid = org.apache.commons.validator.GenericValidator
tim@171:                         .matchRegexp(values[i], "[a-zA-Z0-9]"); // TODO: FIXME:
tim@171:                                                                 // VALIDATE
tim@171:                                                                 // REGEXP
tim@173:             } else if ("Coordinate".equalsIgnoreCase(type)) {
tim@173:                     try {
ingo@785:                         valid = getPointValue(values[i]) != null;
tim@173:                     } catch (ValidationException e) {
tim@173:                         log.debug(e.getMessage());
tim@173:                         valid = false;
tim@173:                     }
tim@171:             } else {
tim@101:                 valid = false;
tim@101:             }
tim@171:             if (!valid) {
tim@171:                 returnValue = false;
tim@101:                 break;
tim@171:             } else {
tim@101:                 returnValue = true;
tim@101:             }
tim@101:         }
tim@171:         log.debug("Is valid? " + returnValue);
tim@101:         return returnValue;
tim@101:     }
sascha@778: 
sascha@778: 
ingo@806:     /**
ingo@806:      * Returns a point from wkt string.
ingo@806:      *
ingo@806:      * @param value The wkt string.
ingo@806:      * @return a point.
ingo@806:      * @throws ValidationException if <i>value</i> is not valid.
ingo@806:      */
ingo@785:     public static Point getPointValue(String value) throws ValidationException{
tim@173:         log.debug("InputValidator.getPointValue " + value);
sascha@778: 
tim@746:         if (value.toLowerCase().startsWith("point")){
tim@746:             try {
tim@746:                 return (Point)new WKTReader().read(value);
tim@746:             } catch (ParseException e) {
tim@746:                 log.error(e,e);
tim@746:                 throw new ValidationException(e);
tim@746:             }
tim@746:         }else{
tim@746:             String[] s, p;
sascha@778: 
tim@746:             double x=0,y=0;
tim@746:             log.info("Position :"+value);
tim@746:             s = value.split(" ");
tim@746:             if (s.length != 2) {
tim@746:                   throw new ValidationException("Kein Blank separiert Breite und Länge");
tim@746:             }
tim@746:             p = s[0].split("[nNsS]");
tim@746:             try {
tim@746:                 if (p.length == 1)
tim@746:                     y = new Double(p[0]);
tim@746:                 else
tim@746:                     y = new Double(p[0]) +   new Double(p[1]) / new Double(60.);
tim@746:                 if (s[0].toLowerCase().contains("s"))
tim@746:                     y = -y;
tim@746:             }
tim@746:             catch (Exception e) {
tim@746:                 throw new ValidationException("Kein N|S oder nicht im ersten Substring, zB 56n42");
sascha@778: 
sascha@778:             }
tim@746:             p = s[1].split("[eEwW]");
tim@746:             try {
tim@746:                 if (p.length ==1)
tim@746:                     x = new Double(p[0]);
tim@746:                 else
tim@746:                     x = new Double(p[0]) +  new Double(p[1]) / new Double(60.) ;
tim@746:                 if (s[1].toLowerCase().contains("w"))
tim@746:                     x = -x;
tim@746:             }
tim@746:             catch (Exception e) {
tim@746:                 throw new ValidationException("Kein E|W oder nicht im zweiten Substring");
sascha@778:             }
tim@746:             return new GeometryFactory().createPoint(new Coordinate(x,y));
tim@173:         }
tim@173:     }
tim@101: 
ingo@784: 
ingo@806:     /**
ingo@806:      * Makes sure that <i>tmp</i> is between <i>lo</i> and <i>up</i>.
ingo@806:      *
ingo@806:      * @param tmp The value to validate.
ingo@806:      * @param lo The lower range bound.
ingo@806:      * @param up The upper range bound.
ingo@806:      * @return true, if tmp is valid, otherwise false.
ingo@806:      */
ingo@785:     public static boolean isDateValid(Date tmp, Date lo, Date up) {
ingo@1051:         long tmpTime = tmp.getTime();
ingo@1051:         long tmpLow  = lo.getTime();
ingo@1051:         long tmpUp   = up.getTime();
ingo@784: 
ingo@1051:         if (tmpTime < tmpLow - DATE_EPSILON || tmpTime > tmpUp + DATE_EPSILON) {
ingo@784:             log.warn(
ingo@784:                 "Date [" + tmp.toString() + "] is out of range ["
ingo@784:                 + lo.toString() + " to "+ up.toString() + "].");
ingo@784:             return false;
ingo@784:         }
ingo@784: 
ingo@784:         return true;
ingo@784:     }
tim@101: }
sascha@836: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :