/*
 * Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

/* clang-format off */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>

#include "aom_dsp/bitwriter.h"
#include "av1/common/generic_code.h"
#include "av1/common/odintrin.h"
#include "pvq_encoder.h"

/** Encodes a value from 0 to N-1 (with N up to 16) based on a cdf and adapts
 * the cdf accordingly.
 *
 * @param [in,out] w     multi-symbol entropy encoder
 * @param [in]     val   variable being encoded
 * @param [in,out] cdf   CDF of the variable (Q15)
 * @param [in]     n     number of values possible
 * @param [in,out] count number of symbols encoded with that cdf so far
 * @param [in]     rate  adaptation rate shift (smaller is faster)
 */
void aom_encode_cdf_adapt_q15(aom_writer *w, int val, uint16_t *cdf, int n,
 int *count, int rate) {
  int i;
  if (*count == 0) {
    /* On the first call, we normalize the cdf to (32768 - n). This should
       eventually be moved to the state init, but for now it makes it much
       easier to experiment and convert symbols to the Q15 adaptation.*/
    int ft;
    ft = cdf[n - 1];
    for (i = 0; i < n; i++) {
      cdf[i] = AOM_ICDF(cdf[i]*32768/ft);
    }
  }
  aom_write_cdf(w, val, cdf, n);
  aom_cdf_adapt_q15(val, cdf, n, count, rate);
}

/** Encodes a random variable using a "generic" model, assuming that the
 * distribution is one-sided (zero and up), has a single mode, and decays
 * exponentially past the model.
 *
 * @param [in,out] w     multi-symbol entropy encoder
 * @param [in,out] model generic probability model
 * @param [in]     x     variable being encoded
 * @param [in,out] ExQ16 expectation of x (adapted)
 * @param [in]     integration integration period of ExQ16 (leaky average over
 * 1<<integration samples)
 */
void generic_encode(aom_writer *w, generic_encoder *model, int x,
 int *ex_q16, int integration) {
  int lg_q1;
  int shift;
  int id;
  uint16_t *cdf;
  int xs;
  lg_q1 = log_ex(*ex_q16);
  OD_LOG((OD_LOG_ENTROPY_CODER, OD_LOG_DEBUG,
   "%d %d", *ex_q16, lg_q1));
  /* If expectation is too large, shift x to ensure that
     all we have past xs=15 is the exponentially decaying tail
     of the distribution */
  shift = OD_MAXI(0, (lg_q1 - 5) >> 1);
  /* Choose the cdf to use: we have two per "octave" of ExQ16 */
  id = OD_MINI(GENERIC_TABLES - 1, lg_q1);
  cdf = model->cdf[id];
  xs = (x + (1 << shift >> 1)) >> shift;
  aom_write_symbol_pvq(w, OD_MINI(15, xs), cdf, 16);
  if (xs >= 15) {
    int e;
    unsigned decay;
    /* Estimate decay based on the assumption that the distribution is close
       to Laplacian for large values. We should probably have an adaptive
       estimate instead. Note: The 2* is a kludge that's not fully understood
       yet. */
    OD_ASSERT(*ex_q16 < INT_MAX >> 1);
    e = ((2**ex_q16 >> 8) + (1 << shift >> 1)) >> shift;
    decay = OD_MAXI(2, OD_MINI(254, 256*e/(e + 256)));
    /* Encode the tail of the distribution assuming exponential decay. */
    aom_laplace_encode_special(w, xs - 15, decay);
  }
  if (shift != 0) {
    int special;
    /* Because of the rounding, there's only half the number of possibilities
       for xs=0. */
    special = xs == 0;
    if (shift - special > 0) {
      aom_write_literal(w, x - (xs << shift) + (!special << (shift - 1)),
       shift - special);
    }
  }
  generic_model_update(ex_q16, x, integration);
  OD_LOG((OD_LOG_ENTROPY_CODER, OD_LOG_DEBUG,
   "enc: %d %d %d %d %d %x", *ex_q16, x, shift, id, xs, enc->rng));
}

/** Estimates the cost of encoding a value with generic_encode().
 *
 * @param [in,out] model generic probability model
 * @param [in]     x     variable being encoded
 * @param [in,out] ExQ16 expectation of x (adapted)
 * @return number of bits (approximation)
 */
double generic_encode_cost(generic_encoder *model, int x, int *ex_q16) {
  int lg_q1;
  int shift;
  int id;
  uint16_t *cdf;
  int xs;
  int extra;
  lg_q1 = log_ex(*ex_q16);
  /* If expectation is too large, shift x to ensure that
       all we have past xs=15 is the exponentially decaying tail
       of the distribution */
  shift = OD_MAXI(0, (lg_q1 - 5) >> 1);
  /* Choose the cdf to use: we have two per "octave" of ExQ16 */
  id = OD_MINI(GENERIC_TABLES - 1, lg_q1);
  cdf = model->cdf[id];
  xs = (x + (1 << shift >> 1)) >> shift;
  extra = 0;
  if (shift) extra = shift - (xs == 0);
  xs = OD_MINI(15, xs);
  /* Shortcut: assume it's going to cost 2 bits for the Laplace coder. */
  if (xs == 15) extra += 2;
  return
      extra - OD_LOG2((double)(cdf[xs] - (xs == 0 ? 0 : cdf[xs - 1]))/cdf[15]);
}

/*Estimates the cost of encoding a value with a given CDF.*/
double od_encode_cdf_cost(int val, uint16_t *cdf, int n) {
  int total_prob;
  int prev_prob;
  double val_prob;
  OD_ASSERT(n > 0);
  total_prob = cdf[n - 1];
  if (val == 0) {
    prev_prob = 0;
  }
  else {
    prev_prob = cdf[val - 1];
  }
  val_prob = (cdf[val] - prev_prob) / (double)total_prob;
  return -OD_LOG2(val_prob);
}