public class FormChecker {
	Request req;
	boolean firstRun = true;
	boolean isValid = true;
	FormCheckerForm form = null;
	Validator validator = new DefaultValidator();

	@Deprecated
	String id;

	/**
	 * Maximal lenght of input vars to avoid too long requests If you want to
	 * get longer element-vals, override it for each element!
	 */
	int defaultMaxLenElements = 1000;

	FormCheckerConfig config;

	String formAction = "#";

	// holds temporaryly config-infos while construction-process of fc
	private GenericFormBuilder tempFormBuilder;
	private MessageSource tempProperties;

	public static final String SUBMIT_KEY = "submitted";
	public static final String SUBMIT_VALUE_PREFIX = "FORMCHECKER-";

	/**
	 * Deprecated: Put id into the FormcheckerForm and use build(request, form)
	 * or Formchecker(request)
	 * 
	 * @param _id
	 * @param request
	 */
	@Deprecated
	public FormChecker(String _id, Request request) {
		id = _id;
		req = request;
	}

	public FormChecker(Request request) {
		req = request;
	}

	/**
	 * Deprecated: Use build(Request _req, FormCheckerForm form) and put id into
	 * the FormCheckerForm
	 * 
	 * @param _id
	 * @param _req
	 * @param form
	 * @return
	 */
	@Deprecated
	public static FormChecker build(String _id, Request _req, FormCheckerForm form) {
		FormChecker fc = new FormChecker(_id, _req);
		fc.id = _id;
		fc.addForm(form);
		return fc;
	}

	public static FormChecker build(Request _req, FormCheckerForm form) {
		FormChecker fc = new FormChecker(_req);
		fc.addForm(form);
		return fc;
	}

	public FormChecker setProtectAgainstCSRF(SessionGet sessionGet, SessionSet sessionSet) {
		if (form == null) {
			throw new IllegalArgumentException("Set the FormcheckerForm BEFORE calling setAgainstCSRF");
		}
		form.setProtectedAgainstCSRF(true);
		form.setSessionGet(sessionGet);
		form.setSessionSet(sessionSet);
		return this;
	}

	public FormChecker setConfig(FormCheckerConfig config) {
		this.config = config;
		return this;
	}

	public boolean isValid() {
		return isValid;
	}

	public boolean isValidAndNotFirstRun() {
		return isValid && !firstRun;
	}

	public FormCheckerForm getForm() {
		return form;
	}

	
	private GenericFormBuilder getFormBuilder() {
		return config.getFormBuilder();
	}

	public FormChecker setFormBuilder(GenericFormBuilder formBuilder) {
		this.tempFormBuilder = formBuilder;
		return this;
	}

	public FormChecker setProperties(MessageSource properties) {
		this.tempProperties = properties;
		return this;
	}


	public String getValue(String elementName) {
		return form.getElement(elementName).getValue();
	}




	/**
	 * Get the view for displaying html in the template
	 * 
	 * @return
	 */
	public View getView() {
		return new View(form, this.getFormBuilder(), this);
	}

	/**
	 * Get the view for displaying html in the template
	 * 
	 * @return
	 */
	@Deprecated
	public View getViewWithAccessObjects() {
		return new View(form, this.getFormBuilder(), this).generateAccessObjects();
	}

	
	public void setFormAction(String formAction) {
		this.formAction = formAction;
	}

	private void prepareElement(FormCheckerElement element) {
		element.setFormChecker(this);

		// check, if maxLen is set. If not, add default-max-len
		// defaultMaxLenElements;
		boolean maxLenAvail = false;

		for (Criterion criterion : element.getCriteria()) {
			if (criterion instanceof MaxLength) {
				maxLenAvail = true;
			}
		}
		if (!maxLenAvail) {
			element.getCriteria().add(Criteria.maxLength(defaultMaxLenElements));
		}
	}

