/*
* Copyright (c) 1998-2017 by Richard A. Wilkes. All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, version 2.0. If a copy of the MPL was not distributed with
* this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This Source Code Form is "Incompatible With Secondary Licenses", as
* defined by the Mozilla Public License, version 2.0.
*/
package com.trollworks.gcs.prereq;
import com.trollworks.gcs.character.GURPSCharacter;
import com.trollworks.gcs.criteria.IntegerCriteria;
import com.trollworks.gcs.criteria.NumericCompareType;
import com.trollworks.gcs.criteria.StringCompareType;
import com.trollworks.gcs.criteria.StringCriteria;
import com.trollworks.gcs.spell.Spell;
import com.trollworks.gcs.widgets.outline.ListRow;
import com.trollworks.toolkit.annotation.Localize;
import com.trollworks.toolkit.io.xml.XMLNodeType;
import com.trollworks.toolkit.io.xml.XMLReader;
import com.trollworks.toolkit.io.xml.XMLWriter;
import com.trollworks.toolkit.utility.Localization;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.HashSet;
/** A Spell prerequisite. */
public class SpellPrereq extends HasPrereq {
@Localize("spell")
@Localize(locale = "de", value = "Zauber")
@Localize(locale = "ru", value = "заклинание")
@Localize(locale = "es", value = "sortilegio")
private static String ONE_SPELL;
@Localize("spells")
@Localize(locale = "de", value = "Zauber")
@Localize(locale = "ru", value = "заклинания")
@Localize(locale = "es", value = "sortilegios")
private static String MULTIPLE_SPELLS;
@Localize("{0}{1} {2} {3} whose name {4}\n")
@Localize(locale = "de", value = "{0}{1} {2} {3}, deren/dessen Namen {4}\n")
@Localize(locale = "ru", value = "{0}{1} {2} {3} с названием {4}\n")
@Localize(locale = "es", value = "{0}{1} {2} {3}, cuyo nombre es {4}\n")
private static String WHOSE_NAME;
@Localize("{0}{1} {2} {3} of any kind\n")
@Localize(locale = "de", value = "{0}{1} {2} {3} jeglicher Art\n")
@Localize(locale = "ru", value = "{0}{1} {2} {3} любого вида\n ")
@Localize(locale = "es", value = "{0}{1} {2} {3} de cualquier tipo\n")
private static String OF_ANY_KIND;
@Localize("{0}{1} {2} {3} whose college {4}\n")
@Localize(locale = "de", value = "{0}{1} {2} {3}, deren/dessen Schule {4}\n")
@Localize(locale = "ru", value = "{0}{1} {2} {3} со школой {4}\n")
@Localize(locale = "es", value = "{0}{1} {2} {3} cuya escuela se llama {4}\n")
private static String WHOSE_COLLEGE;
@Localize("{0}{1} college count which {2}\n")
@Localize(locale = "de", value = "{0}{1} Zauber von {4} unterschiedlichen Schulen\n")
@Localize(locale = "ru", value = "{0}{1} заклинаний школы {2}\n")
@Localize(locale = "es", value = "{0}{1} Escuela que cuenta como {2}\n")
private static String COLLEGE_COUNT;
static {
Localization.initialize();
}
/** The XML tag for this class. */
public static final String TAG_ROOT = "spell_prereq"; //$NON-NLS-1$
/** The tag/type for name comparison. */
public static final String TAG_NAME = "name"; //$NON-NLS-1$
/** The tag/type for any. */
public static final String TAG_ANY = "any"; //$NON-NLS-1$
/** The tag/type for college name comparison. */
public static final String TAG_COLLEGE = "college"; //$NON-NLS-1$
/** The tag/type for college count comparison. */
public static final String TAG_COLLEGE_COUNT = "college_count"; //$NON-NLS-1$
private static final String TAG_QUANTITY = "quantity"; //$NON-NLS-1$
private static final String EMPTY = ""; //$NON-NLS-1$
private String mType;
private StringCriteria mStringCriteria;
private IntegerCriteria mQuantityCriteria;
/**
* Creates a new prerequisite.
*
* @param parent The owning prerequisite list, if any.
*/
public SpellPrereq(PrereqList parent) {
super(parent);
mType = TAG_NAME;
mStringCriteria = new StringCriteria(StringCompareType.IS, EMPTY);
mQuantityCriteria = new IntegerCriteria(NumericCompareType.AT_LEAST, 1);
}
/**
* Loads a prerequisite.
*
* @param parent The owning prerequisite list, if any.
* @param reader The XML reader to load from.
*/
public SpellPrereq(PrereqList parent, XMLReader reader) throws IOException {
this(parent);
String marker = reader.getMarker();
loadHasAttribute(reader);
do {
if (reader.next() == XMLNodeType.START_TAG) {
String name = reader.getName();
if (TAG_NAME.equals(name)) {
setType(TAG_NAME);
mStringCriteria.load(reader);
} else if (TAG_ANY.equals(name)) {
setType(TAG_ANY);
mQuantityCriteria.load(reader);
} else if (TAG_COLLEGE.equals(name)) {
setType(TAG_COLLEGE);
mStringCriteria.load(reader);
} else if (TAG_COLLEGE_COUNT.equals(name)) {
setType(TAG_COLLEGE_COUNT);
mQuantityCriteria.load(reader);
} else if (TAG_QUANTITY.equals(name)) {
mQuantityCriteria.load(reader);
} else {
reader.skipTag(name);
}
}
} while (reader.withinMarker(marker));
}
/**
* Creates a copy of the specified prerequisite.
*
* @param parent The owning prerequisite list, if any.
* @param prereq The prerequisite to clone.
*/
protected SpellPrereq(PrereqList parent, SpellPrereq prereq) {
super(parent, prereq);
mType = prereq.mType;
mStringCriteria = new StringCriteria(prereq.mStringCriteria);
mQuantityCriteria = new IntegerCriteria(prereq.mQuantityCriteria);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof SpellPrereq && super.equals(obj)) {
SpellPrereq sp = (SpellPrereq) obj;
return mType.equals(sp.mType) && mStringCriteria.equals(sp.mStringCriteria) && mQuantityCriteria.equals(sp.mQuantityCriteria);
}
return false;
}
@Override
public String getXMLTag() {
return TAG_ROOT;
}
@Override
public Prereq clone(PrereqList parent) {
return new SpellPrereq(parent, this);
}
@Override
public void save(XMLWriter out) {
out.startTag(TAG_ROOT);
saveHasAttribute(out);
out.finishTagEOL();
if (mType == TAG_NAME || mType == TAG_COLLEGE) {
mStringCriteria.save(out, mType);
if (mQuantityCriteria.getType() != NumericCompareType.AT_LEAST || mQuantityCriteria.getQualifier() != 1) {
mQuantityCriteria.save(out, TAG_QUANTITY);
}
} else if (mType == TAG_COLLEGE_COUNT) {
mQuantityCriteria.save(out, mType);
} else if (mType == TAG_ANY) {
out.startTag(TAG_ANY);
out.finishEmptyTagEOL();
mQuantityCriteria.save(out, TAG_QUANTITY);
}
out.endTagEOL(TAG_ROOT, true);
}
/** @return The type of comparison to make. */
public String getType() {
return mType;
}
/**
* @param type The type of comparison to make. Must be one of {@link #TAG_NAME},
* {@link #TAG_ANY}, {@link #TAG_COLLEGE}, or {@link #TAG_COLLEGE_COUNT}.
*/
public void setType(String type) {
if (type == TAG_NAME || type == TAG_COLLEGE || type == TAG_COLLEGE_COUNT || type == TAG_ANY) {
mType = type;
} else if (TAG_NAME.equals(type)) {
mType = TAG_NAME;
} else if (TAG_ANY.equals(type)) {
mType = TAG_ANY;
} else if (TAG_COLLEGE.equals(type)) {
mType = TAG_COLLEGE;
} else if (TAG_COLLEGE_COUNT.equals(type)) {
mType = TAG_COLLEGE_COUNT;
} else {
mType = TAG_NAME;
}
}
/** @return The string comparison object. */
public StringCriteria getStringCriteria() {
return mStringCriteria;
}
/** @return The quantity comparison object. */
public IntegerCriteria getQuantityCriteria() {
return mQuantityCriteria;
}
@Override
public boolean satisfied(GURPSCharacter character, ListRow exclude, StringBuilder builder, String prefix) {
HashSet<String> colleges = new HashSet<>();
String techLevel = null;
int count = 0;
boolean satisfied;
if (exclude instanceof Spell) {
techLevel = ((Spell) exclude).getTechLevel();
}
for (Spell spell : character.getSpellsIterator()) {
if (exclude != spell && spell.getPoints() > 0) {
boolean ok;
if (techLevel != null) {
String otherTL = spell.getTechLevel();
ok = otherTL == null || techLevel.equals(otherTL);
} else {
ok = true;
}
if (ok) {
if (mType == TAG_NAME) {
if (mStringCriteria.matches(spell.getName())) {
count++;
}
} else if (mType == TAG_ANY) {
count++;
} else if (mType == TAG_COLLEGE) {
if (mStringCriteria.matches(spell.getCollege())) {
count++;
}
} else if (mType == TAG_COLLEGE_COUNT) {
colleges.add(spell.getCollege());
}
}
}
}
if (mType == TAG_COLLEGE_COUNT) {
count = colleges.size();
}
satisfied = mQuantityCriteria.matches(count);
if (!has()) {
satisfied = !satisfied;
}
if (!satisfied && builder != null) {
if (mType == TAG_NAME) {
builder.append(MessageFormat.format(WHOSE_NAME, prefix, has() ? HAS : DOES_NOT_HAVE, mQuantityCriteria.toString(EMPTY), mQuantityCriteria.getQualifier() == 1 ? ONE_SPELL : MULTIPLE_SPELLS, mStringCriteria.toString()));
} else if (mType == TAG_ANY) {
builder.append(MessageFormat.format(OF_ANY_KIND, prefix, has() ? HAS : DOES_NOT_HAVE, mQuantityCriteria.toString(EMPTY), mQuantityCriteria.getQualifier() == 1 ? ONE_SPELL : MULTIPLE_SPELLS));
} else if (mType == TAG_COLLEGE) {
builder.append(MessageFormat.format(WHOSE_COLLEGE, prefix, has() ? HAS : DOES_NOT_HAVE, mQuantityCriteria.toString(EMPTY), mQuantityCriteria.getQualifier() == 1 ? ONE_SPELL : MULTIPLE_SPELLS, mStringCriteria.toString()));
} else if (mType == TAG_COLLEGE_COUNT) {
builder.append(MessageFormat.format(COLLEGE_COUNT, prefix, has() ? HAS : DOES_NOT_HAVE, mQuantityCriteria.toString()));
}
}
return satisfied;
}
@Override
public void fillWithNameableKeys(HashSet<String> set) {
if (mType != TAG_COLLEGE_COUNT) {
ListRow.extractNameables(set, mStringCriteria.getQualifier());
}
}
@Override
public void applyNameableKeys(HashMap<String, String> map) {
if (mType != TAG_COLLEGE_COUNT) {
mStringCriteria.setQualifier(ListRow.nameNameables(map, mStringCriteria.getQualifier()));
}
}
}