text: import isArray from 'es-is/array'
  
  import * as ECCode  from './error-correction-code'
  import * as ECLevel from './error-correction-level'
  import * as Mode    from './mode'
  import {getBCHDigit, getSymbolTotalCodewords} from './utils'
  
  // Generator polynomial used to encode version information
  var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0)
  var G18_BCH = getBCHDigit(G18)
  
  function getBestVersionForDataLength (mode, length, errorCorrectionLevel) {
    for (var currentVersion = 1; currentVersion <= 40; currentVersion++) {
      if (length <= getCapacity(currentVersion, errorCorrectionLevel, mode)) {
        return currentVersion
      }
    }
  
    return undefined
  }
  
  function getReservedBitsCount (mode, version) {
    // Character count indicator + mode indicator bits
    return Mode.getCharCountIndicator(mode, version) + 4
  }
  
  function getTotalBitsFromDataArray (segments, version) {
    var totalBits = 0
  
    segments.forEach(function (data) {
      var reservedBits = getReservedBitsCount(data.mode, version)
      totalBits += reservedBits + data.getBitsLength()
    })
  
    return totalBits
  }
  
  function getBestVersionForMixedData (segments, errorCorrectionLevel) {
    for (var currentVersion = 1; currentVersion <= 40; currentVersion++) {
      var length = getTotalBitsFromDataArray(segments, currentVersion)
      if (length <= getCapacity(currentVersion, errorCorrectionLevel, Mode.MIXED)) {
        return currentVersion
      }
    }
  
    return undefined
  }
  
  /**
   * Check if QR Code version is valid
   *
   * @param  {Number}  version QR Code version
   * @return {Boolean}         true if valid version, false otherwise
   */
  export function isValid(version) {
    return !isNaN(version) && version >= 1 && version <= 40
  }
  
  /**
   * Returns version number from a value.
   * If value is not a valid version, returns defaultValue
   *
   * @param  {Number|String} value        QR Code version
   * @param  {Number}        defaultValue Fallback value
   * @return {Number}                     QR Code version number
   */
  export function from(value, defaultValue) {
    if (isValid(value)) {
      return parseInt(value, 10)
    }
  
    return defaultValue
  }
  
  /**
   * Returns how much data can be stored with the specified QR code version
   * and error correction level
   *
   * @param  {Number} version              QR Code version (1-40)
   * @param  {Number} errorCorrectionLevel Error correction level
   * @param  {Mode}   mode                 Data mode
   * @return {Number}                      Quantity of storable data
   */
  export function getCapacity(version, errorCorrectionLevel, mode) {
    if (!isValid(version)) {
      throw new Error('Invalid QR Code version')
    }
  
    // Use Byte mode as default
    if (typeof mode === 'undefined') mode = Mode.BYTE
  
    // Total codewords for this QR code version (Data + Error correction)
    var totalCodewords = getSymbolTotalCodewords(version)
  
    // Total number of error correction codewords
    var ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel)
  
    // Total number of data codewords
    var dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8
  
    if (mode === Mode.MIXED) return dataTotalCodewordsBits
  
    var usableBits = dataTotalCodewordsBits - getReservedBitsCount(mode, version)
  
    // Return max number of storable codewords
    switch (mode) {
      case Mode.NUMERIC:
        return Math.floor((usableBits / 10) * 3)
  
      case Mode.ALPHANUMERIC:
        return Math.floor((usableBits / 11) * 2)
  
      case Mode.KANJI:
        return Math.floor(usableBits / 13)
  
      case Mode.BYTE:
      default:
        return Math.floor(usableBits / 8)
    }
  }
  
  /**
   * Returns the minimum version needed to contain the amount of data
   *
   * @param  {Segment} data                    Segment of data
   * @param  {Number} [errorCorrectionLevel=H] Error correction level
   * @param  {Mode} mode                       Data mode
   * @return {Number}                          QR Code version
   */
  export function getBestVersionForData(data, errorCorrectionLevel) {
    var seg
  
    var ecl = ECLevel.from(errorCorrectionLevel, ECLevel.M)
  
    if (isArray(data)) {
      if (data.length > 1) {
        return getBestVersionForMixedData(data, ecl)
      }
  
      if (data.length === 0) {
        return 1
      }
  
      seg = data[0]
    } else {
      seg = data
    }
  
    return getBestVersionForDataLength(seg.mode, seg.getLength(), ecl)
  }
  
  /**
   * Returns version information with relative error correction bits
   *
   * The version information is included in QR Code symbols of version 7 or larger.
   * It consists of an 18-bit sequence containing 6 data bits,
   * with 12 error correction bits calculated using the (18, 6) Golay code.
   *
   * @param  {Number} version QR Code version
   * @return {Number}         Encoded version info bits
   */
  export function getEncodedBits(version) {
    if (!isValid(version) || version < 7) {
      throw new Error('Invalid QR Code version')
    }
  
    var d = version << 12
  
    while (getBCHDigit(d) - G18_BCH >= 0) {
      d ^= (G18 << (getBCHDigit(d) - G18_BCH))
    }
  
    return (version << 12) | d
  }
  