// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function(window) {
  'use strict';

  // Prevent redefinition.
  if (window.GrEtagDecorator) { return; }

  // Limit cache size because /change/detail responses may be large.
  const MAX_CACHE_SIZE = 30;

  function GrEtagDecorator() {
    this._etags = new Map();
    this._payloadCache = new Map();
  }

  /**
   * Get or upgrade fetch options to include an ETag in a request.
   * @param {string} url The URL being fetched.
   * @param {!Object=} opt_options Optional options object in which to include
   *     the ETag request header. If omitted, the result will be a fresh option
   *     set.
   * @return {!Object}
   */
  GrEtagDecorator.prototype.getOptions = function(url, opt_options) {
    const etag = this._etags.get(url);
    if (!etag) {
      return opt_options;
    }
    const options = Object.assign({}, opt_options);
    options.headers = options.headers || new Headers();
    options.headers.set('If-None-Match', this._etags.get(url));
    return options;
  };

  /**
   * Handle a response to a request with ETag headers, potentially incorporating
   * its result in the payload cache.
   *
   * @param {string} url The URL of the request.
   * @param {!Response} response The response object.
   * @param {string} payload The raw, unparsed JSON contained in the response
   *     body. Note: because response.text() cannot be read twice, this must be
   *     provided separately.
   */
  GrEtagDecorator.prototype.collect = function(url, response, payload) {
    if (!response ||
        !response.ok ||
        response.status !== 200 ||
        response.status === 304) {
      // 304 Not Modified means etag is still valid.
      return;
    }
    this._payloadCache.set(url, payload);
    const etag = response.headers && response.headers.get('etag');
    if (!etag) {
      this._etags.delete(url);
    } else {
      this._etags.set(url, etag);
      this._truncateCache();
    }
  };

  /**
   * Get the cached payload for a given URL.
   * @param {string} url
   * @return {string|undefined} Returns the unparsed JSON payload from the
   *     cache.
   */
  GrEtagDecorator.prototype.getCachedPayload = function(url) {
    return this._payloadCache.get(url);
  };

  /**
   * Limit the cache size to MAX_CACHE_SIZE.
   */
  GrEtagDecorator.prototype._truncateCache = function() {
    for (const url of this._etags.keys()) {
      if (this._etags.size <= MAX_CACHE_SIZE) {
        break;
      }
      this._etags.delete(url);
      this._payloadCache.delete(url);
    }
  };

  window.GrEtagDecorator = GrEtagDecorator;
})(window);
