package regexgolf2.controllers;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.Node;
import javax.swing.JOptionPane;
import regexgolf2.model.SolvableChallenge;
import regexgolf2.model.containers.ChallengePool;
import regexgolf2.model.containers.ContainerChangedEvent;
import regexgolf2.services.persistence.PersistenceException;
import regexgolf2.services.persistence.PersistenceService;
import regexgolf2.ui.challengerepositoryview.ChallengeRepositoryUI;
import regexgolf2.ui.subcomponents.challengelisting.challengecell.ChallengeItem;
import com.google.java.contract.Ensures;
import com.google.java.contract.Requires;
public class ChallengeRepositoryController implements ChallengeContainer
{
private final ChallengePool _challengePool;
private final PersistenceService _persistenceService;
private final ChallengeRepositoryUI _ui;
private final Map<ChallengeItem, ChallengeItemController> _itemControllers = new HashMap<>();
private final ObjectProperty<SolvableChallenge> _selectedChObjectProperty = new SimpleObjectProperty<>();
private final BooleanProperty _editmodeProperty = new SimpleBooleanProperty();
@Requires("persistenceService != null")
public ChallengeRepositoryController(PersistenceService persistenceService) throws IOException
{
_challengePool = persistenceService.getChallengePool();
_persistenceService = persistenceService;
_ui = new ChallengeRepositoryUI();
initButtonBindings();
initListeners();
initAddButtonHandler();
initRemoveButtonHandler();
initSaveButtonHandler();
_challengePool.forEach(challenge -> addItem(challenge));
}
private void initButtonBindings()
{
_ui.getRemoveButton().disableProperty().bind(_selectedChObjectProperty.isNull());
_ui.getEditButton().disableProperty().bind(_selectedChObjectProperty.isNull());
_ui.getEditButton().selectedProperty().bindBidirectional(_editmodeProperty);
}
private void initListeners()
{
_ui.selectedChallengeProperty().addListener(
(ChangeListener<ChallengeItem>) (observable, oldValue, newValue) ->
{
if (newValue != null)
// Get the Challenge that corresponds to the Item
_selectedChObjectProperty
.set(_itemControllers.get(newValue).getChallenge());
else
_selectedChObjectProperty.set(null);
// If the selected challenge changed, the edit mode is
// resetted
// to false
setEditmode(false);
});
_challengePool.addListener(event -> refreshListViewItemList(event));
}
private void initAddButtonHandler()
{
_ui.getAddButton().setOnAction(arg0 ->
{
SolvableChallenge newChallenge = _challengePool.createNew();
selectChallenge(newChallenge);
setEditmode(true);
});
}
private void initRemoveButtonHandler()
{
_ui.getRemoveButton()
.setOnAction(
evt ->
{
ChallengeItem item = _ui.getSelectedChallengeItem();
assert item != null : "Remove Button was clicked by no challenge was selected.";
SolvableChallenge challenge = _itemControllers.get(item).getChallenge();
assert _challengePool.contains(challenge) : "The challenge to remove is not contained in the ChallengeRepo.";
_challengePool.remove(challenge);
});
}
private void initSaveButtonHandler()
{
_ui.getSaveButton().setOnAction(arg0 ->
{
try
{
_persistenceService.save(_challengePool);
} catch (PersistenceException e)
{
JOptionPane.showMessageDialog(null, "Something fucked up");
}
});
}
/**
* Synchronizes the List of Challenges in the UI with the List of Challenges
* in the Repository. This method ensures, that for every Challenge in the
* Repository, there exists an item in the UI. This method is called from
* the ServiceChangedListener that listens to the Repository.
*/
private void refreshListViewItemList(ContainerChangedEvent<? extends SolvableChallenge> event)
{
if (event.getRemovedItem() != null)
removeItemFor(event.getRemovedItem());
if (event.getAddedItem() != null)
addItem(event.getAddedItem());
}
private void removeItemFor(SolvableChallenge challenge)
{
_ui.getChallengeItemList().stream()
.filter(item -> _itemControllers.get(item).getChallenge().equals(challenge))
.findFirst()
.ifPresent(item -> {
_ui.getChallengeItemList().remove(item);
_itemControllers.get(item).discard();
_itemControllers.remove(item);
});
}
/**
* Initializes a new Controller with the given Challenge and puts the
* Controller in the map. The Item controlled by the Controller is added to
* the UI list.
*
* @return The item that was added to the UI.
*/
private ChallengeItem addItem(SolvableChallenge challenge)
{
ChallengeItemController controller = new ChallengeItemController(challenge,
_persistenceService.getPersistenceInformation().getPersistenceState(challenge));
_ui.getChallengeItemList().add(controller.getItem());
_itemControllers.put(controller.getItem(), controller);
return controller.getItem();
}
/**
* Selects the ChallengeItem in the UI for a given SolvableChallenge. This
* is used to immediately select a newly created Challenge.
*
* @param challenge
* the
*/
private void selectChallenge(SolvableChallenge challenge)
{
for (ChallengeItem item : _ui.getChallengeItemList())
{
SolvableChallenge itemChallenge = getChallengeFor(item);
if (itemChallenge == challenge)
{
_ui.select(item);
return;
}
}
throw new IllegalArgumentException("Challenge " + challenge
+ " does not have an Item in the UI.");
}
/**
* Helper method to get the Challenge that corresponds to an Item. The
* ItemController holds the Challenge reference.
*
* @param item
* The item for which the challenge should be returned
* @return The SolvableChallenge, or null if none could be found
*/
private SolvableChallenge getChallengeFor(ChallengeItem item)
{
// XXX this could possibly refactored. maybe the SolvableChallenge
// belongs inside the Item?
if (item == null)
return null;
ChallengeItemController controller = _itemControllers.get(item);
if (controller != null)
return controller.getChallenge();
else
return null;
}
@Override
public ReadOnlyObjectProperty<SolvableChallenge> challengeProperty()
{
return _selectedChObjectProperty;
}
private void setEditmode(boolean edit)
{
_editmodeProperty.set(edit);
}
@Override
public ReadOnlyBooleanProperty editableProperty()
{
return _editmodeProperty;
}
@Ensures("result != null")
public Node getUINode()
{
return _ui.getUINode();
}
}