//
// @(#)Unit.java 4/2002
//
// Copyright 2002 Zachary DelProposto. All rights reserved.
// Use is subject to license terms.
//
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// Or from http://www.gnu.org/
//
package dip.world;
import dip.order.Order;
import dip.misc.Utils;
/**
*
* A Unit is an object that has an owner (power), a coast location, and a Type
* describing that unit.
* <p>
* Units are placed in Provinces.
* <p>
* <b>This object is not immutable!</b>
*/
public class Unit implements java.io.Serializable, Cloneable
{
/**
*
*/
private static final long serialVersionUID = -9051046255140798593L;
// instance variables
protected final Unit.Type type;
protected final Power owner;
protected Coast coast = Coast.UNDEFINED;
/**
* Creates a new Unit
*/
public Unit(Power power, Unit.Type unitType)
{
if(power == null || unitType == null)
{
throw new IllegalArgumentException("null arguments not permitted");
}
if(unitType == Unit.Type.UNDEFINED)
{
throw new IllegalArgumentException("cannot create a unit with undefined type");
}
this.owner = power;
this.type = unitType;
}// Unit()
/** For Cloning: *NO* arguments are checked. */
private Unit(Power power, Unit.Type unitType, Coast coast)
{
this.owner = power;
this.type = unitType;
this.coast = coast;
}// Unit()
/**
* Set the coast of a unit.
*/
public void setCoast(Coast coast)
{
if(coast == null)
{
throw new IllegalArgumentException("null coast");
}
this.coast = coast;
}// setCoast()
/** Get the Coast where this Unit is located */
public Coast getCoast() { return coast; }
/** Get the Power who controls this Unit */
public Power getPower() { return owner; }
/** Get the Type of unit (e.g., Army or Fleet) */
public Unit.Type getType() { return type; }
/** Returns if two Units are equivalent. */
public boolean equals(final Object obj)
{
if(obj == this)
{
return true;
}
else if(obj instanceof Unit)
{
Unit unit = (Unit) obj;
return (unit.type == this.type && unit.owner == this.owner
&& unit.coast == this.coast);
}
return false;
}// equals()
/**
* Returns a Clone of the unit. Note that this is not a
* strict implementation of clone(); a constructor is
* invoked for performance reasons.
*/
public Object clone()
{
return new Unit(owner, type, coast);
}// clone()
/** Displays internal object values. For debugging use only! */
public String toString()
{
StringBuffer sb = new StringBuffer(64);
sb.append("Unit:[type=");
sb.append(type);
sb.append(",power=");
sb.append(owner);
sb.append(",coast=");
sb.append(coast);
sb.append(']');
return sb.toString();
}// toString()
/**
* A Type is the class of unit, for example, Army or Fleet.
* <p>
* Type constans should be used; new Type objects should not be created
* unless the game concepts are being extended.
*
*/
public static class Type extends Object implements java.io.Serializable
{
/**
*
*/
private static final long serialVersionUID = 6516825379720373661L;
// internal i18n key constants
private static final String UNIT_TYPE_PREFIX = "unit.type.";
private static final String UNIT_TYPE_BRIEF_SUFFIX = ".brief";
private static final String UNIT_TYPE_ARTICLE_SUFFIX = ".witharticle";
// so, for an army (brief name), the key would be:
// UNIT_TYPE_PREFIX + NAME_ARMY + UNIT_TYPE_BRIEF_SUFFIX
// internal constants, also used in i18n keys
private static final String NAME_ARMY = "army";
private static final String NAME_FLEET = "fleet";
private static final String NAME_WING = "wing";
private static final String NAME_UNDEFINED = "undefined";
/** Constant representing an Army */
public static final Unit.Type ARMY = new Unit.Type(NAME_ARMY);
/** Constant representing a Fleet */
public static final Unit.Type FLEET = new Unit.Type(NAME_FLEET);
/** Constant representing a Wing */
public static final Unit.Type WING = new Unit.Type(NAME_WING);
/** Constant representing an unknown type */
public static final Unit.Type UNDEFINED = new Unit.Type(NAME_UNDEFINED);
// instance variables
private final String internalName;
private final transient String name;
private final transient String shortName;
private final transient String nameWithArticle;
/** Create a new Type */
protected Type(String internalName)
{
this.internalName = internalName;
this.name = Utils.getLocalString(UNIT_TYPE_PREFIX + internalName);
this.shortName = Utils.getLocalString(UNIT_TYPE_PREFIX +
internalName + UNIT_TYPE_BRIEF_SUFFIX);
this.nameWithArticle = Utils.getLocalString(UNIT_TYPE_PREFIX +
internalName + UNIT_TYPE_ARTICLE_SUFFIX);
}// Type()
/** Get the full name of this type (e.g., 'Army') */
public String getFullName()
{
return name;
}// getName()
/** Get the short name of this type (e.g., 'A') */
public String getShortName()
{
return shortName;
}// getShortName();
/** Get the short name */
public String toString()
{
return shortName;
}// toString()
/** Get the full name, including an article*/
public String getFullNameWithArticle()
{
return nameWithArticle;
}// getFullNameWithArticle()
/** Returns the hashcode */
public int hashCode()
{
return name.hashCode();
}// hashCode()
@Override
public boolean equals(Object obj) {
if (obj instanceof Unit.Type){
return obj.hashCode() == this.hashCode();
}
return false;
}
/*
equals():
We use Object.equals(), which just does a test of
referential equality.
*/
/**
* Returns a type constant corresponding to the input.
* Case insensitive. This will parse localized names,
* AS WELL AS the standard English names. So, for
* English names (and all other languages):
* <pre>
* null -> Type.UNDEFINED
* 'f' or 'fleet' -> Type.FLEET
* 'a' or 'army' -> Type.ARMY
* 'w' or 'wing' -> Type.WING
* any other -> null
* </pre>
*
*/
public static Unit.Type parse(String text)
{
if(text == null)
{
return Unit.Type.UNDEFINED;
}
String input = text.toLowerCase().trim();
if(Unit.Type.ARMY.getShortName().equals(input)
|| Unit.Type.ARMY.getFullName().equals(input))
{
return Unit.Type.ARMY;
}
else if(Unit.Type.FLEET.getShortName().equals(input)
|| Unit.Type.ARMY.getFullName().equals(input))
{
return Unit.Type.FLEET;
}
else if(Unit.Type.WING.getShortName().equals(input)
|| Unit.Type.ARMY.getFullName().equals(input))
{
return Unit.Type.WING;
}
// test against standard English names after trying
// localized names.
//
if("a".equals(input) || "army".equals(input))
{
return Unit.Type.ARMY;
}
else if("f".equals(input) || "fleet".equals(input))
{
return Unit.Type.FLEET;
}
else if("w".equals(input) || "wing".equals(input))
{
return Unit.Type.WING;
}
return null;
}// parse()
/** Assigns serialized objects to a single constant reference */
protected Object readResolve()
throws java.io.ObjectStreamException
{
Type type = null;
if(internalName.equals(NAME_ARMY))
{
type = ARMY;
}
else if(internalName.equals(NAME_FLEET))
{
type = FLEET;
}
else if(internalName.equals(NAME_WING))
{
type = WING;
}
else if(internalName.equals(NAME_UNDEFINED))
{
type = UNDEFINED;
}
else
{
throw new java.io.InvalidObjectException("Unknown Unit.Type: "+internalName);
}
return type;
}// readResolve()
}// inner class Type
}// class Unit