package utils;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Repository;
import org.springframework.beans.factory.annotation.Autowire;

import bean.AppVariables;
import bean.query.CondizioniCtrlBean;
import common.utility.CodiceFiscale;
import common.utility.DateUtils;
import dao.ApCabDao;
import dao.CondizioniCtrlDAO;
import sicura.entities.CondizioniCtrlRid;

@Repository
public class ConvalidaClass {

	@Autowired
	CondizioniCtrlDAO condizioniCtrlDao;
	@Autowired
	ApCabDao abiCabDao;

	List<CondizioniCtrlRid> condizioni;

	public ConvalidaClass() {

	}

//	 public ConvalidaClass(int securityOrganizationUnitId, String tipologia,CondizioniCtrlDAO condizioniCtrlDao,ApCabDao abiCabDao) {
//		 //this.condizioniCtrlDao  = condizioniCtrlDao;
//		 //this.abiCabDao = abiCabDao;
//		 
//	 }

	private String normalizzaNome(String nome) {
		String res = "";
		if (nome != null && nome.length() > 0) {

			res += Character.toLowerCase(nome.charAt(0));
			for (int i = 1; i < nome.length(); i++) {
				if (nome.charAt(i) == '_') {
					i++;
					if (res.length() > 1
							&& Character.toUpperCase(res.charAt(res.length() - 1)) != res.charAt(res.length() - 1))
						res += Character.toUpperCase(nome.charAt(i));
					else
						res += Character.toLowerCase(nome.charAt(i));
				} else
				// se il carattere è maiuscolo, e lo era anche il precedente nella stringa
				// originale, forza il lowercase
				if (i > 1 && Character.toUpperCase(nome.charAt(i)) == nome.charAt(i)
						&& Character.toUpperCase(nome.charAt(i - 1)) == nome.charAt(i - 1))
					res += Character.toLowerCase(nome.charAt(i));
				else
					res += nome.charAt(i);
			}

		}
		return res;
	}

	private String capitalize(String nome) {
		String res = "";
		if (nome != null && nome.length() > 0) {
			res += Character.toUpperCase(nome.charAt(0));
			for (int i = 1; i < nome.length(); i++)
				res += nome.charAt(i);
		}
		return res;
	}

