<commit_before>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import SpellLink from 'common/SpellLink';
import ITEMS from 'common/ITEMS';
import { formatPercentage } from 'common/format';

import Analyzer from 'Parser/Core/Analyzer';
import Combatants from 'Parser/Core/Modules/Combatants';
import StatisticBox, { STATISTIC_ORDER } from 'Main/StatisticBox';

class ColdHeartEfficiency extends Analyzer {
  static dependencies = {
    combatants: Combatants,
  };
  on_initialized() {
    this.active = this.combatants.selected.hasChest(ITEMS.COLD_HEART.id);
  }

  totalColdHeartCasts = 0;
  correctColdHeartCasts = 0;
  buffColdHeart = 0;
  
  unholyStrengthStart = 0;
  unholyStrengthRemaining = 0;
  
  concordanceStart = 0;
  concordanceRemaining = 0;
  
  khazgorothStart = 0;
  khazgorothRemaining = 0;
  
  timeAtMaxStacksStart = 0;
  timeAtMaxStacks = 0;

  on_byPlayer_applybuff(event) {
    const spellID = event.ability.guid;
    if (spellID === SPELLS.UNHOLY_STRENGTH_BUFF.id) {
      this.unholyStrengthStart = event.timestamp;
    }
	if (spellID === SPELLS.CONCORDANCE_OF_THE_LEGIONFALL_STRENGTH.id) {
		this.concordanceStart = event.timestamp;
	}
	if (spellID === SPELLS.KHAZGOROTHS_SHAPING.id) {
		this.khazgorothStart = event.timestamp;
	}
  }
  
  on_byPlayer_refreshbuff(event) {
	const spellID = event.ability.guid;
	if (spellID === SPELLS.UNHOLY_STRENGTH_BUFF.id) {
      this.unholyStrengthStart = event.timestamp;
    }
	if (spellID === SPELLS.CONCORDANCE_OF_THE_LEGIONFALL_STRENGTH.id) {
		this.concordanceStart = event.timestamp;
	}
	if (spellID === SPELLS.KHAZGOROTHS_SHAPING.id) {
		this.khazgorothStart = event.timestamp;
	}
  }
  
  on_byPlayer_removebuff(event) {
    const spellID = event.ability.guid;
    if (spellID === SPELLS.UNHOLY_STRENGTH_BUFF.id) {
      this.unholyStrengthStart = 0;
    }
	if (spellID === SPELLS.CONCORDANCE_OF_THE_LEGIONFALL_STRENGTH.id) {
		this.concordanceStart = 0;
    }
	if (spellID === SPELLS.KHAZGOROTHS_SHAPING.id) {
		this.khazgorothStart = 0;
	}
  }

  on_byPlayer_applybuffstack(event) {
    const spellID = event.ability.guid;
    if (spellID === SPELLS.COLD_HEART_BUFF.id) {
      this.buffColdHeart = event.stack;
	  if (this.buffColdHeart == 20) {
		  this.timeAtMaxStacksStart = event.timestamp;
	  }
    }
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
	
    const unholyStrengthDuration = 15000;
	const concordanceDuration = 10000;
	const khazgorothDuration = 15000;
	
    const coldHeartMaxStack = 20;
    const coldHeartOptimalMinStack = 14;
	
    const remainingDurationAllowed = 4000;
	
	this.timeAtMaxStacks = event.timestamp - this.timeAtMaxStacksStart;
	
    this.unholyStrengthRemaining = unholyStrengthDuration - (event.timestamp - this.unholyStrengthStart);
	this.concordanceRemaining = concordanceDuration - (event.timestamp - this.concordanceStart);
	this.khazgorothRemaining = khazgorothDuration - (event.timestamp - this.khazgorothStart);
	
    if (spellId === SPELLS.CHAINS_OF_ICE.id) {
      this.totalColdHeartCasts++;
	  //This checks wether or not any of the three buffs are about to fall off within the next 4 seconds.
      if ((this.unholyStrengthRemaining > 0 & this.unholyStrengthRemaining < remainingDurationAllowed) || (this.concordanceRemaining > 0 & this.concordanceRemaining < remainingDurationAllowed) || (this.khazgorothRemaining > 0 & this.khazgorothRemaining < remainingDurationAllowed) & this.buffColdHeart < coldHeartMaxStack & this.buffColdHeart >= coldHeartOptimalMinStack) {
         this.correctColdHeartCasts++;
      }
      if (this.buffColdHeart === 20 & this.timeAtMaxStacks <= 4000) {
        this.correctColdHeartCasts++;
      }
      //This is only here for double casting Cold Heart. If Cold Heart is casted again before it reaches 2 stacks, the event won't update.
      this.buffColdHeart = 0;
    }

  }

