import{isEmpty,waitFor}from"../base/helpers.mjs";class HistoryDatabase{static databaseName="enfugue";static databaseVersion=1;constructor(t,e){this.size=t,this.request=window.indexedDB.open(this.constructor.databaseName,this.constructor.databaseVersion),this.request.onerror=t=>this.setError(t),this.request.onsuccess=t=>this.setSuccess(t),this.request.onupgradeneeded=t=>{this.setSuccess(t),this.migrate()},this.debug=!0===e}setError(t){this.error=t.target.errorCode}setSuccess(t){this.database=t.target.result}migrate(){this.database.createObjectStore("history",{keyPath:"id"})}trimDatabase(){return new Promise(((t,e)=>{this.getIDs().then((s=>{let r=s.slice(this.size+1);r.length>0?(this.debug&&console.log("Removing history ID(s)",r),Promise.all(r.map((t=>this.deleteByID(t)))).then(t).catch(e)):this.debug&&(console.log(`Database does not need truncation (${s.length} < ${this.size+1})`),t())})).catch(e)}))}searchHistoryItems(t){return new Promise(((e,s)=>{this.getHistoryItems().then((s=>{e(s.filter((e=>this.searchState(e.state,t))))}))}))}searchState(t,e){if(null==t)return!1;if(Array.isArray(t)){for(let s of t)if(this.searchState(s,e))return!0}else if("object"==typeof t){for(let s of Object.getOwnPropertyNames(t))if(this.searchState(t[s],e))return!0}else if("function"!=typeof t)return-1!==`${t}`.toLowerCase().indexOf(e.toLowerCase());return!1}getLastHistoryItems(t=10){return new Promise(((e,s)=>{this.getLastIDs(t+1).then((t=>{Promise.all(t.slice(1).map((t=>this.getByID(t)))).then(e).catch(s)})).catch(s)}))}getHistoryItems(){return this.getLastHistoryItems(1/0)}getLastIDs(t=10){return new Promise(((e,s)=>{this.getDatabase().then((r=>{const o=r.transaction("history","readonly"),a=o.objectStore("history").openKeyCursor(null,"prev");let i=[],n=0;a.onsuccess=s=>{const r=s.target.result;if(r)return i.push(r.key),++n>=t?(e(i),void o.abort()):void r.continue();e(i)},a.onerror=t=>{s(`Cursor request failed: ${t.errorCode}`)}})).catch(s)}))}getIDs(){return this.getLastIDs(1/0)}async getLastID(){let t=await this.getLastIDs(1);return 0===t.length?null:t[0]}getByID(t){return new Promise(((e,s)=>{this.getDatabase().then((r=>{const o=r.transaction(["history"],"readonly").objectStore("history").get(t);o.onsuccess=t=>e(t.target.result),o.onerror=e=>{s(`Retrieving ${t} failed: ${e.errorCode}`)}})).catch(s)}))}deleteByID(t){return new Promise(((e,s)=>{this.getDatabase().then((r=>{const o=r.transaction(["history"],"readwrite").objectStore("history").delete(t);o.onsuccess=s=>{this.debug&&console.log("Successfully deleted history at ID",t),e()},o.onerror=e=>{s(`Couldn't delete ${t}: ${e.errorCode}`)}})).catch(s)}))}flush(t){return new Promise(((e,s)=>{this.getLastID().then((r=>{isEmpty(r)?s("No current history stored, call setCurrentState at least once before flushing."):this.getDatabase().then((o=>{const a=o.transaction(["history"],"readwrite").objectStore("history").add({state:t,timestamp:(new Date).getTime(),id:r+1});a.onsuccess=t=>{this.debug&&console.log("Successfully inserted new history state."),e(r+1),this.trimDatabase()},a.onerror=t=>{s(`Inserting new history failed: ${t.errorCode}`)}})).catch(s)}))}))}setCurrentState(t){return new Promise(((e,s)=>{this.getLastID().then((r=>{this.getDatabase().then((o=>{const a=o.transaction(["history"],"readwrite").objectStore("history");if(null===r){const r=a.add({state:t,id:1,timestamp:(new Date).getTime()});r.onsuccess=t=>{this.debug&&console.log("Successfully inserted first history state."),e(1)},r.onerror=t=>{s(`Inserting first history failed: ${t.errorCode}`)}}else this.getByID(r).then((a=>{a.state=t,a.timestamp=(new Date).getTime();const i=o.transaction(["history"],"readwrite").objectStore("history").put(a);i.onsuccess=t=>{this.debug&&console.log(`Successfully updated current state by ID ${r}`),e(r)},i.onerror=t=>{s(`Updating ${r} failed: ${t.errorCode}`)}})).catch(s)})).catch(s)})).catch(s)}))}getCurrentState(){return new Promise(((t,e)=>{this.getLastID().then((s=>{if(null===s)return this.debug&&console.log("No history currently saved, returning null."),void t(null);this.getDatabase().then((r=>{const o=r.transaction(["history"],"readonly").objectStore("history").get(s);o.onsuccess=e=>{this.debug&&console.log(`Successfully retrieved current state by ID ${s}.`),t(o.result.state)},o.onerror=t=>{e(`Couldn't get history ${s}: ${t.errorCode}`)}})).catch(e)})).catch(e)}))}async getDatabase(){if(await waitFor((()=>!isEmpty(this.error)||!isEmpty(this.database))),!isEmpty(this.error))throw`Error: ${this.error}`;return this.database}}export{HistoryDatabase};
