// TODO: move the getSACResponse to outputPZ or something.
  protected void outputFile(SacTimeSeries timeSeries, DateTime begin, String mask, String pzunit) {

    NSCL nscl =
        new NSCL(
            timeSeries.knetwk,
            timeSeries.kstnm,
            timeSeries.kcmpnm,
            timeSeries.khole.length() != 0 ? timeSeries.khole : "__");

    String filename = Filename.makeFilename(mask, nscl, begin);
    if (mask.equals("%N")) {
      filename += ".sac";
    }
    filename = filename.replaceAll("[__]", "_");

    try {
      timeSeries.write(filename);
      if (pzunit != null && metaDataServer != null) {
        MetaDataQuery mdq = new MetaDataQuery(metaDataServer);
        mdq.getSACResponse(nscl, begin, pzunit, filename + ".pz");
      }
    } catch (FileNotFoundException ex) {
      Logger.getLogger(SacFileFactory.class.getName())
          .log(Level.SEVERE, "File not found writing to SAC", ex);
    } catch (IOException ex) {
      Logger.getLogger(SacFileFactory.class.getName())
          .log(Level.SEVERE, "IO exception writing to SAC", ex);
    }
  }
  public SacTimeSeries makeTimeSeries(
      TreeSet<MiniSeed> miniSeed,
      DateTime begin,
      double duration,
      Integer fill,
      boolean gaps,
      boolean trim) {
    // This logic isn't strictly the same as SacOutputter.
    if (!gaps && fill == null) {
      fill = 2147000000;
    }

    // Use the span to populate a sac file

    TimeZone tz = TimeZone.getTimeZone("GMT+0");
    TimeZone.setDefault(tz);
    GregorianCalendar start = new GregorianCalendar();
    start.setTimeInMillis(begin.getMillis());

    // build the zero filled area (either with exact limits or with all blocks)
    ZeroFilledSpan span = new ZeroFilledSpan(new ArrayList(miniSeed), start, duration, fill);
    if (span.getRate() <= 0.00) {
      return null; // There is no real data to put in SAC
    }

    NSCL nscl = NSCL.stringToNSCL(miniSeed.first().getSeedName());

    logger.fine("ZeroSpan=" + span.toString());

    int noval = span.getNMissingData();

    if (!gaps && span.hasGapsBeforeEnd()) {
      logger.warning("  ** " + nscl.toString() + " has gaps - discarded # missing =" + noval);
      return null;
    }

    // ZeroFilledSpan span = new ZeroFilledSpan(blks);

    SacTimeSeries sac = new SacTimeSeries();
    sac.npts = span.getNsamp();

    // Set the byteOrder based on native architecture and sac statics
    sac.nvhdr = 6; // Only format supported
    sac.b = 0.; // beginning time offsed
    sac.e = ((span.getNsamp() - 1) / span.getRate());
    sac.iftype = SacTimeSeries.ITIME;
    sac.leven = SacTimeSeries.TRUE;
    sac.delta = (1. / span.getRate());
    sac.depmin = span.getMin();
    sac.depmax = span.getMax();
    sac.nzyear = span.getStart().get(Calendar.YEAR);
    sac.nzjday = span.getStart().get(Calendar.DAY_OF_YEAR);
    sac.nzhour = span.getStart().get(Calendar.HOUR_OF_DAY);
    sac.nzmin = span.getStart().get(Calendar.MINUTE);
    sac.nzsec = span.getStart().get(Calendar.SECOND);
    sac.nzmsec = span.getStart().get(Calendar.MILLISECOND);
    sac.iztype = SacTimeSeries.IB;

    sac.knetwk = nscl.getNetwork().replaceAll("_", "").trim();
    sac.kstnm = nscl.getStation().replaceAll("_", "").trim();
    sac.kcmpnm = nscl.getChannel().replaceAll("_", "").trim();
    sac.khole = nscl.getLocation().replaceAll("_", "").trim();

    logger.finer(
        "Sac stla="
            + sac.stla
            + " stlo="
            + sac.stlo
            + " stel="
            + sac.stel
            + " cmpaz="
            + sac.cmpaz
            + " cmpinc="
            + sac.cmpinc
            + " stdp="
            + sac.stdp);
    sac.y = new double[span.getNsamp()]; // allocate space for data
    int nodata = 0;
    for (int i = 0; i < span.getNsamp(); i++) {
      sac.y[i] = span.getData(i);
      if (sac.y[i] == fill) {
        nodata++;
        // if(nodata <3) logger.finest(i+" nodata len="+span.getNsamp());
      }
    }
    if (nodata > 0) {
      logger.finest("#No data points = " + nodata + " fill=" + fill + " npts=" + sac.npts);
    }
    if (trim) {
      int trimmed = sac.trimNodataEnd(fill);
      if (trimmed > 0) {
        logger.info(trimmed + " data points trimmed from end containing no data");
      }
    }

    if (metaDataServer != null) {
      MetaDataQuery mdq = new MetaDataQuery(metaDataServer);
      ChannelMetaData md = mdq.getChannelMetaData(nscl, begin);
      sac = SacHeaders.setChannelHeader(sac, md);
    }

    return sac;
  }