package com.idunnolol.sotm.data;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Pair;
import com.idunnolol.sotm.data.Card.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Represents a setup of a game (i.e., which heroes are selected,
* as well as villain and environment).
*/
public class GameSetup implements Parcelable {
private static final int MIN_HEROES = 3;
private static final int MAX_HEROES = 5;
private List<Card> mHeroes = new ArrayList<Card>(5);
private Card mVillain;
private List<Card> mVillainTeam = new ArrayList<Card>(1);
private Card mEnvironment;
public GameSetup() {
// Default setup is 3 random heroes, 1 random villain and 1 random environment
mHeroes.add(Card.RANDOM_HERO);
mHeroes.add(Card.RANDOM_HERO);
mHeroes.add(Card.RANDOM_HERO);
mVillain = Card.RANDOM_VILLAIN;
mEnvironment = Card.RANDOM_ENVIRONMENT;
}
public GameSetup(GameSetup toCopy) {
mHeroes.addAll(toCopy.mHeroes);
mVillain = toCopy.mVillain;
mEnvironment = toCopy.mEnvironment;
}
public void reset() {
for (int a = 0; a < mHeroes.size(); a++) {
mHeroes.set(a, Card.RANDOM_HERO);
}
mVillain = Card.RANDOM_VILLAIN;
mEnvironment = Card.RANDOM_ENVIRONMENT;
mVillainTeam.clear();
}
public List<Card> getHeroes() {
return mHeroes;
}
public int getHeroCount() {
return mHeroes.size();
}
public void addHero() {
mVillainTeam.clear();
mHeroes.add(Card.RANDOM_HERO);
}
public void setHero(int index, Card card) {
mHeroes.set(index, card);
}
public void removeHero(int index) {
mVillainTeam.clear();
mHeroes.remove(index);
}
public boolean canRemoveHero() {
return mHeroes.size() > MIN_HEROES;
}
public boolean canAddHero() {
return mHeroes.size() < MAX_HEROES;
}
public void setVillain(Card card) {
mVillainTeam.clear();
mVillain = card;
}
public Card getVillain() {
return mVillain;
}
public Card getVillainAt(int position) {
if (mVillainTeam.size() == 0) {
return mVillain;
}
return mVillainTeam.get(position);
}
public void setVillainTeam(List<Card> villainTeam) {
mVillainTeam = villainTeam;
}
public List<Card> getVillainTeam() {
return mVillainTeam;
}
public int getVillainCount() {
return Math.max(mVillainTeam.size(), 1);
}
public boolean isAdvancedVillain() {
return mVillain.isAdvanced();
}
public void setEnvironment(Card card) {
mEnvironment = card;
}
public Card getEnvironment() {
return mEnvironment;
}
/**
* @return true if there is a random card in the setup, false if all cards are filled out
*/
public boolean hasRandomCards() {
for (Card card : mHeroes) {
if (card.isRandom()) {
return true;
}
}
// Villain is either random with no team, or is random but hasn't selected a team
if (mVillain.isRandom() && (!mVillain.isTeam() || mVillainTeam.size() == 0)) {
return true;
}
return mEnvironment.isRandom();
}
public boolean isCompletelyRandom() {
for (Card card : mHeroes) {
if (!card.equals(Card.RANDOM_HERO)) {
return false;
}
}
return mVillain.equals(Card.RANDOM_VILLAIN) && mEnvironment.equals(Card.RANDOM_ENVIRONMENT);
}
/**
* We might not be able to randomize if there aren't enough options available
*/
public boolean canRandomize() {
return getFirstLackingType() == null;
}
/**
* @return the first type without enough enabled cards, or null if we're good to go
*/
public Type getFirstLackingType() {
// Make sure we count each hero (and alternate) only once, as we
// cannot pick the same hero twice (even with promos)
int heroCount = 0;
List<Card> heroList = Db.getCards(Type.HERO);
Set<Card> countedSet = new HashSet<Card>();
for (Card hero : heroList) {
if (!countedSet.contains(hero)) {
heroCount++;
countedSet.addAll(Db.getCardAndAlternates(hero));
}
}
if (heroCount < getHeroCount()) {
return Type.HERO;
}
else if (Db.getCards(Type.VILLAIN).size() == 0) {
return Type.VILLAIN;
}
else if (Db.getCards(Type.ENVIRONMENT).size() == 0) {
return Type.ENVIRONMENT;
}
return null;
}
/**
* Calculates the points that this setup represents. If there
* are random cards, it counts them as 0.
*/
public int getPoints() {
int points = 0;
for (Card card : mHeroes) {
if (card != Card.RANDOM_HERO) {
points += card.getPoints();
}
}
if (mVillain != Card.RANDOM_VILLAIN) {
if (isAdvancedVillain()) {
points += mVillain.getAdvancedPoints();
}
else {
points += mVillain.getPoints();
}
}
if (mEnvironment != Card.RANDOM_ENVIRONMENT) {
points += mEnvironment.getPoints();
}
// Factor in # of players
points += Db.getPointsForNumPlayers(mHeroes.size());
return points;
}
/**
* Gets the possible range of points (if all cards were filled in with
* their highest/lowest scoring items).
*
* If there are no random cards, the range is 0.
*/
public Pair<Integer, Integer> getPointRange() {
return new Pair<Integer, Integer>(getPoints(true), getPoints(false));
}
// Returns either the minimum or maximum points possible with this game setup.
private int getPoints(boolean minPoints) {
int points = getPoints();
List<Card> possibleHeroes = Db.getCards(Type.HERO);
Collections.sort(possibleHeroes, Card.POINT_COMPARATOR);
for (Card hero : mHeroes) {
if (hero.isRandom()) {
if (minPoints) {
points += possibleHeroes.get(0).getPoints();
possibleHeroes.remove(0);
}
else {
points += possibleHeroes.get(possibleHeroes.size() - 1).getPoints();
possibleHeroes.remove(possibleHeroes.size() - 1);
}
}
}
if (mVillain.isRandom()) {
List<Card> possibleVillains = Db.getCards(Type.VILLAIN);
Collections.sort(possibleVillains,
Prefs.isAdvancedAllowed() ? Card.POINT_ADVANCED_COMPARATOR : Card.POINT_COMPARATOR);
if (minPoints) {
points += possibleVillains.get(0).getPoints();
}
else {
points += possibleVillains.get(possibleVillains.size() - 1).getPoints();
}
}
if (mEnvironment.isRandom()) {
List<Card> possibleEnvironments = Db.getCards(Type.ENVIRONMENT);
Collections.sort(possibleEnvironments, Card.POINT_COMPARATOR);
if (minPoints) {
points += possibleEnvironments.get(0).getPoints();
}
else {
points += possibleEnvironments.get(possibleEnvironments.size() - 1).getPoints();
}
}
return points;
}
/**
* @return The estimated chance of winning, as an int 0-100
*/
public int getWinPercent() {
return Db.getWinPercent(getPoints());
}
public void updateFrom(GameSetup other) {
mHeroes.clear();
mHeroes.addAll(other.mHeroes);
mVillain = other.mVillain;
mEnvironment = other.mEnvironment;
mVillainTeam.clear();
mVillainTeam.addAll(other.mVillainTeam);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof GameSetup)) {
return false;
}
GameSetup other = (GameSetup) o;
return mHeroes.equals(other.mHeroes) && mVillain.equals(other.mVillain)
&& mEnvironment.equals(other.mEnvironment);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Heroes: ");
int heroCount = mHeroes.size();
for (int a = 0; a < heroCount; a++) {
if (a != 0) {
sb.append(", ");
}
sb.append(mHeroes.get(a).getId());
}
sb.append("\nVillain: " + mVillain.getId());
if (isAdvancedVillain()) {
sb.append(" (Advanced)");
}
if (mVillainTeam.size() != 0) {
List<String> teamIds = new ArrayList<String>();
for (Card teamMember : mVillainTeam) {
teamIds.add(teamMember.getId());
}
sb.append("\nVillain Team): [" + TextUtils.join(", ", teamIds) + "]");
}
sb.append("\nEnvironment: " + mEnvironment.getId());
return sb.toString();
}
//////////////////////////////////////////////////////////////////////////
// Parcelable
private GameSetup(Parcel in) {
ClassLoader cl = getClass().getClassLoader();
in.readList(mHeroes, cl);
mVillain = in.readParcelable(cl);
mEnvironment = in.readParcelable(cl);
in.readList(mVillainTeam, cl);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(mHeroes);
dest.writeParcelable(mVillain, flags);
dest.writeParcelable(mEnvironment, flags);
dest.writeList(mVillainTeam);
}
@Override
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<GameSetup> CREATOR = new Parcelable.Creator<GameSetup>() {
public GameSetup createFromParcel(Parcel in) {
return new GameSetup(in);
}
public GameSetup[] newArray(int size) {
return new GameSetup[size];
}
};
}