<commit_before>goog.module('soccersub.Player');

const Lineup = goog.require('soccersub.Lineup');
const util = goog.require('soccersub.util');
let Game = goog.forwardDeclare('soccersub.Game');
let Position = goog.forwardDeclare('soccersub.Position');

//const googString = goog.require('goog.string');
//goog.module('Player');
//const Game = goog.require('Game');

class Player {
  /**
   * @param {string} name
   * @param {!Lineup} lineup
   * @param {!Game} game
   */
  constructor(name, lineup, game) {
    this.name = name;
    this.lineup = lineup;
    this.game = game;
    /** @type {boolean} */
    this.availableForGame;
    /** @type {boolean} */
    this.selected = false;
    /** @type {number} */
    this.timeInGameMs;
    /** @type {number} */
    this.timeInShiftMs;
    /** @type {!Object<string, number>} */
    this.timeAtPositionMs;
    /** @type {!Object} */
    this.elementAtPosition;
    /** @type {?Position} */
    this.currentPosition;
    /** @type {?Element} */
    this.nameElement = null;    // initialized on render.
    /** @type {!Element} */
    this.gameTimeElement = document.createElement('td');
    /** @type {number} */
    this.timeInShift;
    /** @type {number} */
    this.percentageInGameNotKeeper;
    this.reset();
  };

  reset() {
    this.timeInGameMs = 0;
    this.timeInShiftMs = 0;
    this.percentageInGameNotKeeper = 0;
    this.availableForGame = true;  
    this.timeAtPositionMs = {};
    this.elementAtPosition = {};
    /** @type {?Position} */
    this.currentPosition = null;
    this.selected = false;
    for (let i = 0; i < this.lineup.positionNames.length; ++i) {
      const positionName = this.lineup.positionNames[i];
      this.timeAtPositionMs[positionName] = 0;
    }
  }

  /** @param {number} elapsedTimeMs */
  computePercentageInGameNotKeeper(elapsedTimeMs) {
    const timeAsKeeperMs = this.timeAtPositionMs['keeper'];
    const totalInGameWhenThisPlayerWasNotKeeperMs = elapsedTimeMs - timeAsKeeperMs;
    if (!totalInGameWhenThisPlayerWasNotKeeperMs) {
      return 0;
    }
    const playtimeTimeWhileNotKeeper = this.timeInGameMs - timeAsKeeperMs;
    this.percentageInGameNotKeeper = 100 * playtimeTimeWhileNotKeeper /
      totalInGameWhenThisPlayerWasNotKeeperMs;
  }

  /** @return {string} */
  status() {
    let msg = this.name + ': [';
    if (this.currentPosition != null) {
      msg += this.currentPosition.name + ': ' +
        util.formatTime(this.timeAtPositionMs[this.currentPosition.name]);
    } else if (this.availableForGame) {
      msg += 'available';
    } else { 
      msg += 'unavailable';
    }
    msg += ']';
    for (let i = 0; i < this.lineup.positionNames.length; ++i) {
      const positionName = this.lineup.positionNames[i];
      if ((this.currentPosition == null) ||
          (this.currentPosition.name != positionName)) {
        const timeMs = this.timeAtPositionMs[positionName];
        if (timeMs && (timeMs != 0)) {
          msg += " " + positionName + ": " + util.formatTime(timeMs);
        }
      }
    }
    return msg;
  }

  /**
   * @param {string} field
   * @param {Object.<string, string>} storage
   * @return {string}
   */
  getStorage(field, storage) {
    return storage['Player:' + this.name + ':' + field];
  }

  /**
   * @param {string} field
   * @param {string} value
   * @param {!Object.<string, string>} storage
   */
  setStorage(field, value, storage) {
    storage['Player:' + this.name + ':' + field] = value;
  };

  /**
   * @param {Object} gameMap
   * @return {?string}
   */
  restore(gameMap) {
    const playerMap = gameMap[this.name];
    if (!playerMap) {
      this.reset();
      return null;
    }
    this.timeInGameMs = playerMap.timeInGameMs;
    this.timeInShiftMs = playerMap.timeInShiftMs;
    this.availableForGame = playerMap.availableForGame;
    // timeAtPositionMs ...
    this.timeAtPositionMs = {};
    for (let i = 0; i < this.lineup.positionNames.length; ++i) {
      const positionName = this.lineup.positionNames[i];
      const timeMs = playerMap[positionName];
      this.timeAtPositionMs[positionName] = timeMs ? timeMs : 0;
    }
    return playerMap.currentPosition;
  }

  /**
   * @param {!Object} gameMap
   */
  save(gameMap) {
    const playerMap = {};
    gameMap[this.name] = playerMap;
    playerMap.timeInGameMs = this.timeInGameMs;
    playerMap.timeInShiftMs = this.timeInShiftMs;
    playerMap.availableForGame = this.availableForGame;
    playerMap.currentPosition = this.currentPosition
      ? this.currentPosition.name : null;
    for (let i = 0; i < this.lineup.positionNames.length; ++i) {
      const positionName = this.lineup.positionNames[i];
      const timeMs = this.timeAtPositionMs[positionName];
      if (timeMs) {
        playerMap[positionName] = timeMs;
      }
    }
  }

  /** @return {boolean} */
  isPlaying() {
    return this.currentPosition != null;
  }