	public DettaglioErrori eseguiConvalida(AppVariables appVariables, int securityOrganizationUnitId, String tipologia,
			Map<String, Object> disposizione, boolean mustResetFlag, boolean useTransactions) throws Exception {

		condizioni = this.condizioniCtrlDao.getCondizioni(appVariables, securityOrganizationUnitId, tipologia,
				useTransactions);
		DettaglioErrori dettaglioErrori = new DettaglioErrori();

		if (condizioni == null || condizioni.size() == 0)
			return dettaglioErrori;

		if (mustResetFlag)
			disposizione = resetFlags(disposizione);

		try {

			boolean CondRisultato = false;
			String StatementAttuale = "";
			boolean CondizioneAttuale = false;
			boolean SkipToNextField = false;
			String NomeAttualeCampoControllo = "";

			NomeAttualeCampoControllo = condizioni.get(0).getCampoChiave();
			for (int countRow = 0; countRow < condizioni.size(); countRow++) {
				CondizioniCtrlRid condizione = condizioni.get(countRow);

				//condizione.setFlagErrore(false);

				// statement1
				String statement1 = condizione.getStatement1();

				if ("IF".equalsIgnoreCase(statement1) || "ELSE IF".equalsIgnoreCase(statement1)
						|| "ELSE".equalsIgnoreCase(statement1))
					CondRisultato = controllaCondizioni(disposizione, condizione, dettaglioErrori);
				else if ("END".equalsIgnoreCase(statement1)) {
					StatementAttuale = "";
					CondRisultato = false;
				} else {

					if ((CondRisultato && "AND".equalsIgnoreCase(StatementAttuale))
							|| (!CondRisultato && "OR".equalsIgnoreCase(StatementAttuale))) {
						CondizioneAttuale = controllaCondizioni(disposizione, condizione, dettaglioErrori);

						if (!CondizioneAttuale && "AND".equalsIgnoreCase(StatementAttuale))
							CondRisultato = false;
						else if (CondizioneAttuale && "OR".equalsIgnoreCase(StatementAttuale))
							CondRisultato = true;
					}
				}

				// statement2
				String statement2 = condizione.getStatement2();
				if ("THEN".equalsIgnoreCase(statement2)) {
					if (CondRisultato) {
						String campoFlag = "flag" + condizione.getCampoChiave();

						if ("IMPORTODBGRID".equalsIgnoreCase(condizione.getCampoChiave()))
							campoFlag = "FlagImporto";
						if (campoFlag.contains("à") && !disposizione.containsKey(normalizzaNome(campoFlag)))
							campoFlag = "flag" + condizione.getCampoChiave().replace("à", "a");

						// Double check

						if (!ControllaConvalida(disposizione, condizione, dettaglioErrori, useTransactions)) {
							if (disposizione.containsKey(normalizzaNome(campoFlag)))
								disposizione.put(normalizzaNome(campoFlag), true); // KO
							else
								throw new Exception("Flag not found: " + campoFlag);
						} else {
							if (disposizione.containsKey(normalizzaNome(campoFlag)))
								disposizione.put(normalizzaNome(campoFlag), false); // OK
																					// //disposizione.get(normalizzaNome(campoFlag));

						}

						StatementAttuale = "";
						CondRisultato = false;
						SkipToNextField = true;

					}
				} else if ("OR".equalsIgnoreCase(statement2)) {
					StatementAttuale = "OR";
					if (CondRisultato) {
						countRow = findStat2Then(countRow);
						if (countRow == -1)
							break;
						condizione = condizioni.get(countRow);
					}
				} else if ("AND".equalsIgnoreCase(statement2)) {
					StatementAttuale = "AND";
					if (!CondRisultato) {
						countRow = findStat2Then(countRow);
						if (countRow == -1)
							break;
						condizione = condizioni.get(countRow);
					}
				}

				// Fine statement2
				if (SkipToNextField) {
					countRow = findCampoChiave(countRow, NomeAttualeCampoControllo);
					if (countRow == -1)
						break;
					condizione = condizioni.get(countRow);

					SkipToNextField = false;
					NomeAttualeCampoControllo = condizione.getCampoChiave();
					countRow--;
					continue;
				}
			}

		} catch (Exception ex) {
			throw ex;
		} finally {
			disposizione.put("erroriCampiObbligatori", (short) dettaglioErrori.getErroriCampiObbligatori());
			disposizione.put("erroriCampiData", (short) dettaglioErrori.getErroriCampiData());
			disposizione.put("erroriCongruenza", (short) dettaglioErrori.getErroriCongruenza());
			disposizione.put("erroriPiazzatura", (short) dettaglioErrori.getErroriPiazzatura());
		}

		if (dettaglioErrori.getErroriCampiData() > 0 || dettaglioErrori.getErroriCampiObbligatori() > 0
				|| dettaglioErrori.getErroriCongruenza() > 0 || dettaglioErrori.getErroriPiazzatura() > 0) {

			dettaglioErrori.setLivelloErrore(DettaglioErrori.LivelliErrore.BLOCCANTE);
			disposizione.put("statoConvalida", (short) 0);
		} else if (dettaglioErrori.getErroriWarning() == 0) {
			dettaglioErrori.setLivelloErrore(DettaglioErrori.LivelliErrore.OK);
			disposizione.put("statoConvalida", (short) -1);
		} else {
			dettaglioErrori.setLivelloErrore(DettaglioErrori.LivelliErrore.WARNING);
			disposizione.put("statoConvalida", (short) 2);
		}

		return dettaglioErrori;
	}

	private Map<String, Object> resetFlags(Map<String, Object> disposizione) {
		if (disposizione != null) {
			for (String key : disposizione.keySet()) {
				String flag = "flag" + capitalize(key);
				if (disposizione.containsKey(flag))
					disposizione.put(flag, false);
			}
		}
		return disposizione;
	}

