/* vim: set expandtab shiftwidth=2 softtabstop=2 tw=70: */

#include <Rcpp.h>
using namespace Rcpp;

// Cross-reference work:
// 1. update ../src/registerDynamicSymbol.c with an item for this
// 2. main code should use the autogenerated wrapper in ../R/RcppExports.R
//
// [[Rcpp::export]]
NumericVector do_fill_gap_1d(NumericVector x, NumericVector rule) {
  int the_rule = (int)floor(0.5 + rule[0]);
  // Rprintf("the_rule=%d\n", the_rule);
  int nx = x.size();
  NumericVector res(nx);
  int *isna = (int *)R_alloc(nx, sizeof(int));
  int last_ok;
  double x_last_ok = 0.0;
  for (int i = 0; i < nx; i++)
    isna[i] = (unsigned char)ISNA(x[i]);
  for (int i = 0; i < nx; i++)
    res[i] = x[i];
  // End points: keep NA or set constant, according to 'rule' value.
  int first_good = -1, last_good = nx; // set to values we can never get
  if (the_rule == 1) {
    ;
  } else if (the_rule == 2) {
    if (isna[0]) {
      for (int i = 0; i < nx; i++) {
        if (!isna[i]) {
          first_good = i;
          break;
        }
      }
      if (first_good == -1) {
        return (res); // whole vector is NA
      }
      for (int i = 0; i < first_good; i++) {
        // Rprintf("setting res[%d] with %f\n", i, res[first_good]);
        res[i] = res[first_good];
      }
    }
    if (isna[nx - 1]) {
      for (int i = nx - 1; i > -1; i--) {
        if (!isna[i]) {
          last_good = i;
          break;
        }
      }
      if (last_good == nx) {
        return (res); // no good data (cannot happen; would be caught already)
      }
      for (int i = nx - 1; i > last_good; i--) {
        res[i] = res[last_good];
      }
    }
  } else {
    Rcpp::stop("'rule' must be 1 or 2");
  }
  // Interior points: linear interpolation
  // Rprintf("first_good=%d last_good=%d\n", first_good, last_good);
  for (int i = first_good + 1; i < last_good - 1; i++) {
    // Rprintf("main loop isna[%d] = %d\n", i, isna[i]);
    if (isna[i]) {
      last_ok = i - 1;
      x_last_ok = x[last_ok];
      for (int j = i; j < nx; j++) {
        if (!isna[j]) {
          for (int ij = last_ok + 1; ij < j; ij++) {
            res[ij] =
                x_last_ok + (ij - last_ok) * (x[j] - x_last_ok) / (j - i + 1);
          }
          i = j - 1;
          break;
        }
      }
    } else {
      res[i] = x[i];
    }
  }
  return (res);
}
