package magic.model.stack;
import magic.model.MagicAbility;
import magic.model.MagicCardDefinition;
import magic.model.MagicColor;
import magic.model.MagicCopyMap;
import magic.model.MagicCounterType;
import magic.model.MagicGame;
import magic.model.MagicMappable;
import magic.model.MagicObject;
import magic.model.MagicObjectImpl;
import magic.model.MagicPlayer;
import magic.model.MagicSource;
import magic.model.MagicSubType;
import magic.model.MagicType;
import magic.model.MurmurHash3;
import magic.model.event.MagicActivation;
import magic.model.event.MagicEvent;
import magic.model.target.MagicTarget;
import magic.model.target.MagicTargetFilter;
import magic.model.target.MagicTargetNone;
public abstract class MagicItemOnStack extends MagicObjectImpl implements MagicTarget, MagicMappable<MagicItemOnStack> {
private final MagicSource source;
private final MagicPlayer controller;
private final MagicEvent event; //may be null
private final MagicActivation<?> activation; //may be null
private final long id;
private Object[] choiceResults=MagicEvent.NO_CHOICE_RESULTS;
MagicItemOnStack(final MagicSource aSource, final MagicPlayer aController, final MagicEvent aEvent, final MagicActivation<?> act) {
source = aSource;
controller = aController;
event = aEvent;
activation = act;
id = aSource.getGame().getUniqueId();
}
MagicItemOnStack(final MagicSource aSource, final MagicPlayer aController, final MagicEvent aEvent) {
this(aSource, aController, aEvent, null);
}
MagicItemOnStack(final MagicSource aSource, final MagicPlayer aController) {
this(aSource, aController, null, null);
}
MagicItemOnStack(final MagicCopyMap copyMap, final MagicItemOnStack sourceItem) {
id = sourceItem.id;
activation = sourceItem.activation;
copyMap.put(sourceItem, this);
source = copyMap.copy(sourceItem.source);
controller = copyMap.copy(sourceItem.controller);
event = copyMap.copy(sourceItem.event);
choiceResults = copyMap.copyObjects(sourceItem.choiceResults,Object.class);
}
@Override
public MagicItemOnStack map(final MagicGame game) {
return game.getStack().getItemOnStack(id);
}
public MagicSource getSource() {
return source;
}
@Override
public MagicPlayer getController() {
return controller;
}
@Override
public MagicCardDefinition getCardDefinition() {
return getSource().getCardDefinition();
}
// only for rendering the card image popup
final public MagicCardDefinition getRealCardDefinition() {
return getSource().getCardDefinition();
}
public int getConvertedCost() {
return 0;
}
MagicActivation<?> getActivation() {
return activation;
}
public MagicEvent getEvent() {
return event;
}
public boolean hasChoice() {
return getEvent().hasChoice();
}
public void setChoiceResults(final Object[] choiceResults) {
this.choiceResults=choiceResults;
}
public Object[] getChoiceResults() {
return choiceResults;
}
public boolean isTarget(final MagicObject obj) {
return obj == getTarget();
}
public MagicTarget getTarget() {
for (Object obj : choiceResults) {
if (obj instanceof MagicTarget) {
return (MagicTarget)obj;
}
}
return MagicTargetNone.getInstance();
}
public long getId() {
return id;
}
public void resolve(final MagicGame game) {
final MagicEvent resolveEvent = getEvent();
if (resolveEvent.isValid(game, choiceResults)) {
game.executeEvent(resolveEvent, choiceResults);
}
}
@Override
public String getName() {
return source.getName();
}
public String getDescription() {
return getEvent().getDescription(choiceResults);
}
@Override
public String toString() {
return getName();
}
@Override
public boolean isPermanent() {
return false;
}
@Override
public boolean isPlayer() {
return false;
}
@Override
public int getPreventDamage() {
return 0;
}
@Override
public void setPreventDamage(final int amount) {
}
@Override
public boolean isValidTarget(final MagicSource aSource) {
return aSource != this.source && aSource != this;
}
@Override
public boolean hasColor(final MagicColor color) {
return source.hasColor(color);
}
@Override
public int getColorFlags() {
return source.getColorFlags();
}
@Override
public boolean hasAbility(final MagicAbility ability) {
return source.hasAbility(ability);
}
@Override
public boolean hasType(final MagicType type) {
return source.hasType(type);
}
@Override
public boolean hasSubType(final MagicSubType subType) {
return source.hasSubType(subType);
}
@Override
public int getCounters(final MagicCounterType counterType) {
return 0;
}
@Override
public void changeCounters(final MagicCounterType counterType,final int amount) {
throw new RuntimeException(counterType + " cannot be modified on item on stack");
}
@Override
public boolean isLegalTarget(final MagicPlayer player, final MagicTargetFilter<? extends MagicTarget> targetFilter) {
return source.getGame().getStack().contains(this);
}
private long getStateId(final Object[] arr) {
final long[] keys = new long[arr.length];
for (int i = 0; i < arr.length; i++) {
keys[i] = MagicObjectImpl.getStateId(arr[i]);
}
return MurmurHash3.hash(keys);
}
@Override
public long getStateId() {
return MurmurHash3.hash(new long[] {
source != null ? source.getStateId() : -1L,
controller != null ? controller.getId() : -1L,
activation != null ? activation.hashCode() : -1L,
getEvent() != null ? getEvent().getStateId() : -1L,
getStateId(choiceResults)
});
}
public abstract boolean isSpell();
public abstract boolean canBeCountered();
}