<commit_before>import React from 'react';

import { formatNumber, formatDuration } from 'common/format';

import SPELLS from 'common/SPELLS/index';
import ITEMS from 'common/ITEMS/index';

import Analyzer, { SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events from 'parser/core/Events';
import Abilities from 'parser/core/modules/Abilities';
import ItemStatistic from 'interface/statistics/ItemStatistic';
import ItemHealingDone from 'interface/others/ItemHealingDone';
import BoringItemValueText from 'interface/statistics/components/BoringItemValueText';

//Example Log: https://www.warcraftlogs.com/reports/vZQfwra1xVK76M4L/#fight=13&source=6

class VoidStone extends Analyzer {
  static dependencies = {
    abilities: Abilities,
  };

  static cooldown = 120; //seconds

  damageAbsorbed = 0;
  absorbedByUse = {};
  uses = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTrinket(ITEMS.VOID_STONE.id);
    if(!this.active) {
      return;
    }
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.UMBRAL_SHELL), this._cast);
    this.addEventListener(Events.absorbed.by(SELECTED_PLAYER).spell(SPELLS.UMBRAL_SHELL), this._absorb);

    this.abilities.add({
      spell: SPELLS.UMBRAL_SHELL,
      name: ITEMS.VOID_STONE.name,
      category: Abilities.SPELL_CATEGORIES.ITEMS,
      cooldown: this.constructor.cooldown,
      castEfficiency: {
        suggestion: false,
      },
    });
  }

  _cast(event){
    this.uses += 1;
    this.absorbedByUse[this.uses] = {time: event.timestamp - this.owner.fight.start_time, amount:0};
  }

  _absorb(event){
    this.damageAbsorbed += event.amount;
    this.absorbedByUse[this.uses].amount += event.amount;
  }


  statistic() {
    return (
      <ItemStatistic
        size="flexible"
        tooltip={(
          <>
            Uses: <b>{this.uses}</b><br />
            Total damage absorbed: <b>{formatNumber(this.damageAbsorbed)}</b><br />
            Average damage absorbed per shield: <b>{formatNumber(this.damageAbsorbed / this.uses)}</b><br />
            {this.uses > 0 &&
              <>Absorb per cast: <br />
                <ul>
                {Object.keys(this.absorbedByUse).map(use => {
                  return <li>Use <b>{use}</b> at <b>{formatDuration(this.absorbedByUse[use].time / 1000)}</b>: <b>{formatNumber(this.absorbedByUse[use].amount)}</b> damage absorbed</li>;
                })}
                </ul>
              </><commit_msg>adjusted formatting<commit_after>import React from 'react';

import { formatNumber, formatDuration } from 'common/format';

import SPELLS from 'common/SPELLS/index';
import ITEMS from 'common/ITEMS/index';

import Analyzer, { SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events from 'parser/core/Events';
import Abilities from 'parser/core/modules/Abilities';
import ItemStatistic from 'interface/statistics/ItemStatistic';
import ItemHealingDone from 'interface/others/ItemHealingDone';
import BoringItemValueText from 'interface/statistics/components/BoringItemValueText';

//Example Log: https://www.warcraftlogs.com/reports/vZQfwra1xVK76M4L/#fight=13&source=6

class VoidStone extends Analyzer {
  static dependencies = {
    abilities: Abilities,
  };

  static cooldown = 120; //seconds

  damageAbsorbed = 0;
  absorbedByUse = {};
  uses = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTrinket(ITEMS.VOID_STONE.id);
    if(!this.active) {
      return;
    }
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.UMBRAL_SHELL), this._cast);
    this.addEventListener(Events.absorbed.by(SELECTED_PLAYER).spell(SPELLS.UMBRAL_SHELL), this._absorb);

    this.abilities.add({
      spell: SPELLS.UMBRAL_SHELL,
      name: ITEMS.VOID_STONE.name,
      category: Abilities.SPELL_CATEGORIES.ITEMS,
      cooldown: this.constructor.cooldown,
      castEfficiency: {
        suggestion: false,
      },
    });
  }

  _cast(event){
    this.uses += 1;
    this.absorbedByUse[this.uses] = {
      time: event.timestamp - this.owner.fight.start_time,
      amount: 0,
      target: event.targetID,
    };
  }

  _absorb(event){
    this.damageAbsorbed += event.amount;
    this.absorbedByUse[this.uses].amount += event.amount;
  }

  get possibleUseCount() {
    return Math.ceil(this.owner.fightDuration / (this.constructor.cooldown * 1000));
  }


  statistic() {
    return (
      <ItemStatistic
        size="flexible"
        tooltip={(
          <>
            Uses: <b>{this.uses}</b> out of <b>{this.possibleUseCount}</b> possible use{this.possibleUseCount !== 1 && <>s</>}<br />
            Total damage absorbed: <b>{formatNumber(this.damageAbsorbed)}</b><br />
            Average damage absorbed per shield: <b>{formatNumber(this.damageAbsorbed / this.uses)}</b><br />
            {this.uses > 0 &&
              <>Absorb per cast: <br />
                <ul>
                {Object.keys(this.absorbedByUse).map(use => {
                  const target = this.owner.players.find(player => player.id === this.absorbedByUse[use].target);
                  return <li key={use}>Use <b>{use}</b> {target !== undefined && <>(on <b>{target.name}</b>)</>} at <b>{formatDuration(this.absorbedByUse[use].time / 1000)}</b>: <b>{formatNumber(this.absorbedByUse[use].amount)}</b> damage absorbed</li>;
                })}
                </ul>
              </>
{'fraction_non_alphanumeric': 0.1434108527131783, 'fraction_numerical': 0.007936507936507936, 'mean_word_length': 3.0500747384155455, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 62, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1465175', 'n_tokens_mistral': 1854, 'n_tokens_neox': 1763, 'n_words': 293}