/*
* Copyright (c) 2009 Tom Parker <thpr@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package plugin.converter;
import java.util.ArrayList;
import java.util.List;
import pcgen.base.lang.StringUtil;
import pcgen.cdom.base.CDOMObject;
import pcgen.gui2.converter.event.TokenProcessEvent;
import pcgen.gui2.converter.event.TokenProcessorPlugin;
import pcgen.rules.persistence.token.AbstractPreEqualConvertPlugin;
public class PreVisionInvertedConvertPlugin implements TokenProcessorPlugin
{
public static final String SET_ANY = "Set unspecified values to ANY (identify as 'present')";
public static final String SET_ZERO_ANY = "Set zero values to ANY (identify as 'present')";
public static final String SET_ZERO_ONE = "Set zero values to 1 (identify as 'possessing distance')";
@Override
public String process(TokenProcessEvent tpe)
{
String formula = tpe.getValue();
int commaLoc = formula.indexOf(',');
if (commaLoc == -1)
{
return "Prerequisite " + tpe.getKey() + " must have a count: "
+ formula;
}
if (commaLoc == formula.length() - 1)
{
return "Prerequisite " + tpe.getKey()
+ " can not have only a count: " + formula;
}
String num = formula.substring(0, commaLoc);
String rest = formula.substring(commaLoc + 1);
try
{
Integer.parseInt(num);
}
catch (NumberFormatException nfe)
{
return "'" + num + "' in " + tpe.getKey()
+ " is not a valid integer";
}
// Work rest here:
commaLoc = rest.indexOf(',');
if (commaLoc == -1)
{
// Unambiguous for y=z, now test for y or y=0
int equalLoc = rest.indexOf('=');
if (equalLoc == -1)
{
// No equals
tpe.append(getPrefix(tpe, num));
tpe.append(rest);
tpe.append("=ANY");
}
else
{
processZero(formula, tpe, num, rest);
}
}
else
{
String[] strings = rest.split(",");
int withEquals = 0;
boolean withoutEquals = false;
boolean lastWithEquals = false;
List<String> list = new ArrayList<>();
for (String tok : strings)
{
int equalLoc = tok.indexOf('=');
if (equalLoc == -1)
{
withoutEquals = true;
lastWithEquals = false;
}
else
{
withEquals++;
lastWithEquals = true;
}
list.add(tok);
}
if (withEquals == 1 && lastWithEquals)
{
// Propagate item to all...
String last = strings[strings.length - 1];
int eqLoc = last.indexOf('=');
String equal = last.substring(eqLoc + 1);
tpe.append(getPrefix(tpe, num));
tpe.append(StringUtil.join(list, "=" + equal + ","));
}
else if (withEquals > 0 && withoutEquals)
{
StringBuilder onebase = new StringBuilder();
StringBuilder leftbase = new StringBuilder();
StringBuilder rightbase = new StringBuilder();
boolean needComma = false;
Integer lastValue = null;
for (int i = 0; i < strings.length; i++)
{
if (needComma)
{
onebase.append(',');
leftbase.append(',');
rightbase.append(',');
}
needComma = true;
String tok = strings[i];
int equalLoc = tok.indexOf('=');
onebase.append(tok);
leftbase.append(tok);
rightbase.append(tok);
if (equalLoc == -1)
{
onebase.append("=ANY");
leftbase.append('=');
if (lastValue == null)
{
leftbase.append("ANY");
}
else
{
leftbase.append(lastValue);
}
rightbase.append('=');
rightbase.append(getNextValue(strings, i));
}
else
{
lastValue = Integer.decode(tok.substring(equalLoc + 1));
}
}
List<String> descr = new ArrayList<>();
List<String> choice = new ArrayList<>();
processChoices(tpe, num, descr, choice, onebase.toString(),
SET_ANY);
processChoices(tpe, num, descr, choice, rightbase.toString(),
AbstractPreEqualConvertPlugin.FLOW_LEFT);
processChoices(tpe, num, descr, choice, leftbase.toString(),
AbstractPreEqualConvertPlugin.FLOW_RIGHT);
String result = null;
boolean match = true;
for (String c : choice)
{
if (result == null)
{
result = c;
}
else if (!result.equals(c))
{
match = false;
break;
}
}
if (match)
{
tpe.append(result);
}
else
{
String decision = tpe.getDecider().getConversionDecision(
"Resolve ambiguity for " + getProcessedToken()
+ ":" + formula, descr, choice, 0);
tpe.append(decision);
}
}
else if (withEquals > 0) // && !withoutEquals
{
processZero(formula, tpe, num, strings);
}
else if (withoutEquals) // && withEquals == 0
{
tpe.append(getPrefix(tpe, num));
tpe.append(StringUtil.join(list, "=ANY,"));
tpe.append("=ANY");
}
}
tpe.consume();
return null;
}
private void processChoices(TokenProcessEvent tpe, String num,
List<String> descr, List<String> choice, String leftbaseResult,
String d)
{
List<String> leftChoices = createZeroChoices(tpe, num, leftbaseResult
.split(","));
if (leftChoices.get(0).equals(leftChoices.get(1)))
{
descr.add(leftbaseResult + " ... " + d);
choice.add(leftbaseResult);
}
else
{
descr
.add(leftChoices.get(0) + " ... " + d + " and "
+ SET_ZERO_ONE);
choice.add(leftChoices.get(0));
descr
.add(leftChoices.get(1) + " ... " + d + " and "
+ SET_ZERO_ANY);
choice.add(leftChoices.get(1));
}
}
private void processZero(String formula, TokenProcessEvent tpe, String num,
String... base)
{
List<String> choice = createZeroChoices(tpe, num, base);
String oneChoice = choice.get(0);
String zeroChoice = choice.get(1);
if (oneChoice.equals(zeroChoice))
{
tpe.append(oneChoice);
}
else
{
List<String> descr = new ArrayList<>();
descr.add(oneChoice + " ... " + SET_ZERO_ONE);
descr.add(zeroChoice + " ... " + SET_ZERO_ANY);
String decision = tpe.getDecider().getConversionDecision(
"Resolve ambiguity for " + getProcessedToken() + ":" + formula,
descr, choice, 0);
tpe.append(decision);
}
}
private List<String> createZeroChoices(TokenProcessEvent tpe, String num,
String... base)
{
StringBuilder one = getPrefix(tpe, num);
StringBuilder any = getPrefix(tpe, num);
boolean needComma = false;
for (int i = 0; i < base.length; i++)
{
String tok = base[i];
// need to check zero...
int equalLoc = tok.indexOf('=');
String target = tok.substring(equalLoc + 1);
if (needComma)
{
one.append(',');
any.append(',');
}
needComma = true;
if (!"ANY".equals(target) && Integer.parseInt(target) == 0)
{
String start = tok.substring(0, equalLoc);
one.append(start);
any.append(start);
one.append("=1");
any.append("=ANY");
}
else
{
one.append(tok);
any.append(tok);
}
}
String oneResult = one.toString();
String anyResult = any.toString();
List<String> choice = new ArrayList<>();
choice.add(oneResult);
choice.add(anyResult);
return choice;
}
private StringBuilder getPrefix(TokenProcessEvent tpe, String num)
{
StringBuilder sb = new StringBuilder();
sb.append(tpe.getKey());
sb.append(':');
sb.append(num);
sb.append(',');
return sb;
}
private String getNextValue(String[] strings, int i)
{
for (int j = i + 1; j < strings.length; j++)
{
String tok = strings[j];
int equalLoc = tok.indexOf('=');
if (equalLoc != -1)
{
return tok.substring(equalLoc + 1);
}
}
return "ANY";
}
@Override
public Class<? extends CDOMObject> getProcessedClass()
{
return CDOMObject.class;
}
@Override
public String getProcessedToken()
{
return "!PREVISION";
}
}