text: const { NotImplementedError } = require('../extensions/index.js');
  
  /**
   * Implement class VigenereCipheringMachine that allows us to create
   * direct and reverse ciphering machines according to task description
   * 
   * @example
   * 
   * const directMachine = new VigenereCipheringMachine();
   * 
   * const reverseMachine = new VigenereCipheringMachine(false);
   * 
   * directMachine.encrypt('attack at dawn!', 'alphonse') => 'AEIHQX SX DLLU!'
   * 
   * directMachine.decrypt('AEIHQX SX DLLU!', 'alphonse') => 'ATTACK AT DAWN!'
   * 
   * reverseMachine.encrypt('attack at dawn!', 'alphonse') => '!ULLD XS XQHIEA'
   * 
   * reverseMachine.decrypt('AEIHQX SX DLLU!', 'alphonse') => '!NWAD TA KCATTA'
   * 
   */
  class VigenereCipheringMachine {
   
    constructor(direction = true) {
      this._direction = direction;
      this._alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      this.messageSigns = [];
      this.keySigns = [];
      this.keyIndices = [];
      this.decriptPermit = false;
    }
  
    encrypt(message, key) {
      this.decriptPermit = false;
      return this.getResult(message, key);
    }
  
    decrypt(message, key) {
      this.decriptPermit = true;
      return this.getResult(message, key);
    }
  
    getResult(message, key) {
      return !message || !key
        ? this.showError(`Incorrect arguments!`)
        : this.transformArguments(message, key);
    }
  
    transformArguments(message, key) {
      this.messageSigns = [...message].map((el) => el.toUpperCase());
      this.keySigns = [...key].map((el) => el.toUpperCase());
      return this.setKeyLength(this.messageSigns);
    }
  
    setKeyLength(arr) {
      let count = 0;
      for (let el of arr) {
        if (this._alphabet.includes(el)) {
          count++;
        }
      }
      return this.setKey(count);
    }
  
    setKey(val) {
      let i = 0;
      while (this.keySigns.length < val) {
        this.keySigns.push(this.keySigns[i]);
        i++;
      }
      return this.setKeyIndices(this.keySigns);
    }
  
    setKeyIndices(arr) {
      this.keyIndices = arr.map((el) => this._alphabet.indexOf(el));
      return this.getResultArray();
    }
  
    getResultArray() {
      let val = 0;
      for (let i = 0; i < this.messageSigns.length; i++) {
        if (this._alphabet.includes(this.messageSigns[i])) {
          const num = this._alphabet.indexOf(this.messageSigns[i]);
          let index = !this.decriptPermit
            ? num + this.keyIndices[val]
            : num - this.keyIndices[val];
          while (index < 0) {
            index = this._alphabet.length - Math.abs(index);
          }
          while (index >= this._alphabet.length) {
            index = index - this._alphabet.length;
          }
          this.messageSigns[i] = this._alphabet.slice(index, index + 1);
          val++;
        }
      }
      return this.getVerifyDirection();
    }
  
    getVerifyDirection() {
      this.messageSigns = this._direction
        ? this.messageSigns
        : this.messageSigns.reverse();
      return this.messageSigns.join('');
    }
  
    showError(str) {
      throw new Error(str);
    }
  }
  
  module.exports = {
    VigenereCipheringMachine
  };
  