ShoppingListController.java
package stud.ntnu.idatt1005.pantrypal.controllers;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import stud.ntnu.idatt1005.pantrypal.PantryPal;
import stud.ntnu.idatt1005.pantrypal.enums.ButtonEnum;
import stud.ntnu.idatt1005.pantrypal.enums.Route;
import stud.ntnu.idatt1005.pantrypal.models.Grocery;
import stud.ntnu.idatt1005.pantrypal.registers.GroceryRegister;
import stud.ntnu.idatt1005.pantrypal.utils.SQL;
import stud.ntnu.idatt1005.pantrypal.utils.ViewManager;
import stud.ntnu.idatt1005.pantrypal.views.ShoppingListView;
/**
* Controller class for the ShoppingListView.
* Handles the logic for the ShoppingListView,
* including managing the grocery register and updating the view.
* Implements the Observer interface to listen for changes in the view.
*/
public class ShoppingListController extends Controller implements Observer {
/**
* The view associated with this controller.
*/
private final ShoppingListView view;
/**
* The register holding the groceries.
*/
private final GroceryRegister register;
/**
* The controller related to the pantry.
* Used to update the pantry view when groceries are added to the shopping list.
*/
private final PantryController pantryController;
/**
* Constructs a new ShoppingListController with a given view manager
* and pantry controller. Initializes the grocery register and the shopping list view.
*
* @param viewManager The view manager for the application.
* @param pantryController The controller for the pantry.
*/
public ShoppingListController(ViewManager viewManager, PantryController pantryController) {
super(viewManager);
this.register = new GroceryRegister();
this.pantryController = pantryController;
this.view = new ShoppingListView(this);
this.view.addObserver(this);
rerender();
this.viewManager.addView(Route.SHOPPING_LIST, view);
if (this.isLoggedIn()) {
this.load();
}
rerender();
}
/**
* Retrieve the user's shopping list from the database and adds it to the register.
* If the user is not logged in, the shopping list is not loaded.
*/
private void load() {
String query = "SELECT * FROM shopping_list_grocery WHERE user_name = ?";
List<Map<String, Object>> groceries = SQL.executeQuery(query, PantryPal.userName);
for (Map<String, Object> grocery : groceries) {
String name = grocery.get("grocery_name") != null
? grocery.get("grocery_name").toString() : null;
int quantity = grocery.get("quantity") != null
? (int) grocery.get("quantity") : 0;
String unit = grocery.get("unit") != null
? grocery.get("unit").toString() : "g";
String shelf = grocery.get("shelf_name") != null
? grocery.get("shelf_name").toString() : null;
boolean isBought = grocery.get("is_bought") != null && ((int) grocery.get("is_bought")) != 0;
if (name != null && unit != null && shelf != null) {
this.register.addGrocery(new Grocery(name, quantity, unit, shelf, isBought));
}
}
}
/**
* Returns the grocery register.
*
* @return the grocery register
*/
public GroceryRegister getRegister() {
return this.register;
}
/**
* Updates the observer based on the button pressed and the grocery item
* associated with the action.
* If the button pressed is ADD, the grocery item is added to the register.
* If the button pressed is REMOVE, the grocery item is removed from the register.
* The view is re-rendered after the grocery item is added or removed.
*
* @param buttonEnum the button that was pressed
* @param object the grocery item associated with the action
* @throws IllegalArgumentException if the object is not of type Grocery
*/
@Override
public void update(ButtonEnum buttonEnum, Object object) {
if (!(object instanceof Grocery grocery)) {
throw new IllegalArgumentException("Object is not of type Grocery");
}
switch (buttonEnum) {
case ADD:
try {
this.addGrocery(grocery);
rerender();
break;
} catch (IllegalArgumentException e) {
break;
}
case REMOVE:
try {
this.removeGrocery(grocery);
rerender();
break;
} catch (IllegalArgumentException e) {
break;
}
default:
throw new IllegalArgumentException("Button not supported by class");
}
}
/**
* Updates the observer based on the button pressed.
* If the button pressed is ADD_TO_PANTRY, the groceries that are checked
* are added to the pantry and removed from the shopping list.
* The view is re-rendered after the groceries are added to the pantry.
*
* @param buttonEnum the button that was pressed
*/
@Override
public void update(ButtonEnum buttonEnum) {
if (Objects.requireNonNull(buttonEnum) == ButtonEnum.ADD_TO_PANTRY) {
addGroceriesToPantry();
rerender();
} else {
throw new IllegalArgumentException("Button not supported by class");
}
}
/**
* Adds groceries to the pantry.
* The groceries in the grocery register that are checked
* are added to the pantry and removed from the shopping list.
*/
public void addGroceriesToPantry() {
List<Grocery> groceriesToRemove = new ArrayList<>();
for (Grocery grocery : register.getRegister().values()) {
if (grocery.getChecked()) {
pantryController.addGrocery(grocery.getShelf(), grocery.getName(), grocery.getQuantity());
groceriesToRemove.add(grocery);
}
}
for (Grocery grocery : groceriesToRemove) {
this.removeGrocery(grocery);
}
}
/**
* Adds a grocery to the register.
* If the user is logged in, the grocery is also added to the database.
*
* @param grocery the grocery to be added to the register
*/
public void addGrocery(Grocery grocery) {
if (grocery == null) {
throw new IllegalArgumentException("Grocery cannot be null");
}
if (register.containsGrocery(grocery.getName())) {
Grocery oldGrocery = register.getGrocery(grocery.getName());
int oldAmount = oldGrocery.getQuantity();
int newAmount = grocery.getQuantity();
if (this.isLoggedIn()) {
String query = "UPDATE shopping_list_grocery SET quantity = ? "
+ "WHERE user_name = ? AND grocery_name = ?";
SQL.executeUpdate(query, oldGrocery.getQuantity() + grocery.getQuantity(),
PantryPal.userName, grocery.getName());
}
oldGrocery.setQuantity(oldAmount + newAmount);
} else {
if (this.isLoggedIn()) {
//Check if grocery exists in grocery table
String checkGroceryQuery = "SELECT * FROM grocery WHERE name = ?";
List<Map<String, Object>> groceries =
SQL.executeQuery(checkGroceryQuery, grocery.getName());
if (groceries.isEmpty()) {
String groceryQuery = "INSERT INTO grocery (name, unit) VALUES (?, ?)";
SQL.executeUpdate(groceryQuery, grocery.getName(), "g");
}
//Add grocery to shopping list
String checkQuery = "SELECT * FROM shopping_list_grocery"
+ " WHERE grocery_name = ? AND user_name = ?";
List<Map<String, Object>> result =
SQL.executeQuery(checkQuery, grocery.getName(), PantryPal.userName);
if (result.isEmpty()) {
String insertQuery = "INSERT INTO shopping_list_grocery "
+ "(grocery_name, user_name, quantity, is_bought, shelf_name) VALUES (?, ?, ?, ?, ?)";
SQL.executeUpdate(insertQuery, grocery.getName(), PantryPal.userName,
grocery.getQuantity(), grocery.getChecked(), grocery.getShelf());
} else {
String updateQuery = "UPDATE shopping_list_grocery SET quantity = quantity + ? "
+ "WHERE grocery_name = ? AND user_name = ?";
SQL.executeUpdate(
updateQuery, grocery.getQuantity(), grocery.getName(), PantryPal.userName);
}
}
register.addGrocery(grocery);
}
}
/**
* Removes a grocery from the register.
* If the user is logged in, the grocery is also removed from the database.
*
* @param grocery the grocery to be removed from the register
*/
private void removeGrocery(Grocery grocery) {
if (grocery == null) {
throw new IllegalArgumentException("Grocery cannot be null");
}
if (this.isLoggedIn()) {
String query = "DELETE FROM shopping_list_grocery WHERE user_name = ? AND grocery_name = ?";
SQL.executeUpdate(query, PantryPal.userName, grocery.getName());
}
register.removeGrocery(grocery);
}
/**
* Re-renders the view.
* Used to update the view with the current grocery register.
*/
public void rerender() {
view.render(this.register);
}
}