  suggestions(when) {
    const castEfficiency = this.correctColdHeartCasts / this.totalColdHeartCasts;
    when(castEfficiency).isLessThan(0.8)
      .addSuggestion((suggest, actual, recommended) => {
        return suggest(<span>You are casting <SpellLink id={SPELLS.CHAINS_OF_ICE.id} /> at non optimal times. You either want to cast <SpellLink id={SPELLS.CHAINS_OF_ICE.id} /> when at 20 stacks of <SpellLink id={SPELLS.COLD_HEART_BUFF.id} /> or when you are above 16 stacks and your buff <SpellLink id={SPELLS.UNHOLY_STRENGTH_BUFF.id} /> is about to run out.</span>)
          .icon(SPELLS.CHAINS_OF_ICE.icon)
          .actual(`${formatPercentage(actual)}% of Chains of Ice were cast correctly.`)
          .recommended(`>${formatPercentage(recommended)}% is recommended`)
          .regular(recommended - 0.20).major(recommended - 0.40);
      });
  }
  statistic() {
    const castEfficiency = this.correctColdHeartCasts / this.totalColdHeartCasts;
    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.CHAINS_OF_ICE.id} />}
        value={`${formatPercentage(castEfficiency)} %`}
        label="Cold Heart Efficiency"
        tooltip={`${this.correctColdHeartCasts} out of ${this.totalColdHeartCasts} casts of Cold Heart were made optimally.`}
      />
    );
  }
  statisticOrder = STATISTIC_ORDER.CORE(5);
}

export default ColdHeartEfficiency;<commit_msg>Update ColdHeartEfficiency.js<commit_after>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import SpellLink from 'common/SpellLink';
import ITEMS from 'common/ITEMS';
import { formatPercentage } from 'common/format';

import Analyzer from 'Parser/Core/Analyzer';
import Combatants from 'Parser/Core/Modules/Combatants';
import StatisticBox, { STATISTIC_ORDER } from 'Main/StatisticBox';

class ColdHeartEfficiency extends Analyzer {
  static dependencies = {
    combatants: Combatants,
  };
  on_initialized() {
    this.active = this.combatants.selected.hasChest(ITEMS.COLD_HEART.id);
  }

  totalColdHeartCasts = 0;
  correctColdHeartCasts = 0;
  buffColdHeart = 0;
  
  unholyStrengthStart = 0;
  unholyStrengthRemaining = 0;
  
  concordanceStart = 0;
  concordanceRemaining = 0;
  
  khazgorothStart = 0;
  khazgorothRemaining = 0;
  
  timeAtMaxStacksStart = 0;
  timeAtMaxStacks = 0;

  on_byPlayer_applybuff(event) {
    const spellID = event.ability.guid;
    if (spellID === SPELLS.UNHOLY_STRENGTH_BUFF.id) {
      this.unholyStrengthStart = event.timestamp;
    }
	if (spellID === SPELLS.CONCORDANCE_OF_THE_LEGIONFALL_STRENGTH.id) {
		this.concordanceStart = event.timestamp;
	}
	if (spellID === SPELLS.KHAZGOROTHS_SHAPING.id) {
		this.khazgorothStart = event.timestamp;
	}
  }
  
  on_byPlayer_refreshbuff(event) {
	const spellID = event.ability.guid;
	if (spellID === SPELLS.UNHOLY_STRENGTH_BUFF.id) {
      this.unholyStrengthStart = event.timestamp;
    }
	if (spellID === SPELLS.CONCORDANCE_OF_THE_LEGIONFALL_STRENGTH.id) {
		this.concordanceStart = event.timestamp;
	}
	if (spellID === SPELLS.KHAZGOROTHS_SHAPING.id) {
		this.khazgorothStart = event.timestamp;
	}
  }
  
  on_byPlayer_removebuff(event) {
    const spellID = event.ability.guid;
    if (spellID === SPELLS.UNHOLY_STRENGTH_BUFF.id) {
      this.unholyStrengthStart = 0;
    }
	if (spellID === SPELLS.CONCORDANCE_OF_THE_LEGIONFALL_STRENGTH.id) {
		this.concordanceStart = 0;
    }
	if (spellID === SPELLS.KHAZGOROTHS_SHAPING.id) {
		this.khazgorothStart = 0;
	}
  }