	private boolean controllaCondizioni(Map<String, Object> disposizione, CondizioniCtrlRid condizione,
			DettaglioErrori dettaglioErrori) {
		String vNomeCampo = condizione.getCampoChiave();
		if ("IMPORTO".equalsIgnoreCase(vNomeCampo))
			vNomeCampo = "ImportoDbgrid";
		if (vNomeCampo != null && vNomeCampo.contains("à")) {
			if (!disposizione.containsKey(normalizzaNome(vNomeCampo))) {

			}
		}

		String vCondizione1 = condizione.getCondizione1();
		String vCongruenzaCondizione1 = condizione.getCongruenzaCondizione1();

		if (StringUtils.isEmpty(vNomeCampo) || StringUtils.isEmpty(vCondizione1)
				|| StringUtils.isEmpty(vCongruenzaCondizione1))
			return true;

		if (StringUtils.isEmpty(condizione.getDataSistemaCond())) {
			boolean statusCongruenza1 = false;
			boolean statusCongruenza2 = false;

			if (!disposizione.containsKey(normalizzaNome(vNomeCampo)))
				statusCongruenza1 = false;
			else
				statusCongruenza1 = EseguiControlloCongruenza(vNomeCampo, disposizione,
						disposizione.get(normalizzaNome(vNomeCampo)), vCongruenzaCondizione1, vCondizione1);

			// In caso di congruenza con "=" o "<>" non vi può essere la seconda condizione
			if ("=".equals(vCondizione1) || "<>".equals(vCondizione1)) {
				statusCongruenza2 = true;
			} else {
				String vCondizione2 = condizione.getCondizione2();
				String vCongruenzaCondizione2 = condizione.getCongruenzaCondizione2();

				// Controllo Condizione 2
				if (StringUtils.isEmpty(vCondizione2) || StringUtils.isEmpty(vCongruenzaCondizione2)) {
					statusCongruenza2 = true;
				} else {
					statusCongruenza2 = EseguiControlloCongruenza(vNomeCampo, disposizione,
							disposizione.get(normalizzaNome(vNomeCampo)), vCongruenzaCondizione2, vCondizione2);
				}
			}

			if (statusCongruenza1 == false || statusCongruenza2 == false)
				return false;
			else
				return true;
		}

		// Controllo per campi data
		if (!StringUtils.isEmpty(condizione.getDataSistemaCond())) {
			boolean StatusCongruenzaData1 = false;
			boolean StatusCongruenzaData2 = false;

			StatusCongruenzaData1 = eseguiControlloRangeDate(disposizione, disposizione.get(normalizzaNome(vNomeCampo)),
					condizione.getDataSistemaCond(), vCongruenzaCondizione1, vCondizione1,
					condizione.isLavorativoCond(), false);

			if ("=".equals(vCondizione1) || "<>".equals(vCondizione1)) {
				StatusCongruenzaData2 = true;
			} else {
				String vCondizione2 = condizione.getCondizione2();
				String vCongruenzaCondizione2 = condizione.getCongruenzaCondizione2();

				// Controllo Condizione 2
				if (StringUtils.isEmpty(vCondizione2) || StringUtils.isEmpty(vCongruenzaCondizione2)) {
					StatusCongruenzaData2 = true;
				} else {
					StatusCongruenzaData2 = eseguiControlloRangeDate(disposizione,
							disposizione.get(normalizzaNome(vNomeCampo)), condizione.getDataSistemaCond(),
							vCongruenzaCondizione2, vCondizione2, condizione.isLavorativoCond(), false);
				}
			}

			if (StatusCongruenzaData1 == false || StatusCongruenzaData2 == false)
				return false;
			else
				return true;
		}

		return false;

	}

