de.rpgframework.genericrpg.data.ComplexDataItemValue Maven / Gradle / Ivy
The newest version!
package de.rpgframework.genericrpg.data;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.UUID;
import org.prelle.simplepersist.Attribute;
import org.prelle.simplepersist.ElementList;
import de.rpgframework.genericrpg.ModifyableNumericalValue;
import de.rpgframework.genericrpg.NumericalValue;
import de.rpgframework.genericrpg.Pool;
import de.rpgframework.genericrpg.modification.Modification;
import de.rpgframework.genericrpg.modification.ModifiedObjectType;
import de.rpgframework.genericrpg.modification.RelevanceModification;
/**
* @author prelle
*
*/
public class ComplexDataItemValue extends DataItemValue implements NumericalValue, DecisionContainer {
private final static Logger logger = System.getLogger(ComplexDataItemValue.class.getPackageName());
@ElementList(entry = "decision", type = Decision.class, inline = true)
protected List decisions;
/** Optional flags added by the user, like "Cheap knock off" */
@ElementList(entry = "flag", type = String.class, inline = true)
protected List flags;
@Attribute
protected UUID uuid;
/** Flags added automatically by item */
protected transient List autoFlags;
/**
* This is calculated by RPG implementations to follow their
* rules on limits and how things interoperate
*/
private transient Pool pool;
//-------------------------------------------------------------------
public ComplexDataItemValue() {
decisions = new ArrayList<>();
flags = new ArrayList<>();
autoFlags = new ArrayList<>();
}
//-------------------------------------------------------------------
public ComplexDataItemValue(T data) {
this();
if (data.getId()==null) throw new IllegalArgumentException("Resolved's getId() returns NULL");
this.ref = data.getId();
this.resolved = data;
}
//-------------------------------------------------------------------
public ComplexDataItemValue(T data, int val) {
this(data);
if (data.getId()==null) throw new IllegalArgumentException("Resolved's getId() returns NULL");
this.ref = data.getId();
value = val;
}
//-------------------------------------------------------------------
/**
* If the referenced ComplexDataItem had choices, these are the
* decisions.
*/
public List getDecisions() {
return decisions;
}
//-------------------------------------------------------------------
public Decision[] getDecisionArray() {
Decision[] ret = new Decision[decisions.size()];
return decisions.toArray(ret);
}
//-------------------------------------------------------------------
public void addDecision(Decision value) {
for (Decision dec : decisions) {
if (dec.getChoiceUUID().equals(value.getChoiceUUID()))
return;
}
decisions.add(value);
}
//-------------------------------------------------------------------
public void removeDecision(Decision value) {
removeDecision(value.getChoiceUUID());
}
//-------------------------------------------------------------------
@Override
public void removeDecision(UUID choiceUUID) {
for (Decision dec : decisions) {
if (dec.getChoiceUUID().equals(choiceUUID)) {
decisions.remove(dec);
return;
}
}
}
//-------------------------------------------------------------------
@Override
public Decision getDecision(UUID uuid) {
for (Decision dec : decisions) {
if (dec==null) continue;
if (dec.getChoiceUUID().equals(uuid)) {
return dec;
}
}
return null;
}
//-------------------------------------------------------------------
public Decision getDecisionByRef(String name) {
for (Decision dec : decisions) {
Choice choice = getResolved().getChoice(dec.getChoiceUUID());
if (choice!=null && choice.getTypeReference()!=null && choice.getTypeReference().equals(name)) {
return dec;
}
}
return null;
}
//-------------------------------------------------------------------
public Decision getDecisionByType(ModifiedObjectType type) {
for (Decision dec : decisions) {
Choice choice = getResolved().getChoice(dec.getChoiceUUID());
if (choice!=null && choice.getChooseFrom()!=null && choice.getChooseFrom()==type) {
return dec;
}
}
return null;
}
//-------------------------------------------------------------------
public void updateDecision(UUID uuid, String value) {
for (Decision dec : decisions) {
if (dec.getChoiceUUID().equals(uuid)) {
dec.setValue(value);
return;
}
}
throw new NoSuchElementException(uuid+" not in "+decisions);
}
//-------------------------------------------------------------------
public String getDecisionString(Locale loc) {
return getDecisionString(loc, character);
}
//-------------------------------------------------------------------
public String getPerDecisionString(Choice choice, Object obj, Decision dec, Locale loc) {
DataItem item = null;
DataItemValue> itemV = null;
if (obj instanceof DataItem) {
item = (DataItem)obj;
} else if (obj instanceof DataItemValue) {
itemV = (DataItemValue>)obj;
} else if (obj instanceof String) {
return (String)obj;
} else if (obj!=null) {
try {
Method getName = obj.getClass().getMethod("getName", Locale.class);
return String.valueOf( getName.invoke(obj, loc) );
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// If there are sub-choices, add them
if (choice.getSubOptions() != null && !choice.getSubOptions().isEmpty()) {
return (resolved.getChoiceOptionStrings(choice, choice.getSubOption(dec.getValue()), loc)[0]);
} else {
if (item!=null) {
return item.getName(loc);
} else if (itemV!=null) {
return itemV.getNameWithoutRating(loc);
} else if (obj instanceof IAttribute) {
return ((IAttribute)obj).getName(loc);
} else {
return dec.getValue();
}
}
}
//-------------------------------------------------------------------
public String getDecisionString(Locale loc, CommonCharacter, ?, ?, ?> model) {
List elem = new ArrayList<>();
try {
if (resolved!=null) {
/*
* Initialize a list of all choices, recursive too and initialize
* it with the the high level choices
*/
Map allChoices = getChoiceMapRecursivly(model);
for (Decision dec : decisions) {
if (logger.isLoggable(Level.TRACE))
logger.log(Level.TRACE, "getDecisionString: dec="+dec);
Choice choice = allChoices.get(dec.getChoiceUUID());
if (choice==null) {
choice = resolved.getHardcodedChoice(dec.getChoiceUUID());
}
// if ("standard".equals(dec.getValue().toLowerCase()))
// continue;
if (choice==null) {
if (!dec.getChoiceUUID().toString().equals("c2d17c87-1cfe-4355-9877-a20fe09c170d")) {
logger.log(Level.WARNING, "No choice found for decision "+dec+" of "+this);
}
elem.add(dec.getValue());
continue;
}
try {
// Determine the selction result
Object obj = null;
if (choice.getChooseFrom().toString().equals("SUBSELECT")) {
obj = choice.getSubOption(dec.getValue());
} else if (choice.getChooseFrom().toString().equals("CARRIED")) {
if (model!=null) {
obj = model.getCarriedItem(dec.getValueAsUUID());
if (obj==null) {
logger.log(Level.ERROR, "Item {0} has a CARRIED decision {1} which is no known carried item in the character", getKey(), dec.getValue());
}
} else if (character!=null) {
obj = character.getCarriedItem(dec.getValueAsUUID());
if (obj==null) {
logger.log(Level.ERROR, "Item {0} has a CARRIED decision {1} which is no known carried item in the character", getKey(), dec.getValue());
}
} else {
logger.log(Level.ERROR, "Item {0} has a CARRIED decision {1}, but the character has not been given", getKey(), dec.getValue());
throw new RuntimeException("Cannot resolve CARRIED:"+dec.getValue()+" without character");
}
// Select a numeric rating for an attribute
//
// Select an enum value
//
} else if (choice.getChooseFrom().toString().equals("CONTACT")) {
continue; //model.getContact(dec.getValue());
} else if (choice.getTypeReference()!=null) {
if (choice.getTypeReference().equals("CHOICE")) {
obj = choice.getChooseFrom().resolve(dec.getValue());
} else {
// try {
// obj = choice.getChooseFrom().resolve(dec.getValue());
// } catch (ReferenceException e) {
// logger.log(Level.ERROR, "Error getting decision string",e);
// logger.log(Level.ERROR, "Error in object {0} for choice {1} with decision {2}", this, choice,dec);
// System.exit(1);
// }
if (obj==null)
obj = dec.getValue();
}
} else {
obj = choice.getChooseFrom().resolve(dec.getValue());
}
if (obj==null) {
System.err.println("Could not resolve "+dec.getValue()+" for choice "+choice);
}
// Add a string representation
String toAdd = getPerDecisionString(choice, obj, dec, loc);
elem.add(toAdd );
} catch (ReferenceException e) {
logger.log(Level.ERROR, "Error resolving ''{0}'' from instance of {1}: "+e.getMessage(), dec.getValue(), getModifyable());
}
}
} else {
logger.log(Level.ERROR, " is null");
}
if (elem.isEmpty()) return "";
return String.join(", ", elem);
} finally {
logger.log(Level.TRACE, "getDecisionString: {0}",elem);
}
}
//-------------------------------------------------------------------
private static void replaceOrAdd(StringBuffer haystack, String needle, String replace, List names) {
int from = haystack.indexOf("("+needle+")");
int to = from + needle.length()+2;
if (from>=0) {
haystack.replace(from, to, replace);
} else
names.add(replace);
}
//-------------------------------------------------------------------
public String getNameWithoutRating(Locale loc) {
StringBuffer ret = new StringBuffer(super.getNameWithoutRating(loc));
// if (decisions!=null && !decisions.isEmpty() && resolved!=null) {
// List names = new ArrayList<>();
// for (Decision dec : decisions) {
// Choice choice = resolved.getChoice(dec.getChoiceUUID());
// if (choice==null && resolved.hasLevel) {
//// names.add(dec.getValue());
// continue;
// }
// if (choice==null || choice.getChooseFrom()==null)
// continue;
// String needle = resolved.getChoiceName(choice, loc);
// Object brr = null;
// if ("CARRIED".equals(String.valueOf(choice.getChooseFrom()))) {
// brr = character.getCarriedItem(UUID.fromString(dec.getValue()));
// } else
// brr = choice.getChooseFrom().resolve(dec.getValue());
// if (brr instanceof DataItem) {
// replaceOrAdd(ret,needle, ((DataItem)brr).getName(loc), names);
// } else if (brr instanceof IItemAttribute) {
// replaceOrAdd(ret,needle, ((IItemAttribute)brr).getName(loc), names);
// } else if (brr instanceof IAttribute) {
// replaceOrAdd(ret,needle, ((IAttribute)brr).getName(loc), names);
// } else
// names.add( resolved.getChoiceName(choice, loc) );
// }
// if (!names.isEmpty()) {
// ret.append("(");
// ret.append(String.join(", ", names));
// ret.append(")");
// }
// }
return ret.toString();
}
//-------------------------------------------------------------------
public String getNameWithoutRating() {
return getNameWithoutRating(Locale.getDefault());
}
//-------------------------------------------------------------------
public String getNameWithRating(Locale loc) {
String decString = decisions.isEmpty()?"":getDecisionString(loc);
if (resolved==null)
return ref+" "+value+" "+decString;
if (decisions.isEmpty() && !resolved.getChoices().isEmpty()) {
decString = "Undecided";
}
if (value==0)
return resolved.getName(loc)+" "+decString;
return resolved.getName(loc)+" "+value+" "+decString;
}
//-------------------------------------------------------------------
/**
* Get the modifications this DataItemValue provides to others,
* after taking all decisions into account
*/
@SuppressWarnings("rawtypes")
public void updateOutgoingModificiations(CommonCharacter,?,?,?> model) {
outgoingModifications.clear();
for (Modification tmp : resolved.getOutgoingModifications()) {
if (tmp.getReferenceType()==null) {
if (!(tmp instanceof RelevanceModification))
logger.log(Level.WARNING, "{0} has a modification without type", this.getKey());
outgoingModifications.add(tmp);
} else {
if (this instanceof ModifyableNumericalValue) {
int lvl = ((ModifyableNumericalValue)this).getModifiedValue();
try {
Modification mod = tmp.getReferenceType().instantiateModification(tmp, this, lvl, model);
outgoingModifications.add(mod);
} catch (Exception e) {
logger.log(Level.ERROR, "Error instantiating mod "+tmp+" from "+tmp.getSource(),e);
}
} else {
Modification mod = tmp.getReferenceType().instantiateModification(tmp, this, getDistributed(), model);
if (mod==null) {
logger.log(Level.DEBUG, "No instantiated {0} will be returned", tmp);
} else {
outgoingModifications.add(mod);
}
}
}
}
for (Choice choice : resolved.getChoices()) {
if (choice.getSubOptions().isEmpty())
continue;
Decision dec = getDecision(choice.getUUID());
if (dec==null) continue;
ChoiceOption sub = choice.getSubOption(dec.getValue());
if (sub!=null) {
for (Modification tmp : sub.getOutgoingModifications()) {
if (tmp.getReferenceType()==null) {
if (!(tmp instanceof RelevanceModification))
logger.log(Level.WARNING, "{0} has a modification without type", this.getKey());
outgoingModifications.add(tmp);
} else {
if (this instanceof ModifyableNumericalValue) {
int lvl = ((ModifyableNumericalValue)this).getModifiedValue();
try {
Modification mod = tmp.getReferenceType().instantiateModification(tmp, this, lvl, model);
outgoingModifications.add(mod);
} catch (Exception e) {
logger.log(Level.ERROR, "Error instantiating mod "+tmp+" from "+tmp.getSource(),e);
}
} else {
Modification mod = tmp.getReferenceType().instantiateModification(tmp, this, getDistributed(), model);
if (mod==null) {
logger.log(Level.DEBUG, "No instantiated {0} will be returned", tmp);
} else {
outgoingModifications.add(mod);
}
}
}
}
}
}
}
//-------------------------------------------------------------------
public void addFlag(Enum> flag) {
if (!flags.contains(flag.name()))
flags.add(flag.name());
}
//-------------------------------------------------------------------
public void addAutoFlag(Enum> flag) {
if (!autoFlags.contains(flag.name()))
autoFlags.add(flag.name());
}
//-------------------------------------------------------------------
public void removeFlag(Enum> flag) {
flags.remove(flag.name());
}
//-------------------------------------------------------------------
public void removeAutoFlag(Enum> flag) {
autoFlags.remove(flag.name());
}
//-------------------------------------------------------------------
public void addAutoFlag(String flag) {
if (!autoFlags.contains(flag))
autoFlags.add(flag);
}
//-------------------------------------------------------------------
public void clearEmptyFlags() {
for (String tmp : new ArrayList<>(flags)) {
if (tmp==null || tmp.isBlank())
flags.remove(tmp);
}
}
//-------------------------------------------------------------------
public List getFlags(Class enumClass) {
List ret = new ArrayList<>();
outer:
for (String name : flags) {
inner:
for (E tmp : enumClass.getEnumConstants()) {
if (tmp.name().equals(name)) {
ret.add(tmp);
continue outer;
}
}
logger.log(Level.WARNING, "Unknown flag {0} in {1} for item {2}", name, enumClass,getKey());
}
return Collections.unmodifiableList(ret) ;
}
//-------------------------------------------------------------------
public List getAutoFlags(Class enumClass) {
List ret = new ArrayList<>();
outer:
for (String name : autoFlags) {
for (E tmp : enumClass.getEnumConstants()) {
if (tmp.name().equals(name)) {
ret.add(tmp);
continue outer;
}
}
logger.log(Level.WARNING, "Unknown flag {0} in class {1} for item {2}", name, enumClass,getKey());
}
return Collections.unmodifiableList(ret) ;
}
//-------------------------------------------------------------------
public boolean hasFlag(Enum> value) {
return flags.contains(value.name()) || autoFlags.contains(value.name());
}
//-------------------------------------------------------------------
public boolean hasFlag(String value) {
return flags.contains(value) || autoFlags.contains(value);
}
//-------------------------------------------------------------------
public void clearAutoFlags() {
autoFlags.clear();
}
//-------------------------------------------------------------------
public boolean hasAutoFlag(Enum> value) {
return autoFlags.contains(value.name());
}
//-------------------------------------------------------------------
public void setFlag(Enum> flag, boolean set) {
if (set) {
if (!flags.contains(flag.name()))
flags.add(flag.name());
} else {
flags.remove(flag.name());
}
}
//-------------------------------------------------------------------
public void setAutoFlag(Enum> flag, boolean set) {
if (set) {
if (!autoFlags.contains(flag.name()))
autoFlags.add(flag.name());
} else {
autoFlags.remove(flag.name());
}
}
//-------------------------------------------------------------------
public void setAutoFlag(String flag, boolean set) {
if (set) {
if (!autoFlags.contains(flag))
autoFlags.add(flag);
} else {
autoFlags.remove(flag);
}
}
//-------------------------------------------------------------------
public Map getChoiceMapRecursivly(CommonCharacter, ?, ?, ?> model) {
Map allChoices = new HashMap<>();
resolved.getChoices().forEach(c -> allChoices.put(c.getUUID(), c));
for (Decision dec : decisions) {
if (logger.isLoggable(Level.TRACE))
logger.log(Level.TRACE, "getDecisionString: dec="+dec);
Choice choice = allChoices.get(dec.getChoiceUUID());
if ("standard".equals(dec.getValue().toLowerCase()))
continue;
if (choice==null && resolved.hasLevel && dec.getChoiceUUID().toString().equals("c2d17c87-1cfe-4355-9877-a20fe09c170d")) {
continue;
}
if (choice==null) {
logger.log(Level.WARNING, "No choice found for decision "+dec+" of "+this);
continue;
}
try {
Object obj = null;
if ("CHOICE".equals(choice.getTypeReference())) {
if ("CARRIED".equals(String.valueOf(choice.getChooseFrom())) && model!=null) {
obj = model.getCarriedItem(UUID.fromString(dec.getValue()));
if (obj==null) {
logger.log(Level.ERROR, "No such CarriedItem {0} in character", dec.getValue());
}
} else {
obj = choice.getChooseFrom().resolve(dec.getValue());
}
} else {
if ("CARRIED".equals(String.valueOf(choice.getChooseFrom()))) {
if (model==null) {
logger.log(Level.ERROR, "Cannot resolve CARRIED:{0}, since model of {1} is NULL", dec.getValue(),this);
}
obj = model.getCarriedItem(UUID.fromString(dec.getValue()));
if (obj==null) {
logger.log(Level.ERROR, "No such CarriedItem {0} in character", dec.getValue());
}
} else {
// Select a numeric rating for an attribute
//
// Select an enum value
//
if (choice.getTypeReference()!=null) {
// Expect choice.getChooseFrom to be some kind of attribute or item reference
// Select a numeric rating for an attribute
if ("CARRIED".equals(String.valueOf(choice.getChooseFrom()))) {
if (model==null) {
logger.log(Level.ERROR, "Cannot resolve CARRIED:{0}, since model of {1} is NULL", dec.getValue(),this);
}
obj = model.getCarriedItem(UUID.fromString(dec.getValue()));
if (obj==null) {
logger.log(Level.ERROR, "No such CarriedItem {0} in character", dec.getValue());
}
} else {
obj = choice.getChooseFrom().resolve(choice.getTypeReference());
if (obj==null) {
logger.log(Level.DEBUG, "Failed to resolve {0} from {1} ", dec.getValue(), choice.getChooseFrom());
obj = choice.getChooseFrom().resolve(dec.getValue());
}
}
} else {
// Select an enum value
obj = choice.getChooseFrom().resolve(dec.getValue());
}
}
}
DataItem item = null;
if (obj instanceof DataItem) {
item = (DataItem)obj;
// item = choice.getChooseFrom().resolveAsDataItem(dec.getValue());
logger.log(Level.DEBUG, "resolved {0} to {1}", dec.getValue(), item);
if (item != null && item instanceof ComplexDataItem) {
// Add choices from resolved
logger.log(Level.DEBUG, "Choices from {0} are {1}", dec.getValue(),
((ComplexDataItem) item).getChoices());
((ComplexDataItem) item).getChoices().forEach(c -> {
logger.log(Level.DEBUG, "Add choice " + c + " for resolution");
allChoices.put(c.getUUID(), c);
});
}
} else if (obj instanceof DataItemValue) {
DataItemValue itemV = (DataItemValue)obj;
item = itemV.getResolved();
logger.log(Level.DEBUG, "resolved {0} to {1}", dec.getValue(), item);
if (itemV instanceof ComplexDataItemValue) {
allChoices.put(dec.getChoiceUUID(), choice);
}
}
} catch (Exception e) {
e.printStackTrace();
logger.log(Level.ERROR, "Failed resolving ''{0}'': {1}", dec.getValue(), e.toString());
}
}
return allChoices;
}
//-------------------------------------------------------------------
public UUID getUuid() {
return uuid;
}
//-------------------------------------------------------------------
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
//-------------------------------------------------------------------
/**
* Remove all incoming and outgoing modifications
*/
public void reset() {
clearIncomingModifications();
}
//-------------------------------------------------------------------
/**
* @see de.rpgframework.genericrpg.ModifyableNumericalValue#getPool()
*/
public Pool getPool() {
return pool;
}
//-------------------------------------------------------------------
public void setPool(Pool pool) {
this.pool = pool;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy