text: 'use strict';
  var __extends = (this && this.__extends) || (function () {
      var extendStatics = Object.setPrototypeOf ||
          ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
          function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
      return function (d, b) {
          extendStatics(d, b);
          function __() { this.constructor = d; }
          d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
      };
  })();
  Object.defineProperty(exports, "__esModule", { value: true });
  var Util_1 = require("../common/Util");
  var strtok3_1 = require("strtok3");
  var Token = require("token-types");
  var Vorbis_1 = require("../vorbis/Vorbis");
  var AbstractID3Parser_1 = require("../id3v2/AbstractID3Parser");
  var FourCC_1 = require("../common/FourCC");
  /**
   * FLAC supports up to 128 kinds of metadata blocks; currently the following are defined:
   * ref: https://xiph.org/flac/format.html#metadata_block
   */
  var BlockType;
  (function (BlockType) {
      BlockType[BlockType["STREAMINFO"] = 0] = "STREAMINFO";
      BlockType[BlockType["PADDING"] = 1] = "PADDING";
      BlockType[BlockType["APPLICATION"] = 2] = "APPLICATION";
      BlockType[BlockType["SEEKTABLE"] = 3] = "SEEKTABLE";
      BlockType[BlockType["VORBIS_COMMENT"] = 4] = "VORBIS_COMMENT";
      BlockType[BlockType["CUESHEET"] = 5] = "CUESHEET";
      BlockType[BlockType["PICTURE"] = 6] = "PICTURE";
  })(BlockType || (BlockType = {}));
  var FlacParser = /** @class */ (function (_super) {
      __extends(FlacParser, _super);
      function FlacParser() {
          var _this = _super !== null && _super.apply(this, arguments) || this;
          _this.tags = [];
          _this.padding = 0;
          _this.warnings = []; // ToDo: should be part of the parsing result
          return _this;
      }
      FlacParser.getInstance = function () {
          return new FlacParser();
      };
      FlacParser.prototype._parse = function (metadata, tokenizer, options) {
          var _this = this;
          this.metadata = metadata;
          this.tokenizer = tokenizer;
          this.options = options;
          return tokenizer.readToken(FourCC_1.FourCcToken).then(function (fourCC) {
              if (fourCC.toString() !== 'fLaC') {
                  throw new Error("Invalid FLAC preamble");
              }
              return _this.parseBlockHeader();
          });
      };
      FlacParser.prototype.parseBlockHeader = function () {
          var _this = this;
          // Read block header
          return this.tokenizer.readToken(Metadata.BlockHeader).then(function (blockHeader) {
              // Parse block data
              return _this.parseDataBlock(blockHeader).then(function () {
                  if (blockHeader.lastBlock) {
                      _this.metadata.native.vorbis = _this.tags;
                      // done
                  }
                  else {
                      return _this.parseBlockHeader();
                  }
              });
          });
      };
      FlacParser.prototype.parseDataBlock = function (blockHeader) {
          switch (blockHeader.type) {
              case BlockType.STREAMINFO:
                  return this.parseBlockStreamInfo(blockHeader.length);
              case BlockType.PADDING:
                  this.padding += blockHeader.length;
                  break;
              case BlockType.APPLICATION:
                  break;
              case BlockType.SEEKTABLE:
                  break;
              case BlockType.VORBIS_COMMENT:
                  return this.parseComment(blockHeader.length);
              case BlockType.CUESHEET:
                  break;
              case BlockType.PICTURE:
                  return this.parsePicture(blockHeader.length);
              default:
                  this.warnings.push("Unknown block type: " + blockHeader.type);
          }
          // Ignore data block
          return this.tokenizer.readToken(new strtok3_1.IgnoreType(blockHeader.length));
      };
      /**
       * Parse STREAMINFO
       */
      FlacParser.prototype.parseBlockStreamInfo = function (dataLen) {
          var _this = this;
          if (dataLen !== Metadata.BlockStreamInfo.len)
              throw new Error("Unexpected block-stream-info length");
          return this.tokenizer.readToken(Metadata.BlockStreamInfo).then(function (streamInfo) {
              _this.metadata.format = {
                  dataformat: 'flac',
                  lossless: true,
                  numberOfChannels: streamInfo.channels,
                  bitsPerSample: streamInfo.bitsPerSample,
                  sampleRate: streamInfo.sampleRate,
                  duration: streamInfo.totalSamples / streamInfo.sampleRate
              };
              // callback('format', 'bitrate', fileSize / duration) // ToDo: exclude meta-data
          });
      };
      /**
       * Parse VORBIS_COMMENT
       * Ref: https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-640004.2.3
       */
      FlacParser.prototype.parseComment = function (dataLen) {
          var _this = this;
          return this.tokenizer.readToken(new Token.BufferType(dataLen)).then(function (data) {
              var decoder = new DataDecoder(data);
              decoder.readStringUtf8(); // vendor (skip)
              var commentListLength = decoder.readInt32();
              for (var i = 0; i < commentListLength; i++) {
                  var comment = decoder.readStringUtf8();
                  var split = comment.split('=');
                  _this.tags.push({ id: split[0].toUpperCase(), value: split.splice(1).join('=') });
              }
          });
      };
      FlacParser.prototype.parsePicture = function (dataLen) {
          var _this = this;
          if (this.options.skipCovers) {
              return this.tokenizer.ignore(dataLen);
          }
          else {
              return this.tokenizer.readToken(new Vorbis_1.VorbisPictureToken(dataLen)).then(function (picture) {
                  _this.tags.push({ id: 'METADATA_BLOCK_PICTURE', value: picture });
              });
          }
      };
      return FlacParser;
  }(AbstractID3Parser_1.AbstractID3v2Parser));
  exports.FlacParser = FlacParser;
  var Metadata = /** @class */ (function () {
      function Metadata() {
      }
      Metadata.BlockHeader = {
          len: 4,
          get: function (buf, off) {
              return {
                  lastBlock: Util_1.default.strtokBITSET.get(buf, off, 7),
                  type: Util_1.default.getBitAllignedNumber(buf, off, 1, 7),
                  length: Token.UINT24_BE.get(buf, off + 1)
              };
          }
      };
      /**
       * METADATA_BLOCK_DATA
       * Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo
       */
      Metadata.BlockStreamInfo = {
          len: 34,
          get: function (buf, off) {
              return {
                  // The minimum block size (in samples) used in the stream.
                  minimumBlockSize: Token.UINT16_BE.get(buf, off),
                  // The maximum block size (in samples) used in the stream.
                  // (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream.
                  maximumBlockSize: Token.UINT16_BE.get(buf, off + 2) / 1000,
                  // The minimum frame size (in bytes) used in the stream.
                  // May be 0 to imply the value is not known.
                  minimumFrameSize: Token.UINT24_BE.get(buf, off + 4),
                  // The maximum frame size (in bytes) used in the stream.
                  // May be 0 to imply the value is not known.
                  maximumFrameSize: Token.UINT24_BE.get(buf, off + 7),
                  // Sample rate in Hz. Though 20 bits are available,
                  // the maximum sample rate is limited by the structure of frame headers to 655350Hz.
                  // Also, a value of 0 is invalid.
                  sampleRate: Token.UINT24_BE.get(buf, off + 10) >> 4,
                  // probably slower: sampleRate: common.getBitAllignedNumber(buf, off + 10, 0, 20),
                  // (number of channels)-1. FLAC supports from 1 to 8 channels
                  channels: Util_1.default.getBitAllignedNumber(buf, off + 12, 4, 3) + 1,
                  // bits per sample)-1.
                  // FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample.
                  bitsPerSample: Util_1.default.getBitAllignedNumber(buf, off + 12, 7, 5) + 1,
                  // Total samples in stream.
                  // 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels.
                  // A value of zero here means the number of total samples is unknown.
                  totalSamples: Util_1.default.getBitAllignedNumber(buf, off + 13, 4, 36),
                  // the MD5 hash of the file (see notes for usage... it's a littly tricky)
                  fileMD5: new Token.BufferType(16).get(buf, off + 18)
              };
          }
      };
      return Metadata;
  }());
  var DataDecoder = /** @class */ (function () {
      function DataDecoder(data) {
          this.data = data;
          this.offset = 0;
      }
      DataDecoder.prototype.readInt32 = function () {
          var value = Token.UINT32_LE.get(this.data, this.offset);
          this.offset += 4;
          return value;
      };
      DataDecoder.prototype.readStringUtf8 = function () {
          var len = this.readInt32();
          var value = this.data.toString('utf8', this.offset, this.offset + len);
          this.offset += len;
          return value;
      };
      return DataDecoder;
  }());
  