using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Objects;
using System.Data.Objects.SqlClient;
using System.Linq;
using System.Net;
using System.Reflection;
using ServicesApiOcaPeek.Data;
using ServicesApiOcaPeek.ExceptionPersonnalisees;
using ServicesApiOcaPeek.Extensions;
using ServicesApiOcaPeek.Models;

namespace ServicesApiOcaPeek.Helpers
{
	/// <summary>
	/// Gestion de l'accès à la couche de données
	/// </summary>
	public class ServicesApiOcaPeekDataHelper : IDisposable
	{
		OCAPEEKEntities ent;

		public virtual void Dispose()
		{
			ent.Dispose();
			ent = null;
		}

		/// <summary>
		/// 
		/// </summary>
		public ServicesApiOcaPeekDataHelper()
		{
			try
			{
				ent = new OCAPEEKEntities();
			}
			catch (Exception exc)
			{
				Utils.ElmahLogException(exc);
				throw exc;
			}
		}


		#region Check connection base

		/// <summary>
		/// Permet de test si la base de données est disponible
		/// </summary>
		/// <returns></returns>
		internal bool CheckConnectionBase()
		{
			return ent.DatabaseExists();
		}


		internal bool CheckAccessTable()
		{
			return ent.OP_VISITE.Any();
		}

		#endregion


		public PAR_GEN_SERV GetParcGenServDansBdd(string environnement)
		{

			return ent.PAR_GEN_SERV.Where(w => w.PGS_ENV.Equals(environnement, StringComparison.OrdinalIgnoreCase))
				.SingleOrDefault();
		}

