spunky / ACLeague MinLaps Validator

// ==UserScript==
// @name         ACLeague MinLaps Validator
// @namespace    http://minlaps.semipro.acleague.pl/
// @version      0.4.7
// @description  Allow to see real drivers' position that do not take to account drivers that hasn't made required number of laps
// @author       spunky
// @include      http://managerdc7.rackservice.org:50175/*
// @grant        none
// @run-at       document-end
// @updateURL    https://openuserjs.org/meta/spunky/ACLeague_MinLaps_Validator.meta.js
// ==/UserScript==

(function () {
  const minLaps = 15;
  const minLmpLaps = 20;
  const serverDriversSlots = 35;
  const noLapsBgColor = '#B40404';
  const noTimeBgColor = '#FE9A2E';
  const proColor = '#BCF5A9';
  const semiColor = '#F4FA58';
  const secondsInMinute = 60;
  const milisecondsInSecond = 1000;
  const gridPlaces = 108;
  const lmpMaxProPlaces = 15;
  const lmpMaxSemiPlaces = 15;

  const url = 'http://lapstat.herokuapp.com/lapstat/pro';

  const getLmpData = () => fetch(url).then(response => response.json());

  const ceilToSeconds = miliseconds => Math.ceil(miliseconds / milisecondsInSecond) * milisecondsInSecond;

  function parseTimeToMilis(time) {
    const timeParts = time.split(/(:|\.)/);

    const minutes = parseInt(timeParts[0]);
    const seconds = parseInt(timeParts[2]);
    const miliseconds = parseInt(timeParts[4]);

    const timeInMiliseconds = (minutes * secondsInMinute * milisecondsInSecond)
      + (seconds * milisecondsInSecond)
      + miliseconds;

    return timeInMiliseconds;
  }

  function getTopLapTimes(data) {
    const topLaps = [...data.times].splice(0, 3);
    const topLapTimes = topLaps.reduce((laps, lap) => [...laps, parseTimeToMilis(lap.bestLap)], []);

    return topLapTimes;
  }

  function countAvarageTime(timeArray) {
    const sum = timeArray.reduce((prev, time) => (prev + time), 0);
    const avg = Math.ceil(sum / timeArray.length);

    return avg;
  }

  function getClassifiedLmpTimes(data, timeToGetIn) {
    const classifiedLaps = data.times.filter(driver => {
      const lapTime = parseTimeToMilis(driver.bestLap);
      return (lapTime < timeToGetIn && parseInt(driver.laps) >= minLmpLaps);
    });

    return classifiedLaps;
  }

  function colorInCell(row, color, cellNumber = 0) {
      //Array.prototype.forEach.call(row.cells, cell => {
      //    cell.style.backgroundColor = color;
      //});
      row.children[cellNumber].style.backgroundColor = color;
  }

  function showClassifiedDrivers(gteGridPlaces, lmpProGridPlaces, lmpSemiGridPlaces) {
    const rows = document.querySelectorAll('tr.clickableRow');
    const maxPositionToPro = serverDriversSlots - lmpProGridPlaces;
    const maxPositionToSemi = 2 * serverDriversSlots - lmpSemiGridPlaces - lmpProGridPlaces;

      console.log(maxPositionToSemi);

    let currentPosition = 1;

    console.log('gte pro grid places: ', maxPositionToPro);
    console.log('gte semi-pro grid places: ', maxPositionToSemi - maxPositionToPro);

    Array.prototype.forEach.call(rows, (row, index) => {
      const positionCell = row.cells[0];
      const laps = parseInt(row.cells[12].innerHTML);

      positionCell.style.textAlign = `right`;
      positionCell.style.paddingRight = '10px';
      positionCell.style.paddingLeft = '10px';

      if (laps < minLaps) {
        positionCell.innerHTML = `(${index+1}) &nbsp;&nbsp;–&nbsp;`;
        colorInCell(row, noLapsBgColor);
        colorInCell(row, noLapsBgColor, 12);
      } else {
        positionCell.innerHTML = `(${index+1}) &nbsp;${currentPosition}`;
        if (currentPosition > gteGridPlaces) {
          colorInCell(row, noTimeBgColor);
          colorInCell(row, noTimeBgColor, 3);
        } else if (currentPosition <= maxPositionToPro) {
          colorInCell(row, proColor);
        } else if (currentPosition <= maxPositionToSemi) {
          colorInCell(row, semiColor);
        }
        currentPosition++;
      }
    });
  }

  getLmpData().then(data => {
    const topLaps = getTopLapTimes(data);
    const avg = countAvarageTime(topLaps);
    const milisecondsToGetIn = ceilToSeconds(avg * 1.04);
    const classifiedLmpTimes = getClassifiedLmpTimes(data, milisecondsToGetIn);
    const lmpGridPlaces = Math.min(classifiedLmpTimes.length, 30);
    const gteGridPlaces = gridPlaces - lmpGridPlaces;
    const lmpProGridPlaces = Math.min(lmpGridPlaces, 15);
    const lmpSemiGridPlaces = Math.min(lmpGridPlaces - lmpProGridPlaces, 15);

    console.log('lmp1 qualified pro drivers: ', lmpProGridPlaces);
    console.log('lmp1 qualified semi-pro drivers: ', lmpSemiGridPlaces);

    showClassifiedDrivers(gteGridPlaces, lmpProGridPlaces, lmpSemiGridPlaces);
  });
})();