<commit_before>import { Injectable } from '@angular/core';
import { Actions, Effect } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { IAppState } from '../';
import {
	DisableImageProcessing,
	EnableImageProcessing,
	SetActiveCenter,
	SetAutoImageProcessing,
	SetAutoImageProcessingSuccess,
	ToolsActionsTypes
} from '@ansyn/menu-items/tools';
import { CasesActionTypes } from '@ansyn/menu-items/cases';
import { ImageryCommunicatorService } from '@ansyn/imagery/communicator-service/communicator.service';
import 'rxjs/add/operator/withLatestFrom';
import { isNil as _isNil, cloneDeep, find } from 'lodash';
import { CommunicatorEntity } from '@ansyn/imagery/communicator-service/communicator.entity';
import {
	AnnotationVisualizerAgentAction,
	DisableMouseShadow,
	EnableMouseShadow,
	GoToAction,
	SetActiveOverlaysFootprintModeAction,
	SetPinLocationModeAction,
	ShowOverlaysFootprintAction,
	StopMouseShadow
} from '@ansyn/menu-items/tools/actions/tools.actions';
import { ActiveMapChangedAction, MapActionTypes, SetMapAutoImageProcessing } from '@ansyn/map-facade';
import { DisplayOverlaySuccessAction, OverlaysActionTypes } from '@ansyn/overlays';
import { IMapState, mapStateSelector } from '@ansyn/map-facade/reducers/map.reducer';
import { MapFacadeService } from '@ansyn/map-facade/services/map-facade.service';
import {
	PinLocationModeTriggerAction,
	SetLayoutAction,
	SetMapsDataActionStore
} from '@ansyn/map-facade/actions/map.actions';
import { Case, CaseMapState } from '@ansyn/core/models/case.model';

import { ILayerState, layersStateSelector } from '@ansyn/menu-items/layers-manager/reducers/layers.reducer';
import { IToolsState, toolsStateSelector } from '@ansyn/menu-items/tools/reducers/tools.reducer';
import { SetMapManualImageProcessing } from '@ansyn/map-facade/actions/map.actions';
import { SetManualImageProcessing, SetManualImageProcessingArguments } from '@ansyn/menu-items/tools/actions/tools.actions';
import { casesStateSelector, ICasesState } from '@ansyn/menu-items/cases/reducers/cases.reducer';
import { UpdateCaseAction } from '@ansyn/menu-items/cases/actions/cases.actions';


@Injectable()
export class ToolsAppEffects {

	/**
	 * @type Effect
	 * @name onActiveMapChanges$
	 * @ofType ActiveMapChangedAction
	 * @dependencies map
	 * @filter There is an active map
	 * @action DisableImageProcessing?, EnableImageProcessing?, SetAutoImageProcessingSuccess?
	 */
	@Effect()
	onActiveMapChanges$: Observable<ActiveMapChangedAction | DisableImageProcessing | SetAutoImageProcessingSuccess> = this.actions$
		.ofType(MapActionTypes.TRIGGER.ACTIVE_MAP_CHANGED)
		.withLatestFrom(this.store$.select(mapStateSelector), (action, mapState: IMapState) => mapState)
		.map(MapFacadeService.activeMap)
		.filter(activeMap => Boolean(activeMap))
		.mergeMap((activeMap: CaseMapState) => {
			if (!activeMap.data.overlay) {
				return [new DisableImageProcessing()];
			} else {
				return [
					new EnableImageProcessing(),
					new SetAutoImageProcessingSuccess(activeMap.data.isAutoImageProcessingActive)
				];
			}
		});

	/**
	 * @type Effect
	 * @name onActiveMapChangesSetOverlaysFootprintMode$
	 * @ofType ActiveMapChangedAction
	 * @dependencies map, layers, tools
	 * @action SetActiveOverlaysFootprintModeAction, AnnotationVisualizerAgentAction, AnnotationVisualizerAgentAction?
	 */
	@Effect()
	onActiveMapChangesSetOverlaysFootprintMode$: Observable<any> = this.actions$
		.ofType(MapActionTypes.TRIGGER.ACTIVE_MAP_CHANGED)
		.withLatestFrom(
			this.store$.select(mapStateSelector),
			this.store$.select(layersStateSelector),
			this.store$.select(toolsStateSelector),
			(action, mapState: IMapState, layerState: ILayerState, toolsState: IToolsState) =>
				[action, mapState, layerState, toolsState])
		.map(([action, mapState, layerState, toolsState]: [ActiveMapChangedAction, IMapState, ILayerState, IToolsState]): [CaseMapState, ILayerState, IToolsState] =>
			[MapFacadeService.activeMap(mapState), layerState, toolsState])
		.mergeMap(([activeMap, layerState, toolsState]: [CaseMapState, ILayerState, IToolsState]) => {
				const result = [new SetActiveOverlaysFootprintModeAction(activeMap.data.overlayDisplayMode)];
				if (layerState.displayAnnotationsLayer) {
					result.push(new AnnotationVisualizerAgentAction({
						action: 'show',
						maps: 'all'
					}));
				}
				// if the annotation menu is open and we switched active map
				// and the layer is disabled we need to switch the annotation view to
				// new active map
				else if (toolsState.flags.get('annotations')) {
					result.push(new AnnotationVisualizerAgentAction({
						action: 'show',
						maps: 'active'
					}));
					result.push(new AnnotationVisualizerAgentAction({
						action: 'removeLayer',
						maps: 'others'
					}));
				}
				return result;
			}
		);

