/*
* Copyright 1998-2015 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.nc2.iosp.gempak;
import ucar.nc2.constants.CDM;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class to hold a lookup of gempak parameters
*
* @author IDV Development Team
*/
public class GempakParameterTable {
/**
* table to hold the values
*/
private HashMap<String, GempakParameter> paramMap = new HashMap<>(256);
/**
* table to hold the template values
*/
private HashMap<String, GempakParameter> templateParamMap = new HashMap<>(20);
/**
* indices of breakpoints in the table
*/
private static int[] indices = {
0, 4, 38, 59, 72, 79, 90, 97
};
/**
* lengths
*/
private static int[] lengths = {
4, 33, 21, 13, 7, 11, 6, 6
};
/**
* Create a new table.
*/
public GempakParameterTable() {
}
/*
ID# NAME UNITS GNAM SCALE MISSING HZREMAP DIRECTION
*/
/**
* Add parameters from the table
*
* @param tbl table location
* @throws IOException problem reading table.
*/
public void addParameters(String tbl) throws IOException {
try (InputStream is = getInputStream(tbl)) {
if (is == null) {
throw new IOException("Unable to open " + tbl);
}
String content = readContents(is); // LOOK this is silly - should just read one line at a time
// List lines = StringUtil.split(content, "\n", false);
String[] lines = content.split("\n");
List<String[]> result = new ArrayList<>();
for (String line : lines) {
//String line = (String) lines.get(i);
String tline = line.trim();
if (tline.length() == 0) {
continue;
}
if (tline.startsWith("!")) {
continue;
}
String[] words = new String[indices.length];
for (int idx = 0; idx < indices.length; idx++) {
if (indices[idx] >= tline.length()) {
continue;
}
if (indices[idx] + lengths[idx] > tline.length()) {
words[idx] = line.substring(indices[idx]);
} else {
words[idx] = line.substring(indices[idx],
indices[idx] + lengths[idx]);
}
//if (trimWords) {
words[idx] = words[idx].trim();
//}
}
result.add(words);
}
for (String[] aResult : result) {
GempakParameter p = makeParameter(aResult);
if (p != null) {
if (p.getName().contains("(")) {
templateParamMap.put(p.getName(), p);
} else {
paramMap.put(p.getName(), p);
}
}
}
}
}
/**
* Make a parameter from the tokens
*
* @param words the tokens
* @return a grid parameter (may be null)
*/
private GempakParameter makeParameter(String[] words) {
int num = 0;
String description;
if (words[0] != null) {
num = (int) Double.parseDouble(words[0]);
}
if ((words[3] == null) || words[3].equals("")) { // no param name
return null;
}
String name = words[3];
if (name.contains("-")) {
int first = name.indexOf("-");
int last = name.lastIndexOf("-");
StringBuilder buf = new StringBuilder(name.substring(0, first));
buf.append("(");
for (int i = first; i <= last; i++) {
buf.append("\\d");
}
buf.append(")");
buf.append(name.substring(last + 1));
name = buf.toString();
}
if ((words[1] == null) || words[1].equals("")) {
description = words[3];
} else {
description = words[1];
}
String unit = words[2];
if (unit != null) {
unit = unit.replaceAll("\\*\\*", "");
if (unit.equals("-")) {
unit = "";
}
}
int decimalScale;
try {
decimalScale = Integer.parseInt(words[4].trim());
} catch (NumberFormatException ne) {
decimalScale = 0;
}
return new GempakParameter(num, name, description, unit,
decimalScale);
}
/**
* Get the parameter for the given name
*
* @param name name of the parameter (eg:, TMPK);
* @return corresponding parameter or null if not found in table
*/
public GempakParameter getParameter(String name) {
GempakParameter param = paramMap.get(name);
if (param == null) { // try the regex list
Set<String> keys = templateParamMap.keySet();
if (!keys.isEmpty()) {
for (String key : keys) {
Pattern p = Pattern.compile(key);
Matcher m = p.matcher(name);
if (m.matches()) {
//System.out.println("found match " + key + " for " + name);
String value = m.group(1);
GempakParameter match = templateParamMap.get(key);
param = new GempakParameter(match.getNumber(), name,
match.getDescription() + " (" + value
+ " hour)", match.getUnit(),
match.getDecimalScale());
paramMap.put(name, param);
break;
}
}
}
}
return param;
}
/**
* Test
*
* @param args ignored
* @throws IOException problem reading the table.
*/
public static void main(String[] args) throws IOException {
GempakParameterTable pt = new GempakParameterTable();
//pt.addParameters("resources/nj22/tables/gempak/wmogrib3.tbl");
pt.addParameters("resources/nj22/tables/gempak/params.tbl");
if (args.length > 0) {
String param = args[0];
GempakParameter parm = pt.getParameter(param);
if (parm != null) {
System.out.println("Found " + param + ": " + parm);
}
}
}
/**
* Read in the bytes from the given InputStream
* and construct and return a String.
* Closes the InputStream argument.
*
* @param is InputStream to read from
* @return contents as a String
* @throws IOException problem reading contents
*/
private String readContents(InputStream is) throws IOException {
return new String(readBytes(is), CDM.utf8Charset);
}
/**
* Read the bytes in the given input stream.
*
* @param is The input stream
* @return The bytes
* @throws IOException On badness
*/
private byte[] readBytes(InputStream is) throws IOException {
int totalRead = 0;
byte[] content = new byte[1000000];
while (true) {
int howMany = is.read(content, totalRead,
content.length - totalRead);
if (howMany < 0) {
break;
}
if (howMany == 0) {
continue;
}
totalRead += howMany;
if (totalRead >= content.length) {
byte[] tmp = content;
int newLength = ((content.length < 25000000)
? content.length * 2
: content.length + 5000000);
content = new byte[newLength];
System.arraycopy(tmp, 0, content, 0, totalRead);
}
}
is.close();
byte[] results = new byte[totalRead];
System.arraycopy(content, 0, results, 0, totalRead);
return results;
}
/**
* Get the input stream to the given resource
*
* @param resourceName The resource name. May be a file, url,
* java resource, etc.
* @return The input stream to the resource
*/
private InputStream getInputStream(String resourceName) throws IOException {
// Try class loader to get resource
ClassLoader cl = GempakParameterTable.class.getClassLoader();
InputStream s = cl.getResourceAsStream(resourceName);
if (s != null) {
return s;
}
//Try the file system
File f = new File(resourceName);
if (f.exists()) {
s = new FileInputStream(f);
}
if (s != null) {
return s;
}
//Try it as a url
Matcher m = Pattern.compile(" ").matcher(resourceName);
String encodedUrl = m.replaceAll("%20");
URL dataUrl = new URL(encodedUrl);
URLConnection connection = dataUrl.openConnection();
return connection.getInputStream();
}
}