All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.rpgframework.genericrpg.data.GenericRPGTools Maven / Gradle / Ivy

package de.rpgframework.genericrpg.data;

import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.stream.Collectors;

import de.rpgframework.MultiLanguageResourceBundle;
import de.rpgframework.genericrpg.Datable;
import de.rpgframework.genericrpg.HistoryElement;
import de.rpgframework.genericrpg.Possible;
import de.rpgframework.genericrpg.Reward;
import de.rpgframework.genericrpg.ToDoElement;
import de.rpgframework.genericrpg.ToDoElement.Severity;
import de.rpgframework.genericrpg.items.PieceOfGear;
import de.rpgframework.genericrpg.items.PieceOfGearVariant;
import de.rpgframework.genericrpg.modification.DataItemModification;
import de.rpgframework.genericrpg.modification.Modification;
import de.rpgframework.genericrpg.modification.ModificationChoice;
import de.rpgframework.genericrpg.modification.ModifiedObjectType;
import de.rpgframework.genericrpg.modification.ValueModification;

/**
 * @author prelle
 *
 */
public class GenericRPGTools {

	public final static MultiLanguageResourceBundle RES = new MultiLanguageResourceBundle(GenericRPGTools.class.getName(), Locale.ENGLISH, Locale.GERMAN);

	private final static Logger logger = System.getLogger(GenericRPGTools.class.getPackageName());

	//-------------------------------------------------------------------
	public static List decisionToModifications(DataItemModification origMod, Choice choice, Decision dec) {
		if (origMod instanceof ValueModification) {
			return decisionToModifications((ValueModification)origMod, choice, dec);
		}
		if (origMod.getSource()==null) {
			System.getLogger(GenericRPGTools.class.getPackageName()).log(Level.WARNING, "No source for decision "+dec);
		}
		List ret = new ArrayList<>();
		ModifiedObjectType type = choice.getChooseFrom();
		for (String key : dec.getValues()) {
			DataItemModification newMod = new DataItemModification(type, key);
			newMod.setSource(origMod.getSource());
			newMod.setWhen(origMod.getWhen());
			newMod.setApplyTo(origMod.getApplyTo());
			newMod.setConditionString(origMod.getConditionString());
			ret.add(newMod);
			System.getLogger(GenericRPGTools.class.getPackageName()).log(Level.DEBUG, "-->"+newMod);
		}
		return ret;
	}

	//-------------------------------------------------------------------
	public static List decisionToModifications(ModificationChoice origMod, Decision dec) {
		if (origMod.getSource()==null) {
			System.getLogger(GenericRPGTools.class.getPackageName()).log(Level.WARNING, "No source for decision "+dec);
		}
		if (origMod.getUUID()==null)
			throw new IllegalArgumentException("No UUID in ModificationChoice "+origMod);
		if (dec.getChoiceUUID()==null)
			throw new IllegalArgumentException("No UUID in Decision "+dec);
		if (!dec.getChoiceUUID().equals(origMod.getUUID()))
			throw new IllegalArgumentException("Decision does not match ModificationChoice UUID");
		UUID needle = dec.getChoiceUUID();

		List ret = new ArrayList<>();
		for (Modification tmp : origMod) {
			if (!(tmp instanceof DataItemModification))
				continue;
			DataItemModification mod = (DataItemModification)tmp;
			if (needle.equals(mod.getId())) {
				ret.add(tmp);
			}
		}
		if (ret.isEmpty()) {
			System.getLogger(GenericRPGTools.class.getPackageName()).log(Level.WARNING, "No modification {0} found in  {1}", needle, origMod.getUUID());
		}
		return ret;
	}

	//-------------------------------------------------------------------
	public static DataItemModification getModificationFor(ComplexDataItem item, UUID choice) {
		for (Modification mod : item.getOutgoingModifications()) {
			if (mod instanceof DataItemModification) {
				DataItemModification dMod = (DataItemModification)mod;
				if (dMod.getConnectedChoice()!=null && dMod.getConnectedChoice().equals(choice)) {
					return dMod;
				}
			}
		}
		return null;
	}

	//-------------------------------------------------------------------
	public static List decisionToModifications(ValueModification origMod, Choice choice, Decision dec) {
		List ret = new ArrayList<>();

		ModifiedObjectType type = choice.getChooseFrom();
		for (String key : dec.getValues()) {
			ValueModification newMod = null;
			int value = origMod.getValue();
			int pos = key.indexOf(":");
			if (pos>0) {
				value = Integer.parseInt(key.substring(pos+1));
				key = key.substring(0, pos);
			}

			if (value!=0) {
				newMod = new ValueModification(type, key, value);
			} else if (choice.getDistribute()!=null && choice.getDistribute().length>0) {
				int idx = Arrays.asList(dec.getValues()).indexOf(key);
				value = choice.getDistribute()[idx];
				newMod = new ValueModification(type, key, value);
			}
			newMod.setSource(origMod.getSource());
			newMod.setWhen(origMod.getWhen());
			newMod.setSet(origMod.getSet());
			newMod.setApplyTo(origMod.getApplyTo());
			newMod.setConditionString(origMod.getConditionString());
			ret.add(newMod);
		}
		return ret;
	}

