Configures an OpenLayers TileWMS or XyzSource object from the provided
Mapbox GL style object.
@param {Object} glSource The Mapbox GL map source containing a 'tiles' property.
@param {Object} mapProjection The OpenLayers projection object.
@param {string} time TIME parameter.
@param {Object} fetchOptions Options to use for fetch calls.

@returns {Object} Configured OpenLayers TileWMSSource or XyzSource.
function configureTileSource(glSource, mapProjection, time, fetchOptions) {
  const tile_url = glSource.tiles[0];
  const commonProps = {
    attributions: glSource.attribution,
    minZoom: glSource.minzoom,
    maxZoom: 'maxzoom' in glSource ? glSource.maxzoom : 22,
    tileSize: glSource.tileSize || 512,
    crossOrigin: 'crossOrigin' in glSource ? glSource.crossOrigin : 'anonymous',
    projection: mapProjection,
  };
  // when there is an authorization header, enable the async loader.
  if (fetchOptions.headers && fetchOptions.headers.get('Authorization')) {
    commonProps.tileLoadFunction = authTileLoader(fetchOptions);
  }
  // check to see if the url is a wms request.
  if (tile_url.toUpperCase().indexOf('SERVICE=WMS') >= 0) {
    const params = parseQueryString(tile_url.substring(tile_url.lastIndexOf('?') + 1));
    const keys = Object.keys(params);
    for (let i = 0, ii = keys.length; i < ii; ++i) {
      if (keys[i].toUpperCase() === 'REQUEST') {
        delete params[keys[i]];
      }
    }
    if (time) {
      params.TIME = time;
    }
    let layerProjection;
    if (params.CRS !== mapProjection.getCode()) {
      layerProjection = params.CRS;
    }
    return new TileWMSSource(Object.assign({
      url: tile_url.split('?')[0],
      params,
    }, commonProps, {projection: layerProjection}));
  } else {
    const source = new XyzSource(Object.assign({
      urls: glSource.tiles,
    }, commonProps));
    source.setTileLoadFunction(function(tile, src) {
      // copy the src string.
      let img_src = src.slice();
      if (src.indexOf(BBOX_STRING) !== -1) {
        const bbox = source.getTileGrid().getTileCoordExtent(tile.getTileCoord());
        img_src = src.replace(BBOX_STRING, bbox.toString());
      }

      // check to see if a cache invalidation has been requested.
      const ck = source.get('_ck');
      if (ck !== undefined) {
        img_src = addParam(img_src, '_ck', ck);
      }

      // disabled the linter below as this is how
      //  OpenLayers documents this operation.
      // eslint-disable-next-line
      tile.getImage().src = img_src;
    });
    if (glSource.scheme === 'tms') {
      source.setTileUrlFunction((tileCoord, pixelRatio, projection) => {
        const min = 0;
        const max = glSource.tiles.length - 1;
        const idx = Math.floor(Math.random() * (max - min + 1)) + min;
        const z = tileCoord[0];
        const x = tileCoord[1];
        const y = tileCoord[2] + (1 << z);

        let url = glSource.tiles[idx].replace('{z}', z).replace('{y}', y).replace('{x}', x);

        // add cache invalidation as requested.
        const ck = source.get('_ck');
        if (ck !== undefined) {
          url = addParam(url, '_ck', ck);
        }
        return url;
      });
    }
    return source;
  }
}