import Pass from './pass';
export default class LayersPass extends Pass {
  constructor(...args) {
    super(...args);
    this._lastRenderIndex = -1;
  }

  render(options) {
    var _options$clearColor;

    const [width, height] = this.device.canvasContext.getDrawingBufferSize();
    const renderPass = this.device.beginRenderPass({
      framebuffer: options.target,
      parameters: {
        viewport: [0, 0, width, height]
      },
      clearColor: (_options$clearColor = options.clearColor) !== null && _options$clearColor !== void 0 ? _options$clearColor : options.clearCanvas ? [0, 0, 0, 0] : false,
      clearDepth: options.clearCanvas ? 1 : undefined
    });

    try {
      return this._drawLayers(renderPass, options);
    } finally {
      renderPass.end();
    }
  }

  _drawLayers(renderPass, options) {
    const {
      target,
      moduleParameters,
      viewports,
      views,
      onViewportActive,
      clearStack = true
    } = options;
    options.pass = options.pass || 'unknown';

    if (clearStack) {
      this._lastRenderIndex = -1;
    }

    const renderStats = [];

    for (const viewport of viewports) {
      const view = views && views[viewport.id];
      onViewportActive === null || onViewportActive === void 0 ? void 0 : onViewportActive(viewport);

      const drawLayerParams = this._getDrawLayerParams(viewport, options);

      const subViewports = viewport.subViewports || [viewport];

      for (const subViewport of subViewports) {
        const stats = this._drawLayersInViewport(renderPass, {
          target,
          moduleParameters,
          viewport: subViewport,
          view,
          pass: options.pass,
          layers: options.layers
        }, drawLayerParams);

        renderStats.push(stats);
      }
    }

    return renderStats;
  }

  _getDrawLayerParams(viewport, {
    layers,
    pass,
    isPicking = false,
    layerFilter,
    cullRect,
    effects,
    moduleParameters
  }, evaluateShouldDrawOnly = false) {
    const drawLayerParams = [];
    const indexResolver = layerIndexResolver(this._lastRenderIndex + 1);
    const drawContext = {
      layer: layers[0],
      viewport,
      isPicking,
      renderPass: pass,
      cullRect
    };
    const layerFilterCache = {};

    for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) {
      const layer = layers[layerIndex];

      const shouldDrawLayer = this._shouldDrawLayer(layer, drawContext, layerFilter, layerFilterCache);

      const layerParam = {
        shouldDrawLayer
      };

      if (shouldDrawLayer && !evaluateShouldDrawOnly) {
        layerParam.layerRenderIndex = indexResolver(layer, shouldDrawLayer);
        layerParam.moduleParameters = this._getModuleParameters(layer, effects, pass, moduleParameters);
        layerParam.layerParameters = this.getLayerParameters(layer, layerIndex, viewport);
      }

      drawLayerParams[layerIndex] = layerParam;
    }

