/* COPYRIGHT Esri - https://js.arcgis.com/5.0/LICENSE.txt */
import{LRUCache as e}from"../../../../core/LRUCache.js";import{fromValues as i,create as t,intersects as s}from"../../../../geometry/support/aaBoundingRect.js";import{tileSizeInPixels as l}from"./constants.js";import o from"../../tiling/TileCoverage.js";import r from"../../tiling/TileKey.js";const n=1e-6,a=(e,i)=>e+1/(1<<2*i);class c{constructor(i,t){this._tiles=new Map,this._tileCache=new e(40,e=>e.dispose()),this._viewSize=[0,0],this._visibleTiles=new Map,this.acquireTile=i.acquireTile,this.releaseTile=i.releaseTile,this.tileInfoView=i.tileInfoView,this._container=t}destroy(){for(const e of this._tiles.values())e.dispose();this._tiles=null,this._tileCache.clear(),this._tileCache=null}update(e){this._updateCacheSize(e);const i=this.tileInfoView,t=i.getTileCoverage(e.state,0,!0,"smallest");if(!t)return!0;const{spans:s,lodInfo:l}=t,{level:n}=l,a=this._tiles,c=new Set,h=new Set;for(const{row:o,colFrom:_,colTo:f}of s)for(let e=_;e<=f;e++){const i=r.getId(n,o,l.normalizeCol(e),l.getWorldForColumn(e)),t=this._getOrAcquireTile(i);c.add(i),t.processed()?this._addToContainer(t):h.add(new r(i))}for(const[o,r]of a)r.isCoverage=c.has(o);for(const o of h)this._findPlaceholdersForMissingTiles(o,c);let d=!1;for(const[o,r]of a)r.neededForCoverage=c.has(o),r.neededForCoverage||r.isHoldingForFade&&i.intersects(t,r.key)&&c.add(o),r.isFading&&(d=!0);for(const o of this._tiles.keys())c.has(o)||this._releaseTile(o);return o.pool.release(t),!d}clear(){this._tiles.clear(),this._tileCache.clear(),this._visibleTiles.clear()}clearCache(){this._tileCache.clear()}getIntersectingTiles(e,l,o,r,n){const a=[0,0],c=[0,0];r.toMap(a,e-o,l+o),r.toMap(c,e+o,l-o);const h=Math.min(a[0],c[0]),d=Math.min(a[1],c[1]),_=Math.max(a[0],c[0]),f=Math.max(a[1],c[1]),T=i(h,d,_,f),u=t(),p=[];for(const i of this._visibleTiles.values())this.tileInfoView.getTileBounds(u,i.key),s(T,u)&&p.push(i);if(null!=n&&n.length>0){const e=new Set(p.map(e=>e.id)),i=n.filter(i=>!e.has(i.tileKey.id)).map(e=>this._visibleTiles.get(e.tileKey.id)).filter(e=>void 0!==e);p.push(...i)}return p}_findPlaceholdersForMissingTiles(e,i){const t=[];for(const l of this._tiles.values())this._addPlaceholderChild(t,l,e,i);const s=t.reduce(a,0);Math.abs(1-s)<n||this._addPlaceholderParent(e.id,i)}_addPlaceholderChild(e,i,t,s){i.key.level<=t.level||!i.hasData()||d(t,i.key)&&(this._addToContainer(i),s.add(i.id),e.push(i.key.level-t.level))}_addPlaceholderParent(e,i){const t=this._tiles;let s=e;for(;;){if(s=h(s),!s||i.has(s))return;const e=t.get(s);if(e?.hasData())return this._addToContainer(e),void i.add(e.id)}}_getOrAcquireTile(e){let i=this._tiles.get(e);return i||(i=this._tileCache.pop(e),i||(i=this.acquireTile(new r(e))),this._tiles.set(e,i),i)}_releaseTile(e){const i=this._tiles.get(e);this.releaseTile(i),this._removeFromContainer(i),this._tiles.delete(e),i.hasData()?this._tileCache.put(e,i,1):i.dispose()}_addToContainer(e){let i;const t=[],s=this._container;if(s.contains(e))return;const l=this._visibleTiles;for(const o of l.values())this._canConnectDirectly(e,o)&&t.push(o),null==i&&this._canConnectDirectly(o,e)&&(i=o);if(null!=i){for(const s of t)i.childrenTiles.delete(s),e.childrenTiles.add(s),s.parentTile=e;i.childrenTiles.add(e),e.parentTile=i}else for(const o of t)e.childrenTiles.add(o),o.parentTile=e;l.set(e.id,e),s.addChild(e)}_removeFromContainer(e){if(this._visibleTiles.delete(e.id),this._container.removeChild(e),null!=e.parentTile){e.parentTile.childrenTiles.delete(e);for(const i of e.childrenTiles)null!=e.parentTile&&e.parentTile.childrenTiles.add(i)}for(const i of e.childrenTiles)i.parentTile=e.parentTile;e.parentTile=null,e.childrenTiles.clear()}_canConnectDirectly(e,i){const t=e.key;let{level:s,row:l,col:o,world:r}=i.key;const n=this._visibleTiles;for(;s>0;){if(s--,l>>=1,o>>=1,t.level===s&&t.row===l&&t.col===o&&t.world===r)return!0;if(n.has(`${s}/${l}/${o}/${r}`))return!1}return!1}_updateCacheSize(e){const i=e.state.size;if(i[0]===this._viewSize[0]&&i[1]===this._viewSize[1])return;const t=Math.ceil(i[0]/l)+1,s=Math.ceil(i[1]/l)+1;this._viewSize[0]=i[0],this._viewSize[1]=i[1],this._tileCache.maxSize=5*t*s}}function h(e){const[i,t,s,l]=e.split("/"),o=parseInt(i,10);return 0===o?null:`${o-1}/${parseInt(t,10)>>1}/${parseInt(s,10)>>1}/${parseInt(l,10)}`}function d(e,i){const t=i.level-e.level;return e.row===i.row>>t&&e.col===i.col>>t&&e.world===i.world}export{c as TileManager};
