package com.lateensoft.pathfinder.toolkit.views.encounter; import android.content.Context; import android.text.Editable; import android.util.Log; import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.lateensoft.pathfinder.toolkit.dao.DataAccessException; import com.lateensoft.pathfinder.toolkit.db.dao.table.*; import com.lateensoft.pathfinder.toolkit.model.IdNamePair; import com.lateensoft.pathfinder.toolkit.model.NamedList; import com.lateensoft.pathfinder.toolkit.model.character.PathfinderCharacter; import com.lateensoft.pathfinder.toolkit.model.party.Encounter; import com.lateensoft.pathfinder.toolkit.model.party.EncounterParticipant; import com.lateensoft.pathfinder.toolkit.pref.GlobalPrefs; import com.lateensoft.pathfinder.toolkit.pref.Preferences; import com.lateensoft.pathfinder.toolkit.views.character.CharacterCombatStatsFragment; import roboguice.RoboGuice; import java.util.*; public class EncounterPresenter { private static final String TAG = EncounterPresenter.class.getSimpleName(); private Context context; private Preferences preferences; private EncounterDAO<EncounterParticipant> encounterDao; private EncounterParticipantDAO participantDao; private EncounterFragment fragment; private EncounterViewModel encounter; private EncounterRoller roller; private EncounterRoller.SkillCheckType lastSkillCheck; public EncounterPresenter(Context context) { this.context = context; participantDao = new EncounterParticipantDAO(context); encounterDao = new EncounterDAO<EncounterParticipant>(context, participantDao); preferences = RoboGuice.getInjector(context).getInstance(Preferences.class); } public void bind(EncounterFragment encounterFragment) { fragment = encounterFragment; setEncounter(loadCurrentEncounterFromDatabase()); } private void setEncounter(EncounterViewModel encounter) { setCurrentlySelectedEncounter(encounter.getId()); roller = new EncounterRoller(encounter); this.encounter = encounter; notifyModelChanged(); } private void setCurrentlySelectedEncounter(long encounterId) { preferences.put(GlobalPrefs.SELECTED_ENCOUNTER_ID, encounterId); } private void notifyModelChanged() { getFragment().notifyModelChanged(); } private EncounterViewModel loadCurrentEncounterFromDatabase() { long selectedEncounterId = preferences.get(GlobalPrefs.SELECTED_ENCOUNTER_ID, -1L); try { return loadEncounterFromDatabase(selectedEncounterId); } catch (Exception e) { Log.w(TAG, e); return loadDefaultEncounter(); } } private EncounterViewModel loadEncounterFromDatabase(long id) throws IllegalArgumentException { Encounter<EncounterParticipant> encounter = encounterDao.findList(id); if (encounter != null) { return new EncounterViewModel(encounter); } else { throw new IllegalArgumentException("No encounter with id=" + id); } } private EncounterViewModel loadDefaultEncounter() { List<? extends IdNamePair> allParties = encounterDao.findAll(); if (allParties.isEmpty()) { return loadNewEncounter(); } else { long defaultEncounterId = allParties.get(0).getId(); return new EncounterViewModel(encounterDao.findList(defaultEncounterId)); } } private EncounterViewModel loadNewEncounter() { try { EncounterViewModel encounter = new EncounterViewModel(); long id = encounterDao.add(encounter.buildEncounterForModel()); encounter.setId(id); return encounter; } catch (DataAccessException e) { throw new IllegalStateException(e); } } public boolean isEncounterOngoing() { return encounter != null && encounter.isInCombat(); } public void onViewLostFocus() { updateDatabase(); } private void updateDatabase() { try { Encounter<EncounterParticipant> encounter = this.encounter.buildEncounterForModel(); encounterDao.updateFields(encounter); for (EncounterParticipant participant : encounter) { participantDao.update(encounter.getId(), participant); } } catch (DataAccessException e) { Log.e(TAG, "Failed to update encounter", e); } } private EncounterFragment getFragment() { Preconditions.checkState(fragment != null, "Fragment must be bound to presenter using bind()"); return fragment; } public EncounterViewModel getModel() { return encounter; } public EncounterRoller.SkillCheckType getLastSkillCheck() { return lastSkillCheck; } public void onEncounterNameEdited(Editable editedName) { getModel().setName(editedName != null ? editedName.toString() : ""); } public void onNextTurnSelected() { EncounterParticipantRowModel currentTurn = encounter.getCurrentTurn(); if (currentTurn == null && !encounter.isEmpty()) { setCurrentTurn(0); } else if (currentTurn != null) { int currentTurnIndex = encounter.indexOf(currentTurn); int nextTurnIndex = (currentTurnIndex + 1) % encounter.size(); setCurrentTurn(nextTurnIndex); } } private void setCurrentTurn(int index) { encounter.setCurrentTurn(encounter.get(index)); notifyModelAttributesChanged(); } public void onParticipantSelected(EncounterParticipantRowModel participant) { showParticipantDetails(participant); } private void showParticipantDetails(EncounterParticipantRowModel row) { preferences.put(GlobalPrefs.SELECTED_CHARACTER_ID, row.getParticipant().getId()); fragment.switchToPage(CharacterCombatStatsFragment.class); } public void onEncounterSelected(IdNamePair encounterId) { setEncounter(loadEncounterFromDatabase(encounterId.getId())); } public void onCharactersAndPartiesSelectedToAddToEncounter(List<IdNamePair> characters, List<IdNamePair> parties) { Set<IdNamePair> charactersToAdd = getUniqueCharacters(characters, parties); Set<EncounterParticipant> newParticipants = createEncounterParticipantsForCharacters(charactersToAdd); getModel().addAll(EncounterParticipantRowModel.listFrom(newParticipants)); getModel().updateTurnOrders(); notifyModelChanged(); } private Set<IdNamePair> getUniqueCharacters(List<IdNamePair> characters, List<IdNamePair> parties) { Set<IdNamePair> uniqueCharacters = Sets.newHashSet(); uniqueCharacters.addAll(characters); PartyMemberNameDAO memberDao = new PartyMemberNameDAO(context); for (IdNamePair party : parties) { uniqueCharacters.addAll(memberDao.findAllForOwner(party.getId())); } return uniqueCharacters; } private Set<EncounterParticipant> createEncounterParticipantsForCharacters(Collection<IdNamePair> charIds) { Set<EncounterParticipant> participants = Sets.newHashSet(); CharacterModelDAO charDao = new CharacterModelDAO(context); for (IdNamePair id : charIds) { PathfinderCharacter character = charDao.find(id.getId()); try { if (character == null) throw new DataAccessException("No character found for " + id); EncounterParticipant participant = new EncounterParticipant(character); participantDao.add(encounter.getId(), participant); participants.add(participant); } catch (DataAccessException e) { Log.e(TAG, "Could not add participant " + id + " to encounter " + encounter.getId(), e); } } return participants; } public void onParticipantsSelectedForDeletion(List<EncounterParticipantRowModel> participantsToRemove) { removeParticipantsFromEncounter(participantsToRemove); notifyModelChanged(); } public void onInitiativeEdited(Editable initText, EncounterParticipantRowModel row) { try { int init = Integer.parseInt(initText.toString()); row.getParticipant().setInitiativeScore(init); notifyModelAttributesChanged(); } catch (NumberFormatException e) { Log.e(TAG, "Failed to parse int from \"" + initText.toString() + "\""); } } private void removeParticipantsFromEncounter(List<EncounterParticipantRowModel> participantsToRemove) { for (EncounterParticipantRowModel row : participantsToRemove) { try { participantDao.remove(encounter.getId(), row.getParticipant()); encounter.remove(row); } catch (DataAccessException e) { Log.e(TAG, "Could not remove participant " + row.getParticipant().getId() + " from party " + encounter.getId(), e); } } } public void onParticipantOrderChangeConfirmed(int initialPosition, int newPosition) { if (initialPosition != newPosition && Objects.equal(encounter.get(newPosition), encounter.getCurrentTurn())) { setCurrentTurn(initialPosition); } } public void onParticipantOrdersChanged() { getModel().updateTurnOrders(); } public enum EncounterStartMode { AUTO_ROLL, MANUAL } public void onEncounterStarted(EncounterStartMode mode) { if (mode == EncounterStartMode.AUTO_ROLL) { roller.rollInitiatives(); Collections.sort(encounter, new Comparator<EncounterParticipantRowModel>() { @Override public int compare(EncounterParticipantRowModel lhs, EncounterParticipantRowModel rhs) { return rhs.getParticipant().getInitiativeScore() - lhs.getParticipant().getInitiativeScore(); } }); } encounter.setInCombat(true); onNextTurnSelected(); } private void notifyModelAttributesChanged() { getFragment().notifyModelAttributesChanged(); } public void onSkillCheckSelected(EncounterRoller.SkillCheckType checkType) { lastSkillCheck = checkType; roller.rollSkillChecks(checkType); notifyModelAttributesChanged(); } public void onEncounterResetSelected() { roller.resetInitiatives(); roller.resetLastSkillChecks(); lastSkillCheck = null; encounter.setCurrentTurn(null); encounter.setInCombat(false); notifyModelAttributesChanged(); } public List<IdNamePair> getSelectableEncounters() { updateDatabase(); List<? extends IdNamePair> encounterFields = encounterDao.findAll(); Collections.sort(encounterFields); return Lists.newArrayList(encounterFields); } public List<IdNamePair> getCharactersAvailableToAddToEncounter() { return getCharactersNotInEncounter(); } private List<IdNamePair> getCharactersNotInEncounter() { CharacterNameDAO charDao = new CharacterNameDAO(context); List<IdNamePair> characters = charDao.findAll(); characters.removeAll(getModel().getParticipantIds()); return characters; } public List<IdNamePair> getPartiesAvailableToAddToEncounter() { return getPartiesNotEntirelyInEncounter(); } private List<IdNamePair> getPartiesNotEntirelyInEncounter() { PartyMemberNameDAO memberDao = new PartyMemberNameDAO(context); PartyDAO<IdNamePair> partyDao = new PartyDAO<IdNamePair>(context, memberDao); List<IdNamePair> allPartyIds = partyDao.findAll(); List<IdNamePair> nonSelectedParties = Lists.newArrayList(); List<IdNamePair> participantsInEncounter = getModel().getParticipantIds(); for (IdNamePair partyId : allPartyIds) { NamedList<IdNamePair> party = partyDao.findList(partyId.getId()); party.removeAll(participantsInEncounter); if (!party.isEmpty()) { nonSelectedParties.add(party.idNamePair()); } } return nonSelectedParties; } public void onDeleteCurrentEncounterSelected() { deleteCurrentEncounter(); setEncounter(loadDefaultEncounter()); } private void deleteCurrentEncounter() { try { encounterDao.removeById(encounter.getId()); } catch (DataAccessException e) { Log.e(TAG, "Failed to delete encounter with id=" + encounter.getId(), e); } } public void onNewEncounterSelected() { setEncounter(loadNewEncounter()); } }