////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////

package pp.battleship.client.gui;

import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import pp.battleship.model.Item;
import pp.battleship.model.ShipMap;
import pp.battleship.model.Visitor;
import pp.battleship.notification.GameEventListener;
import pp.battleship.notification.ItemAddedEvent;
import pp.battleship.notification.ItemRemovedEvent;
import pp.view.ModelViewSynchronizer;

/**
 * Abstract base class for synchronizing the visual representation of a {@link ShipMap} with its model state.
 * This class handles the addition and removal of items from the ship map, ensuring that changes in the model
 * are accurately reflected in the view.
 * <p>
 * Subclasses are responsible for providing the specific implementation of how each item in the map
 * is represented visually by implementing the {@link Visitor} interface.
 * </p>
 */
abstract class ShipMapSynchronizer extends ModelViewSynchronizer<Item> implements Visitor<Spatial>, GameEventListener {
    // The ship map that this synchronizer is responsible for
    private final ShipMap shipMap;

    /**
     * Constructs a new ShipMapSynchronizer.
     * Initializes the synchronizer with the provided ship map and the root node for attaching view representations.
     *
     * @param map  the ship map to be synchronized
     * @param root the root node to which the view representations of the ship map items are attached
     */
    protected ShipMapSynchronizer(ShipMap map, Node root) {
        super(root);
        this.shipMap = map;
    }

    /**
     * Translates a model item into its corresponding visual representation.
     * The specific visual representation is determined by the concrete implementation of the {@link Visitor} interface.
     *
     * @param item the item from the model to be translated
     * @return the visual representation of the item as a {@link Spatial}
     */
    @Override
    protected Spatial translate(Item item) {
        return item.accept(this);
    }

    /**
     * Adds the existing items from the ship map to the view.
     * This method should be called during initialization to ensure that all current items in the ship map
     * are visually represented.
     */
    protected void addExisting() {
        shipMap.getItems().forEach(this::add);
    }

    /**
     * Handles the event when an item is removed from the ship map.
     * Removes the visual representation of the item from the view if it belongs to the synchronized ship map.
     *
     * @param event the event indicating that an item has been removed from the ship map
     */
    @Override
    public void receivedEvent(ItemRemovedEvent event) {
        if (shipMap == event.map())
            delete(event.item());
    }

    /**
     * Handles the event when an item is added to the ship map.
     * Adds the visual representation of the new item to the view if it belongs to the synchronized ship map.
     *
     * @param event the event indicating that an item has been added to the ship map
     */
    @Override
    public void receivedEvent(ItemAddedEvent event) {
        if (shipMap == event.map())
            add(event.item());
    }
}