	public void addForm(FormCheckerForm form) {
		this.form = form;
		if (id != null) { // Internal id overrides id from form
			form.setId(id);
		}
	}

	private String getGenericForm() {
		return config.getFormBuilder().generateGenericForm(formAction, firstRun, form, req, config.properties);
	}

	// move to ViewFacade
	public String getLabelForElement(FormCheckerElement e, Map<String, String> attribs) {
		return config.getFormBuilder().getLabelForElement(e, new TagAttributes(attribs), firstRun);
	}

	public FormChecker run() {

		setupConfig();

		sortTabIndexes();

		initForm();

		checkIfFirstRun();

		processAndValidateElements();

		validateCompleteForm();

		return this;
	}

	private void validateCompleteForm() {
		if (!firstRun) {
			for (FormValidator formValidator : form.getValidators()) {
				if (formValidator.validate(form) == false) {
					isValid = false;
					// continue loop here, because other FormValidators can set
					// manually errors on vields
				}
			}
		}
	}

	private void processAndValidateElements() {
		for (FormCheckerElement elem : form.getElements()) {
			elem.init(req, firstRun, validator);
			if (!elem.isValid()) {
				isValid = false;
			}
		}
	}

	private void initForm() {
		form.setMessageSource(this.getConfig().getProperties());
		form.init();

		for (FormCheckerElement element : form.getElements()) {
			prepareElement(element);
		}

	}

	/**
	 * set up the config-object for formchecker (handles absence of properties
	 * and formBuider)
	 */
	private void setupConfig() {
		if (config == null) {
			if (tempFormBuilder == null) {
				tempFormBuilder = new BasicFormBuilder();
			}
			if (tempProperties == null) {
				tempProperties = new MinimalMessageSource();
			}
			config = new FormCheckerConfig(tempProperties, tempFormBuilder);
		}
	}

	// resort tab-indexes
	private void sortTabIndexes() {
		int tabIndex = 100;
		for (FormCheckerElement elem : form.getElements()) {
			elem.setTabIndex(tabIndex);
			tabIndex = elem.getLastTabIndex();
			tabIndex++;
		}
	}

	private void checkIfFirstRun() {
		if ((FormChecker.SUBMIT_VALUE_PREFIX + form.getId()).equals(req.getParameter(FormChecker.SUBMIT_KEY))) {
			firstRun = false;
		}
	}

	// move to ViewFacade
	public String getCompleteForm() {
		return this.getGenericForm();
	}

