diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java
index 5570b83ee6..7298b7e4bb 100644
--- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java
@@ -93,11 +93,12 @@ import com.raytheon.viz.warngen.gui.BackupData;
import com.raytheon.viz.warngen.gui.FollowupData;
import com.raytheon.viz.warngen.gui.WarngenLayer;
import com.raytheon.viz.warngen.gui.WarngenUIState;
+import com.raytheon.viz.warngen.text.WarningTextHandler;
+import com.raytheon.viz.warngen.text.WarningTextHandlerFactory;
import com.raytheon.viz.warngen.util.CurrentWarnings;
import com.raytheon.viz.warngen.util.FipsUtil;
import com.raytheon.viz.warngen.util.FollowUpUtil;
import com.raytheon.viz.warngen.util.WarnGenMathTool;
-import com.raytheon.viz.warngen.util.WarningTextHandler;
import com.raytheon.viz.warngen.util.WatchUtil;
import com.raytheon.viz.warngen.util.WeatherAdvisoryWatch;
import com.raytheon.viz.warnings.DateUtil;
@@ -126,7 +127,8 @@ import com.vividsolutions.jts.io.WKTReader;
* from appearing in 2nd and 3rd bullets when not necessary.
* Aug 13, 2012 14493 Qinglu Lin Handled MND time, event time, and TML time specially for COR to NEW.
* Aug 29, 2011 15351 jsanchez Set the timezone for TML time.
- * Sep 10, 2012 15295 snaples Added property setting for runtime log to createScript.
+ * Sep 10, 2012 15295 snaples Added property setting for runtime log to createScript.
+ * Sep 18, 2012 15332 jsanchez Used a new warning text handler.
*
*
* @author njensen
@@ -760,16 +762,19 @@ public class TemplateRunner {
System.out.println("velocity time: "
+ (System.currentTimeMillis() - tz0));
- return WarningTextHandler.handle(script.toString().toUpperCase(),
- areas, cancelareas, selectedAction,
- WarningAction.valueOf((String) context.get("action")),
- config.getAutoLockText());
+ String text = script.toString();
+ WarningTextHandler handler = WarningTextHandlerFactory.getHandler(
+ selectedAction, text, config.getAutoLockText());
+ String handledText = handler.handle(text, areas, cancelareas);
+
+ return handledText;
}
private static VelocityEngine ENGINE = new VelocityEngine();
private static synchronized String createScript(String vmFile,
- VelocityContext context, String site, String logDir) throws EdexException {
+ VelocityContext context, String site, String logDir)
+ throws EdexException {
StringWriter sw = new StringWriter();
try {
Properties p = new Properties();
@@ -780,8 +785,7 @@ public class TemplateRunner {
p.setProperty(
"velocimacro.permissions.allow.inline.to.replace.global",
"true");
- p.setProperty("runtime.log",
- FileUtil.join(logDir, "velocity.log"));
+ p.setProperty("runtime.log", FileUtil.join(logDir, "velocity.log"));
ENGINE.init(p);
context.put("scriptLibrary", "VM_global_library.vm");
Template template = ENGINE.getTemplate(vmFile,
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/AbstractLockingBehavior.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/AbstractLockingBehavior.java
new file mode 100644
index 0000000000..09ee425781
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/AbstractLockingBehavior.java
@@ -0,0 +1,357 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.raytheon.viz.texteditor.util.VtecObject;
+import com.raytheon.viz.texteditor.util.VtecUtil;
+import com.raytheon.viz.warngen.gis.AffectedAreas;
+
+/**
+ * Abstract class that locks certain text patterns in the warning text.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+abstract public class AbstractLockingBehavior implements ICommonPatterns {
+
+ /**
+ * Sorts in reverse order the areas based on the length of the name.
+ *
+ * @author jsanchez
+ *
+ */
+ private class AreaLockingComparator implements Comparator {
+
+ @Override
+ public int compare(AffectedAreas o1, AffectedAreas o2) {
+ Integer i1 = new Integer(o1.getName().length());
+ Integer i2 = new Integer(o2.getName().length());
+ return i2.compareTo(i1);
+ }
+
+ }
+
+ protected List affectedAreas;
+
+ protected String text;
+
+ protected static final String REPLACEMENT = LOCK_START + "$0" + LOCK_END;
+
+ protected String warningType = "(FLOOD ADVISORY)|(FLOOD WARNING)|(FLOOD STATEMENT)"
+ + "|(SEVERE WEATHER STATEMENT)|(EXTREME WIND WARNING)|(FIRE WARNING)"
+ + "|(FLASH FLOOD WARNING)|(FLASH FLOOD STATEMENT)|(SEVERE THUNDERSTORM WARNING)"
+ + "|(TORNADO WARNING)|(MARINE WEATHER STATEMENT)|(SHORT TERM FORECAST)"
+ + "|(SPECIAL WEATHER STATEMENT)|(SPECIAL MARINE WARNING)";
+
+ /**
+ * Locks the particular strings in the texts based on common patterns and
+ * the affected areas.
+ *
+ * @param text
+ * @param affectedAreas
+ * @param canceledAreas
+ * @return
+ */
+ public String lock(String text, AffectedAreas[] affectedAreas,
+ AffectedAreas[] canceledAreas) {
+ this.text = text;
+ intialize(affectedAreas, canceledAreas);
+ ugc();
+ htec();
+ vtec();
+ areaNames();
+ mnd();
+ date();
+ body();
+ callToActions();
+ latLon();
+ tml();
+ testMessages();
+ clean();
+
+ return this.text;
+ }
+
+ /**
+ * Calls the sub classes implementation of the body method.
+ */
+ abstract protected void body();
+
+ /**
+ * Adds the affect areas into the appropriate lists.
+ *
+ * @param affectedAreas
+ * @param canceledAreas
+ */
+ private void intialize(AffectedAreas[] affectedAreas,
+ AffectedAreas[] canceledAreas) {
+ AreaLockingComparator comparator = new AreaLockingComparator();
+
+ if (affectedAreas != null) {
+ this.affectedAreas = new ArrayList(
+ Arrays.asList(affectedAreas));
+ } else {
+ this.affectedAreas = new ArrayList(0);
+ }
+
+ if (canceledAreas != null) {
+ this.affectedAreas.addAll(Arrays.asList(canceledAreas));
+ }
+ Collections.sort(this.affectedAreas, comparator);
+ }
+
+ /**
+ * Locks the UGC line or FIPS line.
+ */
+ private void ugc() {
+ Pattern ugcPtrn = Pattern.compile(ugc + newline, Pattern.MULTILINE);
+ find(ugcPtrn.matcher(text));
+ }
+
+ /**
+ * Locks the HTEC line.
+ */
+ private void htec() {
+ // LOCK_END can be added at the start of the line if a previous line has
+ // been locked.
+ String htec = "^(("
+ + LOCK_END
+ + "){0,1}/[A-Za-z0-9]{5}.[0-3NU].\\w{2}.\\d{6}T\\d{4}Z.\\d{6}T\\d{4}Z.\\d{6}T\\d{4}Z.\\w{2}/"
+ + newline + ")";
+ Pattern htecPtrn = Pattern.compile(htec, Pattern.MULTILINE);
+ find(htecPtrn.matcher(text));
+ }
+
+ /**
+ * Locks the VTEC line.
+ */
+ private void vtec() {
+ // LOCK_END can be added at the start of the line if a previous line has
+ // been locked.
+ String vtec = "^(("
+ + LOCK_END
+ + "){0,1}/[OTEX]\\.([A-Z]{3})\\.[A-Za-z0-9]{4}\\.[A-Z]{2}\\.[WAYSFON]\\.\\d{4}\\.\\d{6}T\\d{4}Z-\\d{6}T\\d{4}Z/"
+ + newline + ")";
+ Pattern vtecPtrn = Pattern.compile(vtec, Pattern.MULTILINE);
+ find(vtecPtrn.matcher(text));
+ }
+
+ /**
+ * Locks the list of area names.
+ */
+ private void areaNames() {
+ find(listOfAreaNamePtrn.matcher(text));
+ }
+
+ /**
+ * Helper method to replace the found patterns.
+ *
+ * @param m
+ */
+ protected void find(Matcher m) {
+ if (m.find()) {
+ String group = m.group();
+ // If line already starts with a LOCK_END, the LOCK_END is removed
+ // and the line just adds to the LOCK_END at the end.
+ if (group.startsWith(LOCK_END)) {
+ this.text = text.replace(group,
+ group.substring(LOCK_END.length()) + LOCK_END);
+ } else {
+ this.text = m.replaceAll(LOCK_START + "$0" + LOCK_END);
+ }
+ }
+ }
+
+ /**
+ * This method locks the entire MND Header block.
+ */
+ private void mnd() {
+ int start = -1;
+ int end = -1;
+
+ StringBuffer mnd = new StringBuffer(
+ "(BULLETIN - IMMEDIATE BROADCAST REQUESTED)|(BULLETIN - EAS ACTIVATION REQUESTED)|"
+ + warningType);
+
+ Pattern startMND = Pattern.compile(mnd.toString());
+ Matcher m = startMND.matcher(text);
+ if (m.find()) {
+ start = m.start();
+ }
+
+ m = datePtrn.matcher(text);
+ if (m.find()) {
+ end = m.start();
+ }
+
+ if (start != -1 && end != -1 && start < end) {
+ String substring = text.substring(start, end);
+ // There should be only one instance of an MND Header block
+ this.text = text.replace(substring, LOCK_START + substring
+ + LOCK_END);
+ }
+ }
+
+ /**
+ * Locks the date.
+ */
+ private void date() {
+ find(datePtrn.matcher(text));
+ }
+
+ /**
+ * Locks the TIME...MOT...LINE (Can be multiple lines).
+ */
+ private void tml() {
+ // LOCK_END can be added at the start of the line if a previous line has
+ // been locked.
+ String tml = "^(("
+ + LOCK_END
+ + "){0,1}(TIME\\.\\.\\.MOT\\.\\.\\.LOC \\d{3,4}Z \\d{3}DEG \\d{1,3}KT(( \\d{3,4} \\d{3,5}){1,})(\\s*\\d{3,5} )*)\\s*"
+ + newline + ")";
+ Pattern tmlPtrn = Pattern.compile(tml, Pattern.MULTILINE);
+ find(tmlPtrn.matcher(text));
+ }
+
+ /**
+ * Locks the coordinates of the polygon.
+ */
+ private void latLon() {
+ // LOCK_END should not be found at the beginning of the LAT...LON since
+ // the previous line should be blank.
+ String latLon = "^((LAT\\.\\.\\.LON( \\d{3,4} \\d{3,5})+)" + newline
+ + ")(((\\s{5}( \\d{3,4} \\d{3,5})+)" + newline + ")+)?";
+ Pattern latLonPtrn = Pattern.compile(latLon, Pattern.MULTILINE);
+ find(latLonPtrn.matcher(text));
+ }
+
+ /**
+ * Locks the Call To Action header and the segment tags.
+ */
+ private void callToActions() {
+ // LOCK_END should not be found at the beginning since the previous line
+ // should be blank.
+ String precautionaryPtrn = "^(PRECAUTIONARY/PREPAREDNESS ACTIONS\\.\\.\\."
+ + newline + ")";
+ String ctaEndPtrn = "^(&&" + newline + ")";
+ String segmentPtrn = "^(\\$\\$" + newline + ")";
+ Pattern cta = Pattern.compile("(" + precautionaryPtrn + ")" + "|("
+ + ctaEndPtrn + ")" + "|(" + segmentPtrn + ")",
+ Pattern.MULTILINE);
+ find(cta.matcher(text));
+ }
+
+ /**
+ * Locks the test messages.
+ */
+ private void testMessages() {
+ String test1 = "THIS IS A TEST MESSAGE\\. DO NOT TAKE ACTION BASED ON THIS MESSAGE\\."
+ + newline;
+ String test2 = "THIS IS A TEST MESSAGE\\.";
+ String test3 = "\\.\\.\\.THIS MESSAGE IS FOR TEST PURPOSES ONLY\\.\\.\\."
+ + newline;
+ Pattern testPtrn = Pattern.compile("(" + test1 + ")|" + "(" + test2
+ + ")|" + "(" + test3 + ")");
+ find(testPtrn.matcher(text));
+ }
+
+ private void clean() {
+ // where a lock close and lock open are only separated by whitespace
+ // remove the close and open to join the two locked areas
+ text = text.replaceAll("([\\s\\n\\r]*)", "$1");
+ }
+
+ /**
+ * Returns true if this is a Marine Weather Statement and not a Standalone
+ * MWS. Standalone MWS do not have VTECs.
+ *
+ * @return
+ */
+ protected boolean isMarineProduct() {
+ VtecObject vtecObj = VtecUtil.parseMessage(text);
+ boolean marineProduct = vtecObj != null
+ && vtecObj.getPhenomena() != null
+ && vtecObj.getPhenomena().equals("MA");
+ return marineProduct;
+ }
+
+ /**
+ * Tests if the LOCK_START count matches the LOCK_END count.
+ *
+ * @return
+ */
+ public static boolean validate(String modified) {
+ int startCount = StringUtils.countMatches(modified, LOCK_START);
+ int endCount = StringUtils.countMatches(modified, LOCK_END);
+
+ return startCount == endCount;
+ }
+
+ /**
+ * Tests if the name has been locked already by the template to avoid
+ * stacked lock tags.
+ *
+ * @return
+ */
+ protected boolean hasBeenLocked(String line, String name) {
+ int index = line.indexOf(name);
+ if (index != -1) {
+ int startBefore = line.lastIndexOf(LOCK_START, index);
+ int endBefore = line.lastIndexOf(LOCK_END, index);
+ int startAfter = line.indexOf(LOCK_START, index);
+ int endAfter = line.indexOf(LOCK_END, index);
+
+ if (startBefore != -1 && endAfter != -1 && startBefore < endAfter) {
+ if (startAfter != -1 && startAfter < endAfter
+ && startAfter > startBefore) {
+ return false;
+ } else if (endBefore != -1 && endBefore > startBefore
+ && endBefore < endAfter) {
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/CorModifyTextBehavior.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/CorModifyTextBehavior.java
new file mode 100644
index 0000000000..eabfc88279
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/CorModifyTextBehavior.java
@@ -0,0 +1,68 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+/**
+ * Modifies the warning text by adding 'CORRECTED' in the MND header.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public class CorModifyTextBehavior implements IModifyTextBehavior {
+
+ private static final String[] types = new String[] { "WARNING", "WATCH",
+ "STATEMENT", "ADVISORY" };
+
+ private static final String correctedText = "...CORRECTED";
+
+ @Override
+ public String modify(String text) {
+ int index = text.indexOf("NATIONAL WEATHER SERVICE");
+
+ int typeIdx = -1, i = 0;
+ if (index > 0) {
+ for (i = 0; i < types.length; i++) {
+ if (text.lastIndexOf(types[i], index) != -1) {
+ typeIdx = text.lastIndexOf(types[i], index);
+ break;
+ }
+ }
+ }
+
+ if (index > 0 && typeIdx > 0 && !text.contains(correctedText)) {
+ text = text.substring(0, typeIdx + types[i].length())
+ + correctedText
+ + text.substring(typeIdx + types[i].length());
+ }
+
+ return text;
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/FollowUpLockingBehavior.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/FollowUpLockingBehavior.java
new file mode 100644
index 0000000000..d8ea2563d1
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/FollowUpLockingBehavior.java
@@ -0,0 +1,199 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.raytheon.viz.warngen.gis.AffectedAreas;
+
+/**
+ * Locks text patterns for follow up warnings.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public class FollowUpLockingBehavior extends AbstractLockingBehavior {
+ /**
+ * Locks the appropriate text of the body of an initial warning.
+ */
+ @Override
+ public void body() {
+ headlines();
+ }
+
+ /**
+ * Locks the cancel and the follow up headlines.
+ *
+ */
+ private void headlines() {
+ // LOCK_END should not be found at the beginning since the previous line
+ // should be blank.
+ Pattern headlinePtrn = Pattern
+ .compile(
+ "^\\.\\.\\.(A|THE) (.*) (WARNING|ADVISORY) .*(REMAINS|EXPIRE|CANCELLED).*(\\.\\.\\.)$",
+ Pattern.MULTILINE);
+ Matcher m = headlinePtrn.matcher(text);
+
+ while (m.find()) {
+ String originalHeadline = m.group();
+ String headline = headline(originalHeadline);
+ headline = remainsInEffect(headline);
+ headline = expired(headline);
+ headline = canceled(headline);
+ this.text = text.replace(originalHeadline, headline);
+ }
+ }
+
+ /**
+ * Locks the expired text.
+ */
+ private String expired(String followupHeadline) {
+ // Based on the templates, the expired text is for the affected areas
+ // not the canceled areas.
+ String expire = "(HAS BEEN ALLOWED TO EXPIRE)|(WILL BE ALLOWED TO EXPIRE)|(WILL EXPIRE)|(HAS EXPIRED)|EXPIRED";
+ String time = "AT \\d{3,4} (AM|PM) \\w{3,4}";
+ return followupHeadline.replaceAll(expire, REPLACEMENT).replaceAll(
+ time, REPLACEMENT);
+ }
+
+ /**
+ * Locks remains in effect text.
+ *
+ * @param followupHeadline
+ * @return
+ */
+ private String remainsInEffect(String followupHeadline) {
+ return followupHeadline.replaceFirst(
+ "REMAINS IN EFFECT UNTIL \\d{3,4} (AM|PM) \\w{3,4}", LOCK_START
+ + "$0" + LOCK_END);
+ }
+
+ /**
+ * Locks the canceled text.
+ *
+ * @param canceledHeadline
+ * @return
+ */
+ private String canceled(String canceledHeadline) {
+ return canceledHeadline.replaceAll("(IS|(HAS BEEN)) CANCELLED",
+ REPLACEMENT);
+ }
+
+ /**
+ * Helper method to lock area names and notations in the headline.
+ *
+ * @param headline
+ * @param areas
+ * @return
+ */
+ private String headline(String headline) {
+ Set notations = new HashSet();
+ Set names = new HashSet();
+
+ for (AffectedAreas affectedArea : affectedAreas) {
+ if (affectedArea.getAreaNotation() != null
+ && affectedArea.getAreaNotation().trim().length() != 0) {
+ notations.add(affectedArea.getAreaNotation().toUpperCase());
+ }
+
+ if (affectedArea.getAreasNotation() != null
+ && affectedArea.getAreasNotation().trim().length() != 0) {
+ notations.add(affectedArea.getAreasNotation().toUpperCase());
+ }
+
+ if (affectedArea.getName() != null
+ && affectedArea.getName().trim().length() != 0) {
+ names.add(affectedArea.getName().toUpperCase());
+ }
+ }
+
+ // Marine products follow different locking rules
+ if (!isMarineProduct()) {
+ headline = keywords(headline);
+ Iterator iterator1 = notations.iterator();
+ while (iterator1.hasNext()) {
+ String notation = iterator1.next();
+ if (!hasBeenLocked(headline, notation)) {
+ headline = headline.replace(notation, LOCK_START + notation
+ + LOCK_END);
+ }
+ }
+
+ Iterator iterator2 = names.iterator();
+ while (iterator2.hasNext()) {
+ String name = iterator2.next();
+ if (!hasBeenLocked(headline, name)) {
+ headline = headline.replace(name, LOCK_START + name
+ + LOCK_END);
+ }
+ }
+ } else {
+ // The full headline of a marine product should be locked.
+ headline = LOCK_START + headline + LOCK_END;
+ }
+
+ return headline;
+ }
+
+ /**
+ * Common key words to be locked in a headline.
+ *
+ * @param headline
+ * @return
+ */
+ private String keywords(String headline) {
+ // Locking the start of a head line (...)
+ headline = headline.replaceFirst("^\\.\\.\\.", LOCK_START + "$0"
+ + LOCK_END);
+ // Locking the end of a head line (...)
+ if (headline.endsWith("...")) {
+ headline = headline.substring(0, headline.length() - 3)
+ + LOCK_START + "..." + LOCK_END;
+ }
+ // Locks warning type (i.e. SEVERE THUNDERSTORM)
+ headline = headline.replaceAll("(A|THE) (" + warningType + ")",
+ LOCK_START + "$0" + LOCK_END);
+
+ // Locks the 'FOR' in the headline
+ headline = headline.replaceFirst(" FOR ", " " + LOCK_START + "FOR"
+ + LOCK_END + " ");
+
+ // Locks the 'AND' in the headline
+ headline = headline.replaceFirst(" AND ", " " + LOCK_START + "AND"
+ + LOCK_END + " ");
+
+ return headline;
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/ICommonPatterns.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/ICommonPatterns.java
new file mode 100644
index 0000000000..19e0c73761
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/ICommonPatterns.java
@@ -0,0 +1,73 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+import java.util.regex.Pattern;
+
+/**
+ * Common patterns.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public interface ICommonPatterns {
+
+ /** Start tag for locking */
+ public static final String LOCK_START = "";
+
+ /** End tag for locking */
+ public static final String LOCK_END = "";
+
+ public static final String newline = "\\n";
+
+ // LOCK_END should not be found at the beginning since the previous line
+ // should be blank.
+ public static final String ugc = "(^(\\w{2}[CZ]\\d{3}\\S*-\\d{6}-)$|((\\d{3}-)*\\d{6}-)$|((\\d{3}-)+))";
+
+ // LOCK_END can be added at the start of the line if a previous line has
+ // been locked.
+ public static Pattern listOfAreaNamePtrn = Pattern.compile("^((" + LOCK_END
+ + "){0,1}(((\\w+\\s{1})+\\w{2}-)*((\\w+\\s{1})+\\w{2}-))" + newline
+ + ")", Pattern.MULTILINE);
+
+ // LOCK_END should not be found at the beginning of a first bullet since the
+ // previous line should be blank.
+ public static final String firstBullet = "^(\\* (.*) (WARNING|ADVISORY)( FOR(.*)|\\.\\.\\.)"
+ + newline + ")";
+
+ // LOCK_END can be added at the start of the line if a previous line has
+ // been locked.
+ public static Pattern datePtrn = Pattern
+ .compile(
+ "^(("
+ + LOCK_END
+ + "){0,1}\\d{3,4} (AM|PM) (\\w{3,4}) \\w{3} (\\w{3})\\s+(\\d{1,2}) (\\d{4})"
+ + newline + ")", Pattern.MULTILINE);
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/IModifyTextBehavior.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/IModifyTextBehavior.java
new file mode 100644
index 0000000000..a304f349cb
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/IModifyTextBehavior.java
@@ -0,0 +1,40 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+/**
+ * Modifies the warning text based on a warning action.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15332 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public interface IModifyTextBehavior {
+ public String modify(String text);
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/InitialLockingBehavior.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/InitialLockingBehavior.java
new file mode 100644
index 0000000000..7967f89e72
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/InitialLockingBehavior.java
@@ -0,0 +1,219 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.raytheon.uf.common.dataplugin.warning.util.FileUtil;
+import com.raytheon.uf.common.status.IUFStatusHandler;
+import com.raytheon.uf.common.status.UFStatus;
+import com.raytheon.uf.common.status.UFStatus.Priority;
+import com.raytheon.viz.warngen.gis.AffectedAreas;
+
+/**
+ * Locks text patterns on initial or new warning.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public class InitialLockingBehavior extends AbstractLockingBehavior {
+ private static final transient IUFStatusHandler statusHandler = UFStatus
+ .getHandler(InitialLockingBehavior.class);
+
+ private static Pattern immediateCausePtrn = null;
+
+ /**
+ * Locks the appropriate text of the body of an initial warning.
+ */
+ @Override
+ public void body() {
+ header();
+ firstBullet();
+ secondBullet();
+ }
+
+ /**
+ * Helper method to determine the index of each bullet.
+ *
+ * @return
+ */
+ private Integer[] bulletIndices() {
+ List bulletIndices = new ArrayList();
+
+ int index = text.indexOf("* ");
+ while (index >= 0) {
+ bulletIndices.add(index);
+ index = text.indexOf("* ", index + 2);
+ }
+
+ return bulletIndices.toArray(new Integer[bulletIndices.size()]);
+ }
+
+ /**
+ * Locks the header before the first bullet.
+ */
+ private void header() {
+ // LOCK_END should not be found at the beginning since the previous line
+ // should be blank.
+ String h = "^((THE NATIONAL WEATHER SERVICE IN .{1,} HAS ISSUED A)"
+ + newline + ")$";
+ Pattern header = Pattern.compile(h, Pattern.MULTILINE);
+ find(header.matcher(text));
+ }
+
+ /**
+ * Locks the affected area names in the first bullet, the immediate cause.
+ *
+ * @param start
+ * @param end
+ */
+ private void firstBullet() {
+ Integer[] bulletIndices = bulletIndices();
+
+ // Short term forecasts don't follow normal bullets?
+ if (bulletIndices.length < 2) {
+ return;
+ }
+ int start = bulletIndices[0];
+ int end = bulletIndices[1];
+
+ if (immediateCausePtrn == null) {
+ immediateCausePtrn = getImmediateCausesPtrn();
+ }
+
+ String firstBulletText = text.substring(start, end);
+
+ // According to the original WarningTextHandler, marine zone names
+ // should not be locked. For some reason, this differs from followups as
+ // stated in DR 15110. Need verification from NWS. This is a variance?
+ if (!isMarineProduct()) {
+ Matcher m = null;
+ for (String line : firstBulletText.split("\\n")) {
+
+ if (immediateCausePtrn != null) {
+ // immediate cause
+ m = immediateCausePtrn.matcher(line);
+ if (m.find()) {
+ String i = line.replace(line, LOCK_START + line
+ + LOCK_END);
+ firstBulletText = firstBulletText.replace(line, i);
+ continue;
+ }
+ }
+
+ for (AffectedAreas affectedArea : affectedAreas) {
+ String name = affectedArea.getName();
+ String areaNotation = affectedArea.getAreaNotation();
+ String parentRegion = affectedArea.getParentRegion();
+ if (name != null && name.trim().length() != 0
+ && line.contains(name.toUpperCase())) {
+ name = name.toUpperCase();
+ String t = line;
+ if (!hasBeenLocked(line, name)) {
+ t = t.replace(name, LOCK_START + name + LOCK_END);
+ }
+
+ if (areaNotation != null
+ && areaNotation.trim().length() != 0) {
+ areaNotation = areaNotation.toUpperCase();
+ if (!hasBeenLocked(line, areaNotation.toUpperCase())) {
+ t = t.replace(areaNotation, LOCK_START
+ + areaNotation + LOCK_END);
+ }
+ }
+
+ if (parentRegion != null
+ && parentRegion.trim().length() != 0) {
+ parentRegion = parentRegion.toUpperCase();
+ if (!hasBeenLocked(line, parentRegion)) {
+ t = t.replace(parentRegion, LOCK_START
+ + parentRegion + LOCK_END);
+ }
+ }
+
+ if (validate(t)) {
+ firstBulletText = firstBulletText.replace(line, t);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ firstBulletText = firstBulletText.replaceAll(firstBullet, LOCK_START
+ + "$0" + LOCK_END);
+
+ this.text = text.replace(text.substring(start, end), firstBulletText);
+ }
+
+ /**
+ * Locks the second bullet.
+ */
+ private void secondBullet() {
+ // LOCK_END should not be found at the beginning since the previous line
+ // should be blank.
+ String secondBullet = "^(\\* UNTIL \\d{3,4} (AM|PM) \\w{3,4}" + newline
+ + ")";
+ Pattern secondBulletPtrn = Pattern.compile(secondBullet,
+ Pattern.MULTILINE);
+ find(secondBulletPtrn.matcher(text));
+ }
+
+ /**
+ * Set the immediateCausePtrn with the info in immediateCause.text.
+ */
+ private static Pattern getImmediateCausesPtrn() {
+ String filename = "immediateCause.txt";
+ StringBuffer pattern = new StringBuffer();
+
+ try {
+ String immediateCause = FileUtil.open(filename, "base");
+ pattern.append("(.*)(A DAM BREAK");
+ for (String ic : immediateCause.split("\n")) {
+ String[] parts = ic.split("\\\\");
+ pattern.append("| " + parts[1].trim());
+ }
+
+ pattern.append(")(.*)");
+ return Pattern.compile(pattern.toString());
+ } catch (Exception e) {
+ statusHandler
+ .handle(Priority.ERROR,
+ "Unable to process immediateCause.txt in the base directory",
+ e);
+ }
+
+ return null;
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/NewModifyTextBehavior.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/NewModifyTextBehavior.java
new file mode 100644
index 0000000000..818bb10d32
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/NewModifyTextBehavior.java
@@ -0,0 +1,62 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+import com.raytheon.uf.common.status.IUFStatusHandler;
+import com.raytheon.uf.common.status.UFStatus;
+import com.raytheon.uf.common.status.UFStatus.Priority;
+import com.raytheon.uf.viz.core.exception.VizException;
+import com.raytheon.viz.texteditor.util.VtecUtil;
+
+/**
+ * Updates the VTEC with a new ETN.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public class NewModifyTextBehavior implements IModifyTextBehavior {
+ private static final transient IUFStatusHandler statusHandler = UFStatus
+ .getHandler(NewModifyTextBehavior.class);
+
+ @Override
+ public String modify(String text) {
+ try {
+ text = VtecUtil.getVtec(text);
+ } catch (VizException e) {
+ statusHandler
+ .handle(Priority.SIGNIFICANT,
+ "WarnGen cannot update the ETN. Please verify the VTEC is valid.",
+ e);
+ }
+
+ return text;
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WarningTextHandler.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WarningTextHandler.java
new file mode 100644
index 0000000000..78c2193821
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WarningTextHandler.java
@@ -0,0 +1,137 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.raytheon.viz.warngen.gis.AffectedAreas;
+
+/**
+ * Handles the raw text message by applying locked text patterns, wrapping, etc.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public class WarningTextHandler {
+
+ private AbstractLockingBehavior lockingBehavior;
+
+ private IModifyTextBehavior modifyTextBehavior;
+
+ public String handle(String text, AffectedAreas[] affectedAreas,
+ AffectedAreas[] canceledAreas) {
+ long t0 = System.currentTimeMillis();
+
+ text = text.toUpperCase();
+
+ if (modifyTextBehavior != null) {
+ text = modifyTextBehavior.modify(text);
+ System.out.println("Modified text...");
+ }
+
+ if (lockingBehavior != null) {
+ text = lockingBehavior.lock(text, affectedAreas, canceledAreas);
+ System.out.println("Locked text...");
+ }
+
+ text = WrapUtil.wrap(text);
+ System.out.println("Wrapped text...");
+
+ text = clean(text);
+
+ System.out.println("Time to handle the text: "
+ + (System.currentTimeMillis() - t0));
+ return text;
+ }
+
+ /**
+ * Sets locking behavior
+ *
+ * @param lockingbehavior
+ */
+ public void setLockingBehavior(AbstractLockingBehavior lockingBehavior) {
+ this.lockingBehavior = lockingBehavior;
+ }
+
+ /**
+ * Sets the modify text behavior.
+ *
+ * @param modifyTextBehavior
+ */
+ public void setModifyTextBehavior(IModifyTextBehavior modifyTextBehavior) {
+ this.modifyTextBehavior = modifyTextBehavior;
+ }
+
+ private String clean(String text) {
+ text = removeExtraLines(text);
+ text = removeLockedBlankLines(text);
+ return text;
+ }
+
+ /**
+ * Removes blank extra lines.
+ *
+ * @param text
+ * @return
+ */
+ private String removeExtraLines(String text) {
+ StringBuffer sb = new StringBuffer();
+ String[] seperatedLines = text.replaceAll("\r", "").trim().split("\n");
+ boolean blankLine = false;
+ for (String line : seperatedLines) {
+ if (line.replace(AbstractLockingBehavior.LOCK_START, "")
+ .replace(AbstractLockingBehavior.LOCK_END, "").trim()
+ .length() > 0) {
+ sb.append(line + "\n");
+ blankLine = false;
+ } else if (blankLine == false) {
+ sb.append(line + "\n");
+ blankLine = true;
+ }
+ }
+
+ return sb.toString().trim();
+ }
+
+ /**
+ * Removes the locked blank lines.
+ *
+ * @param text
+ * @return
+ */
+ private String removeLockedBlankLines(String text) {
+ Pattern lockedBlankLinesPattern = Pattern.compile("(\\s*+)",
+ Pattern.MULTILINE);
+ Matcher matchLockedBlankLines = lockedBlankLinesPattern.matcher(text);
+ return matchLockedBlankLines.replaceAll("$1");
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WarningTextHandlerFactory.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WarningTextHandlerFactory.java
new file mode 100644
index 0000000000..beef381dbf
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WarningTextHandlerFactory.java
@@ -0,0 +1,85 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
+
+/**
+ * Returns a WarningTextHandler with the appropriate behaviors based on the type
+ * of warning is created.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public class WarningTextHandlerFactory {
+
+ public static WarningTextHandler getHandler(WarningAction action,
+ String text, boolean autoLock) {
+ WarningTextHandler handler = new WarningTextHandler();
+
+ if (action == WarningAction.NEW) {
+ handler.setModifyTextBehavior(new NewModifyTextBehavior());
+ } else if (action == WarningAction.COR) {
+ handler.setModifyTextBehavior(new CorModifyTextBehavior());
+ } else {
+ System.out.println("The text will not be updated based on action.");
+ handler.setModifyTextBehavior(null);
+ }
+
+ if (!autoLock) {
+ System.out.println("Config has autoLock set to 'false'");
+ handler.setLockingBehavior(null);
+ } else if (isInitialWarning(action, text)) {
+ handler.setLockingBehavior(new InitialLockingBehavior());
+ } else {
+ handler.setLockingBehavior(new FollowUpLockingBehavior());
+ }
+
+ return handler;
+ }
+
+ private static boolean isInitialWarning(WarningAction action, String text) {
+ if (action == WarningAction.NEW || action == WarningAction.EXT) {
+ return true;
+ } else if (action == WarningAction.COR) {
+ // TODO Need a better solution not to include the text in the
+ // factory.
+ Pattern firstBulletPtrn = Pattern
+ .compile(InitialLockingBehavior.firstBullet);
+ Matcher m = firstBulletPtrn.matcher(text);
+ return m.find();
+ }
+
+ return false;
+ }
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WrapUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WrapUtil.java
new file mode 100644
index 0000000000..aa6e2378c5
--- /dev/null
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/text/WrapUtil.java
@@ -0,0 +1,179 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.viz.warngen.text;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Wraps lines in the warning text that exceed the max width.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * Sep 24, 2012 15322 jsanchez Initial creation
+ *
+ *
+ *
+ * @author jsanchez
+ * @version 1.0
+ */
+public class WrapUtil implements ICommonPatterns {
+
+ /** Maximum width of a warning */
+ private static final int MAX_WIDTH = 69;
+
+ private static final String INDENT = " ";
+
+ private static final String BULLET_START = "* ";
+
+ private static final Pattern wrapUgcPtrn = Pattern.compile("(\\S{1,"
+ + (MAX_WIDTH - 1) + "}-)");
+
+ private static final Pattern wrapListOfNamesPtrn = Pattern.compile("(.{1,"
+ + (MAX_WIDTH - 4) + "} \\w{2}-)");
+
+ // Locations in 4th bullet or locations paragraph of followup
+ // ex: ellipsis, spaces, period
+ private static final Pattern wrapDefaultPtrn = Pattern
+ .compile("(\\w{1,}\\.\\.\\.)|(AND \\w+\\.\\.\\.)|(\\w+\\.\\.\\.\\s{1,2})|"
+ + "("
+ + LOCK_START
+ + "\\w+"
+ + LOCK_END
+ + "\\.\\.\\.)|\\S+\\.\\.\\."
+ + LOCK_END
+ + "|\\S+\\.\\.\\.|"
+ + "(\\s*\\S+\\s+)|(.+\\.)|(\\S+$)");
+
+ // ugc pattern
+ private static final Pattern ugcPtrn = Pattern.compile(ugc);
+
+ /**
+ * Wraps the text independent of being locked before or after.
+ *
+ * @param text
+ * @return
+ */
+ public static String wrap(String text) {
+ StringBuffer sb = new StringBuffer();
+
+ boolean inBullet = false;
+ String addLine = "";
+ String[] lines = text.split("\n");
+ for (int i = 0; i < lines.length; i++) {
+ String line = lines[i];
+ String unlocked = line.replaceAll(LOCK_START + "|" + LOCK_END, "");
+
+ if (unlocked.trim().length() == 0) { // BLANK LINE
+ inBullet = false;
+ addLine = line;
+ } else if (unlocked.length() <= MAX_WIDTH) { // LESS THAN MAX
+ // Add indenting if the template didn't account for it yet.
+ if (inBullet && !unlocked.startsWith(INDENT)) {
+ sb.append(INDENT);
+ }
+
+ if (unlocked.startsWith(BULLET_START)) {
+ inBullet = true;
+ }
+
+ addLine = line;
+ } else { // NEEDS TO BE WRAPPED
+ addLine = wrapLongLines(line, inBullet);
+ }
+
+ sb.append(addLine);
+ if (i != lines.length - 1) {
+ sb.append("\n");
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Wraps lines longer than the MAX WIDTH
+ *
+ * @param line
+ * @param inBullet
+ * @return
+ */
+ private static String wrapLongLines(String line, boolean inBullet) {
+ StringBuffer sb = new StringBuffer(line.length());
+ String unlockedLine = line.replaceAll(LOCK_START + "|" + LOCK_END, "");
+
+ if (unlockedLine.startsWith(BULLET_START)) {
+ inBullet = true;
+ }
+
+ Pattern p = getPattern(line);
+ Matcher m = p.matcher(line.trim());
+ String tmp = inBullet && !unlockedLine.startsWith(BULLET_START) ? INDENT
+ : "";
+
+ while (m.find()) {
+ String group = m.group();
+ String unlocked = group.replaceAll(LOCK_START + "|" + LOCK_END, "");
+
+ int len = tmp.replaceAll(LOCK_START + "|" + LOCK_END, "").length();
+ if (len + unlocked.length() > MAX_WIDTH && tmp.trim().length() > 0) {
+ sb.append(tmp + "\n");
+ tmp = inBullet ? INDENT : "";
+ tmp += group;
+ } else {
+ tmp += group;
+ }
+ }
+
+ if (tmp.trim().length() > 0) {
+ sb.append(tmp);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to return matcher object for wrapping text.
+ *
+ * @param line
+ * @return
+ */
+ private static Pattern getPattern(String line) {
+
+ Matcher m = ugcPtrn.matcher(line);
+ // UGC line or FIPS line
+ if (m.find()) {
+ return wrapUgcPtrn;
+ }
+
+ m = listOfAreaNamePtrn.matcher(line);
+ // List of area names.
+ if (m.find() && !line.startsWith(BULLET_START)) {
+ return wrapListOfNamesPtrn;
+ }
+
+ return wrapDefaultPtrn;
+ }
+
+}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/FollowUpUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/FollowUpUtil.java
index 83f84d051c..1912098865 100644
--- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/FollowUpUtil.java
+++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/FollowUpUtil.java
@@ -1,22 +1,3 @@
-/**
- * This software was developed and / or modified by Raytheon Company,
- * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
- *
- * U.S. EXPORT CONTROLLED TECHNICAL DATA
- * This software product contains export-restricted data whose
- * export/transfer/disclosure is restricted by U.S. law. Dissemination
- * to non-U.S. persons whether in the United States or abroad requires
- * an export license or other authorization.
- *
- * Contractor Name: Raytheon Company
- * Contractor Address: 6825 Pine Street, Suite 340
- * Mail Stop B8
- * Omaha, NE 68106
- * 402.291.0100
- *
- * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
- * further licensing information.
- **/
package com.raytheon.viz.warngen.util;
import java.util.ArrayList;
@@ -34,6 +15,7 @@ import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.viz.warngen.gis.AffectedAreas;
import com.raytheon.viz.warngen.gis.GisUtil;
import com.raytheon.viz.warngen.gis.GisUtil.Direction;
+import com.raytheon.viz.warngen.text.ICommonPatterns;
/**
* This utility will provide methods for determining what followup products are
@@ -64,8 +46,9 @@ public class FollowUpUtil {
* This method checks whether a particular followup should be available
* given a Warning Record, a vtec Action, and a template configuration
*/
- public static boolean checkApplicable(String site, WarngenConfiguration config,
- AbstractWarningRecord record, WarningAction action) {
+ public static boolean checkApplicable(String site,
+ WarngenConfiguration config, AbstractWarningRecord record,
+ WarningAction action) {
// Current Time
Calendar cal = Calendar.getInstance();
@@ -91,14 +74,16 @@ public class FollowUpUtil {
rval = true;
}
}
- if (action == WarningAction.COR && checkCorApplicable(site, config, record)) {
+ if (action == WarningAction.COR
+ && checkCorApplicable(site, config, record)) {
rval = true;
}
}
return rval;
}
-
- private static boolean checkCorApplicable(String site, WarngenConfiguration config, AbstractWarningRecord warnRec) {
+
+ private static boolean checkCorApplicable(String site,
+ WarngenConfiguration config, AbstractWarningRecord warnRec) {
boolean allowsCONProduct = false;
boolean allowsCORProduct = false;
for (String s : config.getFollowUps()) {
@@ -113,29 +98,31 @@ public class FollowUpUtil {
if (allowsCORProduct == false) {
return false;
}
-
+
CurrentWarnings cw = CurrentWarnings.getInstance(site);
- List correctableWarnings = cw.getCorrectableWarnings(warnRec);
-
+ List correctableWarnings = cw
+ .getCorrectableWarnings(warnRec);
+
boolean wasContinued = false;
for (AbstractWarningRecord w : correctableWarnings) {
if (WarningAction.valueOf(w.getAct()) == WarningAction.CON) {
wasContinued = true;
}
}
-
+
// Adding a COR option for continuation follow ups
- if (correctableWarnings.isEmpty() == false && ((allowsCONProduct && wasContinued)
- || (allowsCONProduct == false && wasContinued == false))) {
+ if (correctableWarnings.isEmpty() == false
+ && ((allowsCONProduct && wasContinued) || (allowsCONProduct == false && wasContinued == false))) {
return true;
}
-
+
return false;
}
/**
- * Returns the raw message of the record but removes
- * the first wmoid and the pil (the first two lines of the warning)
+ * Returns the raw message of the record but removes the first wmoid and the
+ * pil (the first two lines of the warning)
+ *
* @param record
* @return
*/
@@ -169,47 +156,49 @@ public class FollowUpUtil {
return originalMessage;
}
-
+
/**
* Returns a list of the canceled areas from the original text
+ *
* @param originalText
* @return
*/
- public static ArrayList canceledAreasFromText(String originalText) {
+ public static ArrayList canceledAreasFromText(
+ String originalText) {
boolean ugcdone = false;
boolean namedone = false;
boolean insideHeadline = false;
String ugcLine = "";
String namesLine = "";
String headline = "";
+ Pattern ugcPtrn = Pattern.compile(ICommonPatterns.ugc);
for (String line : originalText.trim().split("\n")) {
if (line.contains("TEST") || line.trim().length() == 0) {
continue;
}
-
- Matcher m = WarningTextHandler.ugcPtrn.matcher(line);
+ Matcher m = ugcPtrn.matcher(line);
if (!ugcdone && m.find()) {
ugcLine += m.group();
continue;
} else if (ugcLine.length() > 0) {
ugcdone = true;
}
-
- m = WarningTextHandler.listOfAreaNamePtrn.matcher(line);
+
+ m = ICommonPatterns.listOfAreaNamePtrn.matcher(line);
if (!namedone && m.find()) {
namesLine += m.group();
continue;
} else if (namesLine.length() > 0) {
namedone = true;
}
-
+
if (line.startsWith("...")) {
headline += line.substring(3);
insideHeadline = true;
} else if (insideHeadline) {
-
+
if (line.trim().endsWith("...")) {
- headline += line.substring(0,line.length() - 3);
+ headline += line.substring(0, line.length() - 3);
insideHeadline = false;
break;
}
@@ -219,9 +208,9 @@ public class FollowUpUtil {
String[] ugcs = ugcLine.split("-");
String[] names = namesLine.split("-");
String[] areas = headline.split("\\.\\.\\.");
-
+
ArrayList al = new ArrayList();
-
+
String stateAbbreviation = null;
String areaNotation = null;
String areasNotation = null;
@@ -232,7 +221,7 @@ public class FollowUpUtil {
AffectedAreas affectedArea = new AffectedAreas();
String ugc = ugcs[i].trim();
if (ugc.length() == 6) {
- stateAbbreviation = ugc.substring(0,2);
+ stateAbbreviation = ugc.substring(0, 2);
if (ugc.charAt(2) == 'Z') {
areaNotation = "ZONE";
areasNotation = "ZONES";
@@ -241,17 +230,18 @@ public class FollowUpUtil {
areasNotation = "COUNTIES";
}
}
-
+
fips = ugc.substring(ugc.length() - 3);
-
+
if (i < names.length) {
- name = names[i].substring(0, names[i].length()-3);
+ name = names[i].substring(0, names[i].length() - 3);
}
-
+
if (name != null) {
for (String area : areas) {
if (area.contains(name)) {
- EnumSet set = EnumSet.noneOf(Direction.class);
+ EnumSet set = EnumSet
+ .noneOf(Direction.class);
for (Direction direction : Direction.values()) {
if (area.contains(direction.name())) {
set.add(direction);
@@ -262,7 +252,7 @@ public class FollowUpUtil {
}
}
}
-
+
affectedArea.setFips(fips);
affectedArea.setStateabbr(stateAbbreviation);
affectedArea.setAreaNotation(areaNotation);
@@ -274,11 +264,12 @@ public class FollowUpUtil {
return al;
}
-
+
public static String getUgcLineCanFromText(String originalText) {
String ugcLine = "";
- for (String line : originalText.trim().split("\n")) {
- Matcher m = WarningTextHandler.ugcPtrn.matcher(line);
+ Pattern ugcPtrn = Pattern.compile(ICommonPatterns.ugc);
+ for (String line : originalText.trim().split("\n")) {
+ Matcher m = ugcPtrn.matcher(line);
if (m.find()) {
ugcLine += line;
continue;
@@ -286,7 +277,7 @@ public class FollowUpUtil {
break;
}
}
-
+
return ugcLine;
}
diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/WarningTextHandler.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/WarningTextHandler.java
deleted file mode 100644
index c63e16caf6..0000000000
--- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/WarningTextHandler.java
+++ /dev/null
@@ -1,926 +0,0 @@
-/**
- * This software was developed and / or modified by Raytheon Company,
- * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
- *
- * U.S. EXPORT CONTROLLED TECHNICAL DATA
- * This software product contains export-restricted data whose
- * export/transfer/disclosure is restricted by U.S. law. Dissemination
- * to non-U.S. persons whether in the United States or abroad requires
- * an export license or other authorization.
- *
- * Contractor Name: Raytheon Company
- * Contractor Address: 6825 Pine Street, Suite 340
- * Mail Stop B8
- * Omaha, NE 68106
- * 402.291.0100
- *
- * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
- * further licensing information.
- **/
-package com.raytheon.viz.warngen.util;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
-import com.raytheon.uf.common.dataplugin.warning.util.FileUtil;
-import com.raytheon.uf.common.status.IUFStatusHandler;
-import com.raytheon.uf.common.status.UFStatus;
-import com.raytheon.uf.common.status.UFStatus.Priority;
-import com.raytheon.viz.texteditor.TextWarningConstants;
-import com.raytheon.viz.texteditor.util.VtecObject;
-import com.raytheon.viz.texteditor.util.VtecUtil;
-import com.raytheon.viz.warngen.gis.AffectedAreas;
-import com.raytheon.viz.warngen.gis.AffectedAreasComparator;
-
-/**
- * Adds lock tags and wraps the text
- *
- *
- *
- * SOFTWARE HISTORY
- *
- * Date Ticket# Engineer Description
- * ------------ ---------- ----------- --------------------------
- * Dec 2, 2010 jsanchez Initial creation
- * Aug 29, 2011 10719 rferrel applyLocks no longer allows removal of
- * required blank lines.
- * May 10, 2012 14681 Qinglu Lin Updated regex string for Pattern listOfAreaNamePtrn, etc.
- * May 30, 2012 14749 Qinglu Lin Handled CAN in a CANCON specifically.
- * Jun 6, 2012 14749 Qinglu Lin Added code to lock "...THE" in "...THE CITY OF", etc.
- * (David's concise approach was used. A quicker but
- * lengthy code snippet is available) and to resolve issue with
- * empty areaNotation and areasNotation which occurs when,
- * for example, District of Columbia is followed by a county.
- * Jun 19, 2012 15110 Qinglu Lin Fixed issues in CAN of CANCON: a) ST in any words changed to "ST." and
- * locked if county name has ST., e.g., ST. JOSEPH;
- * b)Locking beyond the first paragraph for areal flood warning followup;
- * c)Locking does not work for areal flood advisory followup;
- * d)NullointException/locking does not work for special marine warning
- * and locking beyond first paragragh.
- * Jul 17, 2012 14989 Qinglu Lin Removed locks, and , for county names in pathcast line.
- * Sep 11, 2012 15372 Qinglu Lin Adjusted code so that and in the line of "MAINLY RURAL AREAS"
- * were removed as well.
- *
- *
- *
- * @author jsanchez
- * @version 1.0
- */
-
-public class WarningTextHandler {
- private static final transient IUFStatusHandler statusHandler = UFStatus
- .getHandler(WarningTextHandler.class);
-
- /** Maximum width of a warning */
- private static final int MAX_WIDTH = 69;
-
- private static final String LOCK_START = TextWarningConstants.BEGIN_ELEMENT_TAG;
-
- private static final String LOCK_END = TextWarningConstants.END_ELEMENT_TAG;
-
- private static final String TEST_MSG1 = "...THIS MESSAGE IS FOR TEST PURPOSES ONLY...";
-
- private static final String TEST_MSG2 = "THIS IS A TEST MESSAGE.";
-
- private static final String TEST_MSG3 = "THIS IS A TEST MESSAGE. DO NOT TAKE ACTION BASED ON THIS MESSAGE.";
-
- /** Pattern for wrapping a long line */
- private static final Pattern wrapRE = Pattern
- .compile("(\\S\\S&&([^\\.][^\\.][^\\.]){" + (MAX_WIDTH - 3)
- + ",}|.{1," + (MAX_WIDTH - 3) + "})(" + LOCK_START + "|"
- + LOCK_END + "|-|\\s+|(\\.\\.\\.)|$)");
-
- /** Strictly wraps only after hyphens */
- private static final Pattern hyphenWrapRE = Pattern.compile("(.{1,"
- + (MAX_WIDTH - 1) + "}-)");
-
- private static final Pattern datePtrn = Pattern
- .compile("(\\d{1,2})(\\d{2})\\s(AM|PM)\\s(\\w{3,4})\\s\\w{3}\\s(\\w{3})\\s{1,}(\\d{1,2})\\s(\\d{4})");
-
- /** The UGC line (ex. NEC003-008-010-110325) */
- public static final Pattern ugcPtrn = Pattern
- .compile("((\\w{2}[CZ](\\d{3}-){1,}){1,})|(\\d{3}-){1,}");
-
- /** The VTEC line (ex. /O.NEW.KOAX.TO.W.0001.110715T1722Z-110715T1730Z) */
- private static final Pattern vtecPtrn = Pattern
- .compile("/[OTEX]\\.([A-Z]{3})\\.[A-Za-z0-9]{4}\\.[A-Z]{2}\\.[WAYSFON]\\.\\d{4}\\.\\d{6}T\\d{4}Z-\\d{6}T\\d{4}Z/");
-
- /**
- * The HTEC line (ex.
- * /00000.0.${ic}.000000T0000Z.000000T0000Z.000000T0000Z.OO/)
- */
- private static final Pattern htecPtrn = Pattern
- .compile("/[A-Za-z0-9]{5}.[0-3NU].\\w{2}.\\d{6}T\\d{4}Z.\\d{6}T\\d{4}Z.\\d{6}T\\d{4}Z.\\w{2}/");
-
- /** ex. * TORNADO WARNING FOR... */
- private static final Pattern firstBulletPtrn = Pattern
- .compile("\\*\\s(.*)\\s(WARNING|ADVISORY)(\\sFOR(.*)|\\.\\.\\.)");
-
- private static final Pattern cancelPtrn = Pattern
- .compile("(|(.*))(IS CANCELLED\\.\\.\\.)");
-
- private static final Pattern cancelOnlyPtrn = Pattern
- .compile("(CANCELLED<\\/L>\\.\\.\\.)");
-
- private static final Pattern expirePtrn = Pattern
- .compile("(|(.*))((EXPIRED|WILL EXPIRE)\\sAT\\s\\d{3,4}\\s(AM|PM)\\s\\w{3}...)");
-
- private static final Pattern headlinePtrn = Pattern
- .compile("(\\.\\.\\.((A|THE)\\s(.*)\\s(WARNING|ADVISORY))\\s(FOR|(REMAINS IN EFFECT (|(UNTIL\\s\\d{3,4}\\s(AM|PM)\\s\\w{3})))))(|(.*))");
-
- private static final Pattern canVtecPtrn = Pattern.compile("(\\.CAN\\.)");
-
- private static final Pattern smwCanPtrn = Pattern.compile("(\\.MA\\.W\\.)");
-
- private static final Pattern afaCanPtrn = Pattern.compile("(\\.FA\\.Y\\.)");
-
- private static final Pattern smwHeadlinePtrn = Pattern
- .compile("(THE AFFECTED AREAS WERE)");
-
- private static Pattern immediateCausePtrn = null;
-
- /** ex. SARPY NE-DOUGLAS NE-WASHINGTON NE- */
- public static final Pattern listOfAreaNamePtrn = Pattern
- .compile("(((\\w{1,}\\s{1}){1,}\\w{2}-){0,}((\\w{1,}\\s{1}){1,}\\w{2}-))");
-
- private static final Pattern secondBulletPtrn = Pattern.compile("\\*(|\\s"
- + TEST_MSG2 + ")\\sUNTIL\\s\\d{3,4}\\s(AM|PM)\\s\\w{3,4}");
-
- private static final Pattern testMessagePtrn = Pattern.compile("(|.*)("
- + TEST_MSG2 + ")(.*)");
-
- private static final Pattern latLonPtrn = Pattern
- .compile("^LAT...LON+(\\s\\d{3,4}\\s\\d{3,5}){1,}");
-
- private static final Pattern subLatLonPtrn = Pattern
- .compile("^((?!TIME...MOT... LOC))\\s{1,}\\d{3,4}\\s\\d{3,5}(|(\\s\\d{3,4}\\s\\d{3,5}){1,})");
-
- private static final Pattern tmlPtrn = Pattern
- .compile("TIME...MOT...LOC \\d{3,4}Z\\s\\d{3}DEG\\s\\d{1,3}KT((\\s\\d{3,4}\\s\\d{3,5}){1,})");
-
- private static final Pattern subTMLPtrn = Pattern
- .compile("(\\d{3,5}\\s){1,}");
-
- private static final Pattern lockedBlankLinesPattern = Pattern.compile(
- "(\\s*+)", Pattern.MULTILINE);
-
- private static final String LOCK_REPLACEMENT_TEXT = LOCK_START + "$0"
- + LOCK_END;
-
- private static final Pattern extraTokensPattern = Pattern
- .compile("\\b(?:THE|IS|CANCELLED)\\b");
-
- static {
- String pattern = "";
-
- // Load immediateCausePtrn with immediateCause.txt
- try {
- String immediateCause = FileUtil.open("immediateCause.txt", "base");
- pattern = "(.*)(A DAM BREAK";
- for (String ic : immediateCause.split("\n")) {
- String[] parts = ic.split("\\\\");
- pattern += "| " + parts[1].trim();
- }
- pattern += ")(.*)";
- immediateCausePtrn = Pattern.compile(pattern);
- } catch (Exception e) {
- statusHandler
- .handle(Priority.ERROR,
- "Unable to process immediateCause.txt in the base directory",
- e);
- }
- }
-
- public static String handle(String originalMessage, AffectedAreas[] areas,
- AffectedAreas[] canceledAreas, WarningAction action,
- WarningAction action2, boolean autoLock) {
- long t0 = System.currentTimeMillis();
- if (action == WarningAction.NEW) {
- try {
- originalMessage = VtecUtil.getVtec(originalMessage);
- } catch (Exception e) {
- statusHandler
- .handle(Priority.SIGNIFICANT,
- "WarnGen cannot update the ETN. Please verify the VTEC is valid.",
- e);
- }
- } else if (action == WarningAction.COR) {
- originalMessage = addCorrectedText(originalMessage);
- }
-
- originalMessage = wrap(originalMessage);
-
- if (autoLock) {
- boolean initialWarning = (action == WarningAction.NEW || action == WarningAction.EXT);
-
- if (action == WarningAction.COR) {
- Matcher m = firstBulletPtrn.matcher(originalMessage);
- initialWarning = m.find();
- }
- List areasArr = areas != null ? Arrays.asList(areas)
- : null;
- List canceledAreasArr = canceledAreas != null ? Arrays
- .asList(canceledAreas) : null;
- originalMessage = applyLocks(originalMessage, areasArr,
- canceledAreasArr, initialWarning, action2);
- }
-
- originalMessage = removeExtraLines(originalMessage);
-
- // remove locked blank lines
- Matcher matchLockedBlankLines = lockedBlankLinesPattern
- .matcher(originalMessage);
- originalMessage = matchLockedBlankLines.replaceAll("$1");
-
- System.out.println("Time to handle the text: "
- + (System.currentTimeMillis() - t0));
- return originalMessage;
- }
-
- private static String addCorrectedText(String originalMessage) {
- int index = originalMessage.indexOf("NATIONAL WEATHER SERVICE");
- String[] types = new String[] { "WARNING", "WATCH", "STATEMENT",
- "ADVISORY" };
- int typeIdx = -1, i = 0;
- if (index > 0) {
- for (i = 0; i < types.length; i++) {
- if (originalMessage.lastIndexOf(types[i], index) != -1) {
- typeIdx = originalMessage.lastIndexOf(types[i], index);
- break;
- }
- }
- }
-
- if (index > 0 && typeIdx > 0
- && !originalMessage.contains("...CORRECTED")) {
- originalMessage = originalMessage.substring(0,
- typeIdx + types[i].length())
- + "...CORRECTED"
- + originalMessage.substring(typeIdx + types[i].length());
- }
-
- return originalMessage;
- }
-
- private static String applyLocks(String originalMessage,
- List areas, List canceledAreas,
- boolean initialWarning, WarningAction action) {
- boolean firstBulletFound = false;
- boolean insideFirstBullet = false;
- boolean secondBulletFound = false;
- boolean headlineFound = false;
- // for CAN in a CANCON
- boolean cancelVtecLineFound = false;
- boolean insideLatLon = false;
- boolean insideTML = false;
- boolean checkForMND = true;
- StringBuffer sb = new StringBuffer();
- String[] seperatedLines = originalMessage.trim().split("\n");
- Matcher m = null;
-
- VtecObject vtecObj = VtecUtil.parseMessage(originalMessage);
- boolean marineProduct = vtecObj != null
- && vtecObj.getPhenomena() != null
- && vtecObj.getPhenomena().equals("MA");
-
- AffectedAreasComparator comparator = new AffectedAreasComparator(
- new ArrayList());
-
- if (areas != null) {
- Collections.sort(areas, comparator);
- }
-
- if (canceledAreas != null) {
- Collections.sort(canceledAreas, comparator);
- }
-
- boolean startLines = true;
-
- // Set before to false if the line is beyond
- // "THE NATIONAL WEATHER SERVICE IN" line.
- boolean before = true;
-
- boolean isCancelledFound = false;
-
- // for CAN of CANCON of Special Marine Warning
- boolean smwCan = false;
- boolean lockSmwCan = false;
-
- // for CAN of CANCON of Areal Flood Advisory
- boolean afaCan = false;
- int afaCanBlankline = 0;
-
- String[] tokens = null;
- if (canceledAreas != null) {
- String areaNames = "";
- for (AffectedAreas area : canceledAreas) {
- String areaName = area.getName();
- if (areaName != null && areaName.length() > 0) {
- areaName = areaName.toUpperCase();
- areaNames += areaName + " ";
- }
- }
- areaNames = areaNames.trim();
- HashSet areaNameSet = new HashSet();
- String[] tokens0 = areaNames.split(" ");
- int tokensLength = tokens0.length;
- for (int i = 0; i < tokensLength; i++) {
- areaNameSet.add(tokens0[i]);
- }
-
- tokens = (String[]) areaNameSet.toArray(new String[areaNameSet
- .size()]);
- String s0;
- for (int i = 0; i < areaNameSet.size() - 1; i++) {
- s0 = tokens[i];
- String s1;
- for (int j = i; j < areaNameSet.size(); j++) {
- if (tokens[j].length() > s0.length()) {
- s1 = s0;
- s0 = tokens[j];
- tokens[j] = s1;
- }
- }
- tokens[i] = s0;
- }
- }
-
- boolean ruralFound = false, ruralReplaced = false;
- ArrayList usedAreaNotations = new ArrayList();
- for (int lineIndex = 0; lineIndex < seperatedLines.length; ++lineIndex) {
- String line = seperatedLines[lineIndex];
-
- if (line.contains("THE NATIONAL WEATHER SERVICE IN")
- || line.contains("OTHER LOCATIONS IMPACTED")) {
- before = false;
- }
-
- if (!ruralFound && !ruralReplaced && line.contains("MAINLY RURAL AREAS")) {
- ruralFound = true;
- }
-
- // This prevents blank line(s) after the header from being locked.
- if (startLines && lineIndex > 1) {
- startLines = line.trim().length() == 0;
- }
-
- try {
- // MND header
- if (checkForMND
- && (line.contains("EAS ACTIVATION")
- || line.contains("IMMEDIATE BROADCAST")
- || line.startsWith("NATIONAL WEATHER SERVICE")
- || line.startsWith("THE NATIONAL WEATHER SERVICE")
- || line.startsWith("ISSUED BY ")
- || line.contains("...CORRECTED") || ((line
- .endsWith("WARNING")
- || line.endsWith("WATCH")
- || line.endsWith("STATEMENT") || line
- .endsWith("ADVISORY")) && line.startsWith("*") == false))) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- continue;
- }
-
- // Locking the UGC line
- m = ugcPtrn.matcher(line);
- if (m.find()) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- continue;
- }
-
- // Locking the VTEC
- m = vtecPtrn.matcher(line);
- if (m.find()) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- // check out if .CAN. is in VTEC line of a CANCON product.
- m = canVtecPtrn.matcher(line);
- if (action == WarningAction.CANCON && m.find()) {
- cancelVtecLineFound = true;
- m = smwCanPtrn.matcher(line);
- if (m.find())
- smwCan = true;
- m = afaCanPtrn.matcher(line);
- if (m.find())
- afaCan = true;
- }
- continue;
- }
-
- // Locking the HTEC
- m = htecPtrn.matcher(line);
- if (m.find()) {
- sb.append(LOCK_START + m.group(0) + "\n" + LOCK_END);
- continue;
- }
-
- if (before) {
- m = listOfAreaNamePtrn.matcher(line);
- if (m.matches()) {
- if (!(line.contains("!**") || line.contains("**!") || line
- .contains("OTHER LOCATIONS"))) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- continue;
- }
- }
- }
-
- // Locking Date in the MND header
- m = datePtrn.matcher(line);
- if (m.find()) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- continue;
- }
-
- if (ruralFound)
- if (line.trim().length() == 0)
- ruralFound = false;
- else {
- line = line.replace("", "");
- line = line.replace("", "");
- sb.append(line + "\n");
- if (!ruralReplaced)
- ruralReplaced = true;
- continue;
- }
-
- if (line.trim().length() == 0) {
- insideTML = false;
- insideLatLon = false;
- headlineFound = false;
- if (smwCan) {
- if (lockSmwCan)
- cancelVtecLineFound = false;
- lockSmwCan = false;
- }
- if (afaCan) {
- afaCanBlankline += 1;
- if (afaCanBlankline > 1) {
- afaCan = false;
- cancelVtecLineFound = false;
- }
- }
- if (startLines) {
- // Don't lock blank line after header
- sb.append("\n");
- } else if (sb.lastIndexOf("\n") == (sb.length() - 1)) {
- // Put lock at end of previous line to prevent removal
- // of leading blank line.
- sb.setLength(sb.length() - 1);
- sb.append(LOCK_START + "\n\n" + LOCK_END);
- } else {
- sb.append(LOCK_START + "\n" + LOCK_END);
- }
- continue;
- }
-
- // Hack!
- // This is needed due to a drifting
- // due tothe replaceAll("([\\s\\n\\r]*)", "$1");
- if (line.startsWith("* AT") || line.startsWith("AT")) {
- sb.append(LOCK_START + "" + LOCK_END);
- headlineFound = false;
- }
-
- if (initialWarning) {
- // Locking first bullet
- m = firstBulletPtrn.matcher(line);
- if (m.find() && firstBulletFound == false) {
- checkForMND = false;
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- firstBulletFound = true;
- insideFirstBullet = true;
- continue;
- }
-
- if (insideFirstBullet) {
- // Removes extra spaces between texts in the first
- // bullet
- line = line.replaceAll("\\s{3}", " ").replaceAll(
- "\\b\\s{2,}\\b", " ");
-
- // Lock immediate cause (hydro) (DR 10329)
- if (immediateCausePtrn != null) {
- m = immediateCausePtrn.matcher(line);
- if (m.find()) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- continue; // immediate cause on its own line
- }
- }
-
- boolean countyFound = false;
- boolean areaNotationFound = false;
- boolean stateFound = false;
-
- if (areas != null && !marineProduct) {
- for (int i = areas.size() - 1; i >= 0; i--) {
- AffectedAreas area = areas.get(i);
- // Lock counties & independent cities (DR 10331)
- if (!countyFound
- && area.getName() != null
- && area.getName().length() > 0
- && line.contains(area.getName()
- .toUpperCase())) {
- line = line.replaceFirst(area.getName()
- .toUpperCase(), LOCK_START
- + area.getName().toUpperCase()
- + LOCK_END);
- countyFound = true;
- }
-
- if (!areaNotationFound
- && area.getAreaNotation() != null
- && area.getAreaNotation().length() > 0
- && line.contains(area.getAreaNotation()
- .toUpperCase())) {
- line = line.replaceFirst(
- " " + area.getAreaNotation(),
- LOCK_START + " "
- + area.getAreaNotation()
- + LOCK_END);
- areaNotationFound = true;
- }
- // Lock States (DR 10325)
- if (!stateFound
- && area.getParentRegion() != null
- && area.getParentRegion().length() > 0
- && line.contains(area.getParentRegion()
- .toUpperCase())) {
- line = line.replaceFirst(area
- .getParentRegion().toUpperCase(),
- LOCK_START
- + area.getParentRegion()
- .toUpperCase()
- + LOCK_END);
- stateFound = true;
- }
- }
- }
- }
-
- // Locking second bullet
- m = secondBulletPtrn.matcher(line);
- if (m.find() && secondBulletFound == false) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- insideFirstBullet = false;
- secondBulletFound = true;
- continue;
- }
- } else {
- usedAreaNotations.clear();
- // head line pattern
- m = headlinePtrn.matcher(line);
- if (m.find()) {
- checkForMND = false;
- headlineFound = true;
- line = line.replace(m.group(2), LOCK_START + m.group(2)
- + LOCK_END);
- }
- // CAN portion in a CANCON
- if (cancelVtecLineFound) {
- if (smwCan) {
- // lock marine zone names
- if (lockSmwCan) {
- if (line.length() == 0) {
- lockSmwCan = false;
- } else
- line = LOCK_START + line + LOCK_END;
- } else {
- m = smwHeadlinePtrn.matcher(line);
- if (m.find())
- lockSmwCan = true;
- }
- } else {
- for (String s : tokens)
- if (line.contains(s))
- line = line.replace(s, LOCK_START + s
- + LOCK_END);
- for (AffectedAreas area : canceledAreas) {
- String areaNotation = area.getAreaNotation();
- if (areaNotation != null) {
- // areaNotation, e.g., COUNTY
- if (areaNotation != null
- && areaNotation.length() > 0
- && !usedAreaNotations
- .contains(areaNotation)
- && line.contains(areaNotation)) {
- line = line.replaceAll(areaNotation,
- LOCK_START + areaNotation
- + LOCK_END);
- usedAreaNotations.add(areaNotation);
- }
- // areasNotation, e.g., COUNTIES
- String areasNotation = area
- .getAreasNotation().toUpperCase();
- if (areasNotation != null
- && areasNotation.length() > 0
- && !usedAreaNotations
- .contains(areasNotation)
- && line.contains(areasNotation)) {
- line = line.replaceAll(areasNotation,
- LOCK_START + areasNotation
- + LOCK_END);
- usedAreaNotations.add(areasNotation);
- }
- }
- }
- // locking "THE" in "THE CITY OF MANASSAS", "...THE"
- // in "...THE CITY",
- // and "IS" or "CANCELLED" in "IS CANCELLED...".
- line = extraTokensPattern.matcher(line).replaceAll(
- LOCK_REPLACEMENT_TEXT);
- }
-
- if (cancelVtecLineFound && isCancelledFound)
- cancelVtecLineFound = false;
-
- m = cancelOnlyPtrn.matcher(line);
- if (m.find())
- cancelVtecLineFound = false;
-
- sb.append(line + "\n");
- continue;
- } else {
- // follow-ups other than CAN in a CANCON
- if (headlineFound) {
- usedAreaNotations.clear();
- if (areas != null && !marineProduct) {
- for (AffectedAreas area : areas) {
- if (area.getName() != null
- && line.contains(area.getName()
- .toUpperCase())) {
- line = line.replaceFirst(area.getName()
- .toUpperCase(), LOCK_START
- + area.getName().toUpperCase()
- + LOCK_END);
- }
-
- if (area.getAreaNotation() != null
- && !usedAreaNotations.contains(area
- .getAreaNotation()
- .toUpperCase())
- && line.contains(area
- .getAreaNotation())) {
- line = line
- .replaceAll(
- " "
- + area.getAreaNotation()
- .toUpperCase(),
- LOCK_START
- + " "
- + area.getAreaNotation()
- + LOCK_END);
- usedAreaNotations.add(area
- .getAreaNotation()
- .toUpperCase());
- }
- }
- }
-
- m = cancelPtrn.matcher(line);
- if (m.find()) {
- line = line.replaceFirst(m.group(3), LOCK_START
- + m.group(3) + LOCK_END);
- if (canceledAreas != null) {
- for (AffectedAreas canceledArea : canceledAreas) {
- if (line.contains(canceledArea
- .getName().toUpperCase())) {
- line = line
- .replaceFirst(
- canceledArea
- .getName()
- .toUpperCase(),
- LOCK_START
- + canceledArea
- .getName()
- .toUpperCase()
- + LOCK_END);
- }
- }
- }
- headlineFound = false;
- }
-
- m = expirePtrn.matcher(line);
- if (m.find()) {
- line = line.replaceFirst(m.group(3), LOCK_START
- + m.group(3) + LOCK_END);
- headlineFound = false;
- }
-
- sb.append(line + "\n");
- continue;
- }
- }
- }
-
- // Locking LAT...LON
- m = latLonPtrn.matcher(line);
- if (m.find()) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- insideLatLon = true;
- continue;
- }
-
- if (insideLatLon) {
- m = subLatLonPtrn.matcher(line);
- if (m.find()) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- continue;
- } else {
- insideLatLon = false;
- }
- }
-
- // PRECAUTIONARY/PREPAREDNESS ACTIONS, $$, &&
- if (line.equals("PRECAUTIONARY/PREPAREDNESS ACTIONS...")
- || line.startsWith("$$") || line.startsWith("&&")) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- continue;
- }
- // Locking TIME...MOT..LOC
- m = tmlPtrn.matcher(line);
- if (m.find()) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- insideTML = true;
- continue;
- }
-
- if (insideTML) {
- m = subTMLPtrn.matcher(line);
- if (m.matches()) {
- sb.append(LOCK_START + line + "\n" + LOCK_END);
- continue;
- } else {
- insideTML = false;
- }
-
- }
-
- // Test lines
- if (line.equals(TEST_MSG3)
- || line.equals(TEST_MSG1)
- || (line.startsWith("TEST...") && line
- .endsWith("...TEST"))) {
- sb.append(LOCK_START + line + LOCK_END + "\n");
- continue;
- }
- m = testMessagePtrn.matcher(line);
- if (m.find()) {
- line = line.replace(m.group(2), LOCK_START + m.group(2)
- + LOCK_END);
- }
- } catch (Exception e) {
- // If an exception is thrown,
- // log the exception but continue locking text
- statusHandler.handle(Priority.PROBLEM, "Error locking line: "
- + line + "\n", e);
- }
- sb.append(line + "\n");
- insideLatLon = false;
- insideTML = false;
- }
- String rval = sb.toString().trim();
-
- // where a lock close and lock open are only separated by whitespace
- // remove the close and open to join the two locked areas
- rval = rval.replaceAll("([\\s\\n\\r]*)", "$1");
-
- return rval;
- }
-
- private static String wrap(String str) {
- StringBuffer sb = new StringBuffer();
-
- boolean inLocations = false;
- boolean first = true;
- boolean inBullet = false;
- String[] values = str.split("\n");
- for (String v : values) {
- String ignoreLockTags = v.replace(LOCK_START, "").replace(LOCK_END,
- "");
- if (ignoreLockTags.length() <= MAX_WIDTH) {
- if (!first) {
- sb.append("\n");
- if (inBullet && !ignoreLockTags.startsWith(" ")) {
- sb.append(" ");
- }
- }
- if (ignoreLockTags.startsWith("* ")) {
- inBullet = true;
- if (ignoreLockTags.startsWith("* LOCATIONS")) {
- inLocations = true;
- }
- } else if (ignoreLockTags.trim().equals("")) {
- inBullet = false;
- inLocations = false;
- }
- sb.append(v);
-
- } else {
- Matcher m = null;
-
- if (ignoreLockTags.startsWith("* ")) {
- inBullet = true;
- if (ignoreLockTags.startsWith("* LOCATIONS")) {
- inLocations = true;
- }
- } else if (ignoreLockTags.startsWith("...")
- && ignoreLockTags.endsWith("...")) {
- // headline found
- // use line without lock tags because, lock tags adds to
- // character count with doing a regex pattern
- v = ignoreLockTags;
- }
-
- if (inLocations) {
- sb.append("\n");
- sb.append(wrapLocations(v));
- continue;
- } else {
- m = ugcPtrn.matcher(v);
- if (m.find()) {
- m = hyphenWrapRE.matcher(v);
- } else {
- m = listOfAreaNamePtrn.matcher(v);
- if (m.matches()) {
- m = hyphenWrapRE.matcher(v);
- } else {
- m = wrapRE.matcher(v);
- }
- }
- }
- while (m.find()) {
- String group = m.group().trim();
-
- if (group.trim().length() == 0) {
- break;
- }
-
- sb.append("\n");
- if (group.startsWith("* ") == false && inBullet) {
- sb.append(" ");
- }
-
- sb.append(group);
- }
- }
- first = false;
- }
-
- return sb.toString();
- }
-
- private static String wrapLocations(String locationsLine) {
- StringBuffer sb = new StringBuffer();
-
- String line = " ";
- String[] locations = locationsLine.split("\\.\\.\\.");
-
- for (int i = 0; i < locations.length; i++) {
- String location = locations[i];
- int size = (i == locations.length - 1) ? location.length()
- : location.length() + 3;
-
- if (line.length() + size >= MAX_WIDTH - 2) {
- sb.append(line + "\n");
- line = " ";
- }
-
- if (i == locations.length - 1) {
- line += location;
- } else {
- line += location + "...";
- }
- }
-
- sb.append(line + "\n");
-
- return sb.toString();
- }
-
- private static String removeExtraLines(String originalMessage) {
- StringBuffer sb = new StringBuffer();
- String[] seperatedLines = originalMessage.replaceAll("\r", "").trim()
- .split("\n");
- boolean blankLine = false;
- for (String line : seperatedLines) {
- if (line.replace(LOCK_START, "").replace(LOCK_END, "").trim()
- .length() > 0) {
- sb.append(line + "\n");
- blankLine = false;
- } else if (blankLine == false) {
- sb.append(line + "\n");
- blankLine = true;
- }
- }
-
- return sb.toString().trim();
- }
-
-}