WasteService.java

package ntnu.idatt2016.v233.SmartMat.service.group;

import java.sql.Timestamp;
import java.util.List;
import lombok.AllArgsConstructor;
import ntnu.idatt2016.v233.SmartMat.dto.request.group.WasteRequest;
import ntnu.idatt2016.v233.SmartMat.entity.group.Waste;
import ntnu.idatt2016.v233.SmartMat.entity.group.Group;
import ntnu.idatt2016.v233.SmartMat.entity.product.Product;
import ntnu.idatt2016.v233.SmartMat.repository.group.GroupRepository;
import ntnu.idatt2016.v233.SmartMat.repository.group.WasteRepository;
import ntnu.idatt2016.v233.SmartMat.repository.product.ProductRepository;
import ntnu.idatt2016.v233.SmartMat.util.StatisticUtil;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * Service for waste
 * @author Anders, Pedro, Birk
 * @version 1.1
 */
@Service
@AllArgsConstructor
public class WasteService {
    private final WasteRepository wasteRepository;
    private final GroupRepository groupRepository;
    private final ProductRepository productRepository;


    /**
     * Creates a new waste
     * @param wasteRequest the waste to create
     * @return an optional containing the waste if it was created
     */
    public Optional<Waste> createWaste(WasteRequest wasteRequest) {
        Optional<Group> group = groupRepository.findByGroupId(wasteRequest.groupId());
        Optional<Product> product = productRepository.findById(wasteRequest.ean());
        if(group.isPresent() && product.isPresent()){
            return Optional.of(wasteRepository.save(Waste.builder().unit(wasteRequest.unit()).timestamp(new Timestamp(System.currentTimeMillis())).amount(wasteRequest.amount()).ean(product.get()).groupId(group.get()).build()));
        }
        return Optional.empty();
    }

    /**
     * Gets a waste by its id
     * @param id the id of the waste
     * @return an optional containing the waste if it exists
     */
    public Optional<Waste> getWasteById(long id) {
        return wasteRepository.findById(id);
    }

    /**
     * Gets a waste by its group id
     *
     * @param groupId the id of the group
     * @return an optional containing the waste if it exists
     */
    public Optional<List<Waste>> getWasteByGroupId(long groupId) {
        Optional<Group> group = groupRepository.findByGroupId(groupId);
        if(group.isPresent()) return wasteRepository.findByGroupId(group.get());
        return Optional.empty();
    }

    /**
     * Returns an Optional containing a List of Waste objects for a specific category and group id,
     * or an empty Optional if there are no wastes for that category and group id.
     *
     * @param groupId         the ID of the group to search in
     * @param categoryName    the name of the category to search for
     * @return an Optional containing a List of Waste objects, or an empty Optional if there are no wastes for that category and group id
     */
    public Optional<List<Waste>> getWasteOfCategoryByGroupId(long groupId, String categoryName){
        return wasteRepository.findAllWasteOfOneCategoryFromGroup(groupId,categoryName);
    }

    /**
     * Get the cake diagram for a group of waste.
     *
     * @param groupId The ID of the group for which to retrieve the cake diagram.
     * @return An Optional containing an array of doubles representing the cake diagram for the group,
     *         or an empty Optional if the group is not found.
     */
    public Optional<double[]> getCakeDiagram(long groupId){
        Optional<Group> group = groupRepository.findByGroupId(groupId);
        return group.map(value -> StatisticUtil.getNumberOfWasteByCategoryName(wasteRepository.findByGroupId(value).get()));
    }

    /**
     * Retrieve an optional array of doubles representing the amount of waste produced in each of the last 4 months for a given group.
     *
     * @param groupId a long representing the id of the group whose waste production statistics are to be retrieved
     * @return an optional array of doubles representing the amount of waste produced in each of the last 4 months for the given group,
     *         or an empty optional if the group could not be found or no waste was produced in the last 4 months
     */
    public Optional<double[]>  getLastMonth(long groupId) {
        Optional<Group> group = groupRepository.findByGroupId(groupId);
        return group.map(value -> StatisticUtil.getNumberOfWasteByLastMonth(wasteRepository.findByGroupId(value).get()));
    }

    /**
     * Retrieves the lost money in the last month for the group with the given ID.
     *
     * @param groupId the ID of the group to retrieve the lost money for
     * @return an {@code Optional} containing the lost money if the group exists, or empty if it doesn't exist or there are no wastes in the last month
     */
    public Optional<Double> getLostMoney(long groupId) {
        Optional<Group> group = groupRepository.findByGroupId(groupId);
        return group.map(value -> StatisticUtil.getLostMoneyInLastMonth(wasteRepository.findByGroupId(value).get()));
    }

    /**
     * Calculates the annual average CO2 emissions per person in the specified group.
     *
     * @param groupId the ID of the group for which to calculate CO2 emissions
     * @return an Optional containing the annual average CO2 emissions per person, or empty if the group has no users or does not exist
     */
    public Optional<Double> getCO2PerPerson(long groupId){
        Optional<Group> group = groupRepository.findByGroupId(groupId);
        int number = groupRepository.countAllUserInGroup(groupId);
        if(number == 0 || group.isEmpty()) return Optional.empty();
        List<Waste> wastes = wasteRepository.findByGroupId(group.get()).get();
        return Optional.of(StatisticUtil.getAnnualAverage(wastes,number));
    }


    /**
     * Checks if the user is assosiated with the waste their trying to retrive
     * @param username the username of the user
     * @param wasteId the id of the waste
     * @return true if the user is associated with the waste, false otherwise
     */
    public boolean isUserAssosiatedWithWaste(String username, long wasteId) {
        Optional<Waste> waste = wasteRepository.findById(wasteId);
        return waste.map(value -> value.getGroupId().getUser().stream()
                .anyMatch(user -> user.getUser().getUsername().equals(username))).orElse(false);
    }
}