	public FormCheckerConfig getConfig() {
		return config;
	}
} public abstract class FormCheckerForm {

	List<FormCheckerElement> elements = new ArrayList<>();
	List<FormValidator> validators = new ArrayList<>();
	private Map<String, FormCheckerElement> fastAccess = new LinkedHashMap<>();
	String submitLabel = "OK";
	private MessageSource messageSource;
	
	boolean protectedAgainstCSRF = false;
	boolean showSubmitButton = true;
	
	SessionSet sessionSet;
	SessionGet sessionGet;
	
	String id="id";	// default

	boolean html5Validation = true;

	Method method = Method.POST;


	public String getSubmitLabel() {
		return submitLabel;
	}
	

	public void setSubmitLabel(String submitLabel) {
		this.submitLabel = submitLabel;
	}

	private TagAttributes formTagAttributes = new TagAttributes();

	public TagAttributes getFormTagAttributes() {
		return formTagAttributes;
	}

	public void setFormTagAttributes(LinkedHashMap<String, String> formTagAttributes) {
		this.formTagAttributes = new TagAttributes(formTagAttributes);
	}

	public Map<String, FormCheckerElement> getElementsAsMap() {
		return fastAccess;
	}



	// Should be overriden
	public abstract void init();

	public void disableHtml5Validation() {
		html5Validation = false;
	}

	public List<FormValidator> getValidators() {
		return validators;
	}

	public FormCheckerForm add(FormCheckerElement elem) {
		// RFE: Exception, if elem is added twice!
		elements.add(elem);
		fastAccess.put(elem.getName(), elem);
		return this;
	}

	public List<FormCheckerElement> getElements() {
		return elements;
	}

	public FormCheckerForm addFormValidator(FormValidator formValidator) {
		validators.add(formValidator);
		return this;
	}

	public FormCheckerElement getElement(String name) {
		return fastAccess.get(name);
	}


	public MessageSource getMessageSource() {
		return messageSource;
	}


	public void setMessageSource(MessageSource messageSource) {
		this.messageSource = messageSource;
	}


	public boolean isProtectedAgainstCSRF() {
		return protectedAgainstCSRF;
	}


	public void setProtectedAgainstCSRF(boolean protectedAgainstCSRF) {
		this.protectedAgainstCSRF = protectedAgainstCSRF;
	}


	public SessionGet getSessionGet() {
		return sessionGet;
	}


	public void setSessionGet(SessionGet sessionGet) {
		this.sessionGet = sessionGet;
	}


	public SessionSet getSessionSet() {
		return sessionSet;
	}


	public void setSessionSet(SessionSet sessionSet) {
		this.sessionSet = sessionSet;
	}


	public String getId() {
		return id;
	}


	public void setId(String id) {
		this.id = id;
	}

	public enum Method {
		POST, GET
	}

	public Method getMethod() {
		return method;
	}


	public void setMethod(Method method) {
		this.method = method;
	}


	public void hideSubmitButton() {
		this.showSubmitButton = false;
	}


	public boolean isShowSubmitButton() {
		return this.showSubmitButton;
	}


	public boolean isHtml5Validation() {
		return html5Validation;
	}
	
} public class Criteria {
	private static final Email email = new Email();
	private static final ZipCode zipCode = new ZipCode();
	private static final PostcodeCA postcodeCA = new PostcodeCA();

	public static Criterion and(Criterion... criteria) {
		return new And(criteria);
	}

	public static Criterion or(Criterion... criteria) {
		return new Or(criteria);
	}

	public static Criterion accept(String... values) {
		return new Accept(values);
	}

	public static AcceptString acceptString(String... values) {
		return new AcceptString(values);
	}

	public static Criterion min(int min) {
		return new Min(min);
	}

	public static Criterion max(int max) {
		return new Max(max);
	}
	
	public static Criterion number() {
		return new Number();
	}

	public static Criterion range(int min, int max) {
		return new Range(min, max);
	}

	public static Criterion length(int min, int max) {
		return new Length(min, max);
	}

	public static Criterion exactLength(int length) {
		return new ExactLength(length);
	}

	public static Criterion minLength(int min) {
		return new MinLength(min);
	}

	public static Criterion maxLength(int max) {
		return new MaxLength(max);
	}

	public static Criterion regex(String pattern) {
		return new Regex(pattern);
	}

	public static Criterion startsWith(String... prefix) {
		return new StartsWith(prefix);
	}

	public static Criterion emailAddress() {
		return email;
	}
	
	public static Criterion strongPassword(int minLength) {
		return new StrongPassword(minLength);
	}

	public static Criterion zipcode() {
		return zipCode;
	}

	public static Criterion postcodeCA() {
		return postcodeCA;
	}

} public class CheckboxInput extends AbstractInput<CheckboxInput> implements FormCheckerElement {

	public static CheckboxInput build(String name) {
		CheckboxInput ci = new CheckboxInput();
		ci.name = name;
		return ci;
	}

	@Override
	public String getInputTag(Map<String, String> attributes) {
		String style = "";
		TagAttributes tagAttributes = new TagAttributes(attributes);
		tagAttributes.add(this.inputAttributes);

		return "<input " + buildAllAttributes(tagAttributes) + " type=\"checkbox\" name=\"" + name + "\" value=\"" + name + "\" " + style + " " + getCheckedStatus(name) + ">";
	}

	private String getCheckedStatus(String name) {
		if ("true".equals(value)) {
			return "checked";
		} else {
			return "";
		}
	}

	@Override
	public void init(Request request, boolean firstRun, Validator validator) {
		if (firstRun) {
			this.setValue(this.getPreSetValue());
		} else {
			// RFE: This is fishy. Make the validation more elegant
			if (name.equals(request.getParameter(this.getName()))) {
				this.value = "true";
			} else {
				this.value = null;
			}
			ValidationResult vr = validator.validate(this);
			if (!vr.isValid()) {
				this.valid = false;
				this.setValidationResult(vr);
			}
			if (this.value == null) {
				this.value = "false";
			}
				
		}
	}

	public boolean getBoolValue() {
		if ("true".equals(this.value)) {
			return true;
		} else {
			return false;
		}
	}
	
	@Override
	public String getType() {
		return "checkbox";
	}

} public class DateInputSelectCompound extends AbstractInput<DateInputSelectCompound>
    implements FormCheckerElement {

  SelectInput day;
  SelectInput month;
  SelectInput year;

  static String months[] = {"january", "february", "march", "april", "may", "june", "july",
      "august", "september", "october", "november", "december"};

  int yearStart;
  int yearEnd;


  public static DateInputSelectCompound build(String name, int yearStart, int yearEnd) {
    DateInputSelectCompound i = new DateInputSelectCompound();
    i.yearStart = yearStart;
    i.yearEnd = yearEnd;
    i.name = name;
    return i;
  }


  public static DateInputSelectCompound build(String name, YearRange yearRange) {
    return DateInputSelectCompound.build(name, yearRange.start, yearRange.end);
  }



  LocalDate internalDate = null;

  @Override
  public String getInputTag(Map<String, String> attributes) {
    TagAttributes tagAttributes = new TagAttributes(attributes);
    tagAttributes.add(this.inputAttributes);

    return day.getInputTag(tagAttributes.getAttributes())
        + month.getInputTag(tagAttributes.getAttributes())
        + year.getInputTag(tagAttributes.getAttributes());

  }

  // please use setPresetValue
  @Deprecated
  public DateInputSelectCompound presetValue(LocalDate t) {
    return setPresetValue(t);
  }

  public DateInputSelectCompound setPresetValue(LocalDate t) {
    internalDate = t;
    return this;
  }

  public static final int MONTH = 1;
  public static final int DAY = 2;
  public static final int YEAR = 3;

  public String getDatePartTag(int field, Map<String, String> attributes) {
    String inputField = "wrong field desc!";
    switch (field) {
      case DAY:
        inputField = day.getInputTag(attributes);
        break;
      case MONTH:
        inputField = month.getInputTag(attributes);
        break;
      case YEAR:
        inputField = year.getInputTag(attributes);
        break;
    }
    return inputField;
  }

  @Override
  public void init(Request request, boolean firstRun, Validator validator) {

    createSelectInputs(this.parent.getConfig().getProperties());

    if (firstRun) {
      if (internalDate != null) {
        this.setValue(this.getPreSetValue());
        day.setPreSetValue(Integer.toString(internalDate.getDayOfMonth()));
        month.setPreSetValue(Integer.toString(internalDate.getMonthValue()));
        year.setPreSetValue(Integer.toString(internalDate.getYear()));
      }

    } else {
      day.init(request, firstRun, validator);
      month.init(request, firstRun, validator);
      year.init(request, firstRun, validator);

      // if empty and not required, everything is fine
      if (!isRequired() && StringUtils.isEmpty(day.getValue())
          && StringUtils.isEmpty(month.getValue()) && StringUtils.isEmpty(year.getValue())) {
        this.valid = true;
      } else { // check date format
        String dateVal = year.getValue() + "-" + month.getValue() + "-" + day.getValue();
        this.setValue(dateVal);

        try {
          internalDate = LocalDate.of(Integer.parseInt(year.getValue()),
              Integer.parseInt(month.getValue()), Integer.parseInt(day.getValue()));
          this.valid = true;
          ValidationResult vr = validator.validate(this);
          this.setValidationResult(vr);
        } catch (DateTimeException | NumberFormatException e) {
          this.valid = false;
          this.setValidationResult(ValidationResult.fail("jformchecker.wrong_date_format"));

        }
      }
    }
  }

  private void createSelectInputs(MessageSource messageSource) {
    CommonSelects commonSelects = new CommonSelects(messageSource);
    day = SelectInput.build("day-" + name);
    day.setPossibleValues(commonSelects.buildDays());

    month = SelectInput.build("month-" + name);
    month.setPossibleValues(commonSelects.buildMonths());

    year = SelectInput.build("year-" + name);
    // iterate from large to small for years
    if (yearStart < yearEnd) {
      int temp = yearStart;
      yearStart = yearEnd;
      yearEnd = temp;
    }
    year.setPossibleValues(commonSelects.getYears(this.yearStart, this.yearEnd));
  }



  @Override
  public int getLastTabIndex() {
    return this.getTabIndex() + 2;
  }

  public String getValue() {
    return value;
  }

  public LocalDate getDateValue() {
    return internalDate;
  }

  /**
   * Get internal Date as Date (Please avoid this, because LocalDate is far better.)
   * 
   * @return
   */
  public Date getLegacyDateValue() {
    if (internalDate == null) {
      return null;
    }
    return Date.from(internalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
  }


  /**
   * a range of years - that can be shown in the year-dropdown Use the static convenience methods
   * 
   * @author jochen
   *
   */
  public static class YearRange {
    int start;
    int end;


    /**
     * A range of year.
     * 
     * @param start The smaller value!
     * @param end The bigger value!
     */
    public YearRange(int start, int end) {
      this.start = start;
      this.end = end;
    }

    /**
     * year around now. Example: AroundNow(2) will return for the currentYear=2017 :
     * 2015,2016,2017,2018,2019
     * 
     * @param offset
     * @return
     */
    public static YearRange aroundNow(int offset) {
      return new YearRange(LocalDate.now().getYear() - offset, LocalDate.now().getYear() + offset);
    }

    /**
     * year around year. Example: AroundNow(2019, 2) will return : 2017,2018,2019,2020,2021
     * 
     * @param offset
     * @return
     */
    public static YearRange aroundYear(int year, int offset) {
      return new YearRange(year - offset, year + offset);
    }


    /**
     * Years in the past from today
     * 
     * @param numberOfYears
     * @return
     */
    public static YearRange past(int numberOfYears) {
      return new YearRange(LocalDate.now().getYear() - numberOfYears, LocalDate.now().getYear());
    }


    /**
     * Just the current year
     * 
     * @return
     */
    public static YearRange currentYear() {
      return new YearRange(LocalDate.now().getYear(), LocalDate.now().getYear());
    }


    /**
     * Years from now in the future.
     * 
     * @param numberOfYears
     * @return
     */
    public static YearRange future(int numberOfYears) {
      return new YearRange(LocalDate.now().getYear(), LocalDate.now().getYear() + numberOfYears);
    }

    /**
     * typical Birthday - : 110years in the past - today
     * 
     * @return
     */
    public static YearRange birthday() {
      return new YearRange(LocalDate.now().getYear() - 110, LocalDate.now().getYear());
    }

  }

  @Override
  public String getType() {
    return "date-select";
  }


} public class TextInput extends AbstractInput<TextInput> implements FormCheckerElement {

	private String placeholderText = "";

	public static TextInput build(String name) {
		TextInput i = new TextInput();
		i.name = name;
		return i;
	}

	public TextInput setPlaceholerText(String placeholderText) {
		this.placeholderText = placeholderText;
		return this;
	}

	@Override
	public String getInputTag(Map<String, String> attributes, MessageSource messageSource, boolean html5Validation) {
		TagAttributes tagAttributes = new TagAttributes(attributes);
		tagAttributes.add(this.inputAttributes);
		return String.format("<input " + buildAllAttributes(tagAttributes, messageSource, html5Validation) + buildMaxLen()
				+ "type=\"text\" name=\"%s\" value=\"%s\"" + getPlaceholder() + ">", name,
				(value == null ? "" : getValueHtmlEncoded()));
	}

	
	protected String getPlaceholder() {
		return StringUtils.isEmpty(placeholderText) ? ""
				: " placeholder=\"" + Escape.htmlText(placeholderText) + "\"";
	}
	
	@Override
	public String getType() {
		return "text";
	}


} public class MinimalMessageSource implements MessageSource {

	@Override
	public String getMessage(String key) {
		return key;
	}

} @FunctionalInterface
public interface Request {
	public String getParameter(String name);
} public class ExampleFormBuilder {
	public static FormCheckerForm getVerySimpleForm() {
		return new FormCheckerForm() {
			@Override
			public void init() {
				add(TextInput.build("firstname").setRequired().setPreSetValue("Horst").setHelpText("My Helptext")
						.setDescription("Your firstname"));
			}
		};
	}

	public static FormCheckerForm getVerySimpleFormWithoutHelp() {
		return new FormCheckerForm() {
			@Override
			public void init() {
				add(TextInput.build("firstname").setRequired().setPreSetValue("Horst")
						.setDescription("Your firstname"));
			}
		};
	}

	public static FormCheckerForm getFormWith1RequiredCheckbox(String checkboxname) {
		return new FormCheckerForm() {
			@Override
			public void init() {
				add(CheckboxInput.build(checkboxname).setRequired()
						.setDescription("Please check"));
			}
		};
	}

	public static FormCheckerForm getFormWithElements(String formId, List<FormCheckerElement> elements) {
		FormCheckerForm form = new FormCheckerForm() {
			
			@Override
			public String getId() {
				return formId;
			}

			@Override
			public void init() {
				elements.forEach((elem) -> add(elem));
			}
		};
		return form;
	}	
	
	public static FormCheckerForm getComplexForm(String formId) {
		
		
		return new FormCheckerForm() {

			@Override
			public String getId() {
				return formId;
			}

			@Override
			public void init() {

				add(TextInput.build("firstname").setDescription("Your Firstname").setPreSetValue("Jochen")
						.setCriterias(Criteria.accept("Jochen", "Max")));

				add(TextInput.build("lastname").setDescription("Your Lastname").setPreSetValue("pier")
						.setCriterias(Criteria.accept("Pan", "Mustermann")));

				add(TextInput.build("middelname").setDescription("Your Middelname")
						.setCriterias(new CustomValidation()));

				add(HiddenInput.build("hidden").setPreSetValue("something to remember"));

				add(PasswordInput.build("password").setDescription("Password"));

				add(LongTextInput.build("description").setDescription("Your Description"));

				LinkedHashMap<String, String> radioEntries = SampleMapBuilders.generateRadioMap();

				add(RadioInput.build("rdio").setPossibleValues(radioEntries).setDescription("Your Choice"));

				LinkedHashMap<String, String> selectEntries = SampleMapBuilders.generateSelectMap();

				add(SelectInput.build("select").setPossibleValues(selectEntries).setDescription("Your Selection"));

				add(CheckboxInput.build("check").setDescription("I order everything"));

			}

		};
	}
} public class RequestBuilders {

	public static final String FC_ID = FormIdHolder.COMMON_TEST_FORM_ID;

	public static Request buildExampleHttpRequest() {
		SampleRequest request = new SampleRequest();
		request.setParameter("firstname", "Jochen Pier<bold>");
		return request;
	}

	public static Request buildExampleHttpRequest(Map<String, String> reqVals) {
		SampleRequest request = new SampleRequest();

		reqVals.forEach((k,v) -> request.setParameter(k, reqVals.get(k)));
		
		return request;
	}

	public static Request buildExampleHttpRequestWithFirstRun(Map<String, String> reqVals) {
		SampleRequest request = (SampleRequest)buildFirstRunEmptyHttpRequest();
		reqVals.forEach((k,v) -> request.setParameter(k, reqVals.get(k)));
		return request;
	}

	
	public static Request buildRequestwithFirstRun(String key, String val) {
		SampleRequest r = (SampleRequest)buildFirstRunEmptyHttpRequest();
		r.setParameter(key, val);
		return r;
	}

	public static Request buildEmptyHttpRequest() {
		SampleRequest request = new SampleRequest();
		return request;
	}

	public static Request buildFirstRunEmptyHttpRequest() {
		SampleRequest request = new SampleRequest();
		request.setParameter(FormChecker.SUBMIT_KEY, FormChecker.SUBMIT_VALUE_PREFIX + RequestBuilders.FC_ID);
		return request;
	}

	public static FormChecker buildFcFirstrunRequest() {
		return new FormChecker(RequestBuilders.FC_ID, RequestBuilders.buildFirstRunEmptyHttpRequest());
	}

	
	public static FormChecker buildFcWithEmptyRequest() {
		return new FormChecker(RequestBuilders.FC_ID, RequestBuilders.buildEmptyHttpRequest());
	}

} public class DefaultValidator implements Validator {

	/*
	 * (non-Javadoc)
	 * 
	 * @see de.jformchecker.validator.Validator#validate(de.jformchecker.
	 * FormCheckerElement)
	 */
	@Override
	public ValidationResult validate(FormCheckerElement elem) {
		String value = elem.getValue();
		ValidationResult vr = ValidationResult.ok();
		if (value != null && !"".equals(value)) {
			vr = allCriteriaSatisfied(elem);
		} else {
			// blank input is valid if it's not required
			if (elem.isRequired()) {
				vr = ValidationResult.fail("jformchecker.required", "");
			} 
		}
		return vr;
	}

	// RFE: Maybe return here an array? So we can have more than one error-message per field.
	private ValidationResult allCriteriaSatisfied(FormCheckerElement elem) {
		for (Criterion criterion : elem.getCriteria()) {
			ValidationResult vr = criterion.validate(elem);
			if (!vr.isValid()) {
				return vr;
			}
		}

		return ValidationResult.ok();
	}


}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import de.jformchecker.FormChecker;
import de.jformchecker.FormCheckerForm;
import de.jformchecker.criteria.Criteria;
import de.jformchecker.elements.CheckboxInput;
import de.jformchecker.elements.DateInputSelectCompound;
import de.jformchecker.elements.TextInput;
import de.jformchecker.message.MinimalMessageSource;
import de.jformchecker.request.Request;
import de.jformchecker.test.builders.ExampleFormBuilder;
import de.jformchecker.test.builders.RequestBuilders;
import de.jformchecker.validator.DefaultValidator;
package de.jformchecker.test;





// Test some form - elements and there validation
public class FormElementTests {

	@Test
	public void testNegRegexp() {
		TextInput ti = TextInput.build("test").setCriterias(Criteria.regex("\\d+"));
		ti.init(RequestBuilders.buildRequestwithFirstRun("test", "sdf"), false, new DefaultValidator());
		assertTrue("sdf should not match with \\d", !ti.isValid());
	}

	@Test
	public void testPosRegexp() {
		TextInput ti = TextInput.build("test").setCriterias(Criteria.regex("\\d+"));
		ti.init(RequestBuilders.buildRequestwithFirstRun("test", "44"), false, new DefaultValidator());
		assertTrue("sdf should not match with \\d", ti.isValid());
	}
	
	
	@Test
	public void testDateSelectValidDate() {
		DateInputSelectCompound dateInputSelectCompound = DateInputSelectCompound.build("test", 2000, 2010);