import { BehaviorSubject, fromEvent, NextObserver, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';





export class LocalStorageSubject<T> extends Observable<T>
    implements NextObserver<T>, Pick<BehaviorSubject<T>, 'value'> {
    constructor(private key: string, private defaultValue: T) {
        super(subscriber => {
            subscriber.next(this.value);
            return fromEvent<StorageEvent>(window, 'storage')
                .pipe(filter(event => event.key === key))
                .subscribe(event => {
                    subscriber.next(parseValue(event.newValue, defaultValue));
                });
        });
    }

    public next(value: T): void {
        const v = JSON.stringify(value);
        localStorage.setItem(this.key, v);
        // Does not set oldValue or other StorageEventInit keys because we don't need them.
        window.dispatchEvent(new StorageEvent('storage', { key: this.key, newValue: v }));
    }

    public get value(): T {
        return parseValue(localStorage.getItem(this.key), this.defaultValue);
    }

}

function parseValue<T>(v: string | null, defaultValue: T): T {
    if (v === null) {
        return defaultValue;
    }
    try {
        return JSON.parse(v);
    } catch (err) {
        return defaultValue;
    }
}
