import { Injectable } from '@angular/core' ; import { Subject } from 'rxjs' ; import { Layer } from 'ol/layer' ; import { Source } from 'ol/source' ; import { HsLayerDescriptor } from '../../components/layermanager/layer-descriptor.interface' ; import { HsLogService } from '../log/log.service' ; import { HsUtilsService } from '../../components/utils/utils.service' ; import { WmsLayer } from './wms-get-capabilities-response.interface' ; import { getDimensions , setDimensions } from '../layer-extensions' ; @ Injectable ( { providedIn : 'root' , } ) export class HsDimensionTimeService { /**
     * To communicate changes between this service and HsDimensionService
     */ layerTimeChanges : Subject < { layer : HsLayerDescriptor ; time : string ; } > = new Subject ( ) ; constructor ( public hsLog , public HsUtilsService ) { } param interval returns parseInterval ( interval ) { let dateComponent ; let timeComponent ; let year ; let month ; let day ; let hour ; let minute ; let second ; year = month = day = hour = minute = second = 0 ; const indexOfT = interval . search ( 'T' ) ; if ( indexOfT > - 1 ) { dateComponent = interval . substring ( 1 , indexOfT ) ; timeComponent = interval . substring ( indexOfT + 1 ) ; } else { dateComponent = interval . substring ( 1 ) ; } if ( dateComponent ) { const indexOfY = dateComponent . search ( 'Y' ) > - 1 ? dateComponent . search ( 'Y' ) : undefined ; const indexOfM = dateComponent . search ( 'M' ) > - 1 ? dateComponent . search ( 'M' ) : undefined ; const indexOfD = dateComponent . search ( 'D' ) > - 1 ? dateComponent . search ( 'D' ) : undefined ; if ( indexOfY !== undefined ) { year = parseFloat ( dateComponent . substring ( 0 , indexOfY ) ) ; } if ( indexOfM !== undefined ) { month = parseFloat ( dateComponent . substring ( ( indexOfY || - 1 ) + 1 , indexOfM ) ) ; } if ( indexOfD !== undefined ) { day = parseFloat ( dateComponent . substring ( ( indexOfM || indexOfY || - 1 ) + 1 , indexOfD ) ) ; } } if ( timeComponent ) { const indexOfH = timeComponent . search ( 'H' ) > - 1 ? timeComponent . search ( 'H' ) : undefined ; const indexOfm = timeComponent . search ( 'M' ) > - 1 ? timeComponent . search ( 'M' ) : undefined ; const indexOfS = timeComponent . search ( 'S' ) > - 1 ? timeComponent . search ( 'S' ) : undefined ; if ( indexOfH !== undefined ) { hour = parseFloat ( timeComponent . substring ( 0 , indexOfH ) ) ; } if ( indexOfm !== undefined ) { minute = parseFloat ( timeComponent . substring ( ( indexOfH || - 1 ) + 1 , indexOfm ) ) ; } if ( indexOfS !== undefined ) { second = parseFloat ( timeComponent . substring ( ( indexOfm || indexOfH || - 1 ) + 1 , indexOfS ) ) ; } } const zero = new Date ( 0 , 0 , 0 , 0 , 0 , 0 , 0 ) . getTime ( ) ; const step = new Date ( year , month , day , hour , minute , second , 0 ) . getTime ( ) ; return step - zero ; } param layer returns layerIsWmsT ( layer ) { const olLayer = ( layer as any ) . layer ?? layer ; if ( ! olLayer ) { return false ; } if ( ( layer as HsLayerDescriptor ) . time ) { return true ; } if ( olLayer . get ( 'dimensions_time' ) && Array . isArray ( olLayer . get ( 'dimensions_time' ) . timeInterval ) ) { this . hsLog . warn ( '"dimensions_time" is deprecated, use "dimensions" param with "time" object instead' ) ; const currentDimensions = getDimensions ( olLayer ) ; const newTimeDimension = { label : 'time' , default : olLayer . get ( 'dimensions_time' ) . value , } ; if ( ! currentDimensions ) { setDimensions ( olLayer , { 'time' : newTimeDimension } ) ; } else { setDimensions ( olLayer , Object . assign ( currentDimensions , { 'time' : newTimeDimension } ) ) ; } } if ( getDimensions ( olLayer ) ?. time ) { return true ; } return false ; } parseDimensionParam ( layer ) { const dimensions = getDimensions ( layer ) ; if ( dimensions && dimensions [ 'time' ] ) { const timedata = { } ; let value = dimensions [ 'time' ] . values || dimensions [ 'time' ] . value ; if ( Array . isArray ( value ) ) { value = value [ 0 ] ; } if ( typeof value === 'string' || this . HsUtilsService . instOf ( value , String ) ) { value = value . replace ( /\s*/g , '' ) ; if ( value . search ( '/' ) > - 1 ) { const interval = value . split ( '/' ) . map ( ( d ) => { if ( d . search ( 'Z' ) > - 1 ) { d = d . replace ( 'Z' , '00:00' ) ; } return d ; } ) ; if ( interval . length == 3 ) { timedata . timeStep = this . parseInterval ( interval [ 2 ] ) ; interval . pop ( ) ; } if ( interval . length == 2 ) { timedata . timeInterval = interval ; } } } } } param currentLayer param serviceLayer setupTimeLayer ( currentLayer , serviceLayer ? ) { const olLayer = currentLayer . layer ; const hsLayerTimeConfig = getDimensions ( olLayer ) ?. time ; let serviceLayerTimeConfig ; if ( serviceLayer ) { if ( ! Array . isArray ( serviceLayer . Dimension ) ) { serviceLayerTimeConfig = serviceLayer . Dimension ; } else { serviceLayerTimeConfig = serviceLayer . Dimension ?. find ( ( dim ) => dim . name == 'time' ) ; } } else if ( hsLayerTimeConfig ) { serviceLayerTimeConfig = hsLayerTimeConfig ; } const timePoints = Array . isArray ( serviceLayerTimeConfig . values ) ? serviceLayerTimeConfig . values : this . parseTimePoints ( serviceLayerTimeConfig . values ) ; let today = new Date ( ) . toISOString ( ) ; today = today . slice ( 0 , today . indexOf ( 'T' ) ) ; let defaultTime ; if ( timePoints . includes ( hsLayerTimeConfig ?. default ) ) { defaultTime = hsLayerTimeConfig . default ; } else if ( timePoints . includes ( serviceLayerTimeConfig ?. default ) ) { defaultTime = serviceLayerTimeConfig . default ; } else if ( timePoints . some ( ( point ) => point . startsWith ( today ) ) ) { defaultTime = timePoints . find ( ( point ) => point . startsWith ( today ) ) ; } else { defaultTime = timePoints [ 0 ] ; } currentLayer . time = { default : defaultTime , timePoints , } ; this . polyfillLayerDimensionsValues ( currentLayer ) ; this . setLayerTime ( currentLayer , defaultTime ) ; } param currentLayer param newTime setLayerTime ( currentLayer , newTime ) { if ( currentLayer === undefined || currentLayer . layer === undefined ) { return ; } this . layerTimeChanges . next ( { layer : currentLayer , time : newTime , } ) ; } param values returns parseTimePoints ( values ) { values = values . trim ( ) ; if ( values . includes ( '/' ) ) { const timeValues = values . split ( '/' ) ; if ( timeValues . length == 3 && timeValues [ 2 ] . trim ( ) . startsWith ( 'P' ) ) { return this . timePointsFromInterval ( timeValues [ 0 ] , timeValues [ 1 ] , this . parseInterval ( timeValues [ 2 ] ) ) ; } else if ( timeValues . length == 2 ) { return this . timePointsFromInterval ( timeValues [ 0 ] , timeValues [ 1 ] , 24 * 60 * 60 * 1000 ) ; } else { throw new Error ( `Invalid ISO8601 time definition provided: ${ values }` ) ; } } return values . split ( ',' ) ; } /**
     * Because of the way the HsDimension interface is set up,
     * we need to fill all parsed and currently undefined values
     * into the "dimensions" property of OL Layer as well.
     * Nevertheless we are duplicating some information.
     */ private polyfillLayerDimensionsValues ( layerDescriptor ) { const dimensionTimeProp = getDimensions ( layerDescriptor . layer ) . time ; dimensionTimeProp . label = dimensionTimeProp . label ?? 'time' ; dimensionTimeProp . default = dimensionTimeProp . default ?? layerDescriptor . time . default ; dimensionTimeProp . value = dimensionTimeProp . value ?? layerDescriptor . time . default ; dimensionTimeProp . values = dimensionTimeProp . values ?? layerDescriptor . time . timePoints ; } private timePointsFromInterval ( start , end , step ) { const timePoints = [ ] ; const endMillis = new Date ( end ) . getTime ( ) ; let tempMillis = new Date ( start ) . getTime ( ) ; while ( tempMillis <= endMillis ) { timePoints . push ( new Date ( tempMillis ) . toISOString ( ) ) ; tempMillis += step ; } return timePoints ; } }