AddGroceryListElement.java

package stud.ntnu.idatt1005.pantrypal.views.components;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javafx.geometry.Pos;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import stud.ntnu.idatt1005.pantrypal.controllers.Observer;
import stud.ntnu.idatt1005.pantrypal.enums.ButtonEnum;
import stud.ntnu.idatt1005.pantrypal.models.Grocery;
import stud.ntnu.idatt1005.pantrypal.utils.NodeUtils;
import stud.ntnu.idatt1005.pantrypal.views.Observable;


/**
 * A class for creating input fields and an add button.
 * These fields are used to create and add a grocery to a grocery list.
 * The class extends HBox and implements the Observable interface.
 */
public class AddGroceryListElement extends HBox implements Observable {
  private final List<Observer> observers = new ArrayList<>();
  private static final String OBSERVER_ERROR_MESSAGE = "Observer cannot be null";

  /**
   * Constructor for the AddGroceryListElement class.
   * Creates a text field for the name, shelf and quantity of the grocery.
   * Also creates an add button that adds the grocery to the list.
   *
   * @param shelfName the name of the shelf
   */
  public AddGroceryListElement(String shelfName) {
    StyledTextField name = new StyledTextField("Name");
    StyledTextField shelf = createShelfTextField(shelfName);
    StyledTextField quantity = new StyledTextField("Quantity");
    StyledButton addButton = getStyledButton(name, shelf, quantity);

    this.getStylesheets().add(Objects.requireNonNull(
        getClass().getResource("/styles/pantry.css")).toExternalForm());
    this.setAlignment(Pos.CENTER);
    NodeUtils.addClasses(this, "add-grocery-container");

    if (shelf.getText().isEmpty()) {
      this.getChildren().addAll(
          styleText(name, 200),
          styleText(shelf, 200),
          styleText(quantity, 100),
          addButton);
    } else {
      this.getChildren().addAll(
          styleText(name, 100),
          styleText(quantity, 100),
          addButton);
    }
  }

  /**
   * Creates a styled addButton with the given text fields and returns it.
   * The addButton is styled with the add-grocery-addButton class.
   *
   * @param name the name text field
   * @param shelf the shelf text field
   * @param quantity the quantity text field
   * @return a styled addButton
   */
  private StyledButton getStyledButton(StyledTextField name,
                                       StyledTextField shelf, StyledTextField quantity) {
    StyledButton addButton = new StyledButton(
        "Add", StyledButton.Variant.SOLID, StyledButton.Size.MEDIUM);

    // Set the action for the add addButton
    addButton.setOnAction(e -> {
      if (!name.getText().isEmpty()) {
        if (quantity.getText().isEmpty()) {
          quantity.setText("1");
        }
        if (shelf.getText().isEmpty()) {
          shelf.setText("Unassigned");
        } else {
          // Capitalize the first letter of the shelf
          String str = shelf.getText();
          shelf.setText(str.substring(0, 1).toUpperCase() + str.substring(1));
        }
        notifyObservers(ButtonEnum.ADD, name.getText(), Integer.parseInt(quantity.getText()),
            shelf.getText());
        name.clear();
        shelf.clear();
        quantity.clear();
      }
    });
    return addButton;
  }

  /**
   * Styles the text field given as parameter and returns
   * a StackPane with the text field.
   * The text field is styled with the add-grocery-textfield class
   * and has a max width of the given width.
   *
   * @param textField the text field to be styled
   * @param width the width of the text field
   * @return A Stack pane with the styled text field
   */
  private StackPane styleText(StyledTextField textField, int width) {
    NodeUtils.addClasses(textField, "add-grocery-textfield");
    textField.setMaxWidth(width);

    StackPane stackPane = new StackPane(textField);
    stackPane.setAlignment(Pos.CENTER);

    return stackPane;
  }

  /**
   * Creates a shelf text field with the given shelfName.
   * If the shelfName is empty, the text field will be empty.
   *
   * @param shelfName the name of the shelf
   * @return a styled text field
   */
  private StyledTextField createShelfTextField(String shelfName) {
    StyledTextField shelf = new StyledTextField("Shelf");
    if (!shelfName.isEmpty())  {
      shelf.setText(shelfName);
    }
    return shelf;
  }

  @Override
  public void addObserver(Observer observer) {
    if (observer != null) {
      observers.add(observer);
    } else {
      throw new IllegalArgumentException(OBSERVER_ERROR_MESSAGE);
    }
  }

  @Override
  public void removeObserver(Observer observer) {
    if (observer != null) {
      observers.remove(observer);
    } else {
      throw new IllegalArgumentException(OBSERVER_ERROR_MESSAGE);
    }
  }

  /**
   * Notifies the observers in the observer list with the given buttonEnum.
   *
   * @param buttonEnum the buttonEnum to be sent to the observers
   */
  private void notifyObservers(ButtonEnum buttonEnum, String name, int quantity, String shelf) {
    //TODO: Fix unit
    Grocery grocery = new Grocery(name, quantity, "g", shelf, false);
    List<Observer> observerList = new ArrayList<>(this.observers);
    for (Observer observer : observerList) {
      observer.update(buttonEnum, grocery);
    }
  }
}