import { IImageryMapPosition , IMapSettings } from '@ansyn/imagery' ; import { createFeatureSelector , createSelector , MemoizedSelector } from '@ngrx/store' ; import { createEntityAdapter , EntityAdapter , EntityState } from '@ngrx/entity' ; import { range } from 'lodash' ; import { UUID } from 'angular2-uuid' ; import { Dictionary } from '@ngrx/entity' ; import { sessionData } from '../models/core-session-state.model' ; import { IPendingOverlay , IToastMessage , MapActions , MapActionTypes } from '../actions/map.actions' ; import { LayoutKey , layoutOptions } from '../models/maps-layout' ; import { Point } from 'geojson' ; export interface IFourViewsData { point ? : Point ; active : boolean ; sensors ? : string [ ] ; } export function setMapsDataChanges ( oldEntities , oldActiveMapId , layout ) { const mapsList = [ ] ; const activeMap = oldEntities [ oldActiveMapId ] ; const oldMapsList = Object . values ( oldEntities ) ; range ( layout . mapsCount ) . forEach ( ( index ) => { if ( oldMapsList [ index ] ) { mapsList . push ( oldMapsList [ index ] ) ; } else { const mapStateCopy = { id : UUID . UUID ( ) , data : { position : { extentPolygon : activeMap . data . position . extentPolygon , projectedState : activeMap . data . position . projectedState } , overlaysFootprintActive : false } , worldView : { ... activeMap . worldView } , orientation : activeMap . orientation , flags : { hideLayers : false } } ; mapsList . push ( mapStateCopy ) ; } } ) ; const notExist = ! mapsList . some ( ( { id } ) => id === oldActiveMapId ) ; if ( notExist ) { mapsList [ mapsList . length - 1 ] = activeMap ; } return mapsList ; } export const mapsAdapter = createEntityAdapter < IMapSettings > ( ) ; export interface IMapState extends EntityState < IMapSettings > { activeMapId : string ; isLoadingMaps : Map < string , string > ; isHiddenMaps : Set < string > ; pendingMapsCount : number ; pendingOverlays : IPendingOverlay [ ] ; layout : LayoutKey ; wasWelcomeNotificationShown : boolean ; toastMessage : IToastMessage ; footerCollapse : boolean ; minimalistViewMode : boolean ; fourViewsMode : IFourViewsData ; } export const initialMapState = mapsAdapter . getInitialState ( { activeMapId : null , isLoadingMaps : new Map < string , string > ( ) , isHiddenMaps : new Set < string > ( ) , pendingMapsCount : 0 , pendingOverlays : [ ] , layout : < LayoutKey > 'layout1' , wasWelcomeNotificationShown : sessionData ( ) . wasWelcomeNotificationShown , toastMessage : null , footerCollapse : false , minimalistViewMode : false , fourViewsMode : { point : null , active : false } } ) ; export const mapFeatureKey = 'map' ; export const mapStateSelector = createFeatureSelector < IMapState > ( mapFeatureKey ) ; export function MapReducer ( state = initialMapState , action ) { switch ( action . type ) { case MapActionTypes . SET_TOAST_MESSAGE : return { ... state , toastMessage : action . payload } ; case MapActionTypes . SET_FOUR_VIEWS_MODE : return { ... state , fourViewsMode : action . payload } ; case MapActionTypes . IMAGERY_REMOVED : { const isLoadingMaps = new Map ( state . isLoadingMaps ) ; isLoadingMaps . delete ( action . payload . id ) ; const isHiddenMaps = new Set ( state . isHiddenMaps ) ; isHiddenMaps . delete ( action . payload . id ) ; return { ... state , isLoadingMaps , isHiddenMaps } ; } case MapActionTypes . VIEW . SET_IS_LOADING : { const isLoadingMaps = new Map ( state . isLoadingMaps ) ; const { mapId , show , text } = action . payload ; const exist = state . entities [ mapId ] ; if ( show && exist ) { isLoadingMaps . set ( mapId , text ) ; } else { isLoadingMaps . delete ( mapId ) ; } return { ... state , isLoadingMaps } ; } case MapActionTypes . SET_MAP_ORIENTATION : { return mapsAdapter . updateOne ( { id : action . payload . mapId || state . activeMapId , changes : { orientation : action . payload . orientation } } , state ) ; } case MapActionTypes . VIEW . SET_IS_VISIBLE : { const isHiddenMaps = new Set ( state . isHiddenMaps ) ; const { mapId , isVisible } = action . payload ; if ( ! isVisible ) { isHiddenMaps . add ( mapId ) ; } else { isHiddenMaps . delete ( mapId ) ; } return { ... state , ... action . payload } ; } case MapActionTypes . UPDATE_MAP : { return mapsAdapter . updateOne ( action . payload , state ) ; } case MapActionTypes . POSITION_CHANGED : { const { id , position } = action . payload ; const activeMap = state . entities [ id ] ; if ( activeMap ) { return mapsAdapter . updateOne ( { id , changes : { data : { ... activeMap . data , position } } } , state ) ; } return state ; } case MapActionTypes . SET_ACTIVE_MAP_ID : { return { ... state , activeMapId : action . payload } ; } case MapActionTypes . SET_MAPS_DATA : return mapsAdapter . setAll ( action . payload . mapsList , state ) ; case MapActionTypes . DECREASE_PENDING_MAPS_COUNT : const currentCount = state . pendingMapsCount ; const newCount = currentCount === 0 ? currentCount : currentCount - 1 ; return { ... state , pendingMapsCount : newCount } ; case MapActionTypes . SET_PENDING_OVERLAYS : return { ... state , pendingOverlays : action . payload } ; case MapActionTypes . REMOVE_PENDING_OVERLAY : const pendingOverlays = state . pendingOverlays . filter ( ( pendingOverlay ) => pendingOverlay . id !== action . payload ) ; return { ... state , pendingOverlays } ; case MapActionTypes . TOGGLE_MAP_LAYERS : { const { mapId : id } = action . payload ; const entity = state . entities [ id ] ; const flags = { ... entity . flags , hideLayers : ! entity . flags . hideLayers } ; return mapsAdapter . updateOne ( { id : action . payload . mapId , changes : { flags } } , state ) ; } case MapActionTypes . SET_LAYOUT : const layout = layoutOptions . get ( action . payload ) ; if ( layout . mapsCount !== Object . values ( state . entities ) . length && Object . values ( state . entities ) . length ) { const pendingMapsCount = Math . abs ( layout . mapsCount - Object . values ( state . entities ) . length ) ; const mapsList = setMapsDataChanges ( state . entities , state . activeMapId , layout ) ; return mapsAdapter . setAll ( mapsList , { ... state , pendingMapsCount , layout : action . payload } ) ; } return { ... state , layout : action . payload } ; case MapActionTypes . CHANGE_IMAGERY_MAP_SUCCESS : { const { id , worldView } = action . payload ; return mapsAdapter . updateOne ( { id , changes : { worldView } } , state ) ; } case MapActionTypes . REPLACE_MAP_MAIN_LAYER_SUCCESS : { const { id , sourceType } = action . payload ; const worldView = { ... state . entities [ id ] . worldView , sourceType } ; return mapsAdapter . updateOne ( { id , changes : { worldView } } , state ) ; } case MapActionTypes . SET_WAS_WELCOME_NOTIFICATION_SHOWN_FLAG : return { ... state , wasWelcomeNotificationShown : action . payload } ; case MapActionTypes . FOOTER_COLLAPSE : return { ... state , footerCollapse : action . payload } ; case MapActionTypes . SET_MINIMALIST_VIEW_MODE : return { ... state , minimalistViewMode : action . payload } ; case MapActionTypes . VISUALIZERS . OVERLAYS_FOOTPRINT : const { mapId , show } = action . payload ; const oldData = state . entities [ mapId ] . data ; return mapsAdapter . updateOne ( { id : mapId , changes : { data : { ... oldData , overlaysFootprintActive : show } } } , state ) ; default : return state ; } } const { selectAll , selectEntities , selectIds , selectTotal } = mapsAdapter . getSelectors ( ) ; export const selectActiveMapId = createSelector ( mapStateSelector , ( map ) => map . activeMapId ) ; export const selectFourViewsData = createSelector ( mapStateSelector , ( map ) => map ?. fourViewsMode ) ; export const selectFourViewsMode = createSelector ( selectFourViewsData , ( fourViewsData ) => fourViewsData ?. active ) ; export const selectMapsList = createSelector ( mapStateSelector , selectAll ) ; export const selectMapsTotal = createSelector ( mapStateSelector , selectTotal ) ; export const selectMapsIds = createSelector ( mapStateSelector , selectIds ) ; export const selectMaps = createSelector ( mapStateSelector , selectEntities ) ; export const selectLayout = createSelector ( mapStateSelector , ( state ) => state . layout ) ; export const selectWasWelcomeNotificationShown = createSelector ( mapStateSelector , ( state ) => state . wasWelcomeNotificationShown ) ; export const selectToastMessage = createSelector ( mapStateSelector , ( state ) => state . toastMessage ) ; export const selectFooterCollapse = createSelector ( mapStateSelector , ( state ) => state ?. footerCollapse ) ; export const selectIsMinimalistViewMode = createSelector ( mapStateSelector , ( state ) => state && state . minimalistViewMode ) ; export const selectOverlaysWithMapIds = createSelector ( selectMapsList , selectActiveMapId , ( mapsList , activeMapId ) => { const overlayAndMapId = mapsList . map ( map => map . data . overlay ? ( { overlay : map . data . overlay , mapId : map . id , isActive : map . id === activeMapId } ) : ( { } ) ) ; return overlayAndMapId ; } ) ; export const selectOverlayOfActiveMap = createSelector ( selectMapsList , selectActiveMapId , ( mapsList , activeMapId ) => { const activeMapSettings = mapsList . filter ( ( map ) => map . id === activeMapId ) ; return Boolean ( activeMapSettings [ 0 ] ) && activeMapSettings [ 0 ] . data . overlay ; } ) ; export const selectMapStateById = ( id ) => createSelector ( selectMaps , ( maps ) => maps && maps [ id ] ) ; export const selectMapsStateByIds = ( mapIds ) => createSelector ( selectMaps , ( maps ) => mapIds . map ( id => maps [ id ] ) ) ; export const selectOverlayByMapId = ( mapId ) => createSelector ( selectMapStateById ( mapId ) , ( mapState ) => mapState && mapState . data && mapState . data . overlay ) ; export const selectHideLayersOnMap = ( mapId ) => createSelector ( selectMapStateById ( mapId ) , ( mapState ) => mapState && mapState . flags . hideLayers ) ; export const selectMapPositionByMapId = ( mapId ) => createSelector ( selectMapStateById ( mapId ) , ( mapState ) => mapState && mapState . data . position ) ; export const selectManualProcessArgsByMapId = ( mapId ) => createSelector ( selectMapStateById ( mapId ) , ( mapState ) => mapState && mapState . data . imageManualProcessArgs ) ; export const selectMapTypeById = ( mapId => createSelector ( selectMapStateById ( mapId ) , ( mapState ) => mapState && mapState . worldView . mapType ) ) ; export const selectSourceTypeById = ( mapId => createSelector ( selectMapStateById ( mapId ) , ( mapState ) => mapState && mapState . worldView . sourceType ) ) ; export const selectOverlaysFootprintActiveByMapId = ( mapId ) => createSelector ( selectMapStateById ( mapId ) , ( mapState ) => mapState && mapState . data && mapState . data . overlaysFootprintActive ) ; export const selectMapOrientation = ( mapId ) => createSelector ( selectMapStateById ( mapId ) , ( mapState ) => mapState && mapState . orientation ) ;