const util = require('util');

const Type = require('./type').Type;
const _ = require('./helpers');

/*
 * These functions take an entity (npc/player)
 * and return the correct method or property
 * depending on type.
 */

const getName = entity => Type.isPlayer(entity) ?
  entity.getName() :
  entity.getShortDesc('en');

const getSpeed = entity => entity.getAttackSpeed;

const getWeapon = entity => Type.isPlayer(entity) ?
  entity.getEquipped('wield', true) :
  entity.getAttack('en');

const getOffhand = entity => Type.isPlayer(entity) ?
  entity.getEquipped('offhand', true) :
  null; //TODO: allow for dual attacks for npcs

const getBodyParts = entity => Type.isPlayer(entity) ?
  playerBodyParts :
  entity.getBodyParts();


function CombatHelper(entity) {
  this._entity = entity;

  /*
   * Example modifier: {
      name: 'berserk',
      effect: damage => damage * 2
    }
   * Speed mods will affect time in between attacks
   * in milliseconds. So, doubling it will half attack speed.
   */
  this.speedMods   = {};
  this.damageMods  = {};
  this.toHitMods   = {};

  const addMod = type =>
    modifier => this[type][modifier.name] = modifier.effect;

  this.addSpeedMod  = addMod('speedMods');
  this.addDamageMod = addMod('damageMods');
  this.addToHitMod  = addMod('toHitMods');

  const deleteMod = type =>
    name => delete this[type][name];

  this.removeSpeedMod  = deleteMod('speedMods');
  this.removeDamageMod = deleteMod('damageMods');
  this.removeToHitMod  = deleteMod('toHitMods');

  /**
   * Get primary weapon of player
   *
   */
  this.getWeapon = () => this._entity.getEquipped('wield', true);

  /**
  * Generic func to apply all mods to a stat,
  * starting with the base stat. 
  */
  const applyMods = (base, modsObj) => _
    .values(modsObj)
    .reduce((stat, modifier) => modifier(stat), base);

  /**
   * Get attack speed of a player
   * @return float milliseconds between attacks
   */
  this.getAttackSpeed = secondAttack => {
    const weapon  = secondAttack ? this.getSecondary() : this.getWeapon();
    const minimum = secondAttack ? 750 : 500;
    const maximum = 10 * 1000;

    const unarmedSpeed = this._entity.getAttribute('quickness');
    const weaponSpeed  = (weapon ?
      weapon.getAttribute('speed') :
      unarmedSpeed) * 500;
    const attributesSpeed = unarmedSpeed * 500
      + this._entity.getAttribute('cleverness') * 250;

    const baseSpeed = maximum - weaponSpeed - attributesSpeed;

    util.log("Player's base speed is ", baseSpeed);

    const speed = _
      .values(this.speedMods)
      .reduce((speed, modifier) => modifier(speed), baseSpeed);

    util.log("Player's modified speed is ", speed);

    //TODO: Use mod methods instead.
    // const stanceToSpeed = {
    //   'precise': 1.25,
    //   'cautious': 2,
    //   'berserk': .5,
    // };
    //
    // for (const stance in stanceToSpeed){
    //   if (self.checkStance(stance)) {
    //     const speedModifier = stanceToSpeed[stance];
    //     util.log(self.getName() + '\'s speed is modified: x' + speedModifier);
    //     speed = speed * speedModifier;
    //   }
    // }

    return Math.max(Math.min(maximum, speed), minimum);
  };

  return this;
}

function getHelper(entity) {
  return new CombatHelper(entity);
}

exports.CombatUtil   = { getHelper };
exports.CombatHelper = CombatHelper;

@@ -1712,17 +1712,16 @@
 se stat.
- 
 %0A  */%0A  
@@ -1832,24 +1832,175 @@
 t), base);%0A%0A
+  /**%0A  * Returns the max or min if the stat is out of bounds.%0A  */%0A  const setBounds = (min, max) =%3E stat =%3E%0A    Math.max(Math.min(max, stat), min);%0A%0A
   /**%0A   * G
@@ -2198,16 +2198,17 @@
 apon();%0A
+%0A
     cons
@@ -2273,24 +2273,84 @@
 10 * 1000;%0A%0A
+    const speedWithinBounds = setBounds(minimum, maximum);%0A%0A
     const un
@@ -2743,101 +2743,43 @@
 d = 
-_%0A      .values(this.speedMods)%0A      .reduce((speed, modifier) =%3E modifier(speed), baseSpeed
+applyMods(baseSpeed, this.speedMods
 );%0A%0A
@@ -2987,354 +2987,43 @@
  %7D;%0A
-    //%0A    // for (const stance in stanceToSpeed)%7B%0A    //   if (self.checkStance(stance)) %7B%0A    //     const speedModifier = stanceToSpeed%5Bstance%5D;%0A    //     util.log(self.getName() + '%5C's speed is modified: x' + speedModifier);%0A    //     speed = speed * speedModifier;%0A    //   %7D%0A    // %7D%0A%0A    return Math.max(Math.min(maximum, speed), minimum
+%0A    return speedWithinBounds(speed
 );%0A 

Set up a generic func for setting min and max for a stat.