dip.order.Order.java Source code

Java tutorial

Introduction

Here is the source code for dip.order.Order.java

Source

//   
//    @(#)Order.java   12/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.order.result;
//
package dip.order;

import dip.world.*;
import dip.process.Adjudicator;
import dip.process.OrderState;
import dip.misc.Utils;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.io.*;

import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 *  This is the base class for all Order objects.
 *   <p>
 *    <b>When referring to an Order subclass, it is best to refer to an object
 *   as an "Orderable" object rather than an "Order" object.
 *   </b>
 *   <br>   
 *   For example:
 *   <pre>
 *      GUIOrderFactory gof = new GUIOrderFactory();
 *      
 *       Order order = OrderFactory.getDefault().createHold(a,b,c);         // ok
 *      Orderable order = OrderFactory.getDefault().createHold(a,b,c);      // dangerous
 *      
 *      Order order = gof.createHold(a,b,c);         // this may fail!!
 *      Orderable order = gof.createHold(a,b,c);      // ok
 *   </pre>
 *   <p>
 *   This class provides default implementations for many Order interface
 *   methods, as well as protected convenience methods.
 *   <p>
 *   A note on serialization: provided are several internal fields
 *   which can be used to 'upgrade' objects as needed. These fields
 *   are for future use, but their presence enables future upgradibility.
 *
 *
 *
 */