	//-------------------------------------------------------------------
	public static List convertChoiceToOptions(Choice choice) {
		List optionList = new ArrayList<>();
		if (choice.getChoiceOptions()==null) {
			optionList.addAll(List.of(choice.getChooseFrom().resolveAny()));
		} else if (choice.getRawChoiceOptions()!=null && choice.getRawChoiceOptions().contains(":")) {
				logger.log(Level.ERROR, "GENERIC "+choice.getChooseFrom()+" via "+choice.getRawChoiceOptions());
				String newType = choice.getRawChoiceOptions().substring(0, choice.getRawChoiceOptions().indexOf(":"));
				String newID = choice.getRawChoiceOptions().substring( choice.getRawChoiceOptions().indexOf(":")+1 );

				for (String tmp : newID.split(",")) {
					String newKey = newType+":"+tmp;
					Object[] data = choice.getChooseFrom().resolveVariable(newKey);
					if (data!=null) {
						optionList.addAll(List.of(data));
					}
				}
				logger.log(Level.DEBUG, "Convert ''{0}'' to {1} elements: {2}", choice.getRawChoiceOptions(), optionList.size(), optionList);
		} else {
			for (String tmp : choice.getChoiceOptions()) {
				// Detect variables (they are UPPERCASE)
				Object resolved = (tmp.indexOf(":")==-1) ? choice.getChooseFrom().resolve(tmp):null;
				if (resolved!=null) {
					optionList.add(resolved);
				} else {
					Object[] data = choice.getChooseFrom().resolveVariable(tmp);
					if (data!=null) {
						optionList.addAll(List.of(data));
					}
				}
			}
			logger.log(Level.DEBUG, "Convert ''{0}'' to {1} elements: {2}", Arrays.toString(choice.getChoiceOptions()), optionList.size(), optionList);
		}
		return optionList;
	}

	//-------------------------------------------------------------------
	public static List convertChoiceToOptions(ModificationChoice choice) {
		List optionList = new ArrayList<>();
		for (Modification tmp : choice) {
			if (tmp instanceof DataItemModification) {
				DataItemModification mod = (DataItemModification)tmp;
				Object resolved = mod.getReferenceType().resolve(mod.getKey());
				if (resolved!=null) {
					optionList.add(resolved);
				} else {
					Object[] data = choice.getReferenceType().resolveVariable(mod.getKey());
					if (data!=null) {
						optionList.addAll(List.of(data));
					}
				}
			}
		}
		return optionList;
	}

	//-------------------------------------------------------------------
	public static Decision getDecision(UUID choice, Decision[] decisions) {
		for (Decision dec : decisions) {
			if (dec.getChoiceUUID().equals(choice)) return dec;
		}
		return null;
	}

	//-------------------------------------------------------------------
	public static Possible areAllDecisionsPresent(ComplexDataItem model, Decision...decisions) {
		for (Choice choice : model.getChoices()) {
			boolean decisionMissing = true;
			for (Decision dec : decisions) {
				if (dec==null) continue;
				if (choice.getUUID().equals(dec.getChoiceUUID())) {
					decisionMissing = false;
					break;
				}
			}
			if (decisionMissing) {
				return new Possible(Severity.INFO, RES, "impossible.choiceMissing");
			}
		}

		return Possible.TRUE;
	}

	//-------------------------------------------------------------------
	public static Possible areAllDecisionsPresent(PieceOfGear model, String variantID, Decision...decisions) {
		for (Choice choice : model.getChoices()) {
			boolean decisionMissing = true;
			for (Decision dec : decisions) {
				if (dec==null) continue;
				if (choice.getUUID().equals(dec.getChoiceUUID())) {
					decisionMissing = false;
					// If necessary, compare choice options with decision value
					if (choice.getChoiceOptions()!=null) {
						boolean invalidOption = true;
						for (String opt : choice.getChoiceOptions()) {
							if (dec.getValue().equals(opt)) {
								invalidOption=false;
								break;
							}
						}
						if (invalidOption) {
							return new Possible( Severity.WARNING, RES, "impossible.invalidChoiceForOption", dec.getValue(), Arrays.toString(choice.getChoiceOptions()));
						}
					}
					break;
				}
			}
			if (decisionMissing) {
				return new Possible( Severity.WARNING, RES, "impossible.choiceMissing");
			}
		}

		if (variantID!=null) {
			PieceOfGearVariant variant = model.getVariant(variantID);
			if (variant==null) {
				return new Possible(Severity.STOPPER, RES, "impossible.invalidVariant");
			}

			for (Choice choice : variant.getChoices()) {
				boolean decisionMissing = true;
				for (Decision dec : decisions) {
					if (dec==null) continue;
					if (choice.getUUID().equals(dec.getChoiceUUID())) {
						decisionMissing = false;
						break;
					}
				}
				if (decisionMissing) {
					return new Possible(Severity.INFO, RES, "impossible.choiceMissing");
				}
			}
		}

		return Possible.TRUE;
	}

