WaterLocations_WqDataPortal.java [src/WaterLocations] Revision: default  Date:
package WaterLocations;

import csip.api.client.ModelDataServiceCall;
import java.io.IOException;
import java.util.ArrayList;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import utils.WebPageUtils;

/**
* Last Updated: 3-January-2022
* @author Tyler Wible
* @since 20-November-2018
* The Water Quality Data Portal covers STORET, USGS, and STEWARDS databases, more information available here:
* https://www.waterqualitydata.us/webservices_documentation/
*/
public class WaterLocations_WqDataPortal implements WaterLocationsInterface {
    String database = "STORET"; //This is currently only setup for STORET stations, so it needs expand to USGS and STEWARDS

    private ArrayList<String> downloadStations_orig(String minLat, String maxLat, String minLong, String maxLong, boolean keepHistoricTF) throws WaterLocationsException {
        //WQX discontinued support for the bounding box search function due to upgrades in Amazon's SQL software, this may someday work again, but now right now
        
        //Specify station website from inputs
        //https://www.waterqualitydata.us/data/Station/search?providers=STORET&bBox=-105.204340919673,40.4500296208208,-105.016200050561,40.6972465847942&mimeType=tsv
        String stationUrl = "https://www.waterqualitydata.us/data/Station/search?providers=STORET&bBox=" +
                minLong + "," +
                minLat + "," +
                maxLong + "," +
                maxLat + "&mimeType=tsv";
        
        //Fetch the monitoring stations webpage for current bounding box
        ArrayList<String> webpageAll = new ArrayList<>();
        try {
            webpageAll = WebPageUtils.downloadWebpage(stationUrl);
        } catch (IOException ex) {
            throw new WaterLocationsException("The was an issue extracting " + database + " station locations from the specified URl: " + stationUrl + ". " + ex.getMessage());
        }
        return webpageAll;
    }
    
    @Override
    public ArrayList<String> downloadStations(String minLat, String maxLat, String minLong, String maxLong, boolean keepHistoricTF) throws WaterLocationsException {
        //Fetch stations by list of HUC8s until the bounding box function is fixed with WQX, tcw 20210608
        
        JSONObject boundary = new JSONObject();
        try {
            JSONArray features = new JSONArray();
            
            JSONObject feature = new JSONObject();
            
            JSONObject geometry = new JSONObject();
            
            JSONArray coordinates1 = new JSONArray();
            JSONArray coordinates2 = new JSONArray();
            JSONArray coordinates3 = new JSONArray();
            double minLatd = Double.parseDouble(minLat);
            double maxLatd = Double.parseDouble(maxLat);
            double minLongd = Double.parseDouble(minLong);
            double maxLongd = Double.parseDouble(maxLong);
            JSONArray array1 = new JSONArray();
            array1.put(minLongd);
            array1.put(maxLatd);
            JSONArray array2 = new JSONArray();
            array2.put(maxLongd);
            array2.put(maxLatd);
            JSONArray array3 = new JSONArray();
            array3.put(maxLongd);
            array3.put(minLatd);
            JSONArray array4 = new JSONArray();
            array4.put(minLongd);
            array4.put(minLatd);
            coordinates3.put(array1);
            coordinates3.put(array2);
            coordinates3.put(array3);
            coordinates3.put(array4);
            coordinates3.put(array1);//close the shape back at the original point
            coordinates2.put(coordinates3);
            coordinates1.put(coordinates2);
            
            geometry.put("coordinates", coordinates1);
            geometry.put("type", "MultiPolygon");
            
            feature.put("geometry", geometry);
            JSONObject properties = new JSONObject();
            feature.put("properties", properties);
            feature.put("type", "Feature");
            features.put(feature);
            
            boundary.put("features", features);
            boundary.put("type", "FeatureCollection");
        } catch (JSONException ex) {
            throw new WaterLocationsException("The was an issue generating the boundary for minLat:" + minLat + ", maxLat:" + maxLat + ", minLong:" + minLong + ", maxLong:" + maxLong + ". " + ex.getMessage());
        }
        
        //Call csip service for HUC8 boundaries
        ModelDataServiceCall res;
        try {
            res = new ModelDataServiceCall()
                    .put("huc", 8)
                    .put("boundary", boundary)
                    .url("http://csip.engr.colostate.edu:8088/csip-huc/d/huc/extent/1.0")
                    .withDefaultLogger()
                    .call();
        } catch (Exception ex) {
            throw new RuntimeException("Fetching huc8 boundaries");
        }
        
        //Convert list of HUC8s into strings for the url query with WQX
        String huc8list = "";
        if (res.serviceFinished()) {
            try {
                JSONArray resultList = (JSONArray) res.get("result");
                resultList = resultList.getJSONArray(0);
                if(resultList.length() > 0){
                    JSONObject hucResult = resultList.getJSONObject(0);
                    huc8list = hucResult.getString("huc8");
                    for(int i=1; i<resultList.length(); i++){
                        hucResult = resultList.getJSONObject(i);
                        huc8list += ";" + hucResult.getString("huc8");
                    }
                }
            } catch (Exception ex) {
                throw new RuntimeException("donwloading");
            }
        } else {
            throw new RuntimeException(res.getError());
        }
        
        //Fetch stations by watershed(s)
        ArrayList<String> webpageAll = new ArrayList<>();
        if(!huc8list.isEmpty()){
            webpageAll = downloadStations_huc(huc8list, false);
        }
        return webpageAll;
    }
    
