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(); - } - -}