package net.sf.colossus.client;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.colossus.common.Constants;
import net.sf.colossus.game.Creature;
import net.sf.colossus.game.Legion;
import net.sf.colossus.game.Player;
import net.sf.colossus.variant.CreatureType;
import net.sf.colossus.variant.IOracleLegion;
import net.sf.colossus.variant.MasterHex;
/**
* Client-side version of a legion.
*
* @author David Ripton
*/
public final class LegionClientSide extends Legion implements IOracleLegion
{
private static final Logger LOGGER = Logger
.getLogger(LegionClientSide.class.getName());
private PredictSplitNode myNode;
public LegionClientSide(Player player, String markerId, MasterHex hex)
{
super(player, markerId, hex);
myNode = null;
}
private PredictSplitNode getNode(String markerId)
{
PredictSplits ps = getPlayer().getPredictSplits();
PredictSplitNode node = ps.getLeaf(markerId);
return node;
}
private PredictSplitNode getNode()
{
if (myNode == null)
{
myNode = getNode(getMarkerId());
}
return myNode;
}
@Override
public int getHeight()
{
PredictSplitNode node = getNode();
if (node == null)
{
return 0;
}
return node.getHeight();
}
/**
* We don't use the creature list in this class yet, so we override this
* to use the one from the {@link PredictSplitNode}.
*
* TODO fix this, particularly the use of creature names in here. Note that
* the current version also has the issue that every time this method
* is called a new list with new creatures is created, which will break
* identity checks.
*/
@Override
public List<? extends Creature> getCreatures()
{
List<Creature> result = new ArrayList<Creature>();
for (String name : getContents())
{
result.add(new Creature(getPlayer().getGame().getVariant()
.getCreatureByName(name), this));
}
return result;
}
/**
* Return an immutable copy of the legion's contents, in sorted order.
*
* TODO get rid of this string-based version in favor of the typesafe ones
*/
private List<String> getContents()
{
try
{
return Collections.unmodifiableList(getNode().getCreatures()
.getCreatureNames());
}
catch (NullPointerException ex)
{
return new ArrayList<String>();
}
}
/**
* A less typesafe version of {@link #contains(CreatureType)}.
*
* TODO deprecate and remove
*/
public boolean contains(String creatureName)
{
return getContents().contains(creatureName);
}
/**
* TODO get rid of string-based version
*/
public int numCreature(String creatureName)
{
int count = 0;
for (CreatureType type : getCreatureTypes())
{
if (type.getName().equals(creatureName))
{
count++;
}
}
return count;
}
/** Return a list of Strings. Use the proper string for titans and
* unknown creatures. */
public List<String> getImageNames()
{
List<String> names = new ArrayList<String>();
names.addAll(getContents());
int j = names.indexOf(Constants.titan);
if (j != -1)
{
names.set(j, getPlayer().getTitanBasename());
}
while ((j = names.indexOf(Constants.angel)) != -1)
{
names.set(j, getPlayer().getAngelBasename());
}
return names;
}
/** Return a list of Booleans. */
public List<Boolean> getCertainties()
{
List<Boolean> booleans = new ArrayList<Boolean>();
List<CreatureInfo> cil = getNode().getCreatures();
Iterator<CreatureInfo> it = cil.iterator();
while (it.hasNext())
{
CreatureInfo ci = it.next();
booleans.add(Boolean.valueOf(ci.isCertain()));
}
return booleans;
}
@Override
public PlayerClientSide getPlayer()
{
return (PlayerClientSide)super.getPlayer();
}
/**
* Add a new creature to this legion.
*/
@Override
public void addCreature(CreatureType creature)
{
getNode().addCreature(creature);
}
@Override
public void removeCreature(CreatureType creature)
{
getNode().removeCreature(creature);
}
/**
* Reveal creatures in this legion, some of which already may be known.
*/
void revealCreatures(final List<CreatureType> creatures)
{
// TODO find better way of initialising the PredictSplits object in Player
if (getPlayer().getPredictSplits() == null)
{
getPlayer().initPredictSplits(this, creatures);
}
getNode().revealCreatures(creatures);
}
void split(int childHeight, Legion child, int turn)
{
getNode().split(childHeight, child, turn);
myNode = myNode.getChild1();
}
void merge(Legion splitoff)
{
LOGGER.log(Level.FINER, "LegionInfo.merge() for " + splitoff + " "
+ splitoff);
getNode().merge(getNode(splitoff.getMarkerId()));
// since this is potentially a merge of a 3-way split, be safe and
// find the node again
myNode = getNode(getMarkerId());
}
/** Return the point value of suspected contents of this legion. */
@Override
public int getPointValue()
{
int sum = 0;
for (CreatureType type : getCreatureTypes())
{
if (type.isTitan())
{
// Titan skill is changed by variants.
sum += getPlayer().getTitanPower() * type.getSkill();
}
else
{
sum += type.getPointValue();
}
}
return sum;
}
/** Return the total point value of those creatures of this legion
* which are certain.
*/
public int getCertainPointValue()
{
int sum = 0;
for (CreatureType type : getNode().getCertainCreatures()
.getCreatureTypes())
{
if (type.isTitan())
{
// Titan skill is changed by variants.
sum += getPlayer().getTitanPower() * type.getSkill();
}
else
{
sum += type.getPointValue();
}
}
return sum;
}
public int numUncertainCreatures()
{
return getNode().numUncertainCreatures();
}
}