	/**
	 * @type Effect
	 * @name onShowOverlayFootprint$
	 * @ofType ShowOverlaysFootprintAction
	 * @action SetActiveOverlaysFootprintModeAction
	 */
	@Effect()
	onShowOverlayFootprint$: Observable<any> = this.actions$
		.ofType<ShowOverlaysFootprintAction>(ToolsActionsTypes.SHOW_OVERLAYS_FOOTPRINT)
		.map((action) => new SetActiveOverlaysFootprintModeAction(action.payload));

	/**
	 * @type Effect
	 * @name onDisplayOverlaySuccess$
	 * @ofType DisplayOverlaySuccessAction
	 * @dependencies map
	 * @action EnableImageProcessing, SetMapAutoImageProcessing, SetAutoImageProcessingSuccess
	 */

	@Effect()
	onDisplayOverlaySuccess$: Observable<any> = this.actions$
		.ofType<DisplayOverlaySuccessAction>(OverlaysActionTypes.DISPLAY_OVERLAY_SUCCESS)
		.withLatestFrom(this.store$.select(casesStateSelector), this.store$.select(mapStateSelector),
			(action: DisplayOverlaySuccessAction, cases: ICasesState, mapsState: IMapState) => {
				return [action, cloneDeep(cases.selectedCase), mapsState];
			})
		.mergeMap(([action, selectedCase, mapsState]: [DisplayOverlaySuccessAction, Case, IMapState]) => {
			const activeMapState: CaseMapState  = find(mapsState.mapsList, map => map.id === mapsState.activeMapId);
			// action 1: EnableImageProcessing
			const actions = [new EnableImageProcessing()];
			let manualProcessArgs = null;

			// action 2: SetMapManualImageProcessing / SetMapAutoImageProcessing (optional)
			if (selectedCase.state.overlaysManualProcessArgs) {
				manualProcessArgs = selectedCase.state.overlaysManualProcessArgs.get(action.payload.id)
			}
			if (activeMapState.data.isAutoImageProcessingActive) {
				// auto process action
				actions.push(new SetMapAutoImageProcessing({mapId: activeMapState.id, toggleValue: activeMapState.data.isAutoImageProcessingActive}));
			} else if (manualProcessArgs) {
				// manual process action
				actions.push(new SetMapManualImageProcessing({
					mapId: activeMapState.id,
					processingParams: manualProcessArgs
				}));
			}
			// action 3: update Manual Image Processing Arguments
			actions.push(new SetManualImageProcessingArguments({ processingParams: manualProcessArgs }));

			// action 4: SetAutoImageProcessingSuccess (autoImageProcessing / manualImageProcessing / null)
			actions.push(new SetAutoImageProcessingSuccess(activeMapState.data.isAutoImageProcessingActive));
			return actions;
		});

	/**
	 * @type Effect
	 * @name backToWorldView$
	 * @ofType BackToWorldAction
	 * @action DisableImageProcessing
	 */
	@Effect()
	backToWorldView$: Observable<DisableImageProcessing> = this.actions$
		.ofType(MapActionTypes.BACK_TO_WORLD)
		.map(() => new DisableImageProcessing());

	/**
	 * @type Effect
	 * @name onSelectCase$
	 * @ofType SelectCaseAction
	 * @action DisableImageProcessing
	 */
	@Effect()
	onSelectCase$: Observable<DisableImageProcessing> = this.actions$
		.ofType(CasesActionTypes.SELECT_CASE)
		.map(() => new DisableImageProcessing());

