/**
 * MemoryStorage is a wrapper around mw.SafeStorage objects.
 *
 * It provides two mechanisms to improve their behavior when the underlying storage mechanism fails
 * (e.g. quota exceeded):
 *
 * - Duplicating their contents in memory, so that the storage can be relied on before the page has
 *   been reloaded. This is used by the "Show N new messages" feature which reloads the reply widget
 *   after refreshing the page contents.
 * - Storing all keys in a single underlying key, to make the stores are atomic: either all values
 *   are stored or none.
 *
 * This has two additional consequences which are convenient for our use case:
 *
 * - All keys share the same expiry time, removing the need to specify it repeatedly.
 * - When multiple processes try to write the same keys (e.g. having the same comment open in
 *   multiple tabs), all keys are overwritten, so that we don't have to worry about inconsistent data.
 *
 * @example
 * var localStorage = new MemoryStorage( mw.storage, 'myprefix' );
 * var sessionStorage = new MemoryStorage( mw.storage.session, 'myprefix' );
 */
class MemoryStorage {
	/**
	 * @param {mw.SafeStorage} backend
	 * @param {string} key Key name to store under
	 * @param {number} [expiry] Number of seconds after which this item can be deleted
	 */
	constructor( backend, key, expiry ) {
		this.backend = backend;
		this.key = key;
		this.expiry = expiry;

		this.data = this.backend.getObject( this.key ) || {};
	}

	get( key ) {
		if ( Object.prototype.hasOwnProperty.call( this.data, key ) ) {
			return this.data[ key ];
		}
		return null;
	}

	set( key, value ) {
		this.data[ key ] = value;
		this.backend.setObject( this.key, this.data, this.expiry );
		return true;
	}

	remove( key ) {
		delete this.data[ key ];
		if ( Object.keys( this.data ).length === 0 ) {
			this.backend.remove( this.key );
		} else {
			this.backend.setObject( this.key, this.data, this.expiry );
		}
		return true;
	}

	clear() {
		this.data = {};
		this.backend.remove( this.key );
	}

	// For compatibility with mw.SafeStorage API
	getObject( key ) {
		return this.get( key );
	}

	// For compatibility with mw.SafeStorage API
	setObject( key, value ) {
		return this.set( key, value );
	}
}

module.exports = MemoryStorage;
