import { TileKey } from "@here/harp-geoutils" ; import { LoggerManager } from "@here/harp-utils" ; import { DataSource } from "./DataSource" ; import { ITileLoader , TileLoaderState } from "./ITileLoader" ; const logger = LoggerManager . instance . create ( "BaseTileLoader" ) ; internal export abstract class BaseTileLoader implements ITileLoader { state : TileLoaderState = TileLoaderState . Initialized ; /**
     * Error object if loading or decoding failed.
     */ error ? : Error ; protected m_priority : number = 0 ; /**
     * The abort controller notifying the [[DataProvider]] to cancel loading.
     */ private loadAbortController = new AbortController ( ) ; /**
     * The promise which is resolved when loading and decoding have finished.
     */ private donePromise ? : Promise < TileLoaderState > ; /**
     * The internal function that is called when loading and decoding have finished successfully.
     */ private resolveDonePromise ? : ( state : TileLoaderState ) => void ; /**
     * The internal function that is called when loading and decoding failed.
     */ private rejectedDonePromise ? : ( state : TileLoaderState ) => void ; param dataSource param tileKey constructor ( protected dataSource , protected tileKey ) { } @override
      get priority ( ) : number { return this . m_priority ; } @override
      set priority ( value ) { this . m_priority = value ; } @override
      loadAndDecode ( ) { switch ( this . state ) { case TileLoaderState . Loading : case TileLoaderState . Loaded : case TileLoaderState . Decoding : return this . donePromise ! ; case TileLoaderState . Ready : case TileLoaderState . Failed : case TileLoaderState . Initialized : case TileLoaderState . Canceled : this . load ( ) ; return this . donePromise ! ; } } @override
      waitSettled ( ) { if ( ! this . donePromise ) { return Promise . resolve ( this . state ) ; } return this . donePromise ; } @override
      cancel ( ) { if ( this . state === TileLoaderState . Loading ) { this . loadAbortController . abort ( ) ; this . loadAbortController = new AbortController ( ) ; } this . cancelImpl ( ) ; this . onDone ( TileLoaderState . Canceled ) ; } @override
      get isFinished ( ) : boolean { return ( this . state === TileLoaderState . Ready || this . state === TileLoaderState . Canceled || this . state === TileLoaderState . Failed ) ; } /**
     * Called on load cancelation, may be overriden to extend behaviour.
     */ protected cancelImpl ( ) { } param abortSignal param onDone param onError protected abstract loadImpl ( abortSignal , onDone , onError ) ; /**
     * Start loading. Only call if loading did not start yet.
     */ private load ( ) { this . loadImpl ( this . loadAbortController . signal , this . onDone . bind ( this ) , this . onError . bind ( this ) ) ; if ( this . donePromise === undefined ) { this . donePromise = new Promise < TileLoaderState > ( ( resolve , reject ) => { this . resolveDonePromise = resolve ; this . rejectedDonePromise = reject ; } ) ; } this . state = TileLoaderState . Loading ; } param doneState private onDone ( doneState ) { if ( this . resolveDonePromise && doneState === TileLoaderState . Ready ) { this . resolveDonePromise ( doneState ) ; } else if ( this . rejectedDonePromise ) { this . rejectedDonePromise ( doneState ) ; } this . resolveDonePromise = undefined ; this . rejectedDonePromise = undefined ; this . donePromise = undefined ; this . state = doneState ; } param error private onError ( error ) { if ( this . state === TileLoaderState . Canceled ) { return ; } const dataSource = this . dataSource ; logger . error ( `[${ dataSource . name }]: failed to load tile ${ this . tileKey . mortonCode ( ) }` , error ) ; this . error = error ; this . onDone ( TileLoaderState . Failed ) ; } }