//
// @(#)JudgeOrderParser.java 1.00 6/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.judge.parser;
import dip.world.Phase.PhaseType;
import dip.world.Map;
import dip.world.Power;
import dip.order.result.*;
import dip.order.OrderFactory;
import dip.order.OrderException;
import dip.order.NJudgeOrderParser;
import dip.order.NJudgeOrderParser.NJudgeOrder;
import dip.misc.Utils;
import dip.misc.Log;
import java.io.*;
import java.util.regex.*;
import java.util.*;
/**
*
* Parses Move, Retreat, and Adjustment phase orders.
* <p>
* This assumes that orders never span lines.
*
*
*/
public class JudgeOrderParser
{
// i18n
private static final String WAIVED_BUILDS = "JOP.adjust.waived";
private static final String UNUSABLE_WAIVED = "JOP.adjust.unusable.waived";
private static final String UNUSABLE_PENDING = "JOP.adjust.unusable.pending";
// regular expressions
/** Parse Season and Year for these orders */
public static final String SEASON_YEAR_REGEX = "(([0-9]+))"; // "(\\S+)\\s+of\\s+(([0-9]+))";
/** Header for recognizing the start of game block */
public static final String GAME_STARTING_HEADER = "(?i)you\\s+have\\s+been\\s+selected\\s+as";
/** Recognize the starting position header */
public static final String STARTING_POSITION_REGEX = "Starting\\s+position\\s+for\\s+(\\p{Alpha}+)\\s+of\\s+((\\p{Digit}+))";
/** Header for recognizing the movement order block */
public static final String MOVE_ORDER_HEADER = "(?i)movement\\s+results\\s+for";
/**
* Recognize an order line; all orders must begin with this.
*/
private static final String ORDER_PREFIX = "^\\s*[\\p{Alnum}\\-\\_]+:\\s+";
/**
* Header for recognizing the retreat order block.<br>
* Note that older nJudge versions use "retreat orders for" while newer
* versions use "retreat results for".
*/
public static final String RETREAT_ORDER_HEADER = "(?i)retreat\\s+(?:orders|results)\\s+for";
/**
* Header for recognizing the adjustment order block.<br>
* Note that older nJudge versions use "adjustment orders for" while newer
* versions use "adjustment results for".
*/
public static final String ADJUSTMENT_ORDER_HEADER = "(?i)adjustment\\s+(?:results|orders)\\s+for";
// instance variables
private NJudgeOrder[] nJudgeOrders = null;
private PhaseType phaseType = null;
private final dip.world.Map map;
private final NJudgeOrderParser parser;
private final OrderFactory orderFactory;
/** Create a JudgeOrderParser */
public JudgeOrderParser(final dip.world.Map map,
final OrderFactory orderFactory, final String input)
throws IOException, PatternSyntaxException
{
this.map = map;
this.parser = new NJudgeOrderParser();
this.orderFactory = orderFactory;
parseInput(input);
}// JudgeOrderParser
/** Returns the phase of the processed orders. This is null when getOrderInfo() is zero-length. */
public PhaseType getPhaseType()
{
return phaseType;
}// getPhaseType()
/** Returns the NJudgeOrder(s) after parsing. This is never null, but may be a zero-length array. */
public NJudgeOrder[] getNJudgeOrders()
{
return nJudgeOrders;
}// getNJudgeOrders()
/**
* Looks for the header line. When the appropriate phase header is found, this method
* sets the PhaseType and calls the phase-specific parser. This analyzes input line-by-line.
*
*/
private void parseInput(String input)
throws IOException, PatternSyntaxException
{
// search for header input. once found, shuttle all input to the appropriate
// handler type.
Pattern hm = Pattern.compile(MOVE_ORDER_HEADER);
Pattern hr = Pattern.compile(RETREAT_ORDER_HEADER);
Pattern ha = Pattern.compile(ADJUSTMENT_ORDER_HEADER);
// create List
List orderList = new ArrayList(64);
BufferedReader br = new BufferedReader(new StringReader(input));
String line = ParserUtils.getNextLongLine(br);
while(line != null)
{
Matcher m = hm.matcher(line);
if(m.lookingAt())
{
phaseType = PhaseType.MOVEMENT;
break;
}
m = hr.matcher(line);
if(m.lookingAt())
{
phaseType = PhaseType.RETREAT;
break;
}
m = ha.matcher(line);
if(m.lookingAt())
{
phaseType = PhaseType.ADJUSTMENT;
break;
}
line = ParserUtils.getNextLongLine(br);
}
// parse based on type
parseOrders(br, phaseType, orderList);
// cleanup
br.close();
// create array
nJudgeOrders = (NJudgeOrder[]) orderList.toArray(new NJudgeOrder[orderList.size()]);
}// parseInput()
/** Parse move and retreat orders */
private void parseOrders(BufferedReader br,
PhaseType phaseType, List orderList)
throws IOException, PatternSyntaxException
{
final Pattern prefix = Pattern.compile(ORDER_PREFIX);
String line = ParserUtils.getNextLongLine(br).trim();
try
{
while(line != null)
{
// only parse lines starting with ORDER_PREFIX
Matcher m = prefix.matcher(line);
if(m.lookingAt())
{
orderList.add(parser.parse(map, orderFactory, phaseType, line));
}
else
{
Log.println("parseOrders() stopped at line: ", line);
break;
}
line = ParserUtils.getNextLongLine(br);
}
}
catch(OrderException oe)
{
IOException ioe = new IOException(oe.getMessage());
ioe.initCause(oe);
throw ioe;
}
}// moveAndRetreatParser()
}// class JudgeOrderParser