	private boolean eseguiControlloRangeDate(Map<String, Object> source, Object valore, String CampoConfronto,
			String ValoreConfronto, String Statement, boolean SoloGiorniLavorativi, boolean CheckGiornoLavorativo) {
		if (valore == null)
			return true;

		Date valoreData = DateUtils.parse(valore);

		Date DataConfronto = new Date(Long.MIN_VALUE);
		if ("DATA DI SISTEMA".equalsIgnoreCase(CampoConfronto))
			DataConfronto = new Date();
		else {
			DataConfronto = DateUtils.parse(CampoConfronto);
			if (DataConfronto == null) {
				return true;
				// throw new ApplicationException(string.Format("EseguiControlloRangeDate: La
				// data specificata non è valida ({0})", CampoConfronto));
			}
		}

		// Calcolo valore di confronto
		if (!StringUtils.isEmpty(ValoreConfronto) && CommonFunctions.IsInteger(ValoreConfronto)) {
			// TODO
			int somma = Integer.parseInt(ValoreConfronto);
			DataConfronto = DateUtils.addDays(DataConfronto, somma);
		}

		boolean ok = false;

		if ("=".equals(Statement))
			ok = valoreData.compareTo(DataConfronto) == 0;
		else if ("<>".equals(Statement))
			ok = valoreData.compareTo(DataConfronto) != 0;
		else if (">".equals(Statement))
			ok = valoreData.compareTo(DataConfronto) > 0;
		else if ("<".equals(Statement))
			ok = valoreData.compareTo(DataConfronto) < 0;
		else if (">=".equals(Statement))
			ok = valoreData.compareTo(DataConfronto) >= 0;
		else if ("<=".equals(Statement))
			ok = valoreData.compareTo(DataConfronto) <= 0;

		if (ok == true && CheckGiornoLavorativo == true) {
			DateTime dt = new DateTime(valoreData);
			if (dt.getDayOfWeek() == DateUtils.SATURDAY || dt.getDayOfWeek() == DateUtils.SUNDAY)
				return false;
		}

		return ok;
	}

	private boolean EseguiControlloCongruenza(String vNomeCampo, Map<String, Object> source, Object value,
			String ValoreConfronto, String Statement) {
		if (value instanceof String) {
			String valueString = (String) value;
			if ("=".equals(Statement)) {
				if ("NULL".equalsIgnoreCase(ValoreConfronto))
					return StringUtils.isEmpty(value.toString());

				if (valueString.equals(ValoreConfronto))
					return true;
				else {
					if (StringUtils.isEmpty(valueString) == false && valueString.startsWith(ValoreConfronto))
						return true;
					return false;
				}
			} else if ("<>".equals(Statement)) {
				if ("NULL".equalsIgnoreCase(ValoreConfronto))
					return !StringUtils.isEmpty(value.toString());

				return !valueString.equals(ValoreConfronto);
			} else if (">=".equals(Statement))
				return valueString.compareTo(ValoreConfronto) == 1 || valueString.equals(ValoreConfronto);
			else if ("<=".equals(Statement))
				return valueString.compareTo(ValoreConfronto) == -1 || valueString.equals(ValoreConfronto);
			else if (">".equals(Statement))
				return valueString.compareTo(ValoreConfronto) == 1;
			else if ("<".equals(Statement))
				return valueString.compareTo(ValoreConfronto) == -1;
		} else if (value instanceof Integer || value instanceof Double) {
			Double valoreDecimal = ToDecimal(value);
			Double valoreConfrontoDecimal = ToDecimal(ValoreConfronto);

			if ("=".equals(Statement))
				return valoreDecimal.equals(valoreConfrontoDecimal);
			else if ("<>".equals(Statement))
				return !valoreDecimal.equals(valoreConfrontoDecimal);
			else if (">".equals(Statement))
				return valoreDecimal.compareTo(valoreConfrontoDecimal) > 0;
			else if (">=".equals(Statement))
				return valoreDecimal.compareTo(valoreConfrontoDecimal) >= 0;
			else if ("<".equals(Statement))
				return valoreDecimal.compareTo(valoreConfrontoDecimal) < 0;
			else if ("<=".equals(Statement))
				return valoreDecimal.compareTo(valoreConfrontoDecimal) <= 0;
		} else if (value instanceof Date) {
			Date valoreDateTime = ParseDate(value);
			Date valoreConfrontoDateTime = ParseDate(ValoreConfronto);

			if ("=".equals(Statement))
				return valoreDateTime.equals(valoreConfrontoDateTime);
			else if ("<>".equals(Statement))
				return !valoreDateTime.equals(valoreConfrontoDateTime);
			else if (">".equals(Statement))
				return valoreDateTime.compareTo(valoreConfrontoDateTime) > 0;
			else if (">=".equals(Statement))
				return valoreDateTime.compareTo(valoreConfrontoDateTime) >= 0;
			else if ("<".equals(Statement))
				return valoreDateTime.compareTo(valoreConfrontoDateTime) < 0;
			else if ("<=".equals(Statement))
				return valoreDateTime.compareTo(valoreConfrontoDateTime) <= 0;
		}

		if (value == null)
			return false;

		return false;
	}

