text: 'use strict';
  
  var GenericGF = require('./GenericGF.js');
  var GenericGFPoly = require('./GenericGFPoly.js');
  
  /**
   * @module index
   * @author nuintun
   * @author Cosmo Wolfe
   * @license https://raw.githubusercontent.com/cozmo/jsQR/master/LICENSE
   */
  function runEuclideanAlgorithm(field, a, b, R) {
      var _a;
      // Assume a's degree is >= b's
      if (a.degree() < b.degree()) {
          _a = [b, a], a = _a[0], b = _a[1];
      }
      var rLast = a;
      var r = b;
      var tLast = field.zero;
      var t = field.one;
      // Run Euclidean algorithm until r's degree is less than R/2
      while (r.degree() >= R / 2) {
          var rLastLast = rLast;
          var tLastLast = tLast;
          rLast = r;
          tLast = t;
          // Divide rLastLast by rLast, with quotient in q and remainder in r
          if (rLast.isZero()) {
              // Euclidean algorithm already terminated?
              return null;
          }
          r = rLastLast;
          var q = field.zero;
          var denominatorLeadingTerm = rLast.getCoefficient(rLast.degree());
          var dltInverse = field.inverse(denominatorLeadingTerm);
          while (r.degree() >= rLast.degree() && !r.isZero()) {
              var degreeDiff = r.degree() - rLast.degree();
              var scale = field.multiply(r.getCoefficient(r.degree()), dltInverse);
              q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale));
              r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
          }
          t = q.multiplyPoly(tLast).addOrSubtract(tLastLast);
          if (r.degree() >= rLast.degree()) {
              return null;
          }
      }
      var sigmaTildeAtZero = t.getCoefficient(0);
      if (sigmaTildeAtZero === 0) {
          return null;
      }
      var inverse = field.inverse(sigmaTildeAtZero);
      return [t.multiply(inverse), r.multiply(inverse)];
  }
  function findErrorLocations(field, errorLocator) {
      // This is a direct application of Chien's search
      var numErrors = errorLocator.degree();
      if (numErrors === 1) {
          return [errorLocator.getCoefficient(1)];
      }
      var errorCount = 0;
      var result = new Array(numErrors);
      for (var i = 1; i < field.size && errorCount < numErrors; i++) {
          if (errorLocator.evaluateAt(i) === 0) {
              result[errorCount] = field.inverse(i);
              errorCount++;
          }
      }
      if (errorCount !== numErrors) {
          return null;
      }
      return result;
  }
  function findErrorMagnitudes(field, errorEvaluator, errorLocations) {
      // This is directly applying Forney's Formula
      var s = errorLocations.length;
      var result = new Array(s);
      for (var i = 0; i < s; i++) {
          var denominator = 1;
          var xiInverse = field.inverse(errorLocations[i]);
          for (var j = 0; j < s; j++) {
              if (i !== j) {
                  denominator = field.multiply(denominator, GenericGF.addOrSubtractGF(1, field.multiply(errorLocations[j], xiInverse)));
              }
          }
          result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator));
          if (field.generatorBase !== 0) {
              result[i] = field.multiply(result[i], xiInverse);
          }
      }
      return result;
  }
  function rsDecode(bytes, twoS) {
      var outputBytes = new Uint8ClampedArray(bytes.length);
      outputBytes.set(bytes);
      var field = new GenericGF.GenericGF(0x011d, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1
      var poly = new GenericGFPoly.GenericGFPoly(field, outputBytes);
      var syndromeCoefficients = new Uint8ClampedArray(twoS);
      var error = false;
      for (var s = 0; s < twoS; s++) {
          var evaluation = poly.evaluateAt(field.exp(s + field.generatorBase));
          syndromeCoefficients[syndromeCoefficients.length - 1 - s] = evaluation;
          if (evaluation !== 0) {
              error = true;
          }
      }
      if (!error) {
          return outputBytes;
      }
      var syndrome = new GenericGFPoly.GenericGFPoly(field, syndromeCoefficients);
      var sigmaOmega = runEuclideanAlgorithm(field, field.buildMonomial(twoS, 1), syndrome, twoS);
      if (sigmaOmega === null) {
          return null;
      }
      var errorLocations = findErrorLocations(field, sigmaOmega[0]);
      if (errorLocations == null) {
          return null;
      }
      var errorMagnitudes = findErrorMagnitudes(field, sigmaOmega[1], errorLocations);
      for (var i = 0; i < errorLocations.length; i++) {
          var position = outputBytes.length - 1 - field.log(errorLocations[i]);
          if (position < 0) {
              return null;
          }
          outputBytes[position] = GenericGF.addOrSubtractGF(outputBytes[position], errorMagnitudes[i]);
      }
      return outputBytes;
  }
  
  exports.rsDecode = rsDecode;
  