package haven; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import static haven.Tempers.anm; import static haven.Tempers.rnm; public abstract class ItemFilter { private static final Pattern q = Pattern.compile("(?:(\\w+):)?([\\w\\*]+)(?:([<>=+~])(\\d+(?:\\.\\d+)?)?([<>=+~])?)?"); private static final Pattern float_p = Pattern.compile("(\\d+(?:\\.\\d+)?)"); public boolean matches(List<ItemInfo> info){ for(ItemInfo item : info){ if(item instanceof ItemInfo.Name){ if(match((ItemInfo.Name) item)){ return true;} } else if(item instanceof FoodInfo){ if(match((FoodInfo)item)){return true;} } else if(item instanceof Inspiration){ if(match((Inspiration)item)){return true;} } else if(item instanceof ItemInfo.Contents){ if(match((ItemInfo.Contents)item)){return true;} } else if(item instanceof Alchemy){ if(match((Alchemy)item)){return true;} } else if(item instanceof GobbleInfo){ if(match((GobbleInfo)item)){return true;} } } return false; } protected boolean match(ItemInfo.Contents item) { return false; } protected boolean match(Alchemy item) { return false; } protected boolean match(Inspiration item) { return false; } protected boolean match(GobbleInfo item) { return false; } protected boolean match(FoodInfo item) { return false; } protected boolean match(ItemInfo.Name item) { return false; } public static ItemFilter create(String query){ Compound result = new Compound(); Matcher m = q.matcher(query); while(m.find()){ String tag = m.group(1); String text = m.group(2).toLowerCase(); String sign = m.group(3); String value = m.group(4); String opt = m.group(5); ItemFilter filter = null; if(tag == null){ if(sign != null && text.equals("q")){ filter = new Alch(Alchemy.names[0], sign, value, opt); } else { filter = new Text(text, false); } } else { tag = tag.toLowerCase(); if(tag.equals("heal")){ filter = new Heal(text, sign, value, opt); } else if(tag.equals("gob")){ filter = new Gobble(text, sign, value, opt); } else if(tag.equals("txt")){ filter = new Text(text, true); } else if(tag.equals("xp")){ filter = new XP(text, sign, value, opt); } else if(tag.equals("has")){ filter = new Has(text, sign, value, opt); } else if(tag.equals("alch")){ filter = new Alch(text, sign, value, opt); } } if(filter != null){ result.add(filter); } } return result; } public static class Compound extends ItemFilter{ List<ItemFilter> filters = new LinkedList<ItemFilter>(); @Override public boolean matches(List<ItemInfo> info) { if(filters.isEmpty()){return false;} for(ItemFilter filter : filters){ if(!filter.matches(info)){return false;} } return true; } public void add(ItemFilter filter){ filters.add(filter); } } public static class Complex extends ItemFilter{ protected final String text; protected final Sign sign; protected final Sign opts; protected float value; protected final boolean all; protected final boolean any; public Complex(String text, String sign, String value, String opts){ this.text = text.toLowerCase(); this.sign = getSign(sign); this.opts = getSign(opts); float tmp = 0; try { tmp = Float.parseFloat(value); } catch (Exception ignored){} this.value = tmp; all = text.equals("*") || text.equals("all"); any = text.equals("any"); } protected boolean test(double actual, double target){ switch(sign){ case GREATER : return actual > target; case LESS : return actual <= target; case EQUAL : return actual == target; case GREQUAL : return actual >= target; default : return actual > 0; } } protected Sign getSign(String sign){ if(sign == null){ return getaDefaultSign(); } if(sign.equals(">")){ return Sign.GREATER; } else if(sign.equals("<")){ return Sign.LESS; } else if(sign.equals("=")) { return Sign.EQUAL; } else if(sign.equals("+")) { return Sign.GREQUAL; } else if(sign.equals("~")) { return Sign.WAVE; } else { return getaDefaultSign(); } } protected Sign getaDefaultSign() { return Sign.DEFAULT; } public static enum Sign {GREATER, LESS, EQUAL, GREQUAL, WAVE, DEFAULT} } public static class Heal extends Complex{ public Heal(String text, String sign, String value, String opts) { super(text, sign, value, opts); this.value = 1000*this.value; } @Override protected boolean match(FoodInfo item) { int[] tempers = item.tempers; if(all){ for(int k = 0; k < anm.length; k++){ if(!test(tempers[k], value)){return false;} } } else { for(int k = 0; k < anm.length; k++){ boolean enough = test(tempers[k], value); if((any || anm[k].equals(text)) && enough){return true;} if((any || rnm[k].toLowerCase().contains(text)) && enough){return true;} } } return false; } } public static class Gobble extends Complex { public Gobble(String text, String sign, String value, String opts) { super(text, sign, value, opts); this.value = 1000*this.value; } @Override protected boolean match(GobbleInfo item) { if (all) { for (int k = 0; k < anm.length; k++) { if (!test(getBile(item, k), value)) { return false; } } } else { for (int k = 0; k < anm.length; k++) { boolean enough = test(getBile(item, k), value); if ((any || anm[k].equals(text)) && enough) { return true; } if ((any || rnm[k].toLowerCase().contains(text)) && enough) { return true; } } } return false; } private int getBile(GobbleInfo item, int k) { int result; switch (opts) { case EQUAL: result = (item.h[k] + item.l[k]) / 2; break; case LESS: result = item.l[k]; break; case GREATER: default: result = item.h[k]; } return 100*(result/100); } } public static class Has extends Complex { public Has(String text, String sign, String value, String opts) { super(text, sign, value, opts); } @Override protected boolean match(ItemInfo.Contents item) { String name = this.name(item.sub).toLowerCase(); float num = count(name); return name.contains(text) && test(num, value); } @Override protected Sign getaDefaultSign() { return Sign.GREQUAL; } private float count(String txt){ float n = 0; if (txt != null) { try { Matcher matcher = float_p.matcher(txt); if(matcher.find()) { n = Float.parseFloat(matcher.group(1)); } } catch (Exception ignored){} } return n; } private String name(List<ItemInfo> sub) { String txt = null; for(ItemInfo subInfo : sub){ if(subInfo instanceof ItemInfo.Name){ ItemInfo.Name name = (ItemInfo.Name) subInfo; txt = name.str.text; } } return txt; } } public static class XP extends Complex { public XP(String text, String sign, String value, String opts) { super(text, sign, value, opts); } @Override protected boolean match(Inspiration item) { for(int k = 0; k<item.attrs.length; k++){ boolean enough = test(item.exp[k], value); if((any || item.attrs[k].equals(text)) && enough){return true;} if((any || CharWnd.attrnm.get(item.attrs[k]).toLowerCase().contains(text)) && enough){return true;} } return false; } } public static class Alch extends Complex { public Alch(String text, String sign, String value, String opts) { super(text, sign, value, opts); this.value = (int)(100*this.value); } @Override protected boolean match(Alchemy item) { for(int k = 0; k<item.a.length; k++){ boolean enough = test((int)(10000*item.a[k]), value); if((any || Alchemy.names[k].toLowerCase().equals(text)) && enough){return true;} } return false; } } public static class Text extends ItemFilter{ private String text; private final boolean full; public Text(String text, boolean full){ this.full = full; this.text = text.toLowerCase(); } public void update(String text){ this.text = text.toLowerCase(); } @Override protected boolean match(ItemInfo.Name item) { return item.str.text.toLowerCase().contains(text); } @Override protected boolean match(FoodInfo item) { if(!full){return false;} for(int k = 0; k < anm.length; k++){ boolean notEmpty = item.tempers[k] > 0; if(anm[k].equals(text) && notEmpty){return true;} if(rnm[k].toLowerCase().contains(text) && notEmpty){return true;} } return false; } @Override protected boolean match(GobbleInfo item) { if(!full){return false;} for(int k = 0; k < anm.length; k++){ if(anm[k].equals(text) && item.h[k] > 0){return true;} } for(int k = 0; k < rnm.length; k++){ if(rnm[k].toLowerCase().contains(text) && item.h[k] > 0){return true;} } return false; } @Override protected boolean match(Inspiration item) { if(!full){return false;} for(String attr : item.attrs){ if(attr.equals(text)){return true;} if(CharWnd.attrnm.get(attr).toLowerCase().contains(text)){return true;} } return false; } } }