text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.Particles = void 0;
  const Particle_1 = require("./Particle");
  const Utils_1 = require("../Utils");
  const InteractionManager_1 = require("./InteractionManager");
  const ParticlesOptions_1 = require("../Options/Classes/Particles/ParticlesOptions");
  const Mover_1 = require("./Particle/Mover");
  class Particles {
      constructor(container) {
          this.container = container;
          this.nextId = 0;
          this.array = [];
          this.zArray = [];
          this.mover = new Mover_1.Mover(container);
          this.limit = 0;
          this.needsSort = false;
          this.lastZIndex = 0;
          this.linksFreq = new Map();
          this.trianglesFreq = new Map();
          this.interactionManager = new InteractionManager_1.InteractionManager(container);
          const canvasSize = this.container.canvas.size;
          this.linksColors = new Map();
          this.quadTree = new Utils_1.QuadTree(new Utils_1.Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, (canvasSize.width * 3) / 2, (canvasSize.height * 3) / 2), 4);
          this.updaters = Utils_1.Plugins.getUpdaters(container);
      }
      get count() {
          return this.array.length;
      }
      init() {
          var _a;
          const container = this.container;
          const options = container.actualOptions;
          this.lastZIndex = 0;
          this.needsSort = false;
          this.linksFreq = new Map();
          this.trianglesFreq = new Map();
          let handled = false;
          for (const [, plugin] of container.plugins) {
              if (plugin.particlesInitialization !== undefined) {
                  handled = plugin.particlesInitialization();
              }
              if (handled) {
                  break;
              }
          }
          this.addManualParticles();
          if (!handled) {
              for (const group in options.particles.groups) {
                  const groupOptions = options.particles.groups[group];
                  for (let i = this.count, j = 0; j < ((_a = groupOptions.number) === null || _a === void 0 ? void 0 : _a.value) && i < options.particles.number.value; i++, j++) {
                      this.addParticle(undefined, groupOptions, group);
                  }
              }
              for (let i = this.count; i < options.particles.number.value; i++) {
                  this.addParticle();
              }
          }
          container.pathGenerator.init(container);
      }
      redraw() {
          this.clear();
          this.init();
          this.draw({ value: 0, factor: 0 });
      }
      removeAt(index, quantity = 1, group, override) {
          if (!(index >= 0 && index <= this.count)) {
              return;
          }
          let deleted = 0;
          for (let i = index; deleted < quantity && i < this.count; i++) {
              const particle = this.array[i];
              if (!particle || particle.group !== group) {
                  continue;
              }
              particle.destroy(override);
              this.array.splice(i--, 1);
              const zIdx = this.zArray.indexOf(particle);
              this.zArray.splice(zIdx, 1);
              deleted++;
          }
      }
      remove(particle, group, override) {
          this.removeAt(this.array.indexOf(particle), undefined, group, override);
      }
      update(delta) {
          const container = this.container;
          const particlesToDelete = [];
          container.pathGenerator.update();
          for (const [, plugin] of container.plugins) {
              if (plugin.update !== undefined) {
                  plugin.update(delta);
              }
          }
          for (const particle of this.array) {
              const resizeFactor = container.canvas.resizeFactor;
              if (resizeFactor) {
                  particle.position.x *= resizeFactor.width;
                  particle.position.y *= resizeFactor.height;
              }
              particle.bubble.inRange = false;
              for (const [, plugin] of this.container.plugins) {
                  if (particle.destroyed) {
                      break;
                  }
                  if (plugin.particleUpdate) {
                      plugin.particleUpdate(particle, delta);
                  }
              }
              this.mover.move(particle, delta);
              if (particle.destroyed) {
                  particlesToDelete.push(particle);
                  continue;
              }
              this.quadTree.insert(new Utils_1.Point(particle.getPosition(), particle));
          }
          for (const particle of particlesToDelete) {
              this.remove(particle);
          }
          this.interactionManager.externalInteract(delta);
          for (const particle of container.particles.array) {
              for (const updater of this.updaters) {
                  updater.update(particle, delta);
              }
              if (!particle.destroyed && !particle.spawning) {
                  this.interactionManager.particlesInteract(particle, delta);
              }
          }
          delete container.canvas.resizeFactor;
      }
      draw(delta) {
          const container = this.container;
          container.canvas.clear();
          const canvasSize = this.container.canvas.size;
          this.quadTree = new Utils_1.QuadTree(new Utils_1.Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, (canvasSize.width * 3) / 2, (canvasSize.height * 3) / 2), 4);
          this.update(delta);
          if (this.needsSort) {
              this.zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
              this.lastZIndex = this.zArray[this.zArray.length - 1].position.z;
              this.needsSort = false;
          }
          for (const [, plugin] of container.plugins) {
              container.canvas.drawPlugin(plugin, delta);
          }
          for (const p of this.zArray) {
              p.draw(delta);
          }
      }
      clear() {
          this.array = [];
          this.zArray = [];
      }
      push(nb, mouse, overrideOptions, group) {
          this.pushing = true;
          for (let i = 0; i < nb; i++) {
              this.addParticle(mouse === null || mouse === void 0 ? void 0 : mouse.position, overrideOptions, group);
          }
          this.pushing = false;
      }
      addParticle(position, overrideOptions, group) {
          const container = this.container;
          const options = container.actualOptions;
          const limit = options.particles.number.limit * container.density;
          if (limit > 0) {
              const countToRemove = this.count + 1 - limit;
              if (countToRemove > 0) {
                  this.removeQuantity(countToRemove);
              }
          }
          return this.pushParticle(position, overrideOptions, group);
      }
      addSplitParticle(parent) {
          const splitOptions = parent.options.destroy.split;
          const options = new ParticlesOptions_1.ParticlesOptions();
          options.load(parent.options);
          const factor = Utils_1.getRangeValue(splitOptions.factor.value);
          options.color.load({
              value: {
                  hsl: parent.getFillColor(),
              },
          });
          if (typeof options.size.value === "number") {
              options.size.value /= factor;
          }
          else {
              options.size.value.min /= factor;
              options.size.value.max /= factor;
          }
          options.load(splitOptions.particles);
          const offset = splitOptions.sizeOffset ? Utils_1.setRangeValue(-parent.size.value, parent.size.value) : 0;
          const position = {
              x: parent.position.x + Utils_1.randomInRange(offset),
              y: parent.position.y + Utils_1.randomInRange(offset),
          };
          return this.pushParticle(position, options, parent.group, (particle) => {
              if (particle.size.value < 0.5) {
                  return false;
              }
              particle.velocity.length = Utils_1.randomInRange(Utils_1.setRangeValue(parent.velocity.length, particle.velocity.length));
              particle.splitCount = parent.splitCount + 1;
              particle.unbreakable = true;
              setTimeout(() => {
                  particle.unbreakable = false;
              }, 500);
              return true;
          });
      }
      removeQuantity(quantity, group) {
          this.removeAt(0, quantity, group);
      }
      getLinkFrequency(p1, p2) {
          const key = `${Math.min(p1.id, p2.id)}_${Math.max(p1.id, p2.id)}`;
          let res = this.linksFreq.get(key);
          if (res === undefined) {
              res = Math.random();
              this.linksFreq.set(key, res);
          }
          return res;
      }
      getTriangleFrequency(p1, p2, p3) {
          let [id1, id2, id3] = [p1.id, p2.id, p3.id];
          if (id1 > id2) {
              [id2, id1] = [id1, id2];
          }
          if (id2 > id3) {
              [id3, id2] = [id2, id3];
          }
          if (id1 > id3) {
              [id3, id1] = [id1, id3];
          }
          const key = `${id1}_${id2}_${id3}`;
          let res = this.trianglesFreq.get(key);
          if (res === undefined) {
              res = Math.random();
              this.trianglesFreq.set(key, res);
          }
          return res;
      }
      addManualParticles() {
          const container = this.container;
          const options = container.actualOptions;
          for (const particle of options.manualParticles) {
              const pos = particle.position
                  ? {
                      x: (particle.position.x * container.canvas.size.width) / 100,
                      y: (particle.position.y * container.canvas.size.height) / 100,
                  }
                  : undefined;
              this.addParticle(pos, particle.options);
          }
      }
      setDensity() {
          const options = this.container.actualOptions;
          for (const group in options.particles.groups) {
              this.applyDensity(options.particles.groups[group], 0, group);
          }
          this.applyDensity(options.particles, options.manualParticles.length);
      }
      applyDensity(options, manualCount, group) {
          var _a;
          if (!((_a = options.number.density) === null || _a === void 0 ? void 0 : _a.enable)) {
              return;
          }
          const numberOptions = options.number;
          const densityFactor = this.initDensityFactor(numberOptions.density);
          const optParticlesNumber = numberOptions.value;
          const optParticlesLimit = numberOptions.limit > 0 ? numberOptions.limit : optParticlesNumber;
          const particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount;
          const particlesCount = Math.min(this.count, this.array.filter((t) => t.group === group).length);
          this.limit = numberOptions.limit * densityFactor;
          if (particlesCount < particlesNumber) {
              this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
          }
          else if (particlesCount > particlesNumber) {
              this.removeQuantity(particlesCount - particlesNumber, group);
          }
      }
      initDensityFactor(densityOptions) {
          const container = this.container;
          if (!container.canvas.element || !densityOptions.enable) {
              return 1;
          }
          const canvas = container.canvas.element;
          const pxRatio = container.retina.pixelRatio;
          return (canvas.width * canvas.height) / (densityOptions.factor * Math.pow(pxRatio, 2) * densityOptions.area);
      }
      pushParticle(position, overrideOptions, group, initializer) {
          try {
              const particle = new Particle_1.Particle(this.nextId, this.container, position, overrideOptions, group);
              let canAdd = true;
              if (initializer) {
                  canAdd = initializer(particle);
              }
              if (!canAdd) {
                  return;
              }
              this.array.push(particle);
              this.zArray.push(particle);
              this.nextId++;
              return particle;
          }
          catch (e) {
              console.warn(`error adding particle: ${e}`);
              return;
          }
      }
  }
  exports.Particles = Particles;
  