package thredds.server.ncss.view.dsg;
import org.springframework.http.HttpHeaders;
import thredds.server.ncss.exception.NcssException;
import thredds.server.ncss.exception.VariableNotContainedInDatasetException;
import thredds.server.ncss.format.SupportedFormat;
import thredds.server.ncss.params.NcssParamsBean;
import ucar.nc2.VariableSimpleIF;
import ucar.nc2.ft.FeatureDataset;
import ucar.nc2.ft.FeatureDatasetPoint;
import ucar.nc2.time.CalendarDate;
import ucar.nc2.time.CalendarDateRange;
import ucar.nc2.time.CalendarPeriod;
import ucar.nc2.units.TimeDuration;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* Created by cwardgar on 2014/05/20.
*/
public abstract class AbstractDsgSubsetWriter implements DsgSubsetWriter {
protected final FeatureDatasetPoint fdPoint;
protected final NcssParamsBean ncssParams;
protected final List<VariableSimpleIF> wantedVariables;
protected final CalendarDateRange wantedRange;
public AbstractDsgSubsetWriter(FeatureDatasetPoint fdPoint, NcssParamsBean ncssParams) throws NcssException {
this.fdPoint = fdPoint;
this.ncssParams = ncssParams;
this.wantedVariables = getWantedVariables(fdPoint, ncssParams);
this.wantedRange = getWantedRange(ncssParams);
}
/////////////////////////////////////////////////// NcssResponder //////////////////////////////////////////////////
@Override
public void respond(HttpServletResponse res, FeatureDataset ft, String requestPathInfo, NcssParamsBean queryParams,
SupportedFormat format) throws Exception {
write();
}
@Override
public HttpHeaders getResponseHeaders(FeatureDataset fd, SupportedFormat format, String datasetPath) {
return getHttpHeaders(datasetPath, format.isStream());
}
////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////
// TODO: This needs testing.
public static List<VariableSimpleIF> getWantedVariables(FeatureDatasetPoint fdPoint, NcssParamsBean ncssParams)
throws VariableNotContainedInDatasetException {
if (ncssParams.getVar().size() == 1 && ncssParams.getVar().get(0).equals("all")) {
return fdPoint.getDataVariables(); // Return all variables.
}
// restrict to these variables
Map<String, VariableSimpleIF> dataVarsMap = new HashMap<>();
for (VariableSimpleIF dataVar : fdPoint.getDataVariables()) {
dataVarsMap.put(dataVar.getShortName(), dataVar);
}
List<String> allVarNames = new ArrayList<>(dataVarsMap.keySet());
List<VariableSimpleIF> wantedVars = new ArrayList<>();
for (String varName : ncssParams.getVar()) {
if (allVarNames.contains(varName)) {
VariableSimpleIF var = dataVarsMap.get(varName);
wantedVars.add(var);
} else {
throw new VariableNotContainedInDatasetException(
"Variable: " + varName + " is not contained in the requested dataset");
}
}
return wantedVars;
}
// TODO: This needs testing.
public static CalendarDateRange getWantedRange(NcssParamsBean ncssParams) throws NcssException {
// There are 5 temporal parameters we must examine for DSGs.
boolean isAllTimes = ncssParams.isAllTimes();
String time = ncssParams.getTime();
String timeStart = ncssParams.getTime_start();
String timeEnd = ncssParams.getTime_end();
String timeDuration = ncssParams.getTime_duration();
if (isAllTimes) { // Client explicitly requested all times.
return null; // "null" means that we want ALL times, i.e. "do not subset".
} else if (time != null) { // Means we want just one single time.
// To prevent features from being too agressively excluded, we are accepting times that are within
// an hour of the specified time.
// LOOK: Do we really need the +- increment?
CalendarDate startR = CalendarDate.parseISOformat(null, time);
startR = startR.subtract(CalendarPeriod.Hour);
CalendarDate endR = CalendarDate.parseISOformat(null, time);
endR = endR.add(CalendarPeriod.Hour);
return CalendarDateRange.of(new Date(startR.getMillis()), new Date(endR.getMillis()));
} else if (timeStart == null && timeEnd == null && timeDuration == null) {
// Client did not set any of the time parameters, so give them everything.
return null; // "null" means that we want ALL times, i.e. "do not subset".
} else if (timeStart != null && timeEnd != null) {
CalendarDate startR = CalendarDate.parseISOformat(null, timeStart);
CalendarDate endR = CalendarDate.parseISOformat(null, timeEnd);
return CalendarDateRange.of(new Date(startR.getMillis()), new Date(endR.getMillis()));
} else if (timeStart != null && timeDuration != null) {
CalendarDate startR = CalendarDate.parseISOformat(null, timeStart);
TimeDuration td = ncssParams.parseTimeDuration();
return new CalendarDateRange(startR, (long) td.getValueInSeconds());
} else if (timeEnd != null && timeDuration != null) {
CalendarDate endR = CalendarDate.parseISOformat(null, timeEnd);
TimeDuration td = ncssParams.parseTimeDuration();
return new CalendarDateRange(endR, (long) td.getValueInSeconds() * (-1));
} else {
// We probably already handled this case upstream, but it doesn't hurt to handle it again.
throw new NcssException("Two of \"time_start\", \"time_end\", and \"time_duration\" " +
"must be present to define a valid time range.");
}
}
}