  /**<commit_msg>prefix player data in game-map with PLAYER:NAME:FIELD rather than just NAME:FIELD<commit_after>goog.module('soccersub.Player');

const Lineup = goog.require('soccersub.Lineup');
const util = goog.require('soccersub.util');
let Game = goog.forwardDeclare('soccersub.Game');
let Position = goog.forwardDeclare('soccersub.Position');

//const googString = goog.require('goog.string');
//goog.module('Player');
//const Game = goog.require('Game');

const DB_PREFIX = 'player:';

class Player {
  /**
   * @param {string} name
   * @param {!Lineup} lineup
   * @param {!Game} game
   */
  constructor(name, lineup, game) {
    this.name = name;
    this.lineup = lineup;
    this.game = game;
    /** @type {boolean} */
    this.availableForGame;
    /** @type {boolean} */
    this.selected = false;
    /** @type {number} */
    this.timeInGameMs;
    /** @type {number} */
    this.timeInShiftMs;
    /** @type {!Object<string, number>} */
    this.timeAtPositionMs;
    /** @type {!Object} */
    this.elementAtPosition;
    /** @type {?Position} */
    this.currentPosition;
    /** @type {?Element} */
    this.nameElement = null;    // initialized on render.
    /** @type {!Element} */
    this.gameTimeElement = document.createElement('td');
    /** @type {number} */
    this.timeInShift;
    /** @type {number} */
    this.percentageInGameNotKeeper;
    this.reset();
  };

  reset() {
    this.timeInGameMs = 0;
    this.timeInShiftMs = 0;
    this.percentageInGameNotKeeper = 0;
    this.availableForGame = true;  
    this.timeAtPositionMs = {};
    this.elementAtPosition = {};
    /** @type {?Position} */
    this.currentPosition = null;
    this.selected = false;
    for (let i = 0; i < this.lineup.positionNames.length; ++i) {
      const positionName = this.lineup.positionNames[i];
      this.timeAtPositionMs[positionName] = 0;
    }
  }

  /** @param {number} elapsedTimeMs */
  computePercentageInGameNotKeeper(elapsedTimeMs) {
    const timeAsKeeperMs = this.timeAtPositionMs['keeper'];
    const totalInGameWhenThisPlayerWasNotKeeperMs = elapsedTimeMs - timeAsKeeperMs;
    if (!totalInGameWhenThisPlayerWasNotKeeperMs) {
      return 0;
    }
    const playtimeTimeWhileNotKeeper = this.timeInGameMs - timeAsKeeperMs;
    this.percentageInGameNotKeeper = 100 * playtimeTimeWhileNotKeeper /
      totalInGameWhenThisPlayerWasNotKeeperMs;
  }

  /** @return {string} */
  status() {
    let msg = this.name + ': [';
    if (this.currentPosition != null) {
      msg += this.currentPosition.name + ': ' +
        util.formatTime(this.timeAtPositionMs[this.currentPosition.name]);
    } else if (this.availableForGame) {
      msg += 'available';
    } else { 
      msg += 'unavailable';
    }
    msg += ']';
    for (let i = 0; i < this.lineup.positionNames.length; ++i) {
      const positionName = this.lineup.positionNames[i];
      if ((this.currentPosition == null) ||
          (this.currentPosition.name != positionName)) {
        const timeMs = this.timeAtPositionMs[positionName];
        if (timeMs && (timeMs != 0)) {
          msg += " " + positionName + ": " + util.formatTime(timeMs);
        }
      }
    }
    return msg;
  }

  /**
   * @param {string} field
   * @param {Object.<string, string>} storage
   * @return {string}
   */
  getStorage(field, storage) {
    return storage[DB_PREFIX + this.name + ':' + field];
  }

  /**
   * @param {string} field
   * @param {string} value
   * @param {!Object.<string, string>} storage
   */
  setStorage(field, value, storage) {
    storage[DB_PREFIX + this.name + ':' + field] = value;
  };

  /**
   * @param {Object} gameMap
   * @return {?string}
   */
  restore(gameMap) {
    const playerMap = gameMap[DB_PREFIX + this.name];
    if (!playerMap) {
      this.reset();
      return null;
    }
    this.timeInGameMs = playerMap.timeInGameMs;
    this.timeInShiftMs = playerMap.timeInShiftMs;
    this.availableForGame = playerMap.availableForGame;
    // timeAtPositionMs ...
    this.timeAtPositionMs = {};
    for (let i = 0; i < this.lineup.positionNames.length; ++i) {
      const positionName = this.lineup.positionNames[i];
      const timeMs = playerMap[positionName];
      this.timeAtPositionMs[positionName] = timeMs ? timeMs : 0;
    }
    return playerMap.currentPosition;
  }

  /**
   * @param {!Object} gameMap
   */
  save(gameMap) {
    const playerMap = {};
    gameMap[DB_PREFIX + this.name] = playerMap;
    playerMap.timeInGameMs = this.timeInGameMs;
    playerMap.timeInShiftMs = this.timeInShiftMs;
    playerMap.availableForGame = this.availableForGame;
    playerMap.currentPosition = this.currentPosition
      ? this.currentPosition.name : null;
    for (let i = 0; i < this.lineup.positionNames.length; ++i) {
      const positionName = this.lineup.positionNames[i];
      const timeMs = this.timeAtPositionMs[positionName];
      if (timeMs) {
        playerMap[positionName] = timeMs;
      }
    }
  }

  /** @return {boolean} */
  isPlaying() {
    return this.currentPosition != null;
  }

  /**
{'fraction_non_alphanumeric': 0.1490626889739972, 'fraction_numerical': 0.0028220116911912923, 'mean_word_length': 2.91748914330833, 'pattern_counts': {'":': 2, '<': 17, '<?xml version=': 0, '>': 9, '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': '3190210', 'n_tokens_mistral': 3311, 'n_tokens_neox': 3214, 'n_words': 605}