	private Double ToDecimal(Object value) {
		if (value instanceof Integer)
			return Double.valueOf((Integer) value);

		else if (value instanceof Double)
			return (Double) value;
		else if (value instanceof String) {
			Double v = 0.0;
			try {
				v = Double.parseDouble((String) value);
			} catch (Exception ex) {
				v = 0.0;
			}
			return v;
		}

		return 0.0;

	}

	private String ParseValue(Object v) {
		if (v == null)
			return "(vuoto)";
		else
			return v.toString();
	}

	private Date ParseDate(Object valore) {
		if (valore == null)
			return new Date(Long.MIN_VALUE);
		if (valore instanceof Date)
			return (Date) valore;
		if (valore instanceof String && StringUtils.isEmpty((String) valore))
			return new Date(Long.MIN_VALUE);
		if (valore instanceof String && StringUtils.isEmpty((String) valore) == false
				&& ("NULL".equals((String) valore)))
			return new Date(Long.MIN_VALUE);

		Date v = new Date(Long.MIN_VALUE);
		try {
			v = DateUtils.parse(valore);
		} catch (Exception ex) {
			v = new Date(Long.MIN_VALUE);
		}
		return v;
	}

	private boolean IsEmpty(Map<String, Object> source, String Campo) {
		Campo = normalizzaNome(Campo);
		if (source.containsKey(Campo) == false) {
			return false;
		}

		if (source.get(Campo) == null)
			return true;

		Object v = source.get(Campo);
		if (v instanceof String || v instanceof Integer || v instanceof Double || v instanceof Date
				|| v instanceof java.sql.Date) {
			if (v instanceof String && StringUtils.isEmpty((String) v) == true)
				return true;
			else if (v instanceof Integer && (Integer) v == 0)
				return true;
			else if (v instanceof Double && (Double) v == 0)
				return true;
			else if (v instanceof Date && (Date) v == new Date(Long.MIN_VALUE))
				return true;
			else if (v instanceof java.sql.Date && ((java.sql.Date) v).getTime() == new Date(Long.MIN_VALUE).getTime())
				return true;
		} else {
		}

		return false;
	}