	/**
	 * @type Effect
	 * @name toggleAutoImageProcessing$
	 * @ofType SetAutoImageProcessing
	 * @dependencies map
	 * @action SetMapAutoImageProcessing, SetMapsDataActionStore, SetAutoImageProcessingSuccess
	 */
	@Effect()
	toggleAutoImageProcessing$: Observable<any> = this.actions$
		.ofType(ToolsActionsTypes.SET_AUTO_IMAGE_PROCESSING)
		.withLatestFrom(this.store$.select(mapStateSelector), (action: SetAutoImageProcessing, mapsState: IMapState) => {
			return [action, mapsState];
		})
		.mergeMap(([action, mapsState]: [SetAutoImageProcessing, IMapState]) => {
			mapsState = updatesMapAutoImageProcessingFlag(mapsState, true);
			const activeMap = find(mapsState.mapsList, map => map.id === mapsState.activeMapId);

			return [
				new SetMapAutoImageProcessing({ mapId: mapsState.activeMapId, toggleValue: activeMap.data.isAutoImageProcessingActive }),
				new SetMapsDataActionStore({ mapsList: [...mapsState.mapsList] }),
				new SetAutoImageProcessingSuccess(activeMap.data.isAutoImageProcessingActive)
			];
		});

	/**
	 * @type Effect
	 * @name resetManualImageProcessingArguments$
	 * @ofType SetAutoImageProcessing
	 * @dependencies withLatestFrom, filter, map
	 * @action UpdateCaseAction?
	 */
	@Effect()
	resetManualImageProcessingArguments$: Observable<any> = this.actions$
		.ofType(ToolsActionsTypes.SET_AUTO_IMAGE_PROCESSING, OverlaysActionTypes.DISPLAY_OVERLAY_SUCCESS)
		.withLatestFrom(this.store$.select(casesStateSelector), this.store$.select(mapStateSelector),
			(action: SetAutoImageProcessing, cases: ICasesState, mapsState: IMapState) => {
				const activeMapState: CaseMapState  = find(mapsState.mapsList, map => map.id === mapsState.activeMapId);
				const overlayId = activeMapState.data.overlay.id;
				return [activeMapState, overlayId, cloneDeep(cases.selectedCase)];
			})
		.filter(([activeMapState, overlayId, selectedCase]: [CaseMapState, string, Case]) => {
			const isAutoProcessOn = activeMapState.data.isAutoImageProcessingActive;
			const ManualProcessArgs = selectedCase.state.overlaysManualProcessArgs;
			return Boolean(isAutoProcessOn && ManualProcessArgs && ManualProcessArgs.get(overlayId));
		})
		.mergeMap(([activeMapState, overlayId, selectedCase]: [CaseMapState, string, Case]) => {
			updateOverlaysManualProcessArgs(selectedCase, overlayId, null);
			return [
				new SetManualImageProcessingArguments({ processingParams: null }),
				new UpdateCaseAction(selectedCase)
			];
		});


	/**
	 * @type Effect
	 * @name onManualImageProcessing$
	 * @ofType ofType
	 * @filter There is a active map
	 * @dependencies map, withLatestFrom
	 * @action SetMapManualImageProcessing
	 */
	@Effect()
	onManualImageProcessing$: Observable<any> = this.actions$
		.ofType(ToolsActionsTypes.SET_MANUAL_IMAGE_PROCESSING)
		.withLatestFrom(this.store$.select(casesStateSelector), this.store$.select(mapStateSelector),
			(action: SetManualImageProcessing, cases: ICasesState, mapsState: IMapState) => {
				return [action, cloneDeep(cases.selectedCase), mapsState];
			})
		.filter(([action, selectedCase, mapsState]: [SetManualImageProcessing, Case, IMapState]) => {
			return Boolean(selectedCase.state.maps.activeMapId && mapsState)
		})
		.mergeMap(([action, selectedCase, mapsState]: [SetManualImageProcessing, Case, IMapState]) => {
			const allMapsState = selectedCase.state.maps;
			const activeMapState: CaseMapState  = find(allMapsState.data, map => map.id === allMapsState.activeMapId);

			updateOverlaysManualProcessArgs(selectedCase, activeMapState.data.overlay.id, action.payload.processingParams);
			updatesMapAutoImageProcessingFlag(mapsState, false, false);
			return [
				new UpdateCaseAction(selectedCase),
				new SetMapsDataActionStore({ mapsList: mapsState.mapsList }),
				new SetMapManualImageProcessing({ mapId: allMapsState.activeMapId, processingParams: action.payload.processingParams })
			]
		});