	//-------------------------------------------------------------------
	public static String getToDoString(List todos, Locale loc) {
		return String.join(", ", todos.stream().map(tmp -> tmp.getMessage(loc)).collect(Collectors.toList()));
	}

	//-------------------------------------------------------------------
	private static HistoryElement makeFromReward(CommonCharacter charac, Reward reward) {
		HistoryElement current = new HistoryElement();
		current.setName(reward.getTitle());
//		Adventure adv = null;
//		if (reward.getId()!=null) {
//			adv = sessServ.getAdventure(RoleplayingSystem.SHADOWRUN6, reward.getId());
//			if (adv==null) {
//				logger.warn("Rewards of character '"+charac.getName()+"' reference an unknown adventure: "+reward.getId());
//			}
//		}
		current.addGained(reward);
		return current;
	}

	//-------------------------------------------------------------------
	/**
	 * @param aggregate Aggregate history elements with same adventure
	 */
	public static List convertToHistoryElementList(CommonCharacter charac, boolean aggregate) {
		List ret = new ArrayList();

		if (charac.getRewards().isEmpty())
			return ret;

		// Initial reward
		logger.log(Level.DEBUG, "Sort "+charac.getRewards().size()+" rewards  and "+charac.getHistory().size()+" mods");

		charac.getRewards();
		Reward firstReward = (Reward) charac.getRewards().get(0);

		/*
		 * Build a merged list of rewards and modifications and sort it by time
		 */
		List rewardsAndMods = new ArrayList();
		rewardsAndMods.addAll(charac.getRewards());
		rewardsAndMods.remove(firstReward);
		for (DataItemModification mod : (List)charac.getHistory()) {
			rewardsAndMods.add(mod.clone());
		}
//		rewardsAndMods.addAll(charac.getHistory());
		logger.log(Level.TRACE, "Unsorted = "+rewardsAndMods);
		sort(rewardsAndMods);
		logger.log(Level.TRACE, "Sorted = "+rewardsAndMods);


//		ProductService sessServ = ProductServiceLoader.getInstance();
		/*
		 * Now build a list of HistoryElements. Start a new H
		 */
		HistoryElement current = makeFromReward(charac, firstReward);
		ret.add(current);

		for (Datable item : rewardsAndMods) {
			if (item instanceof Reward) {
				Reward reward = (Reward)item;
//				Adventure adv = null;
//				if (reward.getId()!=null) {
//					adv = sessServ.getAdventure(RoleplayingSystem.SHADOWRUN6, reward.getId());
//					if (adv==null) {
//						logger.log(Level.WARNING, "Rewards of character '"+charac.getName()+"' reference an unknown adventure: "+reward.getId());
//					}
//				}
//				// If is same adventure as current, keep same history element
//				if (!aggregate || !(adv!=null && current!=null && adv.getId().equals(current.getAdventureID())) ) {
				if (!aggregate ) {
					current = new HistoryElement();
					current.setName(reward.getTitle());
//					if (adv!=null) {
//						current.setName(adv.getTitle());
//						current.setAdventure(adv);
//					}
					ret.add(current);
				}
				current.addGained(reward);
			} else if (item instanceof DataItemModification) {
				if (current==null) {
					logger.log(Level.ERROR, "Failed preparing history: Exp spent on modification without previous reward");
				} else {
					current.addSpent( (DataItemModification)item);
				}
			} else {
				logger.log(Level.ERROR, "Don't know how to "+item);
			}
		}


		logger.log(Level.TRACE, "  return "+ret.size()+" elements");
		return ret;
	}

	//-------------------------------------------------------------------
	private static void sort(List rewardsAndMods) {
		Collections.sort(rewardsAndMods, new Comparator() {
			public int compare(Datable o1, Datable o2) {
				Long time1 = 0L;
				Long time2 = 0L;
				if (o1.getDate()!=null)	time1 = o1.getDate().getTime();
				if (o2.getDate()!=null)	time2 = o2.getDate().getTime();

				int cmp = time1.compareTo(time2);
				if (cmp==0) {
					if (o1 instanceof Reward && o2 instanceof Modification) return -1;
					if (o1 instanceof Modification && o2 instanceof Reward) return  1;
				}
				return cmp;
			}
		});
	}

}