	private boolean ControllaConvalida(Map<String, Object> source, CondizioniCtrlRid condizione,
			DettaglioErrori dettaglioErrori, boolean useTransactions) {
		String vCampo_Chiave = condizione.getCampoChiave();
		if ("IMPORTO".equalsIgnoreCase(vCampo_Chiave))
			vCampo_Chiave = "ImportoDbgrid";

		if (vCampo_Chiave.contains("à") && source.containsKey(normalizzaNome(vCampo_Chiave)) == false)
			vCampo_Chiave = vCampo_Chiave.replace("à", "a");

		// Controllo per Flag Forzatura Errore
		if (condizione.isFlagErrore()) {
			dettaglioErrori.AggiungiErroriCongruenza(vCampo_Chiave, "Rilevato Errore",
					ParseValue(source.get(vCampo_Chiave)));
			// cct.ErroriCongruenza = cct.ErroriCongruenza + 1
			// ccrc.ErroriCongruenza = True
			// ccrc.CurrentError = ErrorEnum.ForzaturaErrore
			// ccrc.CurrentValue = vv

			return false;
		}

		boolean IsEmptyCampoChiave = IsEmpty(source, vCampo_Chiave);

		// Controllo per campo obbligatorio
		if (condizione.isObbligatorio()) {
			if (IsEmptyCampoChiave == true) {
				dettaglioErrori.AggiungiErroriCampiObbligatori(vCampo_Chiave, "(vuoto)");
				// cct.ErroriCampiObbligatori = cct.ErroriCampiObbligatori + 1
				// ccrc.ErroriCampiObbligatori = True
				// ccrc.CurrentValue = "<nessun valore>"
				// ccrc.CurrentError = ErrorEnum.CampoObbligatorio
				return false;
			}
		}

		// Controllo per range ( non di date )
		if (StringUtils.isEmpty(condizione.getCampoDataSistema())
				&& StringUtils.isEmpty(condizione.getCondizione3()) == false) {
			boolean StatusCongruenza1 = false;
			boolean StatusCongruenza2 = false;

			// Controllo Condizione 3
			String Condizione3 = condizione.getCondizione3();
			StatusCongruenza1 = EseguiControlloCongruenza(vCampo_Chiave, source,
					source.get(normalizzaNome(vCampo_Chiave)), condizione.getCongruenzaCondizione3(), Condizione3);
			if ("=".equals(Condizione3) || "<>".equals(Condizione3)) {
				StatusCongruenza2 = true;
			} else {
				// Controllo Condizione 4
				if (StringUtils.isEmpty(condizione.getCondizione4())
						&& StringUtils.isEmpty(condizione.getCongruenzaCondizione4())) {
					StatusCongruenza2 = true;
				} else {
					StatusCongruenza2 = EseguiControlloCongruenza(vCampo_Chiave, source,
							source.get(normalizzaNome(vCampo_Chiave)), condizione.getCongruenzaCondizione4(),
							condizione.getCondizione4());
				}
			}

			if (StatusCongruenza1 == false || StatusCongruenza2 == false) {
				dettaglioErrori.AggiungiErroriCongruenza(vCampo_Chiave, "Condizione Errata",
						ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
				// cct.ErroriCongruenza = cct.ErroriCongruenza + 1
				// ccrc.ErroriCongruenza = True
				// ccrc.CurrentError = ErrorEnum.FuoriRange
				// ccrc.CurrentValue = vv
				return false;
			}
		}

		// Controllo per range (campi data)
		if (StringUtils.isEmpty(condizione.getCampoDataSistema()) == false
				&& StringUtils.isEmpty(condizione.getCondizione3()) == false) {
			boolean StatusCongruenzaData1 = false;
			boolean StatusCongruenzaData2 = false;
			String Condizione3 = condizione.getCondizione3();
			Object valore = source.get(normalizzaNome(vCampo_Chiave));

			StatusCongruenzaData1 = eseguiControlloRangeDate(source, valore, condizione.getCampoDataSistema(),
					condizione.getCongruenzaCondizione3(), Condizione3, condizione.isFlagLavorativo(),
					condizione.isFlagSoloGiornoLavorativo());

			if ("=".equals(Condizione3) || "<>".equals(Condizione3)) {
				StatusCongruenzaData2 = true;
			} else {
				// Controllo Condizione 4
				if (StringUtils.isEmpty(condizione.getCondizione4())
						&& StringUtils.isEmpty(condizione.getCongruenzaCondizione4())) {
					StatusCongruenzaData2 = true;
				} else {
					StatusCongruenzaData2 = eseguiControlloRangeDate(source, valore, condizione.getCampoDataSistema(),
							condizione.getCongruenzaCondizione4(), condizione.getCondizione4(),
							condizione.isFlagLavorativo(), condizione.isFlagSoloGiornoLavorativo());
				}
			}

			if (StatusCongruenzaData1 == false || StatusCongruenzaData2 == false) {
				dettaglioErrori.AggiungiErroriCampiData(vCampo_Chiave, ParseValue(valore));
				// cct.ErroriCampiData = cct.ErroriCampiData + 1
				// ccrc.ErroriCampiData = True
				// ccrc.CurrentError = ErrorEnum.FuoriRange
				// ccrc.CurrentValue = vv
				return false;
			}
		}

		// Controllo Banca Aderente (non legato alla configurazione di convalida ma
		// forzato per RIB, RID E UTENZE)
		// Controllo di Piazzatura
		short FlagPiazzatura = condizione.getFlagPiazzatura();
		if (IsEmptyCampoChiave == false && FlagPiazzatura != 0) {
			boolean isinError = false;

			if (StringUtils.isEmpty(condizione.getCampoReciprocoPiazzatura()) == false) {
				if (!abiCabDao.existsAbiCab(
						(String) source.get(normalizzaNome(condizione.getCampoReciprocoPiazzatura())),
						(String) source.get(normalizzaNome(vCampo_Chiave)), useTransactions))
					isinError = true;

			} else {
				if (!abiCabDao.existsAbi((String) source.get(normalizzaNome(vCampo_Chiave)), useTransactions))
					isinError = true;
			}

			if (isinError == true) {
				if (FlagPiazzatura == 2)
					dettaglioErrori.AggiungiErroriWarning(vCampo_Chiave,
							ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
				else
					dettaglioErrori.AggiungiErroriPiazzatura(vCampo_Chiave,
							ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
				return false;
			}
		}

		// Controllo Codice Fiscale
		short FlagControlloCodiceFiscale = condizione.getControlloCodiceFiscale();
		if (IsEmptyCampoChiave == false && FlagControlloCodiceFiscale != 0) {
			if (CodiceFiscale.ControllaCF((String) source.get(normalizzaNome(vCampo_Chiave))) != CodiceFiscale.CF_OK) {
				if (FlagControlloCodiceFiscale == 2)
					dettaglioErrori.AggiungiErroriWarning(vCampo_Chiave,
							ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
				else
					dettaglioErrori.AggiungiErroriCongruenza(vCampo_Chiave, "ControlloCodiceFiscale",
							ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
				// cct.ErroriCongruenza = cct.ErroriCongruenza + 1
				// ccrc.ErroriCongruenza = True
				// ccrc.CurrentError = ErrorEnum.CodiceFiscaleErrato
				// ccrc.CurrentValue = vv
				return false;
			}
		}

		// Controllo Cin
		if (IsEmptyCampoChiave == false && condizione.isControlloCin() == true) {
			if (Formalismi.CheckCin((String) source.get(normalizzaNome(vCampo_Chiave)),
					(String) source.get(normalizzaNome(condizione.getAbiControlloCin())),
					(String) source.get(normalizzaNome(condizione.getCabControlloCin())),
					(String) source.get(normalizzaNome(condizione.getContoControlloCin()))) == false) {
				dettaglioErrori.AggiungiErroriCongruenza(vCampo_Chiave, "ControlloCin",
						ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
				// cct.ErroriCongruenza = cct.ErroriCongruenza + 1
				// ccrc.ErroriCongruenza = True
				// ccrc.CurrentError = ErrorEnum.CodiceFiscaleErrato
				// ccrc.CurrentValue = vv
				return false;
			}
		}

		// Controllo IBAN

		// if (IsEmptyCampoChiave == false && condizione.isControlloIban() == true)
		if (condizione.isControlloIban()) {
			if (!IsEmptyCampoChiave
					&& !StringUtils.isEmpty(ParseValue(source.get(source.get(normalizzaNome(vCampo_Chiave)))))
					&& !"CheckDigit".equals(vCampo_Chiave)) {
				if (Formalismi.CheckIBAN((String) source.get(normalizzaNome(vCampo_Chiave))) == false) {
					dettaglioErrori.AggiungiErroriCongruenza(vCampo_Chiave, "ControlloIBAN",
							ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
					// cct.ErroriCongruenza = cct.ErroriCongruenza + 1
					// ccrc.ErroriCongruenza = True
					// ccrc.CurrentError = ErrorEnum.CodiceFiscaleErrato
					// ccrc.CurrentValue = vv
					return false;
				}
			}
		}

		if (condizione.isControlloIban()) {
			if (!IsEmptyCampoChiave
					&& !StringUtils.isEmpty(ParseValue(source.get(source.get(normalizzaNome(vCampo_Chiave)))))
					&& "CheckDigit".equals(vCampo_Chiave)) {

				if (Formalismi.CheckIBAN((String) source.get(normalizzaNome("CodicePaese"))
						+ (String) source.get(normalizzaNome("CheckDigit")) + (String) source.get(normalizzaNome("Cin"))
						+ (String) source.get(normalizzaNome("Codice_Abi_Destinatario"))
						+ (String) source.get(normalizzaNome("Cab_Destinatario"))
						+ (String) source.get(normalizzaNome("Conto_Destinatario"))) == false) {
					dettaglioErrori.AggiungiErroriCongruenza(vCampo_Chiave, "ControlloIBAN-CheckDigit",
							ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
					// cct.ErroriCongruenza = cct.ErroriCongruenza + 1
					// ccrc.ErroriCongruenza = True
					// ccrc.CurrentError = ErrorEnum.CodiceFiscaleErrato
					// ccrc.CurrentValue = vv
					return false;
				}
			}
		}

		// Controllo Caratteri Ammessi
		if (IsEmptyCampoChiave == false && !StringUtils.isEmpty(condizione.getCaratteriAbilitati())) {
			String caratteriValidi = condizione.getCaratteriAbilitati();
			if (Formalismi.EseguiControlloCaratteriAmmessi((String) source.get(normalizzaNome(vCampo_Chiave)),
					caratteriValidi) == false) {
				dettaglioErrori.AggiungiErroriCongruenza(vCampo_Chiave,
						String.format("CaratteriAbilitati=%s", caratteriValidi),
						ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
				// cct.ErroriCongruenza = cct.ErroriCongruenza + 1
				// ccrc.ErroriCongruenza = True
				// ccrc.CurrentError = ErrorEnum.CodiceFiscaleErrato
				// ccrc.CurrentValue = vv
				return false;
			}
		}

		// Controllo Lunghezza Campo Vincolante
		if (IsEmptyCampoChiave == false && !StringUtils.isEmpty(condizione.getControlloLunghezzaCampo())) {
			if (condizione.getControlloLunghezzaCampo() != null) {
				String v = (String) source.get(normalizzaNome(vCampo_Chiave));
				int num = 0;
				try {
					num = Integer.parseInt(condizione.getControlloLunghezzaCampo());
					if (v.trim().length() != num) {
						dettaglioErrori.AggiungiErroriCongruenza(vCampo_Chiave,
								String.format("ControlloLunghezzaCampo=%d", num),
								ParseValue(source.get(normalizzaNome(vCampo_Chiave))));
						// cct.ErroriCongruenza = cct.ErroriCongruenza + 1
						// ccrc.ErroriCongruenza = True
						// ccrc.CurrentError = ErrorEnum.CodiceFiscaleErrato
						// ccrc.CurrentValue = vv
						return false;
					}
				} catch (Exception ex) {
					num = 0;
				}
			}
		}

		// Controllo tipo bollettino mav
		// Controllo valore univoco

		return true;
	}

	private int findCampoChiave(int countRow, String CampoControllo) {
		if (countRow + 1 >= condizioni.size())
			return -1;
		for (int row = countRow + 1; row != condizioni.size(); row++) {
			if (!CampoControllo.equals(condizioni.get(row).getCampoChiave()))
				return row;
		}
		return -1;
	}

	private int findStat2Then(int countRow) {
		if (countRow + 1 >= condizioni.size())
			return -1;
		for (int row = countRow + 1; row != condizioni.size(); row++) {
			if ("THEN".equals(condizioni.get(countRow).getStatement2()))
				return row - 1;
		}
		return countRow;
	}

}
