package de.lukasniemeier.mensa.parser; import android.content.Context; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.lukasniemeier.mensa.model.Mensa; import de.lukasniemeier.mensa.model.Menu; import de.lukasniemeier.mensa.model.WeeklyMenu; import de.lukasniemeier.mensa.utils.SerializableTime; import de.lukasniemeier.mensa.utils.Utils; /** * Created on 17.09.13. */ public class TodaysMenuParser extends WeeklyMenuParser { private static final String priceGroup = "Studierende"; private final Map<String, Collection<String>> alternativeNameMap; public TodaysMenuParser(Context context, Document page, Mensa mensa) { super(context, page, mensa); alternativeNameMap = new HashMap<String, Collection<String>>(); alternativeNameMap.put("Veganes Angebot", Arrays.asList("Veganes Essen")); } @Override protected SerializableTime parseDate(Element menuTable) { return Utils.today(); } @Override protected Menu parseMenu(WeeklyMenu weeklyMenu, Element menuTable) throws WeeklyMenuParseException { Menu menu = new Menu(weeklyMenu); Elements rows = menuTable.select("tr"); for (Element nameElement : rows.select("td.head")) { int index = nameElement.parent().children().indexOf(nameElement); Element nextParent = nameElement.parent().nextElementSibling(); if (nextParent == null) { throw new WeeklyMenuParseException("Expected parent for description"); } Element nextNextParent = nextParent.nextElementSibling(); if (nextParent == null) { throw new WeeklyMenuParseException("Expected description and meal type elements"); } Element descriptionElement = getChild(index, nextParent); Element mealTypesElement = getChild(index, nextNextParent); String name = nameElement.text(); String price = getPrice(menuTable.ownerDocument(), name); addMeal(menu, nameElement.text(), descriptionElement.text(), parseMealTypes(mealTypesElement), price); } return menu; } private String getPrice(Document document, String name) { String price = null; for (String alternativeName : getAlternativeNames(name)) { price = findPriceInDocument(document, alternativeName); if (price != null) { break; } } if (price == null) { price = getDefaultPrice(name); } return price; } private Collection<String> getAlternativeNames(String name) { Collection<String> names = alternativeNameMap.get(name); if (names == null) { names = new ArrayList<String>(1); } else { names = new ArrayList<String>(names); } // always add original name names.add(name); return names; } private String findPriceInDocument(Document document, String name) { String paragraphRegex = String.format("%s.*" + priceGroup + ":", name); Elements priceElements = document.select("p:matches(" + paragraphRegex + ")"); if (priceElements.size() == 1) { Pattern priceRegex = Pattern.compile(name + ".*?" + priceGroup + ": (\\d+,\\d+)", Pattern.DOTALL); Matcher match = priceRegex.matcher(priceElements.get(0).text()); if (match.find()) { return match.group(1); } } return null; } private Element getChild(int index, Element parent) throws WeeklyMenuParseException { if (parent.children().size() <= index) { throw new WeeklyMenuParseException("Expected element for description or meal types"); } return parent.child(index); } }