public abstract class Order extends Object implements Orderable, java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 5487204449795813995L;
    // resource keys
    private static final String ORD_VAL_NOUNIT = "ORD_VAL_NOUNIT";
    private static final String ORD_VAL_BADPOWER = "ORD_VAL_BADPOWER";
    private static final String ORD_VAL_BADTYPE = "ORD_VAL_BADTYPE";
    private static final String ORD_VAL_SZ_RETREAT = "ORD_VAL_SZ_RETREAT";
    private static final String ORD_VAL_SZ_ADJUST = "ORD_VAL_SZ_ADJUST";
    private static final String ORD_VAL_SZ_MOVEMENT = "ORD_VAL_SZ_MOVEMENT";
    //private static final String ORD_VAL_SZ_SETUP = "ORD_VAL_SZ_SETUP";
    //private static final String ORD_VAL_PWR_DISORDER = "ORD_VAL_PWR_DISORDER";
    private static final String ORD_VAL_PWR_ELIMINATED = "ORD_VAL_PWR_ELIMINATED";
    private static final String ORD_VAL_PWR_INACTIVE = "ORD_VAL_PWR_INACTIVE";
    protected static final String ORD_VAL_BORDER = "ORD_VAL_BORDER";

    /** Power who gave the order to the unit */
    protected Power power = null;

    /** Location of the ordered unit */
    protected Location src = null;

    /** Type of the ordered unit */
    protected Unit.Type srcUnitType = null;

    /**
    *   No-arg constructor
    */
    protected Order() {
    }// Order()

    /**
     *  Constructor for the Order object
     *
     *@param  power    Power giving the Order
     *@param  src      Location of the ordered unit
     *@param  srcUnit  Unit type
     *@since
     */
    protected Order(Power power, Location src, Unit.Type srcUnit) {

        if (power == null || src == null || srcUnit == null) {
            throw new IllegalArgumentException("null parameter(s)");
        }

        this.power = power;
        this.src = src;
        this.srcUnitType = srcUnit;
    }// Order()

    public final Location getSource() {
        return src;
    }// getSource()

    public final Unit.Type getSourceUnitType() {
        return srcUnitType;
    }// getSourceUnitType()

    public final Power getPower() {
        return power;
    }// getPower()

    // 
    // Format methods
    // 
    public String toFormattedString(OrderFormatOptions ofo) {
        return OrderFormat.format(ofo, getDefaultFormat(), this);
    }// toFormattedString()

    // 
    // Adjudicator methods
    // 

    /**
     * Validate the order. 
     * <p>
     * This checks the order for legality. An order is not considered to be 
     * well-formed until it has been validated.
     * It validates locations (at the least), and other order
     * syntax as appropriate, throwing exceptions if there is a conflict.
     * <p>
     * This is used by the UI to flag bad orders, as well as by the adjudicator
     * to eliminate bad orders before processing.
     * <p>
     * Important Note:
     * <p>
     * The only state that should be assumed is the following:
     *       1) orders for this power (if entered)
     *      2) the positions of all units.
     * Thus, the orders of units not controlled by this power may
     * not be known (in multiplayer games, this information would not
     * be available until adjudication took place). DO NOT assume order
     * information for the units of any power other than that of this unit/order!
     * <p>
     * Usage Notes:
     * <p>
     * Subclasses should generally call super.validate() before performing
     * additional validation. 
     * <p>
     * There should be no side effects of calling validate() multiple times, nor
     * should behavior differ between multiple calls of validate(), given the same
     * order.
     * 
     *
     *@param  state               Current turn state
     *@param valOpts          Current validation options
     *@exception  OrderException  
     */
    public void validate(TurnState state, ValidationOptions valOpts, RuleOptions ruleOpts) throws OrderException {
        Position position = state.getPosition();
        Unit unit = position.getUnit(src.getProvince());
        validate(valOpts, unit);
    }// validate()

    //
    //   Convenience methods
    //
    //

    /**
    *   Convenience method typically used in determineDependencies(); this 
    *   method gets all Support and Move orders to this space and adds 
    *   them to the dependency list. 
    *   <p>
    *   Only "hold" supports are added. Invalid Move orders are NEVER added.
    *
    */
    protected final void addSupportsOfAndMovesToSource(Adjudicator adjudicator) {
        OrderState thisOS = adjudicator.findOrderStateBySrc(getSource());
        ArrayList depMTS = null;
        ArrayList depSup = null;

        OrderState[] orderStates = adjudicator.getOrderStates();
        for (int osIdx = 0; osIdx < orderStates.length; osIdx++) {
            OrderState dependentOS = orderStates[osIdx];
            Order order = dependentOS.getOrder();

            if (order != this) // always exclude self
            {
                if (order instanceof Move && ((Move) order).getDest().isProvinceEqual(this.getSource())) {
                    if (depMTS == null) {
                        depMTS = new ArrayList(5);
                    }
                    depMTS.add(dependentOS);
                } else if (order instanceof Support) {
                    Support support = (Support) order;

                    // if we don't check for hold-type support (Support.isSupportingHold() == true)
                    // we will accidentally add move-supports! (bad)
                    if (support.isSupportingHold() && support.getSupportedSrc().isProvinceEqual(this.getSource())) {
                        if (depSup == null) {
                            depSup = new ArrayList(5);
                        }
                        depSup.add(dependentOS);
                    }
                }
            }
        }

        // set supports / endangering moves in OrderState
        if (depMTS != null) {
            thisOS.setDependentMovesToSource(depMTS);
        }

        if (depSup != null) {
            thisOS.setDependentSupports(depSup);
        }
    }// addSupportsOfAndMovesToSource()      

    /** 
    *   Validates a dislodged or non-dislodged unit, depending upon what type of
    *   unit is specified
    */
    protected void validate(ValidationOptions valOpts, Unit unit) throws OrderException {
        // Basic Validation: [not in correct order]
        //    1) must be a unit in the province ordered.
        //   2) Power of unit in Province must == Power of this Order
        //   3) if unit type is undefined, determine correct type.
        //       if type mismatch, throw exception.
        //   4) validate the source location given the unit type.
        //      (ensure coast is correct)
        //
        Province srcProvince = src.getProvince();

        // unit-existence
        if (unit == null) {
            throw new OrderException(Utils.getLocalString(ORD_VAL_NOUNIT, srcProvince));
        }

        // power-matching
        if (!power.equals(unit.getPower())) {
            throw new OrderException(Utils.getLocalString(ORD_VAL_BADPOWER));
        }

        // unit type matching
        srcUnitType = getValidatedUnitType(srcProvince, srcUnitType, unit);

        // Location verification; derive info if missing from unit, since 
        // we know it to exist.
        src = src.getValidatedAndDerived(srcUnitType, unit);
    }// validate()

    /** 
    *   Convenience method for matching unit types.
    *   <p>
    *   If a type is undefined, the type is derived from the existing unit. If the 
    *   existing unit is not found (or mismatched), an exception is thrown.
    */
    protected final Unit.Type getValidatedUnitType(Province province, Unit.Type unitType, Unit unit)
            throws OrderException {
        if (unit == null) {
            throw new OrderException(Utils.getLocalString(ORD_VAL_NOUNIT, province));
        }

        if (unitType.equals(Unit.Type.UNDEFINED)) {
            // make unitType correct.
            return unit.getType();
        } else {
            if (!unitType.equals(unit.getType())) {
                throw new OrderException(Utils.getLocalString(ORD_VAL_BADTYPE, province,
                        unit.getType().getFullNameWithArticle(), unitType.getFullNameWithArticle()));
            }
        }

        return unitType;
    }// getValidatedUnitType()

    /** Validates the given Power */
    protected final void checkPower(Power power, TurnState turnState, boolean checkIfActive) throws OrderException {
        Position position = turnState.getPosition();
        if (position.isEliminated(power)) {
            throw new OrderException(Utils.getLocalString(ORD_VAL_PWR_ELIMINATED, power));
        }
        if (!power.isActive() && checkIfActive) {
            throw new OrderException(Utils.getLocalString(ORD_VAL_PWR_INACTIVE, power));
        }
    }// checkPower()

    /** Convenience method to check that we are in the Retreat phase */
    protected final void checkSeasonRetreat(TurnState state, String orderName) throws OrderException {
        if (state.getPhase().getPhaseType() != Phase.PhaseType.RETREAT) {
            throw new OrderException(Utils.getLocalString(ORD_VAL_SZ_RETREAT, orderName));
        }
    }// checkSeasonRetreat()

    /** Convenience method to check that we are in the Adjustment phase */
    protected final void checkSeasonAdjustment(TurnState state, String orderName) throws OrderException {
        if (state.getPhase().getPhaseType() != Phase.PhaseType.ADJUSTMENT) {
            throw new OrderException(Utils.getLocalString(ORD_VAL_SZ_ADJUST, orderName));
        }
    }// checkSeasonAdjustment()

    /** Convenience method to check that we are in the Movement phase */
    protected final void checkSeasonMovement(TurnState state, String orderName) throws OrderException {
        if (state.getPhase().getPhaseType() != Phase.PhaseType.MOVEMENT) {
            throw new OrderException(Utils.getLocalString(ORD_VAL_SZ_MOVEMENT, orderName));
        }
    }// checkSeasonMovement()

    /** 
    *   Convenience Method: prints the beginning of an order in a verbose format.
    *   <br>
    *   Example: France: Army Spain/sc
    */
    protected final void appendFull(StringBuffer sb) {
        sb.append(power);
        sb.append(": ");
        sb.append(srcUnitType.getFullName());
        sb.append(' ');
        src.appendFull(sb);
    }// appendFull()

    /** 
    *   Convenience Method: prints the beginning of an order in a brief format.
    *   <br>
    *   Example: France: Army spa/sc
    */
    protected final void appendBrief(StringBuffer sb) {
        sb.append(power);
        sb.append(": ");
        sb.append(srcUnitType.getShortName());
        sb.append(' ');
        src.appendBrief(sb);
    }// appendBrief()

    //
    // 
    // java.lang.Object method implementations
    // 
    //

    /** For debugging: calls toBriefString(). Note this will fail if order is null. */
    public String toString() {
        return toBriefString();
    }// toString()

    /** 
    *   Determines if the orders are equal.
    *   <p>
    *   Note that full equality MUST be implemented for each 
    *   subclassed Order object! Subclasses are advised to call
    *   the super method for assistance.
    */
    public boolean equals(Object obj) {
        // speedy reference check
        if (this == obj) {
            return true;
        } else if (obj instanceof Order) {
            Order o = (Order) obj;

            if (power.equals(o.power) && src.equals(o.src) && srcUnitType.equals(o.srcUnitType)) {
                return true;
            }
        }

        return false;
    }// equals()

    @Override
    public int hashCode() {
        return new HashCodeBuilder(11, 31).append(power).append(src).append(srcUnitType).toHashCode();
    }

}// abstract class Order