const MagicString = require( '../../' );
const assert = require( 'assert' );

class IntegrityCheckingMagicString extends MagicString {
	checkIntegrity () {
		let prevChunk = null;
		let chunk = this.firstChunk;
		let numNodes = 0;
		while ( chunk ) {
			assert.strictEqual( this.byStart[chunk.start], chunk );
			assert.strictEqual( this.byEnd[chunk.end], chunk );
			assert.strictEqual( chunk.previous, prevChunk );
			if ( prevChunk ) {
				assert.strictEqual( prevChunk.next, chunk );
			}
			prevChunk = chunk;
			chunk = chunk.next;
			numNodes++;
		}
		assert.strictEqual( prevChunk, this.lastChunk );
		assert.strictEqual( this.lastChunk.next, null );
		assert.strictEqual( Object.keys(this.byStart).length, numNodes );
		assert.strictEqual( Object.keys(this.byEnd).length, numNodes );
	}
}

for (const key in MagicString.prototype) {
	if ( !MagicString.prototype.hasOwnProperty( key ) ) {
		continue;
	}
	const func = MagicString.prototype[key];
	if ( typeof func === 'function' ) {
		IntegrityCheckingMagicString.prototype[key] = function () {
			const result = func.apply( this, arguments );
			try {
				this.checkIntegrity();
			} catch ( e ) {
				e.message = `Integrity error after invoking ${key}:\n${e.message}`;
				throw e;
			}
			return result;
		};
	}
}

module.exports = IntegrityCheckingMagicString;
