awips2/cave/com.raytheon.viz.hydrobase/src/com/raytheon/viz/hydrobase/FloodReportDataManager.java
2022-05-05 12:34:50 -05:00

705 lines
20 KiB
Java

/**
* 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.hydrobase;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.viz.hydrocommon.HydroConstants;
import com.raytheon.viz.hydrocommon.HydroDataCache;
import com.raytheon.viz.hydrocommon.datamanager.HydroDataManager;
/**
* Flood Report Dialog data manager.
*
* <pre>
*
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sep 2, 2009 2259 mpduff Initial creation
* May 14, 2012 14965 wkwock Fix crash in query for data
* Jun 10, 2015 DCS15095 wkwock Added edit/insert flood event feature.
* May 31, 2017 DR18902 JingtaoD Hydrobase flood events not grouped properly
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class FloodReportDataManager extends HydroDataManager {
private static FloodReportDataManager instance = null;
private static final int INDEX_PT_A = 0;
private static final int INDEX_PT_B = 1;
private static final int INDEX_PT_C = 2;
private static final int INDEX_PT_D = 3;
private static final int INDEX_ANCHOR1 = 4;
private static final int INDEX_ANCHOR2 = 5;
private Map<String, FloodReportData> dataMap = new TreeMap<String, FloodReportData>();
private Object[] lastCrest = null;
/**
* The selected location id.
*/
private String selectedLid = null;
/**
* The selected key for the dataMap.
*/
private String selectedKey = null;
/**
* The data start date
*/
private Date startDate;
/**
* The data end date
*/
private Date endDate;
private boolean drawGraph = false;
/**
* Private constructor for Singleton.
*/
private FloodReportDataManager() {
}
/**
* Get an instance of the data manager class.
*
* @return An instance of FloodReportDataManager
*/
public static synchronized FloodReportDataManager getInstance() {
if (instance == null) {
instance = new FloodReportDataManager();
}
return instance;
}
/**
* Get a list of HSA's out of the HSA table.
*
* @return ArrayList of HSA's, or null if no data
*/
public ArrayList<String> getHsaList() {
ArrayList<String> hsaList = new ArrayList<String>();
String query = "select hsa from hsa order by hsa";
ArrayList<Object[]> rs = runQuery(query);
if (rs.size() > 0) {
for (Object[] oa : rs) {
hsaList.add((String) oa[0]);
}
}
return hsaList;
}
/**
* Get a list of lids from the locview joint floodts table order by basin,
* stream, lid.
*
* @param where
* The where clause to constrain the query
* @return ArrayList<String> of location ids
*/
public ArrayList<String> getLidList(String getLidQuery) {
ArrayList<String> lidList = new ArrayList<String>();
String query1 = "select * from locview where lid IN ";
String query2 = " order by rb, stream, lid";
ArrayList<Object[]> rs = runQuery(query1 + getLidQuery + query2);
if (rs.size() > 0) {
for (Object[] oa : rs) {
lidList.add((String) oa[0]);
}
}
return lidList;
}
/**
* Get a list of lids from the riverstat table.
*
* @param where
* The where clause to constrain the query
* @return ArrayList<String> of location ids
*/
public List<String> getLidListFromRiverStat(String where) {
List<String> lidList = new ArrayList<String>();
String query = "select distinct lid from riverstat ";
List<Object[]> rs = runQuery(query + where);
if (rs != null) {
for (Object[] oa : rs) {
lidList.add((String) oa[0]);
}
}
return lidList;
}
/**
* Get Flood Report data.
*
* @param lid
* The location id
* @return FloodReportData object populated with data, null if problem or no
* data
*/
public ArrayList<FloodReportData> getFloodRptData(String lid, String start,
String end) {
ArrayList<FloodReportData> dataList = new ArrayList<FloodReportData>();
String lname = HydroDataCache.getInstance().getLocationMap().get(lid);
double fs = getFloodStage(lid);
int[] fldEventIds = getFloodEventIds(lid, start, end);
for (int i = 0; i < fldEventIds.length; i++) {
Object[] crestData = getCrest(lid, fldEventIds[i]);
FloodReportData data = new FloodReportData();
if ((crestData == null) || (crestData.length == 0)) {
return null;
}
data.setCrest((Double) crestData[0]);
data.setCrestDate(((Date) crestData[1]));
data.setFloodEventId(fldEventIds[i]);
data.setFloodStage(fs);
data.setLid(lid);
data.setLongName(lname);
if (lastCrest != null) {
data.setLastCrest((Double) lastCrest[0]);
data.setLastCrestDate((Date) lastCrest[1]);
}
dataList.add(data);
}
return dataList;
}
/**
* Get the flood stage for the site.
*
* @param lid
* @return The flood stage for the site
*/
public double getFloodStage(String lid) {
double fs = -999;
List<Object[]> rs = runQuery(
"select fs from riverstat where lid = '" + lid + "'");
if ((rs != null) && (rs.size() > 0) && rs.get(0)[0] != null) {
fs = (Double) rs.get(0)[0];
}
return fs;
}
/**
* Get the river basin.
*
* @param lid
* The location id
* @return The name of the river basin the gage is in
*/
public String getRiverBasin(String lid) {
String basin = null;
List<Object[]> rs = runQuery(
"select rb from location where lid = '" + lid + "'");
if (rs != null) {
basin = (String) rs.get(0)[0];
}
return basin;
}
/**
* Get the state.
*
* @param lid
* The location id
* @return The state the gage is in
*/
public String getState(String lid) {
String state = null;
List<Object[]> rs = runQuery(
"select state from location where lid = '" + lid + "'");
if (rs != null) {
state = (String) rs.get(0)[0];
}
return state;
}
/**
* Get the river name.
*
* @param lid
* The location id
* @return The name of the river the gage is on
*/
public String getRiver(String lid) {
String river = null;
List<Object[]> rs = runQuery(
"select stream from riverstat where lid = '" + lid + "'");
if (rs != null) {
river = (String) rs.get(0)[0];
}
return river;
}
/**
* Get the flood event id.
*
* @param lid
* The lid to search on
* @return The ids for the lid
*/
public int[] getFloodEventIds(String lid, String start, String end) {
int[] id = null;
List<Object[]> rs = runQuery(
"select distinct flood_event_id from floodts where lid = '"
+ lid + "' and obstime >= '" + start
+ "' and obstime <= '" + end + "'");
if ((rs != null) && (rs.size() > 0)) {
id = new int[rs.size()];
for (int i = 0; i < rs.size(); i++) {
Object[] oa = rs.get(i);
id[i] = (Integer) oa[0];
}
}
return id;
}
/**
* Get the crest and date/time of the crest.
*
* @param lid
* The location id
* @param id
* The flood event id
* @return Object[] where element 0 = crest value (double) and element 1 =
* date/time (Date)
*/
public Object[] getCrest(String lid, int id) {
String query = "Select value, obstime from floodts where lid = '" + lid
+ "' and flood_event_id = " + id + " order by obstime";
List<Object[]> rs = runQuery(query);
lastCrest = new Object[rs.get(0).length];
Object[] retVal = new Object[2];
if ((rs != null) && (rs.size() > 0)) {
System.arraycopy(rs.get(0), 0, lastCrest, 0, rs.get(0).length);
int numberSinceCrest = 0;
// The crest value
double crestVal = HydroConstants.FLOOD_REPORT_MSG;
for (Object[] oa : rs) {
if (oa != null) {
/*
* if a crest is already defined and the value immediately
* after the crest is identical, consider it a sustained
* crest
*/
double crest = (Double) oa[0];
if ((crestVal != HydroConstants.FLOOD_REPORT_MSG)
&& (crest == crestVal) && (numberSinceCrest == 0)) {
System.arraycopy(oa, 0, lastCrest, 0, oa.length);
} else if ((crest > crestVal)
|| (crestVal == HydroConstants.FLOOD_REPORT_MSG)) {
/*
* check for a higher crest. if new crest found, then
* clear out the sustained crest
*/
crestVal = (Double) oa[0];
lastCrest[0] = HydroConstants.FLOOD_REPORT_MSG;
numberSinceCrest = 0;
System.arraycopy(oa, 0, retVal, 0, oa.length);
} else {
numberSinceCrest++;
}
}
}
}
return retVal;
}
/**
* get the max flood_event_id of a lid. Default to 0.
*
* @param lid
* @return
*/
public int getMaxFloodeventID(String lid) {
String query = "Select max(flood_event_id) from floodts where lid = '"
+ lid + "' and flood_event_id > 0";
List<Object[]> rs = runQuery(query);
Integer feID = new Integer(0);
if ((rs != null) && (rs.size() > 0)) {
feID = (Integer) rs.get(0)[0];
if (feID == null) {
return 0;
}
}
return feID.intValue();
}
/**
* Get the value and obstime from the floodts table.
*
* @param lid
* The lid to query on
* @param eventId
* The event id to query on
* @return ArrayList<Object[]> of {value, obstime}
*/
public ArrayList<Object[]> getFloodEventData(String lid, int eventId) {
String query = "Select value, obstime from floodts where lid = '" + lid
+ "' and flood_event_id = " + eventId + " order by obstime";
ArrayList<Object[]> rs = runQuery(query);
return rs;
}
/**
* Get the times the floodstage was crossed.
*
* @param data
* The FloodReportData object
* @param fs
* The flood stage
* @return String[] { "time above flood stage", "time below flood stage" }
*/
public Date[] getPassthruTimes(FloodReportData data) {
if (data == null) {
return null;
}
double floodStage = data.getFloodStage();
Date[] times = new Date[2];
int index = 0;
boolean[] ptsMissing = { true, true, true, true, true, true };
FloodReportData ptA = new FloodReportData();
FloodReportData ptB = new FloodReportData();
FloodReportData ptC = new FloodReportData();
FloodReportData ptD = new FloodReportData();
FloodReportData anchor1 = new FloodReportData();
FloodReportData anchor2 = new FloodReportData();
boolean findFirstAnchor = true;
boolean findLastAnchor = true;
/* Get the data to search */
ArrayList<Object[]> rs = FloodReportDataManager.getInstance()
.getFloodEventData(data.getLid(), data.getFloodEventId());
/* get first Anchor point */
for (int i = 0; i < rs.size(); i++) {
index = i;
if (findFirstAnchor == false) {
// Break out of for loop
break;
}
Object[] oa = rs.get(i);
if ((Double) oa[0] < floodStage) {
ptA.setCrest((Double) oa[0]);
ptA.setCrestDate((Date) oa[1]);
ptsMissing[INDEX_PT_A] = false;
if (i + 1 < rs.size()) {
Object[] next = rs.get(i + 1);
if ((Double) next[0] >= floodStage) {
ptB.setCrest((Double) next[0]);
ptB.setCrestDate((Date) next[1]);
ptsMissing[INDEX_PT_B] = false;
findFirstAnchor = false;
}
}
} else { /* missing ptA */
ptB.setCrest((Double) oa[0]);
ptB.setCrestDate((Date) oa[1]);
ptsMissing[INDEX_PT_B] = false;
findFirstAnchor = false;
}
}
/* interpolate to find time of progression above flood stage */
if ((ptsMissing[INDEX_PT_A] == false)
&& (ptsMissing[INDEX_PT_B] == false)) {
anchor1 = FloodReportUtils.floodreptInterp(ptA, ptB, floodStage);
ptsMissing[INDEX_ANCHOR1] = false;
} else {
if (ptA.getCrest() == floodStage) {
anchor1 = FloodReportUtils.copyFloodReportData(ptA);
ptsMissing[INDEX_ANCHOR1] = false;
} else if (ptB.getCrest() == floodStage) {
anchor1 = FloodReportUtils.copyFloodReportData(ptB);
ptsMissing[INDEX_ANCHOR1] = false;
}
}
/*
* get last Anchor point, use index to continue loop where we left off
*/
for (int i = index; i < rs.size(); i++) {
if (findLastAnchor == false) {
// Break out of for loop
break;
}
Object[] oa = rs.get(i);
if ((Double) oa[0] >= floodStage) {
Object[] next;
if (i == rs.size() - 1) {
next = null;
} else {
next = rs.get(i + 1);
}
if (next != null) {
if ((Double) next[0] < floodStage) {
ptC.setCrest((Double) oa[0]);
ptC.setCrestDate((Date) oa[1]);
ptsMissing[INDEX_PT_C] = false;
ptD.setCrest((Double) next[0]);
ptD.setCrestDate((Date) next[1]);
ptsMissing[INDEX_PT_D] = false;
findLastAnchor = false;
}
} else {
ptC.setCrest((Double) oa[0]);
ptC.setCrestDate((Date) oa[1]);
ptsMissing[INDEX_PT_C] = false;
findLastAnchor = false;
}
} else { /* point C was skipped or MSG. */
/* ptB is MSG or above fs */
ptC = FloodReportUtils.copyFloodReportData(ptB);
ptsMissing[INDEX_PT_C] = false;
ptD.setCrest((Double) oa[0]);
ptD.setCrestDate((Date) oa[1]);
ptsMissing[INDEX_PT_D] = false;
findLastAnchor = false;
}
}
/* interpolate to find time of recession below flood stage */
if ((ptsMissing[INDEX_PT_C] == false)
&& (ptsMissing[INDEX_PT_D] == false)) {
anchor2 = FloodReportUtils.floodreptInterp(ptC, ptD, floodStage);
ptsMissing[INDEX_ANCHOR2] = false;
} else {
if (ptC.getCrest() == floodStage) {
anchor2 = FloodReportUtils.copyFloodReportData(ptC);
ptsMissing[INDEX_ANCHOR2] = false;
} else if (ptD.getCrest() == floodStage) {
anchor2 = FloodReportUtils.copyFloodReportData(ptD);
ptsMissing[INDEX_ANCHOR2] = false;
}
}
if (anchor1.getCrest() != HydroConstants.FLOOD_REPORT_MSG) {
times[0] = anchor1.getCrestDate();
}
if (anchor2.getCrest() != HydroConstants.FLOOD_REPORT_MSG) {
times[1] = anchor2.getCrestDate();
}
return times;
}
/**
* Delete a flood event.
*
* @param where
* Where clause
* @return 1 if successful, -1 if unsuccessful
*/
public int deleteFloodEvent(String where) {
int status = 1;
String query = "delete from floodts";
try {
runStatement(query + where);
} catch (VizException e) {
e.printStackTrace();
status = -1;
}
return status;
}
/**
* Insert a new Crest record.
*
* @param query
* The query
* @return 1 if successful, -1 if unsuccessful, -2 if record already exists
*/
public int insertCrest(String query) {
int status = 1;
try {
runStatement(query);
} catch (VizException e) {
if (e.getCause().toString()
.indexOf("violates unique constraint") > 0) {
status = -2;
} else {
status = -1;
}
}
return status;
}
/**
* Set the dataMap.
*
* @param dataMap
* The dataMap to set
*/
public void setReportData(Map<String, FloodReportData> dataMap) {
this.dataMap = dataMap;
}
/**
* Return the dataMap holding the crest data.
*
* @return The dataMap
*/
public Map<String, FloodReportData> getReportData() {
return dataMap;
}
/**
* @return the selectedLid
*/
public String getSelectedLid() {
return selectedLid;
}
/**
* @param selectedLid
* the selectedLid to set
*/
public void setSelectedLid(String selectedLid) {
this.selectedLid = selectedLid;
}
/**
* @return the startDate
*/
public Date getStartDate() {
return startDate;
}
/**
* @param startDate
* the startDate to set
*/
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
/**
* @return the endDate
*/
public Date getEndDate() {
return endDate;
}
/**
* @param endDate
* the endDate to set
*/
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
/**
* @return the drawGraph
*/
public boolean isDrawGraph() {
return drawGraph;
}
/**
* @param drawGraph
* the drawGraph to set
*/
public void setDrawGraph(boolean drawGraph) {
this.drawGraph = drawGraph;
}
/**
* @return the selectedKey
*/
public String getSelectedKey() {
return selectedKey;
}
/**
* @param selectedKey
* the selectedKey to set
*/
public void setSelectedKey(String selectedKey) {
this.selectedKey = selectedKey;
}
}