import jsonop from 'jsonop';

export default class State {
	constructor (options) {
		this.data = {};
		this._options = options;
		this._watches = {};
	}

	put (changes) {
		jsonop(this.data, changes, this._options.op);

		function fire(data, change, watch) {
			if (watch._cb_) { watch._cb_.forEach(fn => fn(data)); }

			for (let prop in change) {
				if (!watch[prop] || prop[0] === '_') { continue; }
				fire(data[prop], change[prop], watch[prop]);
			}
		}

		fire(this.data, changes, this._watches);
	}

	get (path) {
		let val = this.data;

		for (let prop of path) {
			val = val[prop];
			if (typeof val !== 'object' || val === null) { return val; }
		}

		return val;
	}

	watch (path, callback) {
		let point = this._watches;

		if (!callback) { throw Error('ERR_WATCH_NO_CALLBACK'); }

		for (let prop of path) {
			if (!point[prop]) { point[prop] = {}; }
			point = point[prop];
		}

		if (!point._cb_) { point._cb_ = []; }
		point._cb_.push(callback);

		callback(this.get(path));

		function cleanup () {
			// TODO: do this.
		}

		return () => {
			point._cb_.splice(point._cb_.indexOf(callback), 1);
			if (point._cb_.length === 0) {
				delete point._cb_;
				cleanup();
			}
		};
	}
}

/* @flow */

export default class State {
	_subscriptions: { [key: string]: Array<Function> } = {};
	_data: { [key: string]: any } = {};

	get(key: string): any {
		return this._data[key];
	}

	set(key: string, value: any) {
		const old = this._data;
		const data = this._data = { ...old, [key]: value };

		if (data[key] !== old[key]) {
			const subscriptions = this._subscriptions[key];

			if (subscriptions) {
				for (let i = 0, l = subscriptions.length; i < l; i++) {
					subscriptions[i](data[key]);
				}
			}
		}
	}

	put(changes: Object) {
		for (const key in changes) {
			this.set(key, changes[key]);
		}
	}

	watch(key: string, callback: Function): Function {
		callback(this.get(key));

		if (!this._subscriptions[key]) {
			this._subscriptions[key] = [];
		}

		const subscriptions = this._subscriptions[key];

		subscriptions.push(callback);

		return () => {
			const index = subscriptions.indexOf(callback);

			if (index !== -1) {
				subscriptions.splice(index, 1);
			}
		};
	}
}

Simplify State.js