import { m as macro } from '../../macros2.js';
import { s as style } from './FPSMonitor/FPSMonitor.module.css.js';

const noOp = Function.prototype;
function formatNumbers(n) {
  const sections = [];
  let size = n;
  while (size > 1000) {
    sections.push(`000${size % 1000}`.slice(-3));
    size = Math.floor(size / 1000);
  }
  if (size > 0) {
    sections.push(size);
  }
  sections.reverse();
  return sections.join("'");
}

// ----------------------------------------------------------------------------
// vtkFPSMonitor methods
// ----------------------------------------------------------------------------

function vtkFPSMonitor(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkFPSMonitor');
  model.fpsMonitorContainer = document.createElement('div');
  model.fpsMonitorContainer.setAttribute('class', model.orientationClass);
  model.fpsMonitorContainer.innerHTML = `
    <div class="${style.leftPane}">
      <div class="js-title ${style.title}">Mean N/A - Current N/A</div>
      <canvas class="js-graph ${style.graph}"></canvas>
    </div>
    <div class="js-info ${style.rightPane}">
    </div>`;

  // Extract various containers
  model.canvas = model.fpsMonitorContainer.querySelector('.js-graph');
  model.title = model.fpsMonitorContainer.querySelector('.js-title');
  model.info = model.fpsMonitorContainer.querySelector('.js-info');

  // --------------------------------------------------------------------------
  // Private methods
  // --------------------------------------------------------------------------

  function renderTitle() {
    model.title.style.display = model.titleVisibility ? 'block' : 'none';
    if (!model.titleVisibility) {
      return;
    }
    const nextFPS = model.buffer[model.buffer.length - 1];
    const newTxt = `Mean: ${Math.round(model.fpsSum / model.buffer.length)} - Current: ${Math.round(nextFPS)}`;
    if (newTxt !== model.lastText) {
      model.lastText = newTxt;
      model.title.innerHTML = newTxt;
    }
  }
  function renderInfo() {
    model.info.style.display = model.infoVisibility ? 'grid' : 'none';
    if (!model.infoVisibility) {
      return;
    }
    const infoItems = [];
    if (model.renderWindow) {
      const realView = model.renderWindow.getViews()[0];
      if (realView && realView.getSize) {
        infoItems.push(`<label class="${style.label}">Resolution</label><span class="${style.value}">${realView.getSize().join('x')}</span>`);
      }
      const stats = {
        ...model.renderWindow.getStatistics(),
        ...model.addOnStats
      };
      const keys = Object.keys(stats);
      keys.sort();
      for (let i = 0; i < keys.length; i++) {
        if (keys[i] === 'str') {
          continue; // eslint-disable-line
        }

        if (stats[keys[i]]) {
          infoItems.push(`<label class="${style.label}">${keys[i]}</label><span class="${style.value}">${formatNumbers(stats[keys[i]])}</span>`);
        }
      }
    }
    model.info.innerHTML = infoItems.join('');
  }
  function renderCanvas() {
    model.canvas.style.display = model.canvasVisibility ? 'block' : 'none';
    if (!model.canvasVisibility) {
      return;
    }
    // Although this is called frequently, setting an attribute to the same value is a no-op
    model.canvas.setAttribute('width', model.bufferSize);
    model.canvas.setAttribute('height', model.graphHeight);
    const ctx = model.canvas.getContext('2d');
    const {
      width,
      height
    } = model.canvas;
    ctx.clearRect(0, 0, width, height);
    // Current fps
    ctx.strokeStyle = 'green';
    ctx.beginPath();
    ctx.moveTo(0, height - model.buffer[0]);
    for (let i = 1; i < model.buffer.length; i++) {
      ctx.lineTo(i, height - model.buffer[i]);
    }
    ctx.stroke();
    // 60 fps ref
    ctx.strokeStyle = 'black';
    ctx.beginPath();
    ctx.moveTo(0, height - 60);
    ctx.lineTo(width, height - 60);
    ctx.stroke();
  }
  function frameChanged() {
    if (!model.interactor) {
      return;
    }
    const nextFPS = 1 / model.interactor.getLastFrameTime();
    model.buffer.push(nextFPS);
    model.fpsSum += nextFPS;
    while (model.buffer.length > model.bufferSize) {
      model.fpsSum -= model.buffer.shift();
    }
    renderTitle();
    renderInfo();
    renderCanvas();
  }

  // --------------------------------------------------------------------------
  // Public methods
  // --------------------------------------------------------------------------

  publicAPI.update = () => {
    publicAPI.render();
  };

  // --------------------------------------------------------------------------

  publicAPI.setRenderWindow = rw => {
    while (model.subscriptions.length) {
      model.subscriptions.pop().unsubscribe();
    }
    model.renderWindow = rw;
    model.interactor = rw ? rw.getInteractor() : null;
    if (model.interactor) {
      model.subscriptions.push(model.interactor.onAnimation(frameChanged));
    }
  };

  // --------------------------------------------------------------------------

  publicAPI.setContainer = el => {
    if (model.container && model.container !== el) {
      model.container.removeChild(model.fpsMonitorContainer);
    }
    if (model.container !== el) {
      model.container = el;
      if (model.container) {
        model.container.appendChild(model.fpsMonitorContainer);
        publicAPI.resize();
      }
      publicAPI.modified();
    }
  };

  // --------------------------------------------------------------------------

  publicAPI.render = () => {
    renderTitle();
    renderInfo();
    renderCanvas();
  };

  // --------------------------------------------------------------------------

  publicAPI.resize = noOp;

  // --------------------------------------------------------------------------

  publicAPI.setOrientationToHorizontal = () => {
    model.fpsMonitorContainer.classList.remove(model.orientationClass);
    model.orientationClass = style.horizontalContainer;
    model.fpsMonitorContainer.classList.add(model.orientationClass);
  };

  // --------------------------------------------------------------------------

  publicAPI.setOrientationToVertical = () => {
    model.fpsMonitorContainer.classList.remove(model.orientationClass);
    model.orientationClass = style.verticalContainer;
    model.fpsMonitorContainer.classList.add(model.orientationClass);
  };

  // --------------------------------------------------------------------------

  publicAPI.setOrientation = function () {
    let mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'horizontal';
    if (mode === 'horizontal') {
      publicAPI.setOrientationToHorizontal();
    } else {
      publicAPI.setOrientationToVertical();
    }
  };

  // --------------------------------------------------------------------------

  publicAPI.setAddOnStats = addOn => {
    if (!model.addOnStats) {
      model.addOnStats = {};
    }
    Object.assign(model.addOnStats, addOn);
    renderInfo();
  };

  // --------------------------------------------------------------------------

  publicAPI.setMonitorVisibility = function () {
    let title = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
    let graph = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
    let info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
    publicAPI.setCanvasVisibility(graph);
    publicAPI.setInfoVisibility(info);
    publicAPI.setTitleVisibility(title);
  };

  // --------------------------------------------------------------------------

  const superDelete = publicAPI.delete;
  publicAPI.delete = () => {
    publicAPI.setRenderWindow(null);
    publicAPI.setContainer(null);
    superDelete();
  };

  // --------------------------------------------------------------------------

  model.subscriptions.push(publicAPI.onModified(publicAPI.update));
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
  bufferSize: 200,
  graphHeight: 120,
  buffer: [60],
  subscriptions: [],
  fpsSum: 0,
  orientationClass: style.horizontalContainer,
  canvasVisibility: true,
  titleVisibility: true,
  infoVisibility: true
};

// ----------------------------------------------------------------------------

function extend(publicAPI, model) {
  let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Object methods
  macro.obj(publicAPI, model);
  macro.get(publicAPI, model, ['fpsMonitorContainer', 'renderWindow', 'addOnStats']);
  macro.setGet(publicAPI, model, ['bufferSize', 'canvasVisibility', 'infoVisibility', 'titleVisibility']);

  // Object specific methods
  vtkFPSMonitor(publicAPI, model);
}

// ----------------------------------------------------------------------------

const newInstance = macro.newInstance(extend, 'vtkFPSMonitor');

// ----------------------------------------------------------------------------

var vtkFPSMonitor$1 = {
  newInstance,
  extend
};

export { vtkFPSMonitor$1 as default, extend, newInstance };