    return drawLayerParams;
  }

  _drawLayersInViewport(renderPass, {
    layers,
    moduleParameters: globalModuleParameters,
    pass,
    target,
    viewport,
    view
  }, drawLayerParams) {
    const glViewport = getGLViewport(this.device, {
      moduleParameters: globalModuleParameters,
      target,
      viewport
    });

    if (view && view.props.clear) {
      console.warn(`${view.id}: Per view clearing not yet implemented in deck.gl v9`);
    }

    const renderStatus = {
      totalCount: layers.length,
      visibleCount: 0,
      compositeCount: 0,
      pickableCount: 0
    };
    renderPass.setParameters({
      viewport: glViewport
    });

    for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) {
      const layer = layers[layerIndex];
      const {
        shouldDrawLayer,
        layerRenderIndex,
        moduleParameters,
        layerParameters
      } = drawLayerParams[layerIndex];

      if (shouldDrawLayer && layer.props.pickable) {
        renderStatus.pickableCount++;
      }

      if (layer.isComposite) {
        renderStatus.compositeCount++;
      } else if (shouldDrawLayer) {
        renderStatus.visibleCount++;
        this._lastRenderIndex = Math.max(this._lastRenderIndex, layerRenderIndex);
        moduleParameters.viewport = viewport;
        layer.context.renderPass = renderPass;

        try {
          layer._drawLayer({
            renderPass,
            moduleParameters,
            uniforms: {
              layerIndex: layerRenderIndex
            },
            parameters: layerParameters
          });
        } catch (err) {
          layer.raiseError(err, `drawing ${layer} to ${pass}`);
        }
      }
    }

    return renderStatus;
  }

  shouldDrawLayer(layer) {
    return true;
  }

  getModuleParameters(layer, effects) {
    return null;
  }

  getLayerParameters(layer, layerIndex, viewport) {
    return layer.props.parameters;
  }

  _shouldDrawLayer(layer, drawContext, layerFilter, layerFilterCache) {
    const shouldDrawLayer = layer.props.visible && this.shouldDrawLayer(layer);

    if (!shouldDrawLayer) {
      return false;
    }

    drawContext.layer = layer;
    let parent = layer.parent;

    while (parent) {
      if (!parent.props.visible || !parent.filterSubLayer(drawContext)) {
        return false;
      }

      drawContext.layer = parent;
      parent = parent.parent;
    }

    if (layerFilter) {
      const rootLayerId = drawContext.layer.id;

      if (!(rootLayerId in layerFilterCache)) {
        layerFilterCache[rootLayerId] = layerFilter(drawContext);
      }

      if (!layerFilterCache[rootLayerId]) {
        return false;
      }
    }

    layer.activateViewport(drawContext.viewport);
    return true;
  }

  _getModuleParameters(layer, effects, pass, overrides) {
    var _layer$internalState;

    const devicePixelRatio = this.device.canvasContext.cssToDeviceRatio();
    const moduleParameters = Object.assign(Object.create(((_layer$internalState = layer.internalState) === null || _layer$internalState === void 0 ? void 0 : _layer$internalState.propsInTransition) || layer.props), {
      autoWrapLongitude: layer.wrapLongitude,
      viewport: layer.context.viewport,
      mousePosition: layer.context.mousePosition,
      picking: {
        isActive: 0
      },
      devicePixelRatio
    });

    if (effects) {
      for (const effect of effects) {
        var _effect$getModulePara;

        Object.assign(moduleParameters, (_effect$getModulePara = effect.getModuleParameters) === null || _effect$getModulePara === void 0 ? void 0 : _effect$getModulePara.call(effect, layer));
      }
    }

    return Object.assign(moduleParameters, this.getModuleParameters(layer, effects), overrides);
  }

}
export function layerIndexResolver(startIndex = 0, layerIndices = {}) {
  const resolvers = {};

  const resolveLayerIndex = (layer, isDrawn) => {
    const indexOverride = layer.props._offset;
    const layerId = layer.id;
    const parentId = layer.parent && layer.parent.id;
    let index;

    if (parentId && !(parentId in layerIndices)) {
      resolveLayerIndex(layer.parent, false);
    }

    if (parentId in resolvers) {
      const resolver = resolvers[parentId] = resolvers[parentId] || layerIndexResolver(layerIndices[parentId], layerIndices);
      index = resolver(layer, isDrawn);
      resolvers[layerId] = resolver;
    } else if (Number.isFinite(indexOverride)) {
      index = indexOverride + (layerIndices[parentId] || 0);
      resolvers[layerId] = null;
    } else {
      index = startIndex;
    }

    if (isDrawn && index >= startIndex) {
      startIndex = index + 1;
    }

    layerIndices[layerId] = index;
    return index;
  };

  return resolveLayerIndex;
}

function getGLViewport(device, {
  moduleParameters,
  target,
  viewport
}) {
  const pixelRatio = moduleParameters && moduleParameters.devicePixelRatio || device.canvasContext.cssToDeviceRatio();
  const [, drawingBufferHeight] = device.canvasContext.getDrawingBufferSize();
  const height = target ? target.height : drawingBufferHeight;
  const dimensions = viewport;
  return [dimensions.x * pixelRatio, height - (dimensions.y + dimensions.height) * pixelRatio, dimensions.width * pixelRatio, dimensions.height * pixelRatio];
}
//# sourceMappingURL=layers-pass.js.map