import { AssetType } from "./AssetTypes" ; import { EventDispatcher } from "./EventDispatcher" ; import { Handle } from "./Handle" ; interface AssetSearchOptions { preload ? : boolean ; } interface Asset { name : string ; value : Promise < AssetType > ; } type AssetMap = Map < string , Promise < AssetType > > ; type SearchAssetMap = Map < BundleHandle , AssetMap > ; export class BundleHandle extends Handle { private _assets : AssetMap = new Map ( ) ; private _dependencies : BundleHandle [ ] = [ ] ; private _registered = this . queue ; private _preload : boolean = false ; private _onLoadProgress = new EventDispatcher < ( amount : number , total : number , name : string ) => Promise < void > > ( ) ; public get onLoadProgress ( ) { return this . _onLoadProgress ; } public get preload ( ) { return this . _preload ; } public set preload ( val ) { this . _preload = val ; } param bundles public registerAsset ( pName , pAsset ) { this . _assets . set ( pName , pAsset ) ; } param bundles public unregisterAsset ( pName ) { this . _assets . delete ( pName ) ; } param bundle public registerDependency ( bundle ) { this . _dependencies . push ( bundle ) ; bundle . use ( ) ; return bundle . _registered ; } param bundles public registerDependencies ( bundles ) { const p = bundles . map ( bundle => this . registerDependency ( bundle ) ) ; return Promise . all ( p ) ; } param bundles public static countAssets ( bundles , options = { preload : false } ) { const countMap = new Map < BundleHandle , number > ( ) ; bundles . forEach ( bundle => this . recursiveCountAssets ( countMap , bundle ) ) ; let total = 0 ; countMap . forEach ( ( amount , bundle ) => { if ( options . preload && ! bundle . preload ) { return ; } total += amount ; } ) ; return total ; } /**
     * Count total number of assets across this bundle and all dependencies
     */ public countAssets ( options ? ) { return BundleHandle . countAssets ( [ this ] , options ) ; } param bundles public static listAssets ( bundles , options = { preload : false } ) { const map = new Map ( ) ; bundles . forEach ( bundle => this . recursiveListAssets ( map , bundle ) ) ; const arr = [ ] ; map . forEach ( ( assetMap , bundle ) => { if ( options . preload && ! bundle . preload ) { return ; } assetMap . forEach ( ( value , name ) => { arr . push ( { name , value } ) ; } ) ; } ) ; return arr ; } /**
     * List of all assets across this bundle and all dependencies
     */ public listAssets ( options ? ) { return BundleHandle . listAssets ( [ this ] , options ) ; } protected load ( ) { this . _registered = super . load ( ) ; return this . _registered . then ( ( ) => { return new Promise ( r => setTimeout ( r , 0 ) ) ; } ) . then ( ( ) => { return this . awaitAllAssets ( ) ; } ) ; } protected unload ( ) { return super . unload ( ) . then ( ( ) => { const deps = this . _dependencies . map ( dep => dep . unuse ( ) ) ; return Promise . all ( deps ) . then ( ( ) => Promise . resolve ( ) ) ; } ) . then ( ( ) => { this . _dependencies = [ ] ; this . _assets . clear ( ) ; return Promise . resolve ( ) ; } ) ; } private awaitAllAssets ( ) { const allAssets = this . listAssets ( { preload : true } ) ; const total = allAssets . length ; let count = 0 ; const pAssets = allAssets . map ( asset => { return asset . value . then ( ( ) => { ++ count ; const progress = this . _onLoadProgress . listeners . map ( fn => fn ( count , total , name ) ) ; return Promise . all ( progress ) ; } ) ; } ) ; return Promise . all ( pAssets ) . then ( ( ) => Promise . resolve ( ) ) ; } private static recursiveCountAssets ( map , pBundle ) { if ( ! map . has ( pBundle ) ) { map . set ( pBundle , pBundle . _assets . size ) ; } pBundle . _dependencies . forEach ( bundle => { this . recursiveCountAssets ( map , bundle ) ; } ) ; } private static recursiveListAssets ( map , pBundle ) { if ( ! map . has ( pBundle ) ) { map . set ( pBundle , pBundle . _assets ) ; } pBundle . _dependencies . forEach ( bundle => { this . recursiveListAssets ( map , bundle ) ; } ) ; } }