package com.tyndalehouse.step.core.data.processors; import java.util.List; import java.util.Locale; import org.apache.lucene.document.Document; import org.apache.lucene.document.Fieldable; import com.tyndalehouse.step.core.data.EntityConfiguration; import com.tyndalehouse.step.core.data.create.PostProcessor; /** * Cleanses strings in descriptions * * @author chrisburrell * */ @SuppressWarnings("PMD") public class MorphologyProcessor implements PostProcessor { private static final char SPACE_SEPARATOR = ' '; @Override public void process(final EntityConfiguration config, final Document doc) { cleanUp(config, doc); renderHtmlFragments(config, doc); } /** * Initialises the inline html * * @param config the entity configuration * @param doc document */ private void renderHtmlFragments(final EntityConfiguration config, final Document doc) { // initialise css initialiseCssClasses(config, doc); boolean openBracket = false; // now we can initialise the inline html final StringBuilder html = new StringBuilder(128); html.append("<span onclick='javascript:showDef(this)' "); html.append("title='"); final String function = doc.get("functionAbrev"); final String functionNotes = getFunctionNotes(function); if (function != null && functionNotes != null) { html.append(functionNotes); html.append(SPACE_SEPARATOR); } renderMood(doc, html); appendNonNullSpacedItem(html, doc.get("gender")); appendNonNullSpacedItem(html, doc.get("number")); openBracket = renderTense(doc, openBracket, html); openBracket = renderCase(doc, openBracket, html); closeBracket(openBracket, html); html.append("' class='"); html.append(doc.get("cssClasses")); html.append("'>"); renderParticiple(doc, html, function); html.append("</span>"); doc.add(config.getField("inlineHtml", html.toString())); } /** * Rends HTML for the participle * * @param doc the document from Lucene * @param html the HTML builder * @param function the function within this document */ private void renderParticiple(final Document doc, final StringBuilder html, final String function) { if ("Participle".equals(doc.get("mood"))) { html.append("Participle"); } else { html.append(getShortFunction(function)); } } /** * Renders HTML for the word case * * @param doc the document from Lucene * @param openBracket whether there is an open bracket * @param html the HTML builder * @return true if a bracket has been opened */ private boolean renderCase(final Document doc, final boolean openBracket, final StringBuilder html) { boolean originalOpenBracket = openBracket; final String wordCase = doc.get("case"); if (wordCase != null) { originalOpenBracket = openBracket(originalOpenBracket, html); html.append(wordCase); html.append(SPACE_SEPARATOR); } return originalOpenBracket; } /** * Renders HTML for the tense * * @param doc the document from Lucene * @param openBracket whether there is an open bracket * @param html the HTML builder * @return true if a bracket has been opened */ private boolean renderTense(final Document doc, final boolean openBracket, final StringBuilder html) { boolean originalOpenBracket = openBracket; final String tense = doc.get("tense"); if (tense != null) { originalOpenBracket = openBracket(originalOpenBracket, html); html.append(tense); html.append(SPACE_SEPARATOR); final String tenseNotes = getTenseNotes(tense); if (tenseNotes != null) { html.append(tenseNotes); html.append(SPACE_SEPARATOR); } } return originalOpenBracket; } /** * Renders HTML for the mood * * @param doc the document from Lucene * @param html the HTML builder */ private void renderMood(final Document doc, final StringBuilder html) { final String mood = doc.get("mood"); if ("Infinitive".equals(mood)) { html.append(mood); html.append(SPACE_SEPARATOR); } } /** * * @param tense the tense in question * @return if indeclinable, returns indeclinable */ private String getTenseNotes(final String tense) { if ("Indeclinable Numeral".equals(tense)) { return "Indeclinable"; } return null; } /** * @param function the function of the word * @return For pronouns, returns 'Pronoun', otherwise the function */ @SuppressWarnings("PMD") // CHECKSTYLE:OFF private String getShortFunction(final String function) { if ("Correlative pronoun".equals(function) || "Demonstrative pronoun".equals(function) || "Indeclinable Noun of Other type".equals(function) || "Indeclinable Proper Noun".equals(function) || "Indefinite pronoun".equals(function) || "Personal pronoun".equals(function) || "Posessive pronoun".equals(function) || "Reciprocal pronoun".equals(function) || "Reflexive pronoun".equals(function) || "Relative pronoun".equals(function)) { return "Pronoun"; } return function; } // CHECKSTYLE:ON /** * @param function the function * @return comments about the function */ @SuppressWarnings("PMD") private String getFunctionNotes(final String function) { if ("Correlative pronoun".equals(function)) { return "Correlative pronoun"; } if ("Demonstrative pronoun".equals(function)) { return "Demonstrative pronoun"; } if ("Indeclinable Noun of Other type".equals(function)) { return "Indeclinable noun"; } if ("Indeclinable Proper Noun".equals(function)) { return "Indeclinable proper noun"; } if ("Indefinite pronoun".equals(function)) { return "Indefinite pronoun"; } if ("Personal pronoun".equals(function)) { return "Personal pronoun"; } if ("Posessive pronoun".equals(function)) { return "Posessive pronoun"; } if ("Reciprocal pronoun".equals(function)) { return "Reciprocal pronoun"; } if ("Reflexive pronoun".equals(function)) { return "Reflexive pronoun"; } if ("Relative pronoun".equals(function)) { return "Relative pronoun"; } return null; } /** * closes the bracket * * @param openBracket indicates whether it was opened in the first place * @param html the html being built up */ private void closeBracket(final boolean openBracket, final StringBuilder html) { if (openBracket) { // trim last space off if (html.charAt(html.length() - 1) == ' ') { html.deleteCharAt(html.length() - 1); } html.append(")"); } } /** * opens a bracket safely * * @param openBracket the open brakcet * @param html the html that is being built up * @return true to indicate the bracket has not been opened - always returns true */ private boolean openBracket(final boolean openBracket, final StringBuilder html) { if (openBracket) { // append a comma html.append(","); html.append(SPACE_SEPARATOR); return true; } html.append("("); return true; } /** * initialises the css classes for the morphology item * * @param config the entity configuration * @param doc document */ private void initialiseCssClasses(final EntityConfiguration config, final Document doc) { final StringBuilder sb = new StringBuilder(10); final String number = doc.get("number"); if (number != null) { sb.append(getNumberCssClass(number)); sb.append(' '); } final String gender = doc.get("gender"); if (gender != null) { sb.append(getGenderCssClass(gender)); } doc.add(config.getField("cssClasses", sb.toString())); } /** * @param gender a given gender * @return its equivalent class, or a blank string */ private String getGenderCssClass(final String gender) { if ("Feminine".equals(gender)) { return "fem"; } if ("Masculine".equals(gender)) { return "mas"; } if ("Neuter".equals(gender)) { return "neut"; } return ""; } /** * @param number a given number * @return its equivalent css class, or a blank string */ private String getNumberCssClass(final String number) { if ("Singular".equals(number)) { return "sing"; } if ("Plural".equals(number)) { return "plur"; } return ""; } /** * adds an item with a space afterwards if the item is not null * * @param html the current content * @param item the item to add */ private void appendNonNullSpacedItem(final StringBuilder html, final Object item) { if (item != null) { html.append(item); html.append(SPACE_SEPARATOR); } } /** * Removes all quote marks from all fields ending in explained/description * * @param config the configuration for this entity * @param document the document that we are processing */ private void cleanUp(final EntityConfiguration config, final Document document) { // need to avoid concurrent modification to the list, so we copy over the names final List<Fieldable> fields = document.getFields(); final String[] fieldNames = new String[fields.size()]; for (int j = 0; j < fields.size(); j++) { fieldNames[j] = fields.get(j).name(); } for (final String field : fieldNames) { final String lowerName = field.toLowerCase(Locale.ENGLISH); if (lowerName.endsWith("explained") || lowerName.endsWith("description")) { cleanUp(config, document, field); } } } /** * Removes all quote marks from a single fields ending in explained/description * * @param config the configuration for this entity * @param document the document that we are processing * @param fieldName the name of the field */ private void cleanUp(final EntityConfiguration config, final Document document, final String fieldName) { final StringBuilder sb = new StringBuilder(document.get(fieldName)); for (int ii = 0; ii < sb.length();) { if (sb.charAt(ii) == '"') { sb.deleteCharAt(ii); } else { ii++; } } document.removeField(fieldName); document.add(config.getField(fieldName, sb.toString().trim())); } }