		/// <summary>
		/// recuperer les visites
		/// </summary>
		/// <param name="site">site</param>
		/// <param name="username">nom d'utilisateur</param>
		/// <param name="startDate">date de debut</param>
		/// <param name="endDate">date de fin</param>
		/// <param name="sortindex">nom propiete </param>
		/// <param name="sortdir">sans de l'ordre (exemple : 'ASC' pour croissant)</param>
		/// <param name="page">numéro de page</param>
		/// <param name="count">nombre element dans une page</param>
		/// <param name="archive"></param>
		/// <returns></returns>
		public ListePaginee<Visite> ListeVisites(string site = null, string username = null, DateTime? startDate = null,
			DateTime? endDate = null, string sortindex = null, string sortdir = "ASC", int page = 1, int count = 10,
			bool archive = false)
		{
			var req = ent.OP_VISITE
				.Join(ent.OP_DATE_HORAIRE, ov => ov.OPV_ID, odh => odh.OPDH_OPV_ID, (ov, odh) => new { ov, odh })
				.Join(ent.OP_VISITE_VISITEUR, joined => joined.ov.OPV_ID, ovv => ovv.OPVVS_OPV_ID,
					(joined, ovv) => new { joined.ov, joined.odh, ovv })
				.Join(ent.OP_VISITEUR, joined => joined.ovv.OPVVS_OPVS_ID, ovvs => ovvs.OPVS_ID,
					(joined, ovvs) => new { joined.ov, joined.odh, joined.ovv, ovvs })
				.Where(joined => (string.IsNullOrEmpty(site) || joined.ov.OPV_SITE.StartsWith(site)) &&
				                 (string.IsNullOrEmpty(username) ||
				                  joined.ov.OPV_COLLAB_USERNAME.StartsWith(username)) &&
				                 (startDate == null || EntityFunctions.TruncateTime(joined.odh.OPDH_DATE_DEBUT) >=
					                 EntityFunctions.TruncateTime(startDate)) &&
				                 (endDate == null || EntityFunctions.TruncateTime(joined.odh.OPDH_DATE_DEBUT) <=
					                 EntityFunctions.TruncateTime(endDate)) &&
				                 (joined.ov.OPV_ARCHIVE == archive))
				.Select(result => new Visite
				{
					id = result.ov.OPV_ID,
					archive = result.ov.OPV_ARCHIVE,
					description = result.ov.OPV_DESCRIPTION,
					site = result.ov.OPV_SITE,
					status = result.ov.OPV_STATUS,
					sujet = result.ov.OPV_SUJET,
					titre = result.ov.OPV_TITRE,
					type = result.ov.OPV_TYPE_VISITE,
					dateDebut = result.odh.OPDH_DATE_DEBUT,
					dateFin = result.odh.OPDH_DATE_FIN,
					duree = result.odh.OPDH_DUREE,
					heureArrivee = result.odh.OPDH_HEURE_ARRIVEE,
					heureDepart = result.odh.OPDH_HEURE_DEPART,
					badge = result.ovv.OPVVS_BADGE,
					overtime = result.ovv.OPVVS_OVERTIME,
					plaqueImmatriculation = result.ovv.OPVVS_PLAQUE_IMMATRICUL,
					parking = result.ovv.OPVVS_PARKING,
					nomCollaborateur = result.ov.OPV_COLLAB_USERNAME,
					contact = new VisiteContact
					{
						nom = result.ov.OPV_NOM_CONTACT,
						telephone = result.ov.OPV_TELEPHONE_CONTACT
					}
				}).OrderBy(x => EntityFunctions.DiffDays(x.dateDebut, DateTime.Now)).AsEnumerable();

			req = req.Distinct();

			var visiteListe = req.ToList();

			List<Visite> listeVisite = new List<Visite>();

			#region système de pagination

			int total = req.Count();

			IEnumerable<Visite> elems = Enumerable.Empty<Visite>();

			if (string.IsNullOrEmpty(sortindex))
			{
				elems = req.AsEnumerable();
			}
			else
			{
				var nomPropriete = typeof(Visite).GetProperty(sortindex,
					BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

				if (sortdir.Equals("ASC", StringComparison.InvariantCultureIgnoreCase))
				{
					elems = req.OrderBy(x => nomPropriete.GetValue(x, null));
				}
				else
				{
					elems = req.OrderByDescending(x => nomPropriete.GetValue(x, null));
				}
			}

			var res = elems.Skip((page - 1) * count).Take(count);

			#endregion

			return new ListePaginee<Visite> { count = count, elements = res.ToList(), page = page, total = total };
		}



		public Visite GetVisite(int visiteId)

		{
			var listeVisiteur = GetListeVisiteurFromVisite(visiteId);

			var req = (from ov in ent.OP_VISITE
				join odh in ent.OP_DATE_HORAIRE on ov.OPV_ID equals odh.OPDH_OPV_ID
				join ovv in ent.OP_VISITE_VISITEUR on ov.OPV_ID equals ovv.OPVVS_OPV_ID
				join ovvs in ent.OP_VISITEUR on ovv.OPVVS_OPVS_ID equals ovvs.OPVS_ID
				where
				(
					ov.OPV_ID.Equals(visiteId)
				)
				select new Visite
				{
					archive = ov.OPV_ARCHIVE,
					badge = ovv.OPVVS_BADGE,
					dateDebut = odh.OPDH_DATE_DEBUT,
					dateFin = odh.OPDH_DATE_FIN,
					overtime = ovv.OPVVS_OVERTIME,
					titre = ov.OPV_TITRE,
					description = ov.OPV_DESCRIPTION,
					site = ov.OPV_SITE,
					type = ov.OPV_TYPE_VISITE,
					status = ov.OPV_STATUS,
					id = ov.OPV_ID,
					duree = odh.OPDH_DUREE,
					heureArrivee = odh.OPDH_HEURE_ARRIVEE,
					heureDepart = odh.OPDH_HEURE_DEPART,
					nomCollaborateur = ov.OPV_COLLAB_USERNAME,
					reponse = new VisiteReponse
					{
						refus = (bool)ovv.OPVVS_REFUS ? ovv.OPVVS_REFUS : false,
						raisonRefus = ovv.OPVVS_RAISON_REFUS
					},
					contact = new VisiteContact
					{
						nom = ov.OPV_NOM_CONTACT,
						telephone = ov.OPV_TELEPHONE_CONTACT
					}
				}).AsEnumerable();


			if (listeVisiteur.Count == 0)
			{
				throw new Exception("Aucun visiteur pour cette visite");
			}

			var visiteWithVisiteurs = req.ToArray();
			var visiteToReturn = req.FirstOrDefault();
			visiteToReturn.reponse = null;

			for (var i = 0; i < visiteWithVisiteurs.Length; i++)
			{
				var visiteur = listeVisiteur.ElementAt(i);
				var visite = visiteWithVisiteurs.ElementAt(i);
				visiteur.reponse = visite.reponse;

			}

			if (visiteToReturn != null)
			{
				visiteToReturn.visiteurs = listeVisiteur;
			}

			//return visiteWithVisiteurs;
			return visiteToReturn;
		}


		public VisiteCourante GetVisiteByKey(string key)
		{
			var vvs = ent.OP_VISITE_VISITEUR.SingleOrDefault(v => v.OPVVS_CLE_LIEN == key);

			if (vvs == null)
			{
				throw new ExceptionNotFoundApi("Clé invalide");
			}

			var visiteur = vvs.OP_VISITEUR;
			var visite = vvs.OP_VISITE;
			var odh = visite.OP_DATE_HORAIRE.SingleOrDefault(dh => dh.OPDH_OPV_ID == visite.OPV_ID);
			if (odh == null || vvs == null)
			{
				throw new ExceptionNotFoundApi("Erreur: Cette visite n'existe pas");
			}

			return new VisiteCourante
			{
				archive = vvs.OP_VISITE.OPV_ARCHIVE,
				collabUsername = visite.OPV_COLLAB_USERNAME,
				confirmee = vvs.OPVVS_CONFIRMEE,
				overtime = vvs.OPVVS_OVERTIME,
				badge = vvs.OPVVS_BADGE,
				parking = vvs.OPVVS_PARKING,
				dateDebut = odh.OPDH_DATE_DEBUT,
				heureDebut = odh.OPDH_HEURE_ARRIVEE,
				heureDebutPrev = odh.OPDH_HEURE_DEBUT_PREV,
				dateDebutPrev = odh.OPDH_DATE_DEBUT_PREV,
				dateFinPrev = odh.OPDH_DATE_FIN_PREV,
				heureFinPrev = odh.OPDH_HEURE_FIN_PREV,
				description = visite.OPV_DESCRIPTION,
				donneeReponse = vvs.OPVVS_DONNEE_REPONSE,
				horaireId = odh.OPDH_ID,
				idVvs = vvs.OPVVS_ID,
				idVisite = visite.OPV_ID,
				idVisiteur = visiteur.OPVS_ID,
				email = visiteur.OPVS_EMAIL,
				nom = visiteur.OPVS_NOM,
				prenom = visiteur.OPVS_PRENOM,
				telephone = visiteur.OPVS_TELEPHONE,
				site = visite.OPV_SITE,
				status = visite.OPV_STATUS,
				titre = visite.OPV_TITRE,
				typeVisite = visite.OPV_TYPE_VISITE,
				duree = odh.OPDH_DUREE.HasValue ? odh.OPDH_DUREE.Value : 0,
			};
		}

		/// <summary>
		/// Crée une visite
		/// </summary>
		/// <param name="valeur"></param>
		/// <returns>Identifiant de la visite crée</returns>
		public VisiteVisiteur CreerVisite(VisiteVisiteur valeur)
		{
			if (valeur.visiteurs.Count <= 0)
			{
				throw new Exception("Au moins un visiteur est requis");
			}

			var visite = new OP_VISITE
			{
				OPV_ARCHIVE = false,
				OPV_DESCRIPTION = valeur.visite.description,
				OPV_SITE = valeur.visite.site,
				OPV_STATUS = valeur.visite.status,
				OPV_SUJET = valeur.visite.sujet,
				OPV_TITRE = valeur.visite.titre,
				OPV_TYPE_VISITE = valeur.visite.type,
				OPV_COLLAB_USERNAME = valeur.visite.initiateur,
				OPV_NOM_CONTACT = valeur.visite.contact.nom,
				OPV_TELEPHONE_CONTACT = valeur.visite.contact.telephone
			};

			var dateHoraire = new OP_DATE_HORAIRE
			{
				OPDH_DATE_DEBUT = valeur.visite.dateDebut,
				OPDH_HEURE_ARRIVEE = valeur.visite.heureArrivee,
				OPDH_DUREE = valeur.visite.duree,
				OPDH_SITE = valeur.visite.site,
				OP_VISITE = visite,

			};
			var index = 0;
			Random rnd = new Random();
			valeur.visiteurs.ForEach((payloadVisiteur) =>
			{

				OP_VISITE_VISITEUR visiteCourrante = new OP_VISITE_VISITEUR
				{
					// données globales
					OPVVS_BADGE = valeur.badge,
					OPVVS_OVERTIME = valeur.overtime,
					OP_VISITE = visite,
					OPVVS_PARKING = payloadVisiteur.parking,
					OPVVS_PLAQUE_IMMATRICUL = payloadVisiteur.plaqueImmatriculation,

				};
				var visiteurExistant = ent.OP_VISITEUR.SingleOrDefault(ov => ov.OPVS_ID == payloadVisiteur.id);

				if (visiteurExistant != null)
				{
					visiteCourrante.OP_VISITEUR = visiteurExistant;
				}
				else
				{
					visiteCourrante.OP_VISITEUR = new OP_VISITEUR
					{
						OPVS_EMAIL = payloadVisiteur.email,
						OPVS_NOM = payloadVisiteur.nom,
						OPVS_PRENOM = payloadVisiteur.prenom,
						OPVS_TELEPHONE = payloadVisiteur.telephone,
					};
				}

				string hash = UtilHelpers.GenSHA512($"{rnd.Next()}{visiteCourrante.OP_VISITEUR.OPVS_EMAIL}");
				visiteCourrante.OPVVS_CLE_LIEN = hash;
				valeur.visiteurs[index].hashKey = hash;

				ent.OP_VISITE_VISITEUR.AddObject(visiteCourrante);

				index++;
			});

			ent.OP_DATE_HORAIRE.AddObject(dateHoraire);


			ent.SaveChanges();
			return new VisiteVisiteur() { id = visite.OPV_ID, visite = valeur.visite, visiteurs = valeur.visiteurs };
		}
		
		
		/// <summary>
		/// Modifier une visite
		/// </summary>
		/// <param name="id"></param>
		/// <param name="valeur"></param>
		/// <returns></returns>
		///
		
		public VisiteVisiteur ModifierVisite(int id, Visite valeur,List<Visiteur> visiteurs)
		{
			
			var visite = ent.OP_VISITE.SingleOrDefault(v => v.OPV_ID == id);
			if (visite == null)
			{
				throw new ExceptionDataConstraint("La visite n'existe pas");
			}
			
			visite.OPV_ARCHIVE = valeur.archive;
			visite.OPV_DESCRIPTION = valeur.description;
			visite.OPV_SITE = valeur.site;
			visite.OPV_STATUS = valeur.status;
			visite.OPV_SUJET = valeur.titre;
			visite.OPV_TITRE = valeur.titre;
		
			
			var dateHoraire = ent.OP_DATE_HORAIRE.SingleOrDefault(dh => dh.OPDH_OPV_ID == visite.OPV_ID);
			if (dateHoraire == null)
			{
				throw new ExceptionDataConstraint("La date de la visite n'existe pas");
			}
			
			dateHoraire.OPDH_DATE_DEBUT = valeur.dateDebut;
			dateHoraire.OPDH_DUREE = valeur.duree;
			
			var visiteursCourants = ent.OP_VISITE_VISITEUR.Where(vv => vv.OPVVS_OPV_ID == visite.OPV_ID).ToList();
			foreach (var visiteurCourant in visiteursCourants)
			{
				ent.OP_VISITE_VISITEUR.DeleteObject(visiteurCourant);
			}
			
			foreach (var visiteur in visiteurs)
			{
				var visiteurExistant = ent.OP_VISITEUR.SingleOrDefault(ov => ov.OPVS_ID == visiteur.id);
				if (visiteurExistant != null)
				{
					var visiteCourrante = new OP_VISITE_VISITEUR
					{
						OPVVS_PARKING = visiteur.parking,
						OPVVS_PLAQUE_IMMATRICUL = visiteur.plaqueImmatriculation,
						OP_VISITE = visite,
						OP_VISITEUR = visiteurExistant
					};
					
					ent.OP_VISITE_VISITEUR.AddObject(visiteCourrante);
					
				}
				
				else
				{
					var visiteurCourant = new OP_VISITEUR
					{
						OPVS_EMAIL = visiteur.email,
						OPVS_NOM = visiteur.nom,
						OPVS_PRENOM = visiteur.prenom,
						OPVS_TELEPHONE = visiteur.telephone
					};
					
					ent.OP_VISITEUR.AddObject(visiteurCourant);
					
					var visiteCourrante = new OP_VISITE_VISITEUR
					{
						OPVVS_PARKING = visiteur.parking,
						OPVVS_PLAQUE_IMMATRICUL = visiteur.plaqueImmatriculation,
						OP_VISITE = visite,
						OP_VISITEUR = visiteurCourant
					};
					
					ent.OP_VISITE_VISITEUR.AddObject(visiteCourrante);
				}
				
			}
			
			ent.SaveChanges();
			
			return new VisiteVisiteur { id = visite.OPV_ID, visite = valeur, visiteurs = visiteurs };
			
		}


		public Visiteur AddVisitortovisit(int id, List<Visiteur> visiteurs)
		{

			var visite = ent.OP_VISITE.SingleOrDefault(v => v.OPV_ID == id);

			if (visite == null)
			{
				throw new ExceptionDataConstraint("La visite n'existe pas");
			}

			foreach (var visiteur in visiteurs)
			{
				var visiteurExistant = ent.OP_VISITEUR.SingleOrDefault(ov => ov.OPVS_ID == visiteur.id);
				if (visiteurExistant != null)
				{
					var visiteCourrante = new OP_VISITE_VISITEUR
					{
						OPVVS_PARKING = visiteur.parking,
						OPVVS_PLAQUE_IMMATRICUL = visiteur.plaqueImmatriculation,
						OP_VISITE = visite,
						OP_VISITEUR = visiteurExistant
					};

					ent.OP_VISITE_VISITEUR.AddObject(visiteCourrante);

				}

				else
				{
					var visiteurCourant = new OP_VISITEUR
					{
						OPVS_EMAIL = visiteur.email,
						OPVS_NOM = visiteur.nom,
						OPVS_PRENOM = visiteur.prenom,
						OPVS_TELEPHONE = visiteur.telephone
					};

					ent.OP_VISITEUR.AddObject(visiteurCourant);
					
				}

			}

			ent.SaveChanges();

			return new Visiteur();
		}





		/// <summary>
		/// 
		/// </summary>
		/// <param name="nom"></param>
		/// <param name="prenom"></param>
		/// <param name="username"></param>
		/// <param name="sortindex"></param>
		/// <param name="sortdir"></param>
		/// <param name="page"></param>
		/// <param name="count"></param>
		/// <returns></returns>
		public ListePaginee<Visiteur> ListeVisiteur(string nom = null, string prenom = null, string username = null, string sortindex = null, string sortdir = "ASC", int page = 1, int count = 10)
		{

			var req = ent.OP_VISITEUR
				.Join(ent.OP_VISITE_VISITEUR,
					ov => ov.OPVS_ID,
					ovv => ovv.OPVVS_OPVS_ID,
				(ov, ovv) => new Visiteur
				{
					nom = ov.OPVS_NOM,
					prenom = ov.OPVS_PRENOM,
					email = ov.OPVS_EMAIL,
					telephone = ov.OPVS_TELEPHONE,
					id = ov.OPVS_ID
				})
				.Where(ov =>
					(string.IsNullOrEmpty(nom) || ov.nom.StartsWith(nom)) &&
					(string.IsNullOrEmpty(prenom) || ov.prenom.StartsWith(prenom)))
				.Distinct()
				.AsEnumerable();

			#region système de pagination
			int total = req.Count();

			IEnumerable<Visiteur> elems = Enumerable.Empty<Visiteur>();

			if (string.IsNullOrEmpty(sortindex))
			{
				elems = req;
			}
			else
			{
				var nomPropriete = typeof(Visiteur).GetProperty(sortindex, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

				if (sortdir.Equals("ASC", StringComparison.InvariantCultureIgnoreCase))
				{
					elems = req.OrderBy(x => nomPropriete.GetValue(x, null));
				}
				else
				{
					elems = req.OrderByDescending(x => nomPropriete.GetValue(x, null));
				}
			}

			var res = elems.Skip((page - 1) * count).Take(count);
			#endregion

			return new ListePaginee<Visiteur> { count = count, elements = res.ToList(), page = 0, total = total };
		}
		
		/// <summary>
		/// 
		/// </summary>
		/// <param name="id"></param>
		/// <param name="valeur"></param>
		/// <returns></returns>
		public VisiteVisiteur ModifierVisiteur(int id, VisiteVisiteur valeur)
		{
			var visiteur = ent.OP_VISITEUR.SingleOrDefault(v => v.OPVS_ID == id);
			if (visiteur == null)
			{
				throw new ExceptionDataConstraint("Le visiteur n'existe pas");
			}
			
			visiteur.OPVS_NOM = valeur.visiteurs[0].nom;
			visiteur.OPVS_PRENOM = valeur.visiteurs[0].prenom;
			visiteur.OPVS_EMAIL = valeur.visiteurs[0].email;
			visiteur.OPVS_TELEPHONE = valeur.visiteurs[0].telephone;
			
			ent.SaveChanges();
			
			return new VisiteVisiteur() { id = visiteur.OPVS_ID, visite = valeur.visite, visiteurs = valeur.visiteurs };
			
		}
		

		public VisiteVisiteur EnvoieReponseVisite(int visiteId, int visiteurId, VisiteReponse valeur)
		{

			var result = GetVisiteCourante(visiteId, visiteurId);
			var visiteCourante = result.Item1;
			
			if (visiteCourante.OPVVS_DONNEE_REPONSE == true)
			{
				throw new ExceptionDataConstraint("Le visiteur à déja repondu à la visite");
			}
			visiteCourante.OPVVS_DONNEE_REPONSE = true;

			if ((bool)valeur.refus)
			{
				visiteCourante.OPVVS_REFUS = valeur.refus;
				visiteCourante.OPVVS_RAISON_REFUS = valeur.raisonRefus;
			}

			visiteCourante.OPVVS_PLAQUE_IMMATRICUL = valeur.plaqueImmat;
			visiteCourante.OPVVS_PARKING = valeur.parking;

			var estCurrVisiteRefusee = estVisiteRefusee(result.Item2);
			var estVisiteInitie = !estCurrVisiteRefusee && estVisiteInitiee(result.Item2);

			if (estCurrVisiteRefusee)
			{
				visiteCourante.OP_VISITE.OPV_STATUS = VisiteStatus.REFUSEE;
			}

			if (estVisiteInitie) // si tous les visiteurs ont repondu
			{
				visiteCourante.OP_VISITE.OPV_STATUS = VisiteStatus.CONFIRMATION_INITIATEUR;
			}


			ent.SaveChanges();

			return new VisiteVisiteur();

		}

		public VisiteVisiteur EnvoieRefusVisiteur(int visiteId, int visiteurId, VisiteReponse valeur)
		{
			var result = GetVisiteCourante(visiteId, visiteurId);
			var visiteCourante = result.Item1;

			if (!visiteCourante.OPVVS_DONNEE_REPONSE)
			{
				throw new ExceptionDataConstraint("Le visiteur n'a pas encore donnée sa réponse");
			}

			if (valeur.refus.HasValue && valeur.refus.Value)
			{
				visiteCourante.OPVVS_REFUS = valeur.refus;
				visiteCourante.OPVVS_RAISON_REFUS = valeur.raisonRefus;
			}

			visiteCourante.OPVVS_CONFIRMEE = true;

			bool isVisitRefusee = estVisiteRefusee(result.Item2);
			bool isVisitProgramme = !isVisitRefusee && estVisiteProgramme(result.Item2);

			if (estVisiteRefusee(result.Item2))
			{
				visiteCourante.OP_VISITE.OPV_STATUS = VisiteStatus.REFUSEE;
			}

			if (isVisitProgramme) // si tous les visiteurs ont repondu
			{
				visiteCourante.OP_VISITE.OPV_STATUS = VisiteStatus.PROGRAMMEE;
			}

			ent.SaveChanges();
			return new VisiteVisiteur { };

		}

		public HttpResponseExtension SignalerPresenceVisiteur(int visiteId, int visiteurId)
		{

			var result = GetVisiteCourante(visiteId, visiteurId);

			HttpResponseExtension reponse = new HttpResponseExtension();

			var visiteCourante = result.Item1;
	
			if (!visiteCourante.OPVVS_DONNEE_REPONSE ||
				!visiteCourante.OPVVS_CONFIRMEE ||
				(visiteCourante.OPVVS_REFUS.HasValue && visiteCourante.OPVVS_REFUS.Value))
			{
				throw new ExceptionDataConstraint("Erreur: L'Etat du visiteur n'est pas valide");
			}

			visiteCourante.OPVVS_PRESENT = true;

			var estCurrVisiteEnCours = estVisiteEnCours(result.Item2);

			if (estCurrVisiteEnCours)
			{
				visiteCourante.OP_VISITE.OPV_STATUS = VisiteStatus.EN_COURS;
				reponse.statusUpdated = true;
 
			}

			ent.SaveChanges();
			reponse.message = "Le visiteur à été signalé comme entré";
			return reponse;
		}

		public Tuple<OP_VISITE_VISITEUR, List<OP_VISITE_VISITEUR>> GetVisiteCourante(int visiteId, int visiteurId)
		{

			var visiteVisiteurs = ent.OP_VISITE_VISITEUR.Where(vvs => vvs.OP_VISITE.OPV_ID == visiteId).ToList();
			var dataVisiteCourante = visiteVisiteurs.Where(visiteur => visiteur.OP_VISITEUR.OPVS_ID == visiteurId).SingleOrDefault();
			if (dataVisiteCourante == null || dataVisiteCourante == null)
			{
				throw new ExceptionDataConstraint("Aucun visiteur ou aucune visite existante");
			}

			return Tuple.Create(dataVisiteCourante, visiteVisiteurs);
		}


		public bool estVisiteRefusee(List<OP_VISITE_VISITEUR> ovvs)
		{
			return ovvs.Where(v => v.OPVVS_REFUS == true).Count() == ovvs.Count();
		}
		public bool estVisiteProgramme(List<OP_VISITE_VISITEUR> ovvs)
		{
			return ovvs.Where(v => v.OPVVS_CONFIRMEE == true).Count() == ovvs.Count();
		}
		public bool estVisiteInitiee(List<OP_VISITE_VISITEUR> ovvs)
		{
			return ovvs.Where(v => v.OPVVS_DONNEE_REPONSE == true).Count() == ovvs.Count();
		}

		public bool estVisiteEnCours(List<OP_VISITE_VISITEUR> ovvs)
		{
			return ovvs.Where(v => v.OPVVS_PRESENT == true).Count() == ovvs.Count();
		}


		public bool ConfirmationVisiteur(int visiteId, int visiteurId)
		{
			var result = GetVisiteCourante(visiteId, visiteurId);
			var visiteCourante = result.Item1;

			visiteCourante.OPVVS_CONFIRMEE = true;

			bool estCurrVisiteRefuse = estVisiteRefusee(result.Item2);
			bool estCurrVisiteProgramme = estVisiteProgramme(result.Item2);

			if (estCurrVisiteRefuse)
			{
				visiteCourante.OP_VISITE.OPV_STATUS = VisiteStatus.REFUSEE;
			}

			if (estCurrVisiteProgramme)
			{
				visiteCourante.OP_VISITE.OPV_STATUS = VisiteStatus.PROGRAMMEE;
			}
			ent.SaveChanges();
			return true;
		}


		public List<Visiteur> GetListeVisiteurFromVisite(int visiteId)
		{
			var visiteurQuery = ent.OP_VISITE
				.Join(ent.OP_DATE_HORAIRE, ov => ov.OPV_ID, odh => odh.OPDH_OPV_ID, (ov, odh) => new { ov, odh })
				.Join(ent.OP_VISITE_VISITEUR, joined => joined.ov.OPV_ID, ovv => ovv.OPVVS_OPV_ID, (joined, ovv) => new { joined.ov, joined.odh, ovv })
				.Join(ent.OP_VISITEUR, joined => joined.ovv.OPVVS_OPVS_ID, ovvs => ovvs.OPVS_ID, (joined, ovvs) => new { joined.ovv, ovvs })
				.Where(joined => joined.ovv.OPVVS_OPV_ID == visiteId)
				.Select(result => new
				{
					result.ovvs.OPVS_NOM,
					result.ovvs.OPVS_PRENOM,
					result.ovvs.OPVS_EMAIL,
					result.ovvs.OPVS_TELEPHONE,
					result.ovvs.OPVS_ID,
					result.ovv.OPVVS_PLAQUE_IMMATRICUL,
					result.ovv.OPVVS_PARKING,
					result.ovv.OPVVS_DONNEE_REPONSE,
					result.ovv.OPVVS_CONFIRMEE,
					result.ovv.OPVVS_RAISON_REFUS,
					result.ovv.OPVVS_REFUS,
					result.ovv.OPVVS_PRESENT
				});

			var visiteurListe = visiteurQuery.ToList();


			if (visiteurListe.Count == 0) throw new DataNotFoundException("Les données demandées n'existent pas");
			List<Visiteur> listeVisiteur = new List<Visiteur>();
			visiteurListe.ForEach((OP_VISITEUR) =>
			{
				listeVisiteur.Add(new Visiteur
				{
					nom = OP_VISITEUR.OPVS_NOM,
					prenom = OP_VISITEUR.OPVS_PRENOM,
					telephone = OP_VISITEUR.OPVS_TELEPHONE,
					email = OP_VISITEUR.OPVS_EMAIL,
					plaqueImmatriculation = OP_VISITEUR.OPVVS_PLAQUE_IMMATRICUL,
					id = OP_VISITEUR.OPVS_ID,
					parking = OP_VISITEUR.OPVVS_PARKING,
					donneeReponse = OP_VISITEUR.OPVVS_DONNEE_REPONSE,
					confirmer = OP_VISITEUR.OPVVS_CONFIRMEE,
					present = OP_VISITEUR.OPVVS_PRESENT,
					reponse = new VisiteReponse
					{
						raisonRefus = OP_VISITEUR.OPVVS_RAISON_REFUS,
						refus = OP_VISITEUR.OPVVS_REFUS,
						plaqueImmat = OP_VISITEUR.OPVVS_PLAQUE_IMMATRICUL
					}
				});
			});


			return listeVisiteur;
		}
		

		/// <summary>
		/// Créer une date horaire
		/// </summary>
		/// <param name="valeur"></param>
		/// <returns></returns>
		public DateHoraire CreeHoraire(DateHoraire valeur)
		{
			return new DateHoraire() { };
		}

		/// <summary>
		/// Création d'un visiteur
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public Visiteur CreerVisiteur(Visiteur value)
		{
			return new Visiteur { };
		}
		
		public Visite ArchiveVisite(int id)
		{
			var visite = ent.OP_VISITE.SingleOrDefault(v => v.OPV_ID == id);
			if (visite == null)
			{
				return null;
			}
			visite.OPV_ARCHIVE = true;
			ent.SaveChanges();
			return new Visite { id = id };
		}

		
	}
}
Modification des visiteurs:
- ajouter une fonction qui boucle des visiteurs en paramètre
et qui les crée et les ajoute à la visite dépendant si il existe ou non.
and adapt AddVisitortovisit method