UpdateCowHealthJob.java

package edu.ucsb.cs156.happiercows.jobs;

import java.util.Optional;


import java.util.Iterator;
import edu.ucsb.cs156.happiercows.services.jobs.JobContext;
import edu.ucsb.cs156.happiercows.services.jobs.JobContextConsumer;
import edu.ucsb.cs156.happiercows.entities.Commons;
import edu.ucsb.cs156.happiercows.entities.UserCommons;
import edu.ucsb.cs156.happiercows.entities.CommonsPlus;
import edu.ucsb.cs156.happiercows.entities.CowLot;
import edu.ucsb.cs156.happiercows.entities.User;
import edu.ucsb.cs156.happiercows.repositories.CommonsRepository;
import edu.ucsb.cs156.happiercows.repositories.UserCommonsRepository;
import edu.ucsb.cs156.happiercows.repositories.UserRepository;
import edu.ucsb.cs156.happiercows.repositories.CowLotRepository;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class UpdateCowHealthJob implements JobContextConsumer {

    @Getter
    private CommonsRepository commonsRepository;
    @Getter
    private UserCommonsRepository userCommonsRepository;
    @Getter
    private CowLotRepository cowLotRepository;
    @Getter
    private UserRepository userRepository;

    @Override
    public void accept(JobContext ctx) throws Exception {
        ctx.log("Starting Update Cow Health job:");
        Iterable<Commons> allCommons = commonsRepository.findAll();
        
        for (Commons commons : allCommons) {
            String name = commons.getName();
            if(commons.gameInProgress()){
                ctx.log("Commons " + commons.getName() + ", degradationRate: " + commons.getDegradationRate() + ", carryingCapacity: " + commons.getCarryingCapacity());
                int carryingCapacity = commons.getCarryingCapacity();
                double degradationRate = commons.getDegradationRate();
                Iterable<UserCommons> allUserCommons = userCommonsRepository.findByCommonsId(commons.getId());

                Integer totalCows = commonsRepository.getNumCows(commons.getId()).orElseThrow(()->new RuntimeException("Error calling getNumCows(" + commons.getId() + ")"));

                for (UserCommons userCommons : allUserCommons) {
                    double totalHealths = 0d;
                    User user = userRepository.findById(userCommons.getUserId()).orElseThrow(()->new RuntimeException("Error calling userRepository.findById(" + userCommons.getUserId() + ")"));
                    ctx.log("User: " + user.getFullName() + ", numCows: " + userCommons.getNumOfCows() + ", cowHealth: " + userCommons.getCowHealth());
                    for(CowLot cowLot: cowLotRepository.findAllByUserCommonsId(userCommons.getId())){
                        double newCowHealth = calculateNewCowHealth(cowLot.getHealth(), userCommons.getNumOfCows(), totalCows, carryingCapacity, degradationRate);
                        ctx.log("old cow health: " + cowLot.getHealth() + ", new cow health: " + newCowHealth);
                        cowLot.setHealth(newCowHealth);
                        if(newCowHealth > 0){
                            cowLotRepository.save(cowLot);
                        } else {
                            cowLotRepository.delete(cowLot);
                            userCommons.setNumOfCows(userCommons.getNumOfCows()-cowLot.getNumCows());
                        }
                        totalHealths += newCowHealth * cowLot.getNumCows();
                    }
                    userCommons.setCowHealth(totalHealths / userCommons.getNumOfCows());
                    userCommonsRepository.save(userCommons);
                }
            } else{
                ctx.log("Game " + name + " is not currently in progress, cow health will not be updated for this commons.");
            }
        }
        ctx.log("Update Cow Health job complete!");
    }

    public static double calculateNewCowHealth(
        double oldCowHealth,
        int numCows,
        int totalCows,
        int carryingCapacity,
        double degradationRate) {
        if (totalCows <= carryingCapacity) {
            // increase cow health but do not exceed 100
            return Math.min(100, oldCowHealth + (degradationRate));
        } else {
            // decrease cow health, don't go lower than 0
            return Math.max(0, oldCowHealth - Math.min((totalCows - carryingCapacity) * degradationRate, 100));
        }
    }

}