	/**
	 * @type Effect
	 * @name getActiveCenter$
	 * @ofType PullActiveCenter
	 * @dependencies map
	 * @filter There is a map communicator
	 * @action SetActiveCenter
	 */
	@Effect()
	getActiveCenter$: Observable<SetActiveCenter> = this.actions$
		.ofType(ToolsActionsTypes.PULL_ACTIVE_CENTER)
		.withLatestFrom(this.store$.select(mapStateSelector), (action, mapState: IMapState): CommunicatorEntity => this.imageryCommunicatorService.provide(mapState.activeMapId))
		.filter(communicator => !_isNil(communicator))
		.map((communicator: CommunicatorEntity) => {
			const activeMapCenter = communicator.getCenter();
			return new SetActiveCenter(activeMapCenter.coordinates);
		});

	/**
	 * @type Effect
	 * @name updatePinLocationAction$
	 * @ofType SetPinLocationModeAction
	 */
	@Effect({ dispatch: false })
	updatePinLocationAction$: Observable<any> = this.actions$
		.ofType(ToolsActionsTypes.SET_PIN_LOCATION_MODE)
		.do((action: SetPinLocationModeAction) => {
			this.imageryCommunicatorService.communicatorsAsArray().forEach((communicator) => {
				if (action.payload) {
					communicator.createMapSingleClickEvent();
				} else {
					communicator.removeSingleClickEvent();
				}
			});
		});

	/**
	 * @type Effect
	 * @name onGoTo$
	 * @ofType GoToAction
	 * @dependencies map
	 * @filter There is a map communicator
	 * @action SetActiveCenter
	 */
	@Effect()
	onGoTo$: Observable<SetActiveCenter> = this.actions$
		.ofType<GoToAction>(ToolsActionsTypes.GO_TO)
		.withLatestFrom(this.store$.select(mapStateSelector), (action, mapState: IMapState): any => ({
			action,
			communicator: this.imageryCommunicatorService.provide(mapState.activeMapId)
		}))
		.filter(({ action, communicator }) => !_isNil(communicator))
		.map(({ action, communicator }) => {
			const center: GeoJSON.Point = {
				type: 'Point',
				coordinates: action.payload
			};
			communicator.setCenter(center);
			return new SetActiveCenter(action.payload);
		});

	/**
	 * @type Effect
	 * @name updatePinLocationState$
	 * @ofType SetPinLocationModeAction
	 * @action PinLocationModeTriggerAction
	 */
	@Effect()
	updatePinLocationState$: Observable<PinLocationModeTriggerAction> = this.actions$
		.ofType<SetPinLocationModeAction>(ToolsActionsTypes.SET_PIN_LOCATION_MODE)
		.map(({ payload }) => new PinLocationModeTriggerAction(payload));

	/**
	 * @type Effect
	 * @name onLayoutsChangeSetMouseShadowEnable$
	 * @ofType SetLayoutAction
	 * @action DisableMouseShadow?, StopMouseShadow?, EnableMouseShadow?
	 */
	@Effect()
	onLayoutsChangeSetMouseShadowEnable$: Observable<any> = this.actions$
		.ofType<SetLayoutAction>(MapActionTypes.SET_LAYOUT)
		.mergeMap(({ payload }) => {
			if (payload.mapsCount === 1) {
				return [
					new DisableMouseShadow(),
					new StopMouseShadow()
				];
			}
			return [new EnableMouseShadow()];
		});

	constructor(protected actions$: Actions, protected store$: Store<IAppState>, protected imageryCommunicatorService: ImageryCommunicatorService) {
	}
}
// update per-overlay manual processing param (saved in case)
function updateOverlaysManualProcessArgs(selectedCase: Case, overlayId: string, processingParams?: Object) {
	if (!processingParams) {
		processingParams = null;
	}
	if (!selectedCase.state.overlaysManualProcessArgs) {
		selectedCase.state.overlaysManualProcessArgs = new Map<string, Object>();
	}
	selectedCase.state.overlaysManualProcessArgs.set(overlayId, processingParams);
	return selectedCase;
}

