// makeProfileTimer
// Напишите функцию makeProfileTimer, которая служит для замера времени выполнения другого кода и работает
// следующим образом: Используйте performance.now()
make_profile_timer: {
  function makeProfileTimer() {
    let t0 = performance.now();
    return function () {
      let t1 = performance.now();
      return t1 - t0;
    }
  }
  var timer = makeProfileTimer();
  alert('Замеряем время работы этого alert');  //некий код, время выполнения которого мы хотим измерить с высокой точностью
  alert(timer()); //alert должен вывести время в микросекундах от выполнения makeProfileTimer до момента вызова timer(), 
  // т. е. измерить время выполнения alert
}

// makeSaver
// Напишите функцию makeSaver, которая:
//создает функцию-хранилище результата переданной в качестве параметра функции (Math.random в примере). На
// этом этапе Math.random НЕ вызывается saver вызывает переданную в makeSaver функцию, запоминает результат
// и возвращает его saver в дальнейшем просто хранит результат функции, и более НЕ вызывает переданную 
//в makeSaver функцию;
make_saver: {
  function makeSaver(fn) {
    let result;
    let resultSaved = false;
    return function () {
      if (!resultSaved) {
        result = fn();
        resultSaved = true;
      }
      return result;
    }
  }

  var saver = makeSaver(Math.random);
  var value1 = saver();
  var value2 = saver();
  value1 === value2;

  var saver2 = makeSaver(() => console.log('saved function called') || [null, undefined, false, '', 0, Math.random()][Math.ceil(Math.random() * 6)]);
  var value3 = saver2();
  var value4 = saver2();

  value3 === value4;

  let namePrompt = prompt.bind(window, 'Как тебя зовут?');
  let nameSaver = makeSaver(namePrompt);
  alert(`Привет! Prompt еще не было!`);
  alert(`Привет ${nameSaver()}. Только что запустился prompt, первый и последний раз`);
  alert(`Слушай, ${nameSaver()}, го пить пиво. Ведь prompt был только один раз`);
}

// myBind
// Изучите встроенную функцию bind, и сделайте свою версию, которая позволит определить "значение по умолчанию"
// не только для первых параметров, но для любых других, например для степени в Math.pow:
// Массив, который идет третьим параметром определяет, какие поля должны подменяться значением по умолчанию, а
// какие - задаваться в последствии (undefined).
my_bind: {
  function myBind(fn, context, defaultParams) {
    return function (...enteredParams) {
      let params = [...defaultParams];
      for (let i = 0; i < defaultParams.length; i++) {
        if (defaultParams[i] === undefined) {
          params[i] = enteredParams.shift();
        }
      };
      return fn.bind(context)(...params);
    }
  }

  var pow5 = myBind(Math.pow, Math, [, 5]);
  var cube = myBind(Math.pow, Math, [, 3]);

  console.log(pow5(2));
  console.log(cube(3));


  var chessMin = myBind(Math.min, Math, [, 4, , 5, , 8, , 9]);
  console.log(chessMin(-1, -5, 3, 15));



  var zeroPrompt = myBind(prompt, window, [undefined, "0"]);
  var someNumber = zeroPrompt("Введите число");
  console.log(someNumber);
  const bindedJoiner = myBind((...params) => params.join(''), null, [, 'b', , , 'e', 'f']);
  console.log(bindedJoiner('a', 'c', 'd') === 'abcdef');
  console.log(bindedJoiner('1', '2', '3') === '1b23ef');
}

// checkResult
// Напишите декоратор checkResult, который:
// принимает функцию для запуска и проверки результата (оригинал)
// принимает функцию для проверки результата (валидатор)
// возвращает обертку, которая запускает оригинал до тех пор, пока оригинал не вернет значение, удовлетворяющее
// функции-валидатору. В валидатор передается результат оригинальной функции. Если валидатор возвращает true,
// то обертка возвращает результат оригинальной функции. Если валидатор возвращает что-то другое, то оригинал
// запускается еще, пока валидатор не вернет true.
// Используя checkResult сделайте функции, которые:
// randomHigh. Возвращает случайное число в диапазоне от 0.5 до 1
// alwaysSayYes. Достает пользователя окном confirm пока он не согласится (не нажмет OK)
// respectMe. Достает пользователя запуском этой фунцкии, пока какое-то из полей не введено
check_result: {
  function checkResult(original, validator) {
    function wrapper(...params) {
      let result;
      do {
        result = original.apply(this, params);
      } while (!validator(result));
      return result;
    }
    return wrapper;
  }
  const numberPrompt = checkResult(prompt, x => !isNaN(+x));
  let number = +numberPrompt("Введите число", "0");
  console.log(number);
  const gamePrompt = checkResult(prompt, x => ['камень', 'ножницы', 'бумага'].includes(x.toLowerCase()));
  const turn = gamePrompt("Введите что то из списка: 'камень', 'ножницы', 'бумага'");
  console.log(turn);
  const randomHigh = checkResult(Math.random, x => x >= 0.5 && x <= 1 ? true : false)
  const alwaysSayYes = checkResult(confirm, x => x)
}