private void aggregateDatapoints(TimeSeries ts) {
    ArrayList<Datapoint> pre;
    ArrayList<Datapoint> range;
    ArrayList<Datapoint> post;

    pre = aggregateDatapoints(ts.getVisiblePre(), ts.getDbRow().getType());
    range = aggregateDatapoints(ts.getVisible(), ts.getDbRow().getType());
    post = aggregateDatapoints(ts.getVisiblePost(), ts.getDbRow().getType());
    ts.setDatapoints(pre, range, post, true);

    return;
  }
  private void generateSynthetic(TimeSeries synth) {
    Formula formula = mFormulaCache.getFormula(synth.getDbRow().getId());

    long ms;
    long firstVisibleMs = Long.MAX_VALUE;
    long lastVisibleMs = Long.MIN_VALUE;

    for (int j = 0; j < synth.getDependents().size(); j++) {
      TimeSeries ts = synth.getDependents().get(j);
      List<Datapoint> range = ts.getVisible();

      if (range != null) {
        ms = range.get(0).mMillis;
        if (ms < firstVisibleMs) firstVisibleMs = ms;
        ms = range.get(range.size() - 1).mMillis;
        if (ms > lastVisibleMs) lastVisibleMs = ms;
      }
    }

    ArrayList<Datapoint> calculated = formula.apply(synth.getDependents());
    ArrayList<Datapoint> pre = new ArrayList<Datapoint>();
    ArrayList<Datapoint> visible = new ArrayList<Datapoint>();
    ArrayList<Datapoint> post = new ArrayList<Datapoint>();

    for (int j = 0; j < calculated.size(); j++) {
      Datapoint d = calculated.get(j);
      d.mCatId = synth.getDbRow().getId();
      d.mSynthetic = true;
      if (d.mMillis < firstVisibleMs) pre.add(d);
      else if (d.mMillis <= lastVisibleMs) visible.add(d);
      else post.add(d);
    }

    pre = aggregateDatapoints(pre, synth.getDbRow().getType());
    visible = aggregateDatapoints(visible, synth.getDbRow().getType());
    post = aggregateDatapoints(post, synth.getDbRow().getType());

    synth.setDatapoints(pre, visible, post, true);
  }