  on_byPlayer_applybuffstack(event) {
    const spellID = event.ability.guid;
    if (spellID === SPELLS.COLD_HEART_BUFF.id) {
      this.buffColdHeart = event.stack;
	  if (this.buffColdHeart === 20) {
		  this.timeAtMaxStacksStart = event.timestamp;
	  }
    }
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
	
    const unholyStrengthDuration = 15000;
	const concordanceDuration = 10000;
	const khazgorothDuration = 15000;
	
    const coldHeartMaxStack = 20;
    const coldHeartOptimalMinStack = 14;
	
    const remainingDurationAllowed = 4000;
	
	this.timeAtMaxStacks = event.timestamp - this.timeAtMaxStacksStart;
	
    this.unholyStrengthRemaining = unholyStrengthDuration - (event.timestamp - this.unholyStrengthStart);
	this.concordanceRemaining = concordanceDuration - (event.timestamp - this.concordanceStart);
	this.khazgorothRemaining = khazgorothDuration - (event.timestamp - this.khazgorothStart);
	
    if (spellId === SPELLS.CHAINS_OF_ICE.id) {
      this.totalColdHeartCasts++;
	  //This checks wether or not any of the three buffs are about to fall off within the next 4 seconds.
      if ((this.unholyStrengthRemaining > 0 & this.unholyStrengthRemaining < remainingDurationAllowed) || (this.concordanceRemaining > 0 & this.concordanceRemaining < remainingDurationAllowed) || (this.khazgorothRemaining > 0 & this.khazgorothRemaining < remainingDurationAllowed) & this.buffColdHeart < coldHeartMaxStack & this.buffColdHeart >= coldHeartOptimalMinStack) {
         this.correctColdHeartCasts++;
      }
      if (this.buffColdHeart === 20 & this.timeAtMaxStacks <= 4000) {
        this.correctColdHeartCasts++;
      }
      //This is only here for double casting Cold Heart. If Cold Heart is casted again before it reaches 2 stacks, the event won't update.
      this.buffColdHeart = 0;
    }

  }

  suggestions(when) {
    const castEfficiency = this.correctColdHeartCasts / this.totalColdHeartCasts;
    when(castEfficiency).isLessThan(0.8)
      .addSuggestion((suggest, actual, recommended) => {
        return suggest(<span> You are casting <SpellLink id={SPELLS.CHAINS_OF_ICE.id} /> at non optimal times. You either want to cast <SpellLink id={SPELLS.CHAINS_OF_ICE.id} /> when at 20 stacks of <SpellLink id={SPELLS.COLD_HEART_BUFF.id} /> or when you are above 13 stacks and either of your buffs <SpellLink id={SPELLS.UNHOLY_STRENGTH_BUFF.id}/> or <SpellLink id={SPELLS.CONCORDANCE_OF_THE_LEGIONFALL_STRENGTH.id} />  or <SpellLink id={SPELLS.KHAZGOROTHS_SHAPING.id} /> are about to run out. You also don't want to hold <SpellLink id={SPELLS.CHAINS_OF_ICE.id} /> at 20 stacks for too long. </span>)
          .icon(SPELLS.CHAINS_OF_ICE.icon)
          .actual(`${formatPercentage(actual)}% of Chains of Ice were cast correctly.`)
          .recommended(`>${formatPercentage(recommended)}% is recommended`)
          .regular(recommended - 0.20).major(recommended - 0.40);
      });
  }
  statistic() {
    const castEfficiency = this.correctColdHeartCasts / this.totalColdHeartCasts;
    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.CHAINS_OF_ICE.id} />}
        value={`${formatPercentage(castEfficiency)} %`}
        label="Cold Heart Efficiency"
        tooltip={`${this.correctColdHeartCasts} out of ${this.totalColdHeartCasts} casts of Cold Heart were made optimally.`}
      />
    );
  }
  statisticOrder = STATISTIC_ORDER.CORE(5);
}

export default ColdHeartEfficiency;
{'fraction_non_alphanumeric': 0.10617511520737327, 'fraction_numerical': 0.011981566820276499, 'mean_word_length': 3.932272727272727, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '1373031', 'n_tokens_mistral': 4070, 'n_tokens_neox': 3749, 'n_words': 716}