    private ArrayList<String> downloadStations_huc(String huc8list, boolean keepHistoricTF) throws WaterLocationsException {
        //WQX discontinued support for the bounding box search function due to upgrades in Amazon's SQL software, this may someday work again, but now right now
        
        //Specify station website from inputs
        //https://www.waterqualitydata.us/data/Station/search?providers=STORET&bBox=-105.204340919673,40.4500296208208,-105.016200050561,40.6972465847942&mimeType=tsv
        String stationUrl = "https://www.waterqualitydata.us/data/Station/search?providers=STORET&huc=" +
                huc8list + "&mimeType=tsv";
        
        //Fetch the monitoring stations webpage for current bounding box
        ArrayList<String> webpageAll = new ArrayList<>();
        try {
            webpageAll = WebPageUtils.downloadWebpage(stationUrl);
        } catch (IOException ex) {
            throw new WaterLocationsException("The was an issue extracting " + database + " station locations from the specified URl: " + stationUrl + ". " + ex.getMessage());
        }
        return webpageAll;
    }

    @Override
    public ArrayList<Station> getStations(String minLat, String maxLat, String minLong, String maxLong, boolean keepHistoricTF) throws WaterLocationsException {
        //Fetch monitoring stations web page for current bounding box
        ArrayList<String> webpageAll = downloadStations(minLat, maxLat, minLong, maxLong, keepHistoricTF);
        
        ArrayList<Station> stations = new ArrayList();
        for(int i=1; i<webpageAll.size(); i++){//Skip header line
            String[] columns = webpageAll.get(i).split("\t");
            //Keep out only the desired data
            //columns[0] = Org. ID
            //columns[1] = Org. Name
            //columns[2] = Station ID
            //columns[3] = Station Name
            //columns[4] = Station Type (River/Stream, Reservoir)
            //columns[7] = Drainage Area
            //columns[8] = Drainage Area Units
            //columns[11] = Latitude
            //columns[12] = Longitude
            //columns[17] = Horizontal Datum
            //columns[18] = Elevation 
            //columns[19] = Elevation Units
            Station currentStation = new Station(database + "-" + columns[2]);
            currentStation.SetOrgId(columns[0]);
            currentStation.SetOrgName(columns[1]);
            currentStation.SetStationId(columns[2]);
            currentStation.SetStationName(columns[3]);
            currentStation.SetStationType(columns[4]);
            currentStation.SetDrainageArea(columns[7]);
            currentStation.SetDrainageAreaUnits(columns[8]);
            currentStation.SetLatitude(columns[11]);
            currentStation.SetLongitude(columns[12]);
            currentStation.SetHorizontalDatum(columns[17]);
            currentStation.SetElevation(columns[18]);
            currentStation.SetElevationUnits(columns[19]);
            stations.add(currentStation);
        }
        return stations;
    }
}