package org.gcube.application.geoportal.model.report;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ConstraintCheck<T> {

	public static <T> ConstraintCheck<T> defaultFor(T toCheck,T defaultValue){
		return new ConstraintCheck<T>(toCheck).withDefault(defaultValue);
	}


	private T theObject;
	private String fieldLabel; 
	private String message;
	private boolean error=false;
	private boolean mandatory;
	private T theDefault;

	private List<Check> additionalChecks=new ArrayList<Check>();

	public ConstraintCheck(T theObject,Check...checks){
		this.theObject=theObject;
		for(Check c:checks)
			additionalChecks.add(c);
		check();

	}
	public ConstraintCheck<T> withDefault(T theDefault){
		this.theDefault=theDefault;
		return this;
	}
	public ConstraintCheck<T> addChecks(Check...checks){
		for(Check c:checks)
			additionalChecks.add(c);
		return this;
	} 
	public ConstraintCheck(T theObject,String fieldLabel,Check...checks){
		this.theObject=theObject;
		this.fieldLabel=fieldLabel;
		for(Check c:checks)
			additionalChecks.add(c);
		check();
	}

	public T evaluate() {
		check();
		T result=theObject;
		if(isError()) {
			result=theDefault;
			if(theDefault!=null && theDefault instanceof Collection) {
				Collection defaultCollection=(Collection) theDefault;
				ArrayList target=new ArrayList(defaultCollection);
				result=(T) target;
			}	
		}
		return result;

	}

	private void check() {
		if(theObject==null) {			
			this.setMessage(fieldLabel+" è un campo obbligatorio.");
			this.setError(true);
		}else
			if((theObject instanceof String) && ((String) theObject).isEmpty()) {
				this.setMessage(fieldLabel+" non può essere vuoto.");
				this.setError(true);	
			}else
				if((theObject instanceof Collection)) {
					Collection toCheckCollection=(Collection) theObject;
					if(toCheckCollection.isEmpty()) {
						this.setMessage("La lista "+fieldLabel+" non può essere vuota.");
						this.setError(true);
					}


					Boolean containsError=false;
					Object[] array=toCheckCollection.toArray(new Object[toCheckCollection.size()]);
					for(int i=0;i<array.length;i++) {
						containsError=new ConstraintCheck(array[i],fieldLabel+" [elemento N° "+i+"]").isError();
					}			

					this.setError(containsError);

				}else {

					for(Check check:additionalChecks) {
						if(!check.isOk(theObject)) {
							this.setError(true);
							this.setMessage(check.getMessage());
						}
					}
				}
	}
}