function updatesMapAutoImageProcessingFlag(mapsState: IMapState, toggle: boolean, newValue?: boolean) {
	const activeMapId = mapsState.activeMapId;
	const activeMap = find(mapsState.mapsList, map => map.id === activeMapId);
	if (toggle) {
		activeMap.data.isAutoImageProcessingActive = !activeMap.data.isAutoImageProcessingActive;
	} else {
		activeMap.data.isAutoImageProcessingActive = newValue;
	}
	return mapsState;
}
<commit_msg>Contrast and brightness works open issues:<commit_after>import { Injectable } from '@angular/core';
import { Actions, Effect } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { IAppState } from '../';
import {
	DisableImageProcessing,
	EnableImageProcessing,
	SetActiveCenter,
	SetAutoImageProcessing,
	SetAutoImageProcessingSuccess,
	ToolsActionsTypes
} from '@ansyn/menu-items/tools';
import { CasesActionTypes } from '@ansyn/menu-items/cases';
import { ImageryCommunicatorService } from '@ansyn/imagery/communicator-service/communicator.service';
import 'rxjs/add/operator/withLatestFrom';
import { isNil as _isNil, cloneDeep, find } from 'lodash';
import { CommunicatorEntity } from '@ansyn/imagery/communicator-service/communicator.entity';
import {
	AnnotationVisualizerAgentAction,
	DisableMouseShadow,
	EnableMouseShadow,
	GoToAction,
	SetActiveOverlaysFootprintModeAction,
	SetPinLocationModeAction,
	ShowOverlaysFootprintAction,
	StopMouseShadow
} from '@ansyn/menu-items/tools/actions/tools.actions';
import { ActiveMapChangedAction, MapActionTypes, SetMapAutoImageProcessing } from '@ansyn/map-facade';
import { DisplayOverlaySuccessAction, OverlaysActionTypes } from '@ansyn/overlays';
import { IMapState, mapStateSelector } from '@ansyn/map-facade/reducers/map.reducer';
import { MapFacadeService } from '@ansyn/map-facade/services/map-facade.service';
import {
	PinLocationModeTriggerAction,
	SetLayoutAction,
	SetMapsDataActionStore
} from '@ansyn/map-facade/actions/map.actions';
import { Case, CaseMapState } from '@ansyn/core/models/case.model';

import { ILayerState, layersStateSelector } from '@ansyn/menu-items/layers-manager/reducers/layers.reducer';
import { IToolsState, toolsStateSelector } from '@ansyn/menu-items/tools/reducers/tools.reducer';
import { SetMapManualImageProcessing } from '@ansyn/map-facade/actions/map.actions';
import { SetManualImageProcessing, SetManualImageProcessingArguments } from '@ansyn/menu-items/tools/actions/tools.actions';
import { casesStateSelector, ICasesState } from '@ansyn/menu-items/cases/reducers/cases.reducer';
import { UpdateCaseAction } from '@ansyn/menu-items/cases/actions/cases.actions';


@Injectable()
export class ToolsAppEffects {

	/**
	 * @type Effect
	 * @name onActiveMapChanges$
	 * @ofType ActiveMapChangedAction
	 * @dependencies map
	 * @filter There is an active map
	 * @action DisableImageProcessing?, EnableImageProcessing?, SetAutoImageProcessingSuccess?
	 */
	@Effect()
	onActiveMapChanges$: Observable<ActiveMapChangedAction | DisableImageProcessing | SetAutoImageProcessingSuccess> = this.actions$
		.ofType(MapActionTypes.TRIGGER.ACTIVE_MAP_CHANGED)
		.withLatestFrom(this.store$.select(mapStateSelector), (action, mapState: IMapState) => mapState)
		.map(MapFacadeService.activeMap)
		.filter(activeMap => Boolean(activeMap))
		.mergeMap((activeMap: CaseMapState) => {
			if (!activeMap.data.overlay) {
				return [new DisableImageProcessing()];
			} else {
				return [
					new EnableImageProcessing(),
					new SetAutoImageProcessingSuccess(activeMap.data.isAutoImageProcessingActive)
				];
			}
		});

	/**
	 * @type Effect
	 * @name onActiveMapChangesSetOverlaysFootprintMode$
	 * @ofType ActiveMapChangedAction
	 * @dependencies map, layers, tools
	 * @action SetActiveOverlaysFootprintModeAction, AnnotationVisualizerAgentAction, AnnotationVisualizerAgentAction?
	 */
	@Effect()
	onActiveMapChangesSetOverlaysFootprintMode$: Observable<any> = this.actions$
		.ofType(MapActionTypes.TRIGGER.ACTIVE_MAP_CHANGED)
		.withLatestFrom(
			this.store$.select(mapStateSelector),
			this.store$.select(layersStateSelector),
			this.store$.select(toolsStateSelector),
			(action, mapState: IMapState, layerState: ILayerState, toolsState: IToolsState) =>
				[action, mapState, layerState, toolsState])
		.map(([action, mapState, layerState, toolsState]: [ActiveMapChangedAction, IMapState, ILayerState, IToolsState]): [CaseMapState, ILayerState, IToolsState] =>
			[MapFacadeService.activeMap(mapState), layerState, toolsState])
		.mergeMap(([activeMap, layerState, toolsState]: [CaseMapState, ILayerState, IToolsState]) => {
				const result = [new SetActiveOverlaysFootprintModeAction(activeMap.data.overlayDisplayMode)];
				if (layerState.displayAnnotationsLayer) {
					result.push(new AnnotationVisualizerAgentAction({
						action: 'show',
						maps: 'all'
					}));
				}
				// if the annotation menu is open and we switched active map
				// and the layer is disabled we need to switch the annotation view to
				// new active map
				else if (toolsState.flags.get('annotations')) {
					result.push(new AnnotationVisualizerAgentAction({
						action: 'show',
						maps: 'active'
					}));
					result.push(new AnnotationVisualizerAgentAction({
						action: 'removeLayer',
						maps: 'others'
					}));
				}
				return result;
			}
		);

