/*
 * Copyright © 2017 spypunk <[email protected]>
 *
 * This work is free. You can redistribute it and/or modify it under the
 * terms of the Do What The Fuck You Want To Public License, Version 2,
 * as published by Sam Hocevar. See the COPYING file for more details.
 */

package spypunk.ephealth.dao;

import java.util.Arrays;
import java.util.Collection;
import java.util.Date;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.TemporalType;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import com.google.inject.Provider;

import spypunk.ephealth.entity.EndPoint;
import spypunk.ephealth.entity.EndPointCheck;

@Singleton
public class EndPointCheckDao extends AbstractDao<EndPointCheck, Long> {

    @Inject
    public EndPointCheckDao(final Provider<EntityManager> entityManager) {
        super(entityManager);
    }

    @Override
    protected Class<EndPointCheck> getEntityClass() {
        return EndPointCheck.class;
    }

    public Collection<EndPointCheck> findByDateRange(final EndPoint endPoint, final Date startDate,
            final Date endDate) {
        final CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
        final CriteriaQuery<EndPointCheck> criteriaQuery = criteriaBuilder.createQuery(getEntityClass());
        final Root<EndPointCheck> root = criteriaQuery
                .from(getEntityManager().getMetamodel().entity(getEntityClass()));

        final ParameterExpression<EndPoint> endPointParameter = criteriaBuilder.parameter(EndPoint.class);
        final ParameterExpression<Date> startDateParameter = criteriaBuilder.parameter(Date.class);
        final ParameterExpression<Date> endDateParameter = criteriaBuilder.parameter(Date.class);

        final Predicate endPointIdPredicate = criteriaBuilder
                .equal(root.get("endPoint"), endPointParameter);

        final Path<Date> checkDatePath = root.<Date> get("checkDate");

        final Predicate startDatePredicate = criteriaBuilder
                .greaterThanOrEqualTo(checkDatePath, startDateParameter);

        final Predicate endDatePredicate = criteriaBuilder.lessThanOrEqualTo(
            checkDatePath,
            endDateParameter);

        criteriaQuery.where(criteriaBuilder.and(endPointIdPredicate, startDatePredicate, endDatePredicate));

        criteriaQuery.orderBy(Arrays.asList(criteriaBuilder.asc(checkDatePath)));

        return getEntityManager().createQuery(criteriaQuery)
                .setParameter(endPointParameter, endPoint)
                .setParameter(startDateParameter, startDate, TemporalType.DATE)
                .setParameter(endDateParameter, endDate, TemporalType.DATE)
                .getResultList();
    }
}