/**
   * permet de poser un nouvelle absence
   *
   * @throws AbsenceException
   */
  @Transactional
  public void poserAbsence(DemandeAbsence absence) throws Exception {

    absence.setStatut(StatutAbsence.POSE);

    // recuperation de l'objet utilisateur
    Utilisateur utilisateur = utilisateurRepository.findOne(absence.getUtilisateur().getId());
    absence.setUtilisateur(utilisateur);

    // verification des dates pour traiter le chevauchement de périodes pour les RTT
    if (absence.getType().equals(TypeAbsence.RTT)
        && isPeriodeCouranteRTT(absence.getDateDebut())
        && !isPeriodeCouranteRTT(absence.getDateFin())) {

      // division en 2 absences (1 par période)
      DemandeAbsence absencePeriodeCourante = absence.cloneAbsence();
      DemandeAbsence absencePeriodeSuivante = absence.cloneAbsence();
      absencePeriodeCourante.setDateFin(getDateFinPeriodeRTT(absence.getDateDebut()));
      absencePeriodeSuivante.setDateDebut(getDateDebutPeriodeRTT(absence.getDateFin()));

      poserAbsence(absencePeriodeSuivante);
      // return poserAbsence(absencePeriodeCourante);
    }

    // verification des dates pour traiter le chevauchement de périodes pour les Congés
    if ((absence.getType().equals(TypeAbsence.CONGE) || absence.getType().equals(TypeAbsence.AUTRE))
        && isPeriodeCouranteConges(absence.getDateDebut())
        && !isPeriodeCouranteConges(absence.getDateFin())) {

      // division en 2 absences (1 par période)
      DemandeAbsence absencePeriodeCourante = absence.cloneAbsence();
      DemandeAbsence absencePeriodeSuivante = absence.cloneAbsence();
      absencePeriodeCourante.setDateFin(getDateFinPeriodeConges(absence.getDateDebut()));
      absencePeriodeSuivante.setDateDebut(getDateDebutPeriodeConges(absence.getDateFin()));

      poserAbsence(absencePeriodeSuivante);
      // return poserAbsence(absencePeriodeCourante);
    }

    // date du jour
    Date now = new Date();
    now = DateUtils.truncate(now, Calendar.DATE);

    // recupération des infos utilisateur
    SessionUtilisateur session =
        loadSessionUtilisateur(absence.getUtilisateur().getId(), absence.getDateDebut());
    CompteurConges compteurs = session.getCompteurs();

    // verification des chevauchements de conges / rtt

    long valDebutTime = absence.getDateDebut().getTime();
    // on ajoute 12H si départ dans l'après midi (12 * 3600 * 1000)
    valDebutTime += (absence.getDebutPM()) ? 43200000 : 0;
    // permet de simplifier les comparaisons
    valDebutTime += 1;

    long valFinTime = DateUtils.addDays(absence.getDateFin(), 1).getTime();
    // on retire 12H si départ dans l'après midi (12 * 3600 * 1000)
    valFinTime -= (absence.getFinAM()) ? 43200000 : 0;
    valFinTime -= 1;

    List<DemandeAbsence> absencesPeriode =
        absenceRepository.findByUtilisateur(
            utilisateur.getId(), absence.getDateDebut(), absence.getDateFin());

    for (DemandeAbsence absencePeriode : absencesPeriode) {

      long tmpValDebutTime = absencePeriode.getDateDebut().getTime();
      tmpValDebutTime += (absencePeriode.getDebutPM()) ? 43200000 : 0;

      long tmpValFinTime = DateUtils.addDays(absencePeriode.getDateFin(), 1).getTime();
      tmpValFinTime -= (absencePeriode.getFinAM()) ? 43200000 : 0;

      if ((valDebutTime >= tmpValDebutTime && valDebutTime <= tmpValFinTime)
          || (valFinTime >= tmpValDebutTime && valFinTime <= tmpValFinTime)
          || (valDebutTime <= tmpValDebutTime && valFinTime >= tmpValFinTime)) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        throw new AbsenceException(
            "L'absence ne peut etre posee car elle se chevauche avec l'absence suivante "
                + "[ "
                + absencePeriode.getType()
                + " du "
                + sdf.format(absencePeriode.getDateDebut())
                + " au "
                + sdf.format(absencePeriode.getDateFin())
                + "]");
      }
    }

    // nombre de jours d'écart entre datedeb et dateFin
    float nbJours = getNbJoursForAbsence(absence);

    // cas des RTT
    if (absence.getType().equals(TypeAbsence.RTT)) {
      if (compteurs.getRttAposer() < nbJours) {
        throw new AbsenceException("Le nombre de RTT restants est insuffisant");
      }
    }

    // cas des Congés
    if (absence.getType().equals(TypeAbsence.CONGE)) {
      if (compteurs.getCongesAposer() < nbJours) {
        throw new AbsenceException("Le nombre de conges restants est insuffisant");
      }
    }

    // si date debut absence < date du jour
    if (absence.getDateDebut().before(now)
        || absence.getUtilisateur().getRole().equals(UserRole.responsable)) {
      // validation automatique
      absence.setStatut(StatutAbsence.VALIDE);
    }

    // sauvegarde de l'absence
    absenceRepository.saveAndFlush(absence);

    // envoi du mail au responsable
    if (!absence.getStatut().equals(StatutAbsence.VALIDE)) {
      mailService.notifierCreationAbsence(absence);
    }

    // création de l'événement dans la calendrier google
    sendToGoogleCalendar(utilisateur, absence, false);
  }
  /**
   * permet de recupérer les dernières infos d'absences lié à un utilisateur et de calculer les nb
   * de jours de congés/rtt restant
   *
   * @param utilisateur
   * @return
   * @throws AbsenceException
   */
  public SessionUtilisateur loadSessionUtilisateur(Long utilisateurId, Date dateAbsence)
      throws Exception {

    // date du jour
    Date now = new Date();
    now = DateUtils.truncate(now, Calendar.DATE);

    Utilisateur utilisateur = utilisateurRepository.findOne(utilisateurId);

    SessionUtilisateur session = new SessionUtilisateur();
    session.setUtilisateur(utilisateur);

    // recuperation des rtt de l'utilisateur sur la période liée à la date d'absence souhaitée
    List<DemandeAbsence> rtts =
        absenceRepository.findByUtilisateur(
            utilisateur.getId(),
            getDateDebutPeriodeRTT(dateAbsence),
            getDateFinPeriodeRTT(dateAbsence),
            TypeAbsence.RTT);

    // recuperation des conges de l'utilisateur sur la période liée à la date d'absence souhaitée
    List<DemandeAbsence> conges =
        absenceRepository.findByUtilisateur(
            utilisateur.getId(),
            getDateDebutPeriodeConges(dateAbsence),
            getDateFinPeriodeConges(dateAbsence),
            TypeAbsence.CONGE);

    // recuperation des conges de l'utilisateur sur la période liée à la date d'absence souhaitée
    List<DemandeAbsence> autresConges =
        absenceRepository.findByUtilisateur(
            utilisateur.getId(), now, DateUtils.addYears(now, 1), TypeAbsence.AUTRE);

    // init des compteurs par rapport aux infos utilisateurs (congés/RTT de l'année + deltas
    // éventuels)
    CompteurConges compteurs = new CompteurConges();
    session.setCompteurs(compteurs);
    compteurs.setCongesAposer(utilisateur.getNbConges());
    compteurs.setRttAposer(utilisateur.getNbRTT());

    // prise en compte des deltas si la date de l'absence se trouve dans la période courante
    if (isPeriodeCouranteConges(dateAbsence)) {
      compteurs.setCongesAposer(compteurs.getCongesAposer() + utilisateur.getDeltaJoursConges());
    }
    if (isPeriodeCouranteRTT(dateAbsence)) {
      compteurs.setRttAposer(compteurs.getRttAposer() + utilisateur.getDeltaJoursRTT());
    }

    // maj des compteurs par rapport à la liste des absences
    // TODO gérer les cas de 80%
    for (DemandeAbsence rtt : rtts) {
      if (!rtt.getStatut().equals(StatutAbsence.REFUSE)) {
        float nbJours = getNbJoursForAbsence(rtt);
        compteurs.setRttAposer(compteurs.getRttAposer() - nbJours);
        if (rtt.getStatut().equals(StatutAbsence.POSE)) {
          compteurs.setRttEnAttente(compteurs.getRttEnAttente() + nbJours);
        }
      }
      if (rtt.getDateDebut().after(now)) {
        session.getAbsences().add(rtt);
      }
    }

    for (DemandeAbsence conge : conges) {
      if (!conge.getStatut().equals(StatutAbsence.REFUSE)) {
        float nbJours = getNbJoursForAbsence(conge);
        compteurs.setCongesAposer(compteurs.getCongesAposer() - nbJours);
        if (conge.getStatut().equals(StatutAbsence.POSE)) {
          compteurs.setCongesEnAttente(compteurs.getCongesEnAttente() + nbJours);
        }
      }
      if (conge.getDateDebut().after(now)) {
        session.getAbsences().add(conge);
      }
    }

    for (DemandeAbsence conge : autresConges) {
      if (conge.getDateDebut().after(now)) {
        session.getAbsences().add(conge);
      }
    }

    Collections.sort(session.getAbsences());

    // ajout des absences sur la période suivante
    List<DemandeAbsence> rttFuturs =
        absenceRepository.findByUtilisateur(
            utilisateur.getId(),
            DateUtils.addDays(getDateFinPeriodeRTT(dateAbsence), 1),
            TypeAbsence.RTT);
    List<DemandeAbsence> congesFuturs =
        absenceRepository.findByUtilisateur(
            utilisateur.getId(),
            DateUtils.addDays(getDateFinPeriodeConges(dateAbsence), 1),
            TypeAbsence.CONGE);
    List<DemandeAbsence> autresCongesFuturs =
        absenceRepository.findByUtilisateur(
            utilisateur.getId(),
            DateUtils.addDays(getDateFinPeriodeConges(dateAbsence), 1),
            TypeAbsence.AUTRE);
    session.getAbsencesFutures().addAll(rttFuturs);
    session.getAbsencesFutures().addAll(congesFuturs);
    session.getAbsencesFutures().addAll(autresCongesFuturs);
    Collections.sort(session.getAbsencesFutures());

    return session;
  }