	/**
	 * @type Effect
	 * @name onShowOverlayFootprint$
	 * @ofType ShowOverlaysFootprintAction
	 * @action SetActiveOverlaysFootprintModeAction
	 */
	@Effect()
	onShowOverlayFootprint$: Observable<any> = this.actions$
		.ofType<ShowOverlaysFootprintAction>(ToolsActionsTypes.SHOW_OVERLAYS_FOOTPRINT)
		.map((action) => new SetActiveOverlaysFootprintModeAction(action.payload));

	/**
	 * @type Effect
	 * @name onDisplayOverlaySuccess$
	 * @ofType DisplayOverlaySuccessAction
	 * @dependencies map
	 * @action EnableImageProcessing, SetMapAutoImageProcessing, SetAutoImageProcessingSuccess
	 */

	@Effect()
	onDisplayOverlaySuccess$: Observable<any> = this.actions$
		.ofType<DisplayOverlaySuccessAction>(OverlaysActionTypes.DISPLAY_OVERLAY_SUCCESS)
		.withLatestFrom(this.store$.select(casesStateSelector), this.store$.select(mapStateSelector),
			(action: DisplayOverlaySuccessAction, cases: ICasesState, mapsState: IMapState) => {
				return [action, cloneDeep(cases.selectedCase), mapsState];
			})
		.mergeMap(([action, selectedCase, mapsState]: [DisplayOverlaySuccessAction, Case, IMapState]) => {
			const activeMapState: CaseMapState  = find(mapsState.mapsList, map => map.id === mapsState.activeMapId);
			// action 1: EnableImageProcessing
			const actions = [new EnableImageProcessing()];
			let manualProcessArgs = null;

			// action 2: SetMapManualImageProcessing / SetMapAutoImageProcessing (optional)
			if (selectedCase.state.overlaysManualProcessArgs && selectedCase.state.overlaysManualProcessArgs.get) {
				manualProcessArgs = selectedCase.state.overlaysManualProcessArgs.get(action.payload.id)
			}
			if (activeMapState.data.isAutoImageProcessingActive) {
				// auto process action
				actions.push(new SetMapAutoImageProcessing({mapId: activeMapState.id, toggleValue: activeMapState.data.isAutoImageProcessingActive}));
			} else if (manualProcessArgs) {
				// manual process action
				actions.push(new SetMapManualImageProcessing({
					mapId: activeMapState.id,
					processingParams: manualProcessArgs
				}));
			}
			// action 3: update Manual Image Processing Arguments
			actions.push(new SetManualImageProcessingArguments({ processingParams: manualProcessArgs }));

			// action 4: SetAutoImageProcessingSuccess (autoImageProcessing / manualImageProcessing / null)
			actions.push(new SetAutoImageProcessingSuccess(activeMapState.data.isAutoImageProcessingActive));
			return actions;
		});

	/**
	 * @type Effect
	 * @name backToWorldView$
	 * @ofType BackToWorldAction
	 * @action DisableImageProcessing
	 */
	@Effect()
	backToWorldView$: Observable<DisableImageProcessing> = this.actions$
		.ofType(MapActionTypes.BACK_TO_WORLD)
		.map(() => new DisableImageProcessing());

	/**
	 * @type Effect
	 * @name onSelectCase$
	 * @ofType SelectCaseAction
	 * @action DisableImageProcessing
	 */
	@Effect()
	onSelectCase$: Observable<DisableImageProcessing> = this.actions$
		.ofType(CasesActionTypes.SELECT_CASE)
		.map(() => new DisableImageProcessing());

