import*as TextUtils from"../text_utils/text_utils.js";import{HeapSnapshotProgress,JSHeapSnapshot}from"./HeapSnapshot.js";export class HeapSnapshotLoader{constructor(s){this._reset(),this._progress=new HeapSnapshotProgress(s),this._buffer="",this._dataCallback=null,this._done=!1,this._parseInput()}dispose(){this._reset()}_reset(){this._json="",this._snapshot=void 0}close(){this._done=!0,this._dataCallback&&this._dataCallback("")}buildSnapshot(){this._snapshot=this._snapshot||{},this._progress.updateStatus("Processing snapshot\u2026");const s=new JSHeapSnapshot(this._snapshot,this._progress);return this._reset(),s}_parseUintArray(){let s=0;const t="0".charCodeAt(0),n="9".charCodeAt(0),i="]".charCodeAt(0),a=this._json.length;for(;;){for(;s<a;){const a=this._json.charCodeAt(s);if(t<=a&&a<=n)break;if(a===i)return this._json=this._json.slice(s+1),!1;++s}if(s===a)return this._json="",!0;let o=0;const e=s;for(;s<a;){const i=this._json.charCodeAt(s);if(t>i||i>n)break;o*=10,o+=i-t,++s}if(s===a)return this._json=this._json.slice(e),!0;if(!this._array)throw new Error("Array not instantiated");this._array[this._arrayIndex++]=o}}_parseStringsArray(){this._progress.updateStatus("Parsing strings\u2026");const s=this._json.lastIndexOf("]");if(-1===s)throw new Error("Incomplete JSON");if(this._json=this._json.slice(0,s+1),!this._snapshot)throw new Error("No snapshot in parseStringsArray");this._snapshot.strings=JSON.parse(this._json)}write(s){this._buffer+=s,this._dataCallback&&(this._dataCallback(this._buffer),this._dataCallback=null,this._buffer="")}_fetchChunk(){return this._done?Promise.resolve(this._buffer):new Promise((s=>{this._dataCallback=s}))}async _findToken(s,t){for(;;){const n=this._json.indexOf(s,t||0);if(-1!==n)return n;t=this._json.length-s.length+1,this._json+=await this._fetchChunk()}}async _parseArray(s,t,n){const i=await this._findToken(s),a=await this._findToken("[",i);for(this._json=this._json.slice(a+1),this._array=n?new Uint32Array(n):[],this._arrayIndex=0;this._parseUintArray();)this._progress.updateProgress(t,this._arrayIndex,this._array.length),this._json+=await this._fetchChunk();const o=this._array;return this._array=null,o}async _parseInput(){const s='"snapshot"',t=await this._findToken(s);if(-1===t)throw new Error("Snapshot token not found");this._progress.updateStatus("Loading snapshot info\u2026");const n=this._json.slice(t+s.length+1);for(this._jsonTokenizer=new TextUtils.TextUtils.BalancedJSONTokenizer((s=>{this._json=this._jsonTokenizer.remainder(),this._jsonTokenizer=null,this._snapshot=this._snapshot||{},this._snapshot.snapshot=JSON.parse(s)})),this._jsonTokenizer.write(n);this._jsonTokenizer;)this._jsonTokenizer.write(await this._fetchChunk());this._snapshot=this._snapshot||{};const i=await this._parseArray('"nodes"',"Loading nodes\u2026 {PH1}%",this._snapshot.snapshot.meta.node_fields.length*this._snapshot.snapshot.node_count);this._snapshot.nodes=i;const a=await this._parseArray('"edges"',"Loading edges\u2026 {PH1}%",this._snapshot.snapshot.meta.edge_fields.length*this._snapshot.snapshot.edge_count);if(this._snapshot.edges=a,this._snapshot.snapshot.trace_function_count){const s=await this._parseArray('"trace_function_infos"',"Loading allocation traces\u2026 {PH1}%",this._snapshot.snapshot.meta.trace_function_info_fields.length*this._snapshot.snapshot.trace_function_count);this._snapshot.trace_function_infos=s;const t=await this._findToken(":"),n=await this._findToken('"',t),i=this._json.indexOf("["),a=this._json.lastIndexOf("]",n);this._snapshot.trace_tree=JSON.parse(this._json.substring(i,a+1)),this._json=this._json.slice(a+1)}if(this._snapshot.snapshot.meta.sample_fields){const s=await this._parseArray('"samples"',"Loading samples\u2026");this._snapshot.samples=s}if(this._snapshot.snapshot.meta.location_fields){const s=await this._parseArray('"locations"',"Loading locations\u2026");this._snapshot.locations=s}else this._snapshot.locations=[];this._progress.updateStatus("Loading strings\u2026");const o=await this._findToken('"strings"'),e=await this._findToken("[",o);for(this._json=this._json.slice(e);!this._done;)this._json+=await this._fetchChunk();this._parseStringsArray()}}