//
// @(#)GUIHold.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.gui.order;
import dip.order.Hold;
import dip.order.Orderable;
import dip.order.ValidationOptions;
import dip.gui.order.GUIOrder.MapInfo;
import dip.misc.Utils;
import dip.misc.Log;
import dip.world.Position;
import dip.world.Location;
import dip.world.Province;
import dip.world.Unit;
import dip.world.Power;
import dip.world.RuleOptions;
import dip.process.Adjustment.AdjustmentInfoMap;
import dip.gui.map.MapMetadata;
import java.awt.geom.Point2D;
import org.apache.batik.util.SVGConstants;
import org.apache.batik.util.CSSConstants;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.w3c.dom.svg.*;
import org.w3c.dom.*;
/**
*
* GUIOrder subclass of Hold order.
*
*
*/
public class GUIHold extends Hold implements GUIOrder
{
// i18n keys
// instance variables
private transient final static int REQ_LOC = 1;
private transient int currentLocNum = 0;
private transient int numSupports = -1; // WARNING: this will become '0' when de-serialized; not -1
private transient Point2D.Float failPt = null;
private transient SVGGElement group = null;
/** Creates a GUIHold */
protected GUIHold()
{
super();
}// GUIHold()
/** Creates a GUIHold */
protected GUIHold(Power power, Location source, Unit.Type sourceUnitType)
{
super(power, source, sourceUnitType);
}// GUIHold()
/** This only accepts Hold orders. All others will throw an IllegalArgumentException. */
public void deriveFrom(Orderable order)
{
if( !(order instanceof Hold) )
{
throw new IllegalArgumentException();
}
Hold hold = (Hold) order;
power = hold.getPower();
src = hold.getSource();
srcUnitType = hold.getSourceUnitType();
// set completed
currentLocNum = REQ_LOC;
}// deriveFrom()
public boolean testLocation(StateInfo stateInfo, Location location, StringBuffer sb)
{
sb.setLength(0);
if(isComplete())
{
sb.append( Utils.getLocalString(GUIOrder.COMPLETE, getFullName()) );
return false;
}
Position position = stateInfo.getPosition();
Province province = location.getProvince();
Unit unit = position.getUnit(province);
if(unit != null)
{
if( !stateInfo.canIssueOrder(unit.getPower()) )
{
sb.append( Utils.getLocalString(GUIOrder.NOT_OWNER, unit.getPower()) );
return false;
}
if( !GUIOrderUtils.checkBorder(this, new Location(province, unit.getCoast()), unit.getType(), stateInfo.getPhase(), sb) )
{
return false;
}
sb.append( Utils.getLocalString(GUIOrder.CLICK_TO_ISSUE, getFullName()) );
return true;
}
// no unit in province
sb.append( Utils.getLocalString(GUIOrder.NO_UNIT, getFullName()) );
return false;
}// testLocation()
public boolean clearLocations()
{
if(isComplete())
{
return false;
}
currentLocNum = 0;
power = null;
src = null;
srcUnitType = null;
return true;
}// clearLocations()
public boolean setLocation(StateInfo stateInfo, Location location, StringBuffer sb)
{
if(testLocation(stateInfo, location, sb))
{
currentLocNum++;
Unit unit = stateInfo.getPosition().getUnit(location.getProvince());
src = new Location(location.getProvince(), unit.getCoast());
power = unit.getPower();
srcUnitType = unit.getType();
sb.setLength(0);
sb.append( Utils.getLocalString(GUIOrder.COMPLETE, getFullName()) );
return true;
}
return false;
}// setLocation()
public boolean isComplete()
{
assert (currentLocNum <= getNumRequiredLocations());
return (currentLocNum == getNumRequiredLocations());
}// isComplete()
public int getNumRequiredLocations() { return REQ_LOC; }
public int getCurrentLocationNum() { return currentLocNum; }
/** Always throws an IllegalArgumentException */
public void setParam(Parameter param, Object value) { throw new IllegalArgumentException(); }
/** Always throws an IllegalArgumentException */
public Object getParam(Parameter param) { throw new IllegalArgumentException(); }
public void removeFromDOM(MapInfo mapInfo)
{
if(group != null)
{
Log.println("GUIHold: removeFromDOM(): group=", group);
SVGGElement powerGroup = mapInfo.getPowerSVGGElement(power, LAYER_TYPICAL);
GUIOrderUtils.removeChild(powerGroup, group);
group = null;
numSupports = -1;
}
}// removeFromDOM()
public void updateDOM(MapInfo mapInfo)
{
Log.println("GUIHold::updateDOM(): group,support: ", group, String.valueOf(numSupports));
// if we are not displayable, we exit, after remove the order (if
// it was created)
if( !GUIOrderUtils.isDisplayable(power, mapInfo) )
{
Log.println("GUIHold::updateDOM(): not displayable.");
removeFromDOM(mapInfo);
return;
}
// determine if any change has occured. If no change has occured,
// we will not change the DOM.
//
// check supports
int support = GUIOrderUtils.getMatchingSupportCount(mapInfo,
src.getProvince(), src.getProvince());
if(numSupports == support && group != null)
{
Log.println("GUIHold::updateDOM(): no change. returning. calc support: ", String.valueOf(support));
return; // no change
}
// we are only at this point if a change has occured.
//
numSupports = support;
// if we've not yet been created, we will create; if we've
// already been created, we must remove the existing elements
// in our group
if(group == null)
{
// create group
Log.println("GUIHold::updateDOM(): creating group.");
group = (SVGGElement) mapInfo.getDocument().createElementNS(
SVGDOMImplementation.SVG_NAMESPACE_URI, SVGConstants.SVG_G_TAG);
group.setId("order_" + this.src.toString());
mapInfo.getPowerSVGGElement(power, LAYER_TYPICAL).appendChild(group);
}
else
{
// remove group children
Log.println("GUIHold::updateDOM(): removing group children.");
GUIOrderUtils.deleteChildren(group);
}
// now, render the order
//
Log.println("GUIHold::updateDOM(): rendering order.");
SVGElement element = null;
// create hilight line
String cssStyle = mapInfo.getMapMetadata().getOrderParamString(MapMetadata.EL_HOLD, MapMetadata.ATT_HILIGHT_CLASS);
if(!cssStyle.equalsIgnoreCase("none"))
{
float offset = mapInfo.getMapMetadata().getOrderParamFloat(MapMetadata.EL_HOLD, MapMetadata.ATT_HILIGHT_OFFSET);
float width = GUIOrderUtils.getLineWidth(mapInfo, MapMetadata.EL_HOLD, MapMetadata.ATT_SHADOW_WIDTHS, numSupports);
element = drawOrder(mapInfo, offset);
element.setAttributeNS(null, SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE, GUIOrderUtils.floatToString(width));
GUIOrderUtils.makeHilight(element, mapInfo.getMapMetadata(), MapMetadata.EL_HOLD);
group.appendChild(element);
}
// create hold polygon
float width = GUIOrderUtils.getLineWidth(mapInfo, MapMetadata.EL_HOLD, MapMetadata.ATT_WIDTHS, numSupports);
element = drawOrder(mapInfo, 0);
element.setAttributeNS(null, SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE, GUIOrderUtils.floatToString(width));
GUIOrderUtils.makeStyled(element, mapInfo.getMapMetadata(), MapMetadata.EL_HOLD, power);
group.appendChild(element);
// draw 'failed' marker, if appropriate.
if(!mapInfo.getTurnState().isOrderSuccessful(this))
{
SVGElement useElement = GUIOrderUtils.createFailedOrderSymbol(mapInfo, failPt.x, failPt.y);
group.appendChild(useElement);
}
}// updateDOM()
private SVGElement drawOrder(MapInfo mi, float offset)
{
MapMetadata mmd = mi.getMapMetadata();
// attributes
Point2D.Float center = mmd.getUnitPt(src.getProvince(), src.getCoast());
float radius = mmd.getOrderRadius(MapMetadata.EL_HOLD, mi.getSymbolName(srcUnitType));
// create the polygon
SVGElement elem = (SVGPolygonElement)
mi.getDocument().createElementNS(
SVGDOMImplementation.SVG_NAMESPACE_URI,
SVGConstants.SVG_POLYGON_TAG);
// add offset (if any) to elements
center.x += offset;
center.y += offset;
Point2D.Float[] pts = GUIOrderUtils.makeOctagon(center, radius);
StringBuffer sb = new StringBuffer(160);
for(int ptsIdx=0; ptsIdx<pts.length; ptsIdx++)
{
GUIOrderUtils.appendFloat(sb, pts[ptsIdx].x);
sb.append(',');
GUIOrderUtils.appendFloat(sb, pts[ptsIdx].y);
sb.append(' ');
}
// create failure marker point, halfway between first & second points.
failPt = GUIOrderUtils.getLineMidpoint(pts[0].x, pts[0].y, pts[1].x, pts[1].y);
elem.setAttributeNS(null, SVGConstants.SVG_POINTS_ATTRIBUTE, sb.toString());
elem.setAttributeNS(null, SVGConstants.SVG_CLASS_ATTRIBUTE, mmd.getOrderParamString(MapMetadata.EL_HOLD, MapMetadata.ATT_STROKESTYLE));
return elem;
}// drawOrder()
/** We are dependent upon Support orders for proper rendering */
public boolean isDependent() { return true; }
public SVGElement orderSVG(MapInfo mapInfo){
updateDOM(mapInfo);
return group;
}
}// class GUIHold