	/**
	 * @type Effect
	 * @name toggleAutoImageProcessing$
	 * @ofType SetAutoImageProcessing
	 * @dependencies map
	 * @action SetMapAutoImageProcessing, SetMapsDataActionStore, SetAutoImageProcessingSuccess
	 */
	@Effect()
	toggleAutoImageProcessing$: Observable<any> = this.actions$
		.ofType(ToolsActionsTypes.SET_AUTO_IMAGE_PROCESSING)
		.withLatestFrom(this.store$.select(mapStateSelector), (action: SetAutoImageProcessing, mapsState: IMapState) => {
			return [action, mapsState];
		})
		.mergeMap(([action, mapsState]: [SetAutoImageProcessing, IMapState]) => {
			mapsState = updatesMapAutoImageProcessingFlag(mapsState, true);
			const activeMap = find(mapsState.mapsList, map => map.id === mapsState.activeMapId);

			return [
				new SetMapAutoImageProcessing({ mapId: mapsState.activeMapId, toggleValue: activeMap.data.isAutoImageProcessingActive }),
				new SetMapsDataActionStore({ mapsList: [...mapsState.mapsList] }),
				new SetAutoImageProcessingSuccess(activeMap.data.isAutoImageProcessingActive)
			];
		});

	/**
	 * @type Effect
	 * @name resetManualImageProcessingArguments$
	 * @ofType SetAutoImageProcessing
	 * @dependencies withLatestFrom, filter, map
	 * @action UpdateCaseAction?
	 */
	@Effect()
	resetManualImageProcessingArguments$: Observable<any> = this.actions$
		.ofType(ToolsActionsTypes.SET_AUTO_IMAGE_PROCESSING, OverlaysActionTypes.DISPLAY_OVERLAY_SUCCESS)
		.withLatestFrom(this.store$.select(casesStateSelector), this.store$.select(mapStateSelector),
			(action: SetAutoImageProcessing, cases: ICasesState, mapsState: IMapState) => {
				const activeMapState: CaseMapState  = find(mapsState.mapsList, map => map.id === mapsState.activeMapId);
				const overlayId = activeMapState.data.overlay.id;
				return [activeMapState, overlayId, cloneDeep(cases.selectedCase)];
			})
		.filter(([activeMapState, overlayId, selectedCase]: [CaseMapState, string, Case]) => {
			const isAutoProcessOn = activeMapState.data.isAutoImageProcessingActive;
			const ManualProcessArgs = selectedCase.state.overlaysManualProcessArgs;
			return Boolean(isAutoProcessOn && ManualProcessArgs && ManualProcessArgs.get(overlayId));
		})
		.mergeMap(([activeMapState, overlayId, selectedCase]: [CaseMapState, string, Case]) => {
			updateOverlaysManualProcessArgs(selectedCase, overlayId, null);
			return [
				new SetManualImageProcessingArguments({ processingParams: null }),
				new UpdateCaseAction(selectedCase)
			];
		});


	/**
	 * @type Effect
	 * @name onManualImageProcessing$
	 * @ofType ofType
	 * @filter There is a active map
	 * @dependencies map, withLatestFrom
	 * @action SetMapManualImageProcessing
	 */
	@Effect()
	onManualImageProcessing$: Observable<any> = this.actions$
		.ofType(ToolsActionsTypes.SET_MANUAL_IMAGE_PROCESSING)
		.withLatestFrom(this.store$.select(casesStateSelector), this.store$.select(mapStateSelector),
			(action: SetManualImageProcessing, cases: ICasesState, mapsState: IMapState) => {
				return [action, cloneDeep(cases.selectedCase), mapsState];
			})
		.filter(([action, selectedCase, mapsState]: [SetManualImageProcessing, Case, IMapState]) => {
			return Boolean(selectedCase.state.maps.activeMapId && mapsState)
		})
		.mergeMap(([action, selectedCase, mapsState]: [SetManualImageProcessing, Case, IMapState]) => {
			const allMapsState = selectedCase.state.maps;
			const activeMapState: CaseMapState  = find(allMapsState.data, map => map.id === allMapsState.activeMapId);

			updateOverlaysManualProcessArgs(selectedCase, activeMapState.data.overlay.id, action.payload.processingParams);
			updatesMapAutoImageProcessingFlag(mapsState, false, false);
			return [
				new UpdateCaseAction(selectedCase),
				new SetMapsDataActionStore({ mapsList: mapsState.mapsList }),
				new SetMapManualImageProcessing({ mapId: allMapsState.activeMapId, processingParams: action.payload.processingParams })
			]
		});

