/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.cr.services.infrastructure.persistence.certificate;

import javax.ejb.Stateless;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;

import com.scytl.products.ov.commons.beans.exceptions.DuplicateEntryException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.infrastructure.persistence.BaseRepositoryImpl;
import com.scytl.products.ov.cr.services.domain.model.certificate.CertificateEntity;
import com.scytl.products.ov.cr.services.domain.model.certificate.CertificateRepository;
import org.hibernate.NonUniqueResultException;

/**
 * Implementetation of the Repository with jpa.
 */
@Stateless
public class CertificateRepositoryImpl extends BaseRepositoryImpl<CertificateEntity, Long> implements
        CertificateRepository {

    // The name of the certificate
    private static final String PARAMETER_CERTIFICATE_NAME = "certificateName";

    // The name of the parameter which identifies the tenantId
    private static final String PARAMETER_TENANT_ID = "tenantId";

    // The name of the parameter which identifies the electionEventId
    private static final String PARAMETER_ELECTION_EVENT_ID = "electionEventId";

    // The constant Tenant
    private static final String CONSTANT_TENANT = "Tenant";

    // The constant CA
    private static final String CONSTANT_CA = "CA";
    public static final String WHITE_SPACE = " ";

    /**
     * @see com.scytl.products.ov.cr.services.domain.model.certificate.CertificateRepository#findByName(java.lang.String)
     */
    @Override
    public CertificateEntity findByName(final String certificateName)
            throws ResourceNotFoundException, DuplicateEntryException {

        TypedQuery<CertificateEntity> query =
            entityManager.createQuery("SELECT c FROM CertificateEntity c WHERE c.certificateName = :certificateName",
                CertificateEntity.class);

        query.setParameter(PARAMETER_CERTIFICATE_NAME, certificateName);

        try {
            return query.getSingleResult();
        } catch (NoResultException e) {
            throw new ResourceNotFoundException("", e);
        } catch (NonUniqueResultException e) {
            throw new DuplicateEntryException("", e);
        }
    }

    /**
     * @see com.scytl.products.ov.cr.services.domain.model.certificate.CertificateRepository#findByTenanElectionEventAndCertificateName(java.lang.String,
     *      java.lang.String, java.lang.String)
     */
    @Override
    public CertificateEntity findByTenanElectionEventAndCertificateName(final String tenantId,
            final String electionEventId, final String certificateName)
            throws ResourceNotFoundException, DuplicateEntryException {

        TypedQuery<CertificateEntity> query =
            entityManager
                .createQuery(
                    "SELECT c FROM CertificateEntity c WHERE c.certificateName = :certificateName AND c.tenantId = :tenantId AND c.electionEventId = :electionEventId",
                    CertificateEntity.class);
        query.setParameter(PARAMETER_TENANT_ID, tenantId);
        query.setParameter(PARAMETER_ELECTION_EVENT_ID, electionEventId);
        query.setParameter(PARAMETER_CERTIFICATE_NAME, certificateName);

        try {
            return query.getSingleResult();
        } catch (NoResultException e) {
            throw new ResourceNotFoundException("", e);
        } catch (NonUniqueResultException e) {
            throw new DuplicateEntryException("", e);
        }

    }

    /**
     * @see com.scytl.products.ov.cr.services.domain.model.certificate.CertificateRepository#saveCertificate(com.scytl.products.ov.cr.services.domain.model.certificate.CertificateEntity)
     */
    @Override
    public void saveCertificate(final CertificateEntity certificateEntity) throws DuplicateEntryException {
        save(certificateEntity);
    }

    /**
     * @see CertificateRepository#findByTenantAndCertificateName(String, String)
     */
    @Override
    public CertificateEntity findByTenantAndCertificateName(String tenantId, String certificateName)
            throws ResourceNotFoundException, DuplicateEntryException {
        TypedQuery<CertificateEntity> query =
            entityManager
                .createQuery(
                    "SELECT c FROM CertificateEntity c WHERE c.certificateName = :certificateName AND c.tenantId = :tenantId",
                    CertificateEntity.class);
        query.setParameter(PARAMETER_TENANT_ID, tenantId);
        query.setParameter(PARAMETER_CERTIFICATE_NAME, certificateName);

        try {
            return query.getSingleResult();
        } catch (NoResultException e) {
            throw new ResourceNotFoundException("", e);
        } catch (NonUniqueResultException e) {
            throw new DuplicateEntryException("", e);
        }
    }

    /**
     * @see CertificateRepository#checkIfCertificateExist(String, String)
     */
    @Override
    public Long checkIfCertificateExist(String tenantId, String name) {
        TypedQuery<Long> query =
            entityManager
                .createQuery(
                    "SELECT COUNT(*) FROM CertificateEntity c WHERE c.certificateName = :certificateName AND c.tenantId = :tenantId",
                    Long.class);
        query.setParameter(PARAMETER_TENANT_ID, tenantId);
        query.setParameter(PARAMETER_CERTIFICATE_NAME, name);

        return query.getResultList().get(0);

    }

    /**
     * @see CertificateRepository#getTenantCertificate(String)
     */
    @Override
    public CertificateEntity getTenantCertificate(String tenantId) throws ResourceNotFoundException,DuplicateEntryException {

        String certificateName = CONSTANT_TENANT.concat(WHITE_SPACE).concat(tenantId)
                .concat(WHITE_SPACE).concat(CONSTANT_CA);
        TypedQuery<CertificateEntity> query =
                entityManager
                        .createQuery(
                                "SELECT c FROM CertificateEntity c WHERE c.certificateName = :certificateName AND c.tenantId = :tenantId",
                                CertificateEntity.class);
        query.setParameter(PARAMETER_TENANT_ID, tenantId);
        query.setParameter(PARAMETER_CERTIFICATE_NAME, certificateName);

        try {
            return query.getSingleResult();
        } catch (NoResultException e) {
            throw new ResourceNotFoundException("", e);
        } catch (NonUniqueResultException e) {
            throw new DuplicateEntryException("", e);
        }
    }
}
