/**
 * @author Don McCurdy / https://www.donmccurdy.com
 */

let init, instance, heap;

const importObject = {

	env: {

		emscripten_notify_memory_growth: function ( index ) {

			heap = new Uint8Array( instance.exports.memory.buffer );

		}

	}

}

/**
 * ZSTD (Zstandard) decoder.
 *
 * Compiled from https://github.com/facebook/zstd/tree/dev/contrib/single_file_libs, with the
 * following steps:
 *
 * ```
 * ./combine.sh -r ../../lib -o zstddeclib.c zstddeclib-in.c
 * emcc zstddeclib.c -Oz -s EXPORTED_FUNCTIONS="['_ZSTD_decompress', '_ZSTD_findDecompressedSize', '_ZSTD_isError', '_malloc', '_free']" -s ALLOW_MEMORY_GROWTH=1 -s MALLOC=emmalloc -o zstddec.wasm
 * base64 zstddec.wasm > zstddec.txt
 * ```
 *
 * The base64 string written to `zstddec.txt` is embedded as the `wasm` variable at the bottom
 * of this file. The rest of this file is written by hand, in order to avoid an additional JS
 * wrapper generated by Emscripten.
 */
export class ZSTDDecoder {

	init () {

		if ( ! init ) {

			init = fetch( 'data:application/wasm;base64,' + wasm )
				.then( ( response ) => response.arrayBuffer() )
				.then( ( arrayBuffer ) => WebAssembly.instantiate( arrayBuffer, importObject ) )
				.then( ( result ) => {

					instance = result.instance;

					importObject.env.emscripten_notify_memory_growth( 0 ); // initialize heap.

				});

		}

		return init;

	}

	decode ( array, uncompressedSize = 0 ) {

		// Write compressed data into WASM memory.
		const compressedSize = array.byteLength;
		const compressedPtr = instance.exports.malloc( compressedSize );
		heap.set( array, compressedPtr );

		// Decompress into WASM memory.
		uncompressedSize = uncompressedSize || Number( instance.exports.ZSTD_findDecompressedSize( compressedPtr, compressedSize ) );
		const uncompressedPtr = instance.exports.malloc( uncompressedSize );
		const actualSize = instance.exports.ZSTD_decompress( uncompressedPtr, uncompressedSize, compressedPtr, compressedSize );

		// Read decompressed data and free WASM memory.
		const dec = heap.slice( uncompressedPtr, uncompressedPtr + actualSize );
		instance.exports.free( compressedPtr );
		instance.exports.free( uncompressedPtr );

		return dec;

	}

}

/**
 * BSD License
 *
 * For Zstandard software
 *
 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  * Neither the name Facebook nor the names of its contributors may be used to
 *    endorse or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
const wasm = '[encoded data, 38976 characters]';