	/**
	 * @type Effect
	 * @name getActiveCenter$
	 * @ofType PullActiveCenter
	 * @dependencies map
	 * @filter There is a map communicator
	 * @action SetActiveCenter
	 */
	@Effect()
	getActiveCenter$: Observable<SetActiveCenter> = this.actions$
		.ofType(ToolsActionsTypes.PULL_ACTIVE_CENTER)
		.withLatestFrom(this.store$.select(mapStateSelector), (action, mapState: IMapState): CommunicatorEntity => this.imageryCommunicatorService.provide(mapState.activeMapId))
		.filter(communicator => !_isNil(communicator))
		.map((communicator: CommunicatorEntity) => {
			const activeMapCenter = communicator.getCenter();
			return new SetActiveCenter(activeMapCenter.coordinates);
		});

	/**
	 * @type Effect
	 * @name updatePinLocationAction$
	 * @ofType SetPinLocationModeAction
	 */
	@Effect({ dispatch: false })
	updatePinLocationAction$: Observable<any> = this.actions$
		.ofType(ToolsActionsTypes.SET_PIN_LOCATION_MODE)
		.do((action: SetPinLocationModeAction) => {
			this.imageryCommunicatorService.communicatorsAsArray().forEach((communicator) => {
				if (action.payload) {
					communicator.createMapSingleClickEvent();
				} else {
					communicator.removeSingleClickEvent();
				}
			});
		});

	/**
	 * @type Effect
	 * @name onGoTo$
	 * @ofType GoToAction
	 * @dependencies map
	 * @filter There is a map communicator
	 * @action SetActiveCenter
	 */
	@Effect()
	onGoTo$: Observable<SetActiveCenter> = this.actions$
		.ofType<GoToAction>(ToolsActionsTypes.GO_TO)
		.withLatestFrom(this.store$.select(mapStateSelector), (action, mapState: IMapState): any => ({
			action,
			communicator: this.imageryCommunicatorService.provide(mapState.activeMapId)
		}))
		.filter(({ action, communicator }) => !_isNil(communicator))
		.map(({ action, communicator }) => {
			const center: GeoJSON.Point = {
				type: 'Point',
				coordinates: action.payload
			};
			communicator.setCenter(center);
			return new SetActiveCenter(action.payload);
		});

	/**
	 * @type Effect
	 * @name updatePinLocationState$
	 * @ofType SetPinLocationModeAction
	 * @action PinLocationModeTriggerAction
	 */
	@Effect()
	updatePinLocationState$: Observable<PinLocationModeTriggerAction> = this.actions$
		.ofType<SetPinLocationModeAction>(ToolsActionsTypes.SET_PIN_LOCATION_MODE)
		.map(({ payload }) => new PinLocationModeTriggerAction(payload));

	/**
	 * @type Effect
	 * @name onLayoutsChangeSetMouseShadowEnable$
	 * @ofType SetLayoutAction
	 * @action DisableMouseShadow?, StopMouseShadow?, EnableMouseShadow?
	 */
	@Effect()
	onLayoutsChangeSetMouseShadowEnable$: Observable<any> = this.actions$
		.ofType<SetLayoutAction>(MapActionTypes.SET_LAYOUT)
		.mergeMap(({ payload }) => {
			if (payload.mapsCount === 1) {
				return [
					new DisableMouseShadow(),
					new StopMouseShadow()
				];
			}
			return [new EnableMouseShadow()];
		});

	constructor(protected actions$: Actions, protected store$: Store<IAppState>, protected imageryCommunicatorService: ImageryCommunicatorService) {
	}
}
// update per-overlay manual processing param (saved in case)
function updateOverlaysManualProcessArgs(selectedCase: Case, overlayId: string, processingParams?: Object) {
	if (!processingParams) {
		processingParams = null;
	}
	if (!selectedCase.state.overlaysManualProcessArgs) {
		selectedCase.state.overlaysManualProcessArgs = new Map<string, Object>();
	}
	selectedCase.state.overlaysManualProcessArgs.set(overlayId, processingParams);
	return selectedCase;
}

function updatesMapAutoImageProcessingFlag(mapsState: IMapState, toggle: boolean, newValue?: boolean) {
	const activeMapId = mapsState.activeMapId;
	const activeMap = find(mapsState.mapsList, map => map.id === activeMapId);
	if (toggle) {
		activeMap.data.isAutoImageProcessingActive = !activeMap.data.isAutoImageProcessingActive;
	} else {
		activeMap.data.isAutoImageProcessingActive = newValue;
	}
	return mapsState;
}

{'fraction_non_alphanumeric': 0.11490275241116345, 'fraction_numerical': 0.00032042039155371846, 'mean_word_length': 5.56914333824458, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 113, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5320406', 'n_tokens_mistral': 10223, 'n_tokens_neox': 9154, 'n_words': 1700}