//
// @(#)ResultWriter.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.gui.report;
import dip.gui.ClientFrame;
import dip.gui.dialog.TextViewer;
import dip.misc.Utils;
import dip.misc.Help;
import dip.world.World;
import dip.world.Power;
import dip.world.Phase;
import dip.world.TurnState;
import dip.world.Position;
import dip.order.Orderable;
import dip.order.result.Result;
import dip.order.result.OrderResult;
import dip.order.result.OrderResult.ResultType;
import dip.order.OrderFormatOptions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JScrollPane;
/**
* Writes a summary of adjudication results in HTML format.
* <p>
* This now supports CSS styles and is internationalized.
* Note: nested <div> indents are cumulative.
*
*/
public class ResultWriter
{
// i18n constants
private static final String HTML_TEMPLATE = "ResultWriter.template";
private static final String HTML_NO_RESULTS = "ResultWriter.noresults.message";
private static final String NO_GENERAL_RESULTS = "ResultWriter.nogeneralresults.message";
// i18n dialog constants
private static final String DIALOG_TITLE = "ResultWriter.dialog.title";
// instance variables
private final Position position;
private final TurnState turnState;
private final World world;
private final Power[] allPowers;
private final OrderFormatOptions ofo;
/**
* Displays a summary of the current results as HTML.
* If the TurnState has not yet been resolved, an
* appropriate message is displayed.
*/
public static String resultsToHTML(TurnState ts, OrderFormatOptions orderFormatOptions)
{
if(!ts.isResolved())
{
return Utils.getText(Utils.getLocalString(HTML_NO_RESULTS));
}
ResultWriter rw = new ResultWriter(ts, orderFormatOptions);
return rw.getResultsAsHTML();
}// resultsToHTML()
/**
* Returns the HTML-encoded adjudication results inside a dialog.
*/
public static void displayDialog(final ClientFrame clientFrame,
final TurnState ts, final OrderFormatOptions orderFormatOptions)
{
final StringBuffer title = new StringBuffer(64);
title.append(Utils.getLocalString(DIALOG_TITLE));
title.append(": ");
title.append(ts.getPhase());
TextViewer tv = new TextViewer(clientFrame);
tv.setEditable(false);
tv.addSingleButton( tv.makeOKButton() );
tv.setTitle(title.toString());
tv.setHelpID(Help.HelpID.Dialog_ResultReport);
tv.setHeaderVisible(false);
tv.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tv.lazyLoadDisplayDialog(new TextViewer.TVRunnable()
{
public void run()
{
setText(resultsToHTML(ts, orderFormatOptions));
}
});
}// displayDialog()
/** ResultWriter constructor. */
private ResultWriter(TurnState ts, OrderFormatOptions ofo)
{
turnState = ts;
world = ts.getWorld();
allPowers = world.getMap().getPowers();
position = ts.getPosition();
this.ofo = ofo;
}// ResultWriter()
/** Write results as HTML */
private String getResultsAsHTML()
{
// get template
String templateText = Utils.getText(Utils.getLocalString(HTML_TEMPLATE));
// get template objects
Object[] templateData = new Object[]
{
turnState.getPhase(), // {0} : Phase
getGeneralResults(), // {1} : General Results
getPerPowerResults(), // {2} : Per-Power results (combined)
};
// format into template
return Utils.format(templateText, templateData);
}// getResultsAsHTML()
/**
* Get the General results (results that are not addressed to
* a specific power).
*/
private String getGeneralResults()
{
List resultList = turnState.getResultList();
// we want only results with a 'null' power.
// these results are addressed to all.
List generalResults = new ArrayList(32);
Iterator iter = resultList.iterator();
while(iter.hasNext())
{
Result r = (Result) iter.next();
if(r.getPower() == null)
{
generalResults.add(r);
}
}
// sort
Collections.sort(generalResults);
// print; if no general results, indicate.
if(generalResults.isEmpty())
{
return Utils.getLocalString(NO_GENERAL_RESULTS);
}
StringBuffer sb = new StringBuffer(2048);
iter = generalResults.iterator();
while(iter.hasNext())
{
Result r = (Result) iter.next();
sb.append( r.getMessage(ofo) );
sb.append("<br>\n");
}
return sb.toString();
}// getGeneralResults()
/**
* Get the per-power results. This will display the power name,
* in bold, followed by an indented list of results. Non-order
* results will come before order results.
*/
private String getPerPowerResults()
{
// Seperate results into OrderResults and 'regular' Results
List orderResults = new ArrayList(128);
List otherResults = new ArrayList(64);
List resultList = turnState.getResultList();
Iterator iter = resultList.iterator();
while(iter.hasNext())
{
Result r = (Result) iter.next();
if(r.getPower() != null)
{
if(r instanceof OrderResult)
{
orderResults.add(r);
}
else
{
otherResults.add(r);
}
}
}
// Sort the results
Collections.sort( orderResults );
Collections.sort( otherResults );
resultList = null;
// Print results, by power.
StringBuffer sb = new StringBuffer(4096);
for(int i=0; i<allPowers.length; i++)
{
// SKIP power if eliminated.
if(!position.isEliminated(allPowers[i]))
{
// power name
sb.append("<div class=\"indent1cm\"><b>");
sb.append(allPowers[i]);
sb.append(':');
sb.append("</b>");
// non-order results
printNonOrderResultsForPower(sb, allPowers[i], otherResults);
// order results
printOrderResultsForPower(sb, allPowers[i], orderResults);
sb.append("</div>");
}
}
return sb.toString();
}// getPerPowerResults()
/** Print non order results for a power. */
private void printNonOrderResultsForPower(StringBuffer sb, Power power, List results)
{
StringBuffer text = new StringBuffer(1024);
boolean foundAnOtherResult = false;
Iterator iter = results.iterator();
while(iter.hasNext())
{
Result result = (Result) iter.next();
if(power.equals(result.getPower()))
{
text.append( result.getMessage(ofo) );
text.append("<br>\n");
foundAnOtherResult = true;
}
}
// if we found any results, append them.
// otherwise, we do nothing.
if(foundAnOtherResult)
{
sb.append("<div class=\"indent1cm\">");
sb.append(text);
sb.append("</div>");
}
}// printGeneralResultsForPower()
/**
* Print the order results for a given power. If the order failed,
* underline it. Failure reasons are always in italics. If there is only
* one failure reason, it is appended to the end of the order. If
* there are multiple failure reasons, they are indented underneath
* the order.
*/
private void printOrderResultsForPower(StringBuffer sb, Power power, List results)
{
// create a mapping of orders -> a list of results. As we find results, add
// it to the map.
LinkedHashMap ordMap = new LinkedHashMap(17);
ArrayList substList = new ArrayList();
Iterator iter = results.iterator();
while(iter.hasNext())
{
OrderResult or = (OrderResult) iter.next();
Orderable order = or.getOrder();
// only use orders for the given power.
if(power == or.getPower())
{
if(order == null)
{
// usually a substituted order; add to substList.
substList.add(or);
}
else
{
if(!ordMap.containsKey(order))
{
// create the entry
List list = new ArrayList();
list.add(or);
ordMap.put(order, list);
}
else
{
// add to the list
List list = (List) ordMap.get(order);
list.add(or);
}
}
}
}
// iterate through substList, printing results
// if we have any substituted order results, print
// a blank line afterwards
sb.append("<div class=\"indent1cm\">\n");
boolean substOrderFound = false;
iter = substList.iterator();
while(iter.hasNext())
{
substOrderFound = true;
OrderResult or = (OrderResult) iter.next();
if(or.getOrder() != null)
{
sb.append( or.getOrder().toFormattedString(ofo) ); // use OrderFormat
}
sb.append(" <i>");
sb.append(or.getMessage(ofo));
sb.append("</i>");
sb.append("<br>\n");
}
if(substOrderFound)
{
sb.append("<br>\n");
}
// iterate through ordMap, chaining the results, if there are more than one.
iter = ordMap.values().iterator();
while(iter.hasNext())
{
Orderable order = null;
boolean hasFailed = false;
List list = (List) iter.next();
// find if we have failed or not
Iterator it = list.iterator();
while(it.hasNext())
{
OrderResult or = (OrderResult) it.next();
ResultType rt = or.getResultType();
order = or.getOrder();
if( rt == ResultType.FAILURE ||
rt == ResultType.DISLODGED ||
rt == ResultType.VALIDATION_FAILURE )
{
hasFailed = true;
break;
}
}
// print the order
// underline order if failure
if(hasFailed)
{
sb.append("<u>");
sb.append(order.toFormattedString(ofo));
sb.append("</u>");
}
else
{
sb.append(order.toFormattedString(ofo));
}
// print the messages; they should always be in italics.
// we always print non-empty messages indented and underneath if there are any.
//
// make a list of non-empty messages. (strings)
//
List nonEmptyList = new ArrayList(list.size());
it = list.iterator();
while(it.hasNext())
{
OrderResult or = (OrderResult) it.next();
final String msg = or.getMessage(ofo);
if(msg.length() > 0)
{
nonEmptyList.add(msg);
}
}
if(nonEmptyList.isEmpty())
{
sb.append("<br>\n");
}
else
{
sb.append("<div class=\"indent1cm\" style=\"margin-bottom:3pt;\">");
it = nonEmptyList.iterator();
while(it.hasNext())
{
final String msg = (String) it.next();
sb.append("<i> ");
sb.append(msg);
sb.append(" </i>\n");
if(it.hasNext())
{
sb.append("<br>\n");
}
}
sb.append("</div>");
}
}
sb.append("</div>");
}// printOrderResultsForPower()
}// class ResultWriter