;(function() {
	'use strict';

	BX.namespace('SB.Service.Site.Tool');

	BX.SB.Service.Site.Tool.GroupStateWatcher = class GroupStateWatcher {
		stabilizeStep = 0;
		inAction = false;
		stabilizer;
		watchers = [];
		watchersStates;
		handlers = [];
		transaction;
		debugId;

		constructor(stabilizer, debugId) {
			if (!BX.type.isFunction(stabilizer))
			{
				throw new Error('Stabilizer must be function');
			}
			this.debugId = debugId;
			this.stabilizer = stabilizer;
		}

		clearWatchers() {
			this.watchers = [];
		}

		watch() {
			if (this.inAction)
			{
				throw new Error('Cant add watcher, when in action');
			}
			let watchers = arguments;
			if (BX.type.isArray(watchers[0]))
			{
				watchers = watchers[0];
			}

			for (let i = 0; i < watchers.length; i++)
			{
				let watcher = watchers[i];
				if (!(watcher instanceof BX.SB.Service.Site.Tool.StateWatcher))
				{
					if (watcher && watcher.stateWatcher instanceof BX.SB.Service.Site.Tool.StateWatcher)
					{
						watcher = watcher.stateWatcher;
					}
					else if (watcher && BX.type.isFunction(watcher.getStateWatcher))
					{
						const watcherFromFunc = watcher.getStateWatcher();
						if (watcherFromFunc instanceof BX.SB.Service.Site.Tool.StateWatcher)
						{
							watcher = watcherFromFunc;
						}
					}
				}

				if (watcher instanceof BX.SB.Service.Site.Tool.StateWatcher)
				{
					if (this.watchers.indexOf(watcher) === -1)
					{
						if (watcher.inAction())
						{
							throw new Error('Cant add watcher in action');
						}
						this.watchers.push(watcher);
						watcher.bindToGroupWatcher(this);
					}
				}
				else
				{
					console.log('Cant get watcher', watcher, this.debugId);
				}
			}
		}

		bindChange(handler) {
			if (this.handlers.indexOf(handler) === -1)
			{
				this.handlers.push(handler);
			}
		}

		/**
		 * @param {BX.SB.Service.Site.Tool.GroupWatcherTransaction} transaction
		 */
		fixStateBeforeChange(transaction) {
			if (this.stabilizeStep === 0)
			{
				this.stabilizeStep = 1;
				this.transaction = transaction;
				this.watchersStates = new WeakMap();
				for (let i = 0; i < this.watchers.length; i++)
				{
					this.watchersStates.set(this.watchers[i], this.watchers[i].state);
				}
			}
		}

		startStabilize() {
			if (this.stabilizeStep === 1)
			{
				let allIsReady = true;
				for (let i = 0; i < this.watchers.length; i++)
				{
					if (this.watchers[i].inAction())
					{
						allIsReady = false;
						break;
					}
				}
				if (allIsReady)
				{
					this.stabilizeStep = 2;
					let watcher = null;
					if (this.watchers.indexOf(this.transaction.initWatcher) !== -1)
					{
						watcher = this.transaction.initWatcher;
					}
					this.stabilizer(watcher);
					this.stabilizeStep = 3;
				}
			}
		}

		isStartStabilize() {
			return this.stabilizeStep === 2;
		}

		isReadyToChange() {
			return this.stabilizeStep === 3;
		}

		startChange() {
			let hasChanges = false;
			for (let i = 0; i < this.watchers.length; i++)
			{
				const state = this.watchersStates.get(this.watchers[i]);
				if (state !== this.watchers[i].getState())
				{
					hasChanges = true;
				}
				this.watchers[i].checkDynamic();
			}
			if (this.handlers.length > 0 && hasChanges)
			{
				for (let i = 0; i < this.handlers.length; i++)
				{
					this.handlers[i]();
				}
			}
		}

		removeTransaction() {
			delete this.watchersStates;
			delete this.transaction;
			this.stabilizeStep = 0;
		}
	};
})();