/*
 * Queue - A Queueing system that can be used to handle labs in higher education
 * Copyright (C) 2016-2021  Delft University of Technology
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
package nl.tudelft.queue.model.embeddables;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.OneToOne;

import lombok.*;
import nl.tudelft.queue.model.LabRequestConstraint;
import nl.tudelft.queue.model.QueueSession;
import nl.tudelft.queue.model.Request;
import nl.tudelft.queue.model.constraints.ClusterConstraint;
import nl.tudelft.queue.model.constraints.ModuleDivisionConstraint;

@Data
@Builder
@Embeddable
@NoArgsConstructor
@AllArgsConstructor
public class LabRequestConstraints {
	/**
	 * An optional {@link ClusterConstraint} that can be added to the lab.
	 */
	@ToString.Exclude
	@EqualsAndHashCode.Exclude
	@OneToOne(mappedBy = "session", cascade = CascadeType.ALL, orphanRemoval = true)
	private ClusterConstraint clusterConstraint;

	/**
	 * An optional {@link ModuleDivisionConstraint} that can be added to the lab.
	 */
	@ToString.Exclude
	@EqualsAndHashCode.Exclude
	@OneToOne(mappedBy = "session", cascade = CascadeType.ALL, orphanRemoval = true)
	private ModuleDivisionConstraint moduleDivisionConstraint;

	/**
	 * @return A list of all the (individual) constraints held by this embeddable.
	 */
	public List<LabRequestConstraint> toList() {
		return Stream.concat(
				Stream.ofNullable(clusterConstraint),
				Stream.ofNullable(moduleDivisionConstraint)).collect(Collectors.toList());
	}

	/**
	 * Checks whether the constraints allow the person with the given id to create a new request.
	 *
	 * @param  personId The id of the person to check for.
	 * @return          Whether the person with the given id may create a request according to this
	 *                  constraint.
	 */
	public boolean canCreateRequest(Long personId) {
		return toList().stream().allMatch(c -> c.canCreateRequest(personId));
	}

	/**
	 * Checks whether the given request is allowed according to the constraints in this object.
	 *
	 * @param  request The request to check for whether it is allowed to be posted.
	 * @return         Whether the given request should be allowed.
	 */
	public boolean allowsRequest(Request<?> request) {
		return toList().stream().allMatch(c -> c.allowsRequest(request));
	}

	/**
	 * Sets the lab to link the constraint to.
	 *
	 * @param session The lab to set.
	 */
	public void setLab(QueueSession<?> session) {
		for (LabRequestConstraint constraint : toList()) {
			constraint.setSession(session);
		}
	}
}
