import{M as Ke}from"./bootstrap-D1-uvFxm.js";import{_ as We,e as Q,d as O,W as Ae,V as F,X as q,M as ut,Y as dt,Z as N,$ as pt,c as H,F as _,S as A,o as ft,O as ht,U as K,a0 as re,a1 as me,a2 as z,k as gt,T as j,a3 as V,a4 as Me,f as be,n as Ie,a5 as ce,K as G,j as yt,L as mt,u as de,a6 as bt}from"./openlayers-D2I-bVN2.js";import{o as wt,a as Et,b as vt,c as Tt,d as xt,e as we,f as Lt,g as J,h as St,i as pe}from"./ol-ext-DytxBANR.js";(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const s of o)if(s.type==="childList")for(const n of s.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&r(n)}).observe(document,{childList:!0,subtree:!0});function t(o){const s={};return o.integrity&&(s.integrity=o.integrity),o.referrerPolicy&&(s.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?s.credentials="include":o.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(o){if(o.ep)return;o.ep=!0;const s=t(o);fetch(o.href,s)}})();const Oe="function",W="64e10b34-2bf7-4616-9668-f99de5aa046e",kt="get",Pt="has",Ct="set",{isArray:te}=Array;let{SharedArrayBuffer:ae,window:_t}=globalThis,{notify:He,wait:Ve,waitAsync:ne}=Atomics,Je=null;ne||(ne=a=>({value:new Promise(e=>{let t=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");t.onmessage=e,t.postMessage(a)})}));try{new ae(4)}catch{ae=ArrayBuffer;const e=new WeakMap;if(_t){const t=new Map,{prototype:{postMessage:r}}=Worker,o=s=>{const n=s.data?.[W];if(!te(n)){s.stopImmediatePropagation();const{id:i,sb:l}=n;t.get(i)(l)}};Je=function(s,...n){const i=s?.[W];if(te(i)){const[l,c]=i;e.set(c,l),this.addEventListener("message",o)}return r.call(this,s,...n)},ne=s=>({value:new Promise(n=>{t.set(e.get(s),n)}).then(n=>{t.delete(e.get(s)),e.delete(s);for(let i=0;i({[W]:{id:r,sb:o}});He=r=>{postMessage(t(e.get(r),r))},addEventListener("message",r=>{const o=r.data?.[W];if(te(o)){const[s,n]=o;e.set(n,s)}})}}/*! (c) Andrea Giammarchi - ISC */const{Int32Array:Ee,Map:De,Uint16Array:ve}=globalThis,{BYTES_PER_ELEMENT:Fe}=Ee,{BYTES_PER_ELEMENT:At}=ve,Mt=(a,e,t)=>{for(;Ve(a,0,0,e)==="timed-out";)t()},Te=new WeakSet,fe=new WeakMap,It={value:{then:a=>a()}};let Ot=0;const Se=(a,{parse:e=JSON.parse,stringify:t=JSON.stringify,transform:r,interrupt:o}=JSON)=>{if(!fe.has(a)){const s=Je||a.postMessage,n=(d,...f)=>s.call(a,{[W]:f},{transfer:d}),i=typeof o===Oe?o:o?.handler,l=o?.delay||42,c=new TextDecoder("utf-16"),u=(d,f)=>d?ne(f,0):(i?Mt(f,l,i):Ve(f,0),It);let p=!1;fe.set(a,new Proxy(new De,{[Pt]:(d,f)=>typeof f=="string"&&!f.startsWith("_"),[kt]:(d,f)=>f==="then"?null:((...y)=>{const b=Ot++;let x=new Ee(new ae(Fe*2)),E=[];Te.has(y.at(-1)||E)&&Te.delete(E=y.pop()),n(E,b,x,f,r?y.map(r):y);const w=a!==globalThis;let L=0;return p&&w&&(L=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${f}(...args) is awaited`)),u(w,x).value.then(()=>{clearTimeout(L);const v=x[1];if(!v)return;const S=At*v;return x=new Ee(new ae(S+S%Fe)),n([],b,x),u(w,x).value.then(()=>e(c.decode(new ve(x.buffer).slice(0,v))))})}),[Ct](d,f,y){const b=typeof y;if(b!==Oe)throw new Error(`Unable to assign ${f} as ${b}`);if(!d.size){const x=new De;a.addEventListener("message",async E=>{const w=E.data?.[W];if(te(w)){E.stopImmediatePropagation();const[L,v,...S]=w;let m;if(S.length){const[T,P]=S;if(d.has(T)){p=!0;try{const k=await d.get(T)(...P);if(k!==void 0){const _e=t(r?r(k):k);x.set(L,_e),v[1]=_e.length}}catch(k){m=k}finally{p=!1}}else m=new Error(`Unsupported action: ${T}`);v[0]=1}else{const T=x.get(L);x.delete(L);for(let P=new ve(v.buffer),k=0;k(Te.add(a),a);function Re(){let a,e;return{lock:async()=>{for(;a;)await a;a=new Promise(o=>{e=o})},unlock:async()=>{const o=e;a=void 0,e=void 0,o?.()}}}async function Qe(a,e){let t;if(a instanceof Blob?t=a.stream():t=a,t instanceof ReadableStream&&e){const o=t.getReader();switch(e){case"callback":return async()=>(await o.read()).value;case"buffer":const s=[];let n=!1;for(;!n;){const u=await o.read();u.value&&s.push(u.value),n=u.done}const i=s.reduce((u,p)=>u+p.length,0),l=new Uint8Array(i);let c=0;return s.forEach(u=>{l.set(u,c),c+=u.length}),l.buffer}}else return t}class se{constructor(e){Object.defineProperty(this,"sqlite3InitModule",{enumerable:!0,configurable:!0,writable:!0,value:e}),Object.defineProperty(this,"sqlite3",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"db",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"pointers",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"writeCallbacks",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),Object.defineProperty(this,"storageType",{enumerable:!0,configurable:!0,writable:!0,value:"memory"})}async init(e){const{databasePath:t}=e,r=this.getFlags(e);if(!this.sqlite3InitModule){const{default:o}=await We(async()=>{const{default:s}=await import("./index-DTMgZTfd.js");return{default:s}},[]);this.sqlite3InitModule=o}this.sqlite3||(this.sqlite3=await this.sqlite3InitModule()),this.db&&await this.destroy(),this.db=new this.sqlite3.oo1.DB(t,r),this.config=e,this.initWriteHook()}onWrite(e){return this.writeCallbacks.add(e),()=>{this.writeCallbacks.delete(e)}}async exec(e){if(!this.db)throw new Error("Driver not initialized");return this.execOnDb(this.db,e)}async execBatch(e){if(!this.db)throw new Error("Driver not initialized");const t=[];return this.db.transaction(r=>{const o=new Map;try{for(let s of e){let n=o.get(s.sql);if(!n){const c=r.prepare(s.sql);o.set(s.sql,c),n=c}s.params?.length&&n.bind(s.params);let i=[],l=[];for(;n.step();)i=n.getColumnNames([]),l.push(n.get([]));t.push({columns:i,rows:l}),n.reset()}}finally{o.forEach(s=>{s.finalize()})}}),t}async isDatabasePersisted(){return!1}async getDatabaseSizeBytes(){const t=(await this.exec({sql:`SELECT page_count * page_size AS size FROM pragma_page_count(), pragma_page_size()`,method:"get"}))?.rows?.[0];if(typeof t!="number")throw new Error("Failed to query database size");return t}async createFunction(e){if(!this.db)throw new Error("Driver not initialized");switch(e.type){case"callback":case"scalar":this.db.createFunction({name:e.name,xFunc:(t,...r)=>e.func(...r),arity:-1});break;case"aggregate":this.db.createFunction({name:e.name,xStep:(t,...r)=>e.func.step(...r),xFinal:(t,...r)=>e.func.final(...r),arity:-1});break}}async import(e){if(!this.sqlite3||!this.db||!this.config)throw new Error("Driver not initialized");const t=await Qe(e,"buffer"),r=this.sqlite3.wasm.allocFromTypedArray(t);this.pointers.push(r);const o=this.sqlite3.capi.sqlite3_deserialize(this.db,"main",r,t.byteLength,t.byteLength,this.config.readOnly?this.sqlite3.capi.SQLITE_DESERIALIZE_READONLY:this.sqlite3.capi.SQLITE_DESERIALIZE_RESIZEABLE);this.db.checkRc(o)}async export(){if(!this.sqlite3||!this.db)throw new Error("Driver not initialized");return{name:"database.sqlite3",data:this.sqlite3.capi.sqlite3_js_db_export(this.db)}}async clear(){}async destroy(){this.closeDb(),this.pointers.forEach(e=>this.sqlite3?.wasm.dealloc(e)),this.pointers=[],this.writeCallbacks.clear()}getFlags(e){const{readOnly:t,verbose:r}=e;return[t===!0?"r":"cw",r===!0?"t":""].join("")}execOnDb(e,t){const r={rows:[],columns:[]},o=e.exec({sql:t.sql,bind:t.params,returnValue:"resultRows",rowMode:"array",columnNames:r.columns});switch(t.method){case"run":break;case"get":r.rows=o[0]??[];break;case"all":default:r.rows=o;break}return r}initWriteHook(){if(!this.config?.reactive)return;if(!this.sqlite3||!this.db)throw new Error("Driver not initialized");const e={[this.sqlite3.capi.SQLITE_INSERT]:"insert",[this.sqlite3.capi.SQLITE_UPDATE]:"update",[this.sqlite3.capi.SQLITE_DELETE]:"delete"};this.sqlite3.capi.sqlite3_update_hook(this.db,(t,r,o,s,n)=>{this.writeCallbacks.forEach(i=>{i({table:s,rowid:n,operation:e[r]})})},0)}closeDb(){this.db&&(this.db.close(),this.db=void 0)}}function Dt(a,e,t){let r,o,s,n,i,l,c=0,u=!1,p=!1,d=!0;if(typeof a!="function")throw new TypeError("Expected a function");e=Number(e)||0,typeof t=="object"&&t!==null&&(u=!!t.leading,p="maxWait"in t,s=p?Math.max(Number(t.maxWait)||0,e):0,d="trailing"in t?!!t.trailing:d);function f(m){const T=r,P=o;return r=o=void 0,c=m,n=a.apply(P,T),n}function y(m){return c=m,i=setTimeout(E,e),u?f(m):n}function b(m){const T=m-(l??0),P=m-c,k=e-T;return p?Math.min(k,s-P):k}function x(m){const T=m-(l??0),P=m-c;return l===void 0||T>=e||T<0||p&&P>=s}function E(){const m=Date.now();if(x(m))return w(m);i=setTimeout(E,b(m))}function w(m){return i=void 0,d&&r?f(m):(r=o=void 0,n)}function L(){i!==void 0&&clearTimeout(i),c=0,r=l=o=i=void 0}function v(){return i===void 0?n:w(Date.now())}function S(){const m=Date.now(),T=x(m);if(r=arguments,o=this,l=m,T){if(i===void 0)return y(l);if(p)return i=setTimeout(E,e),f(l)}return i===void 0&&(i=setTimeout(E,e)),n}return S.cancel=L,S.flush=v,S}function oe(){return crypto.randomUUID()}function Ye(a,e){switch(a){case"session":case":sessionStorage:":let t=sessionStorage._sqlocal_session_key;return t||(t=oe(),sessionStorage._sqlocal_session_key=t),`session:${t}`;case"local":case":localStorage:":return"local";case":memory:":return`memory:${e}`;default:return`path:${a}`}}class Z{constructor(e){Object.defineProperty(this,"driver",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:{}}),Object.defineProperty(this,"userFunctions",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"initMutex",{enumerable:!0,configurable:!0,writable:!0,value:Re()}),Object.defineProperty(this,"transactionMutex",{enumerable:!0,configurable:!0,writable:!0,value:Re()}),Object.defineProperty(this,"transactionKey",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"proxy",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"dirtyTables",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),Object.defineProperty(this,"effectsChannel",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"reinitChannel",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onmessage",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"init",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{if(!(!this.config.databasePath||!this.config.clientKey)){await this.initMutex.lock();try{try{await this.driver.init(this.config)}catch{console.warn(`Persistence failed, so ${this.config.databasePath} will not be saved. For origin private file system persistence, make sure your web server is configured to use the correct HTTP response headers (See https://sqlocal.dev/guide/setup#cross-origin-isolation).`),this.config.databasePath=":memory:",this.driver=new se,await this.driver.init(this.config)}const s=Ye(this.config.databasePath,this.config.clientKey);this.reinitChannel=new BroadcastChannel(`_sqlocal_reinit_(${s})`),this.reinitChannel.onmessage=n=>{const i=n.data;if(this.config.clientKey!==i.clientKey)switch(i.type){case"reinit":this.init(i.reason);break;case"close":this.driver.destroy();break}},this.config.reactive&&(this.effectsChannel=new BroadcastChannel(`_sqlocal_effects_(${s})`),this.driver.onWrite(async n=>{this.dirtyTables.add(n.table),await this.transactionMutex.lock(),this.emitEffectsDebounced(),await this.transactionMutex.unlock()})),await Promise.all(Array.from(this.userFunctions.values()).map(n=>this.initUserFunction(n))),await this.execInitStatements(),this.emitMessage({type:"event",event:"connect",reason:o})}catch(s){this.emitMessage({type:"error",error:s,queryKey:null}),await this.destroy()}finally{await this.initMutex.unlock()}}}}),Object.defineProperty(this,"postMessage",{enumerable:!0,configurable:!0,writable:!0,value:async(o,s)=>{const n=o instanceof MessageEvent?o.data:o;switch(await this.initMutex.lock(),n.type){case"config":this.editConfig(n);break;case"query":case"batch":case"transaction":this.exec(n);break;case"function":this.createUserFunction(n);break;case"getinfo":this.getDatabaseInfo(n);break;case"import":this.importDb(n);break;case"export":this.exportDb(n);break;case"delete":this.deleteDb(n);break;case"destroy":this.destroy(n);break}await this.initMutex.unlock()}}),Object.defineProperty(this,"emitMessage",{enumerable:!0,configurable:!0,writable:!0,value:(o,s=[])=>{this.onmessage&&this.onmessage(o,s)}}),Object.defineProperty(this,"emitEffects",{enumerable:!0,configurable:!0,writable:!0,value:()=>{!this.effectsChannel||this.dirtyTables.size===0||(this.effectsChannel.postMessage({type:"effects",tables:[...this.dirtyTables]}),this.dirtyTables.clear())}}),Object.defineProperty(this,"emitEffectsDebounced",{enumerable:!0,configurable:!0,writable:!0,value:Dt(()=>this.emitEffects(),32,{maxWait:180})}),Object.defineProperty(this,"editConfig",{enumerable:!0,configurable:!0,writable:!0,value:o=>{this.config=o.config,this.init("initial")}}),Object.defineProperty(this,"exec",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{try{const s={type:"data",queryKey:o.queryKey,data:[]};switch(o.type){case"query":const n=this.transactionKey!==null&&this.transactionKey===o.transactionKey;try{n||await this.transactionMutex.lock();const i=await this.driver.exec(o);s.data.push(i)}finally{n||await this.transactionMutex.unlock()}break;case"batch":try{await this.transactionMutex.lock();const i=await this.driver.execBatch(o.statements);s.data.push(...i)}finally{await this.transactionMutex.unlock()}break;case"transaction":if(o.action==="begin"&&(await this.transactionMutex.lock(),this.transactionKey=o.transactionKey,await this.driver.exec({sql:"BEGIN"})),(o.action==="commit"||o.action==="rollback")&&this.transactionKey!==null&&this.transactionKey===o.transactionKey){const i=o.action==="commit"?"COMMIT":"ROLLBACK";await this.driver.exec({sql:i}),this.transactionKey=null,await this.transactionMutex.unlock()}break}this.emitMessage(s)}catch(s){this.emitMessage({type:"error",error:s,queryKey:o.queryKey})}}}),Object.defineProperty(this,"execInitStatements",{enumerable:!0,configurable:!0,writable:!0,value:async()=>{if(this.config.onInitStatements)for(let o of this.config.onInitStatements)await this.driver.exec(o)}}),Object.defineProperty(this,"getDatabaseInfo",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{try{this.emitMessage({type:"info",queryKey:o.queryKey,info:{databasePath:this.config.databasePath,storageType:this.driver.storageType,databaseSizeBytes:await this.driver.getDatabaseSizeBytes(),persisted:await this.driver.isDatabasePersisted()}})}catch(s){this.emitMessage({type:"error",queryKey:o.queryKey,error:s})}}}),Object.defineProperty(this,"createUserFunction",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{const{functionName:s,functionType:n,queryKey:i}=o;let l;if(this.userFunctions.has(s)){this.emitMessage({type:"error",error:new Error(`A user-defined function with the name "${s}" has already been created for this SQLocal instance.`),queryKey:i});return}switch(n){case"callback":l={type:n,name:s,func:(...c)=>{this.emitMessage({type:"callback",name:s,args:c})}};break;case"scalar":l={type:n,name:s,func:this.proxy[`_sqlocal_func_${s}`]};break;case"aggregate":l={type:n,name:s,func:{step:this.proxy[`_sqlocal_func_${s}_step`],final:this.proxy[`_sqlocal_func_${s}_final`]}};break}try{await this.initUserFunction(l),this.emitMessage({type:"success",queryKey:i})}catch(c){this.emitMessage({type:"error",error:c,queryKey:i})}}}),Object.defineProperty(this,"initUserFunction",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{await this.driver.createFunction(o),this.userFunctions.set(o.name,o)}}),Object.defineProperty(this,"importDb",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{const{queryKey:s,database:n}=o;let i=!1;try{await this.driver.import(n),this.driver.storageType==="memory"&&await this.execInitStatements()}catch(l){this.emitMessage({type:"error",error:l,queryKey:s}),i=!0}finally{this.driver.storageType!=="memory"&&await this.init("overwrite")}i||this.emitMessage({type:"success",queryKey:s})}}),Object.defineProperty(this,"exportDb",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{const{queryKey:s}=o;try{const{name:n,data:i}=await this.driver.export();this.emitMessage({type:"buffer",queryKey:s,bufferName:n,buffer:i},[i])}catch(n){this.emitMessage({type:"error",error:n,queryKey:s})}}}),Object.defineProperty(this,"deleteDb",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{const{queryKey:s}=o;let n=!1;try{await this.driver.clear()}catch(i){this.emitMessage({type:"error",error:i,queryKey:s}),n=!0}finally{await this.init("delete")}n||this.emitMessage({type:"success",queryKey:s})}}),Object.defineProperty(this,"destroy",{enumerable:!0,configurable:!0,writable:!0,value:async o=>{await this.driver.exec({sql:"PRAGMA optimize"}),await this.driver.destroy(),this.effectsChannel&&(this.emitEffectsDebounced.flush(),this.effectsChannel.close(),this.effectsChannel=void 0),this.reinitChannel&&(this.reinitChannel.close(),this.reinitChannel=void 0),o&&this.emitMessage({type:"success",queryKey:o.queryKey})}});const r=typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope?Se(globalThis):globalThis;this.proxy=r,this.driver=e}}function ie(a,...e){return{sql:a.join("?"),params:e}}function Ft(a){return!a.some(e=>!Array.isArray(e))}function he(a,e){let t;return Ft(a)?t=a:t=[a],t.map(r=>{const o={};return e.forEach((s,n)=>{o[s]=r[n]}),o})}function Rt(a){return typeof a=="object"&&a!==null&&"getSQL"in a&&typeof a.getSQL=="function"}function Nt(a){return typeof a=="object"&&a!==null&&"sql"in a&&typeof a.sql=="string"&&"params"in a}function Ne(a){if(typeof a=="function"&&(a=a(ie)),Rt(a))try{if(!("toSQL"in a&&typeof a.toSQL=="function"))throw 1;const r=a.toSQL();if(!Nt(r))throw 2;const o="all"in a&&typeof a.all=="function"?a.all:void 0;return{...r,exec:o?()=>o():void 0}}catch{throw new Error("The passed statement could not be parsed.")}const e=a.sql;let t=[];return"params"in a?t=a.params:"parameters"in a&&(t=a.parameters),{sql:e,params:t}}function je(a,e){let t;return typeof a=="string"?t={sql:a,params:e}:t=ie(a,...e),t}async function ee(a,e,t,r){return!e&&"locks"in navigator?navigator.locks.request(`_sqlocal_mutation_(${t.databasePath})`,{mode:a},r):r()}class Be extends se{constructor(e,t){super(t),Object.defineProperty(this,"storageType",{enumerable:!0,configurable:!0,writable:!0,value:e})}async init(e){const t=this.getFlags(e);if(e.readOnly)throw new Error(`SQLite storage type "${this.storageType}" does not support read-only mode.`);if(!this.sqlite3InitModule){const{default:r}=await We(async()=>{const{default:o}=await import("./index-DTMgZTfd.js");return{default:o}},[]);this.sqlite3InitModule=r}this.sqlite3||(this.sqlite3=await this.sqlite3InitModule()),this.db&&await this.destroy(),this.db=new this.sqlite3.oo1.JsStorageDb({filename:this.storageType,flags:t}),this.config=e,this.initWriteHook()}async isDatabasePersisted(){return navigator.storage?.persisted()}async getDatabaseSizeBytes(){if(!this.db)throw new Error("Driver not initialized");return this.db.storageSize()}async import(e){const t=new se;await t.init({}),await t.import(e),await this.clear(),await t.exec({sql:`VACUUM INTO 'file:${this.storageType}?vfs=kvvfs'`}),await t.destroy()}async clear(){if(!this.db)throw new Error("Driver not initialized");this.db.clearStorage()}async destroy(){this.closeDb(),this.writeCallbacks.clear()}}var Xe,Ze;class jt{constructor(e){Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"clientKey",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"processor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"isDestroyed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"bypassMutationLock",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"transactionQueryKeyQueue",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"userCallbacks",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"queriesInProgress",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"proxy",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"reinitChannel",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"effectsChannel",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"processMessageEvent",{enumerable:!0,configurable:!0,writable:!0,value:c=>{const u=c instanceof MessageEvent?c.data:c,p=this.queriesInProgress;switch(u.type){case"success":case"data":case"buffer":case"info":case"error":if(u.queryKey&&p.has(u.queryKey)){const[f,y]=p.get(u.queryKey);u.type==="error"?y(u.error):f(u),p.delete(u.queryKey)}else if(u.type==="error")throw u.error;break;case"callback":const d=this.userCallbacks.get(u.name);d&&d(...u.args??[]);break;case"event":this.config.onConnect?.(u.reason);break}}}),Object.defineProperty(this,"createQuery",{enumerable:!0,configurable:!0,writable:!0,value:async c=>ee("shared",this.bypassMutationLock||c.type==="import"||c.type==="delete",this.config,async()=>{if(this.isDestroyed===!0)throw new Error("This SQLocal client has been destroyed. You will need to initialize a new client in order to make further queries.");const u=oe();switch(c.type){case"import":this.processor.postMessage({...c,queryKey:u},[c.database]);break;default:this.processor.postMessage({...c,queryKey:u});break}return new Promise((p,d)=>{this.queriesInProgress.set(u,[p,d])})})}),Object.defineProperty(this,"broadcast",{enumerable:!0,configurable:!0,writable:!0,value:c=>{this.reinitChannel.postMessage(c)}}),Object.defineProperty(this,"exec",{enumerable:!0,configurable:!0,writable:!0,value:async(c,u,p="all",d)=>{const f=await this.createQuery({type:"query",transactionKey:d,sql:c,params:u,method:p}),y={rows:[],columns:[]};return f.type==="data"&&(y.rows=f.data[0]?.rows??[],y.columns=f.data[0]?.columns??[]),y}}),Object.defineProperty(this,"execBatch",{enumerable:!0,configurable:!0,writable:!0,value:async c=>{const u=await this.createQuery({type:"batch",statements:c}),p=new Array(c.length).fill({rows:[],columns:[]});return u.type==="data"&&u.data.forEach((d,f)=>{p[f]=d}),p}}),Object.defineProperty(this,"sql",{enumerable:!0,configurable:!0,writable:!0,value:async(c,...u)=>{const p=je(c,u),{rows:d,columns:f}=await this.exec(p.sql,p.params,"all");return he(d,f)}}),Object.defineProperty(this,"batch",{enumerable:!0,configurable:!0,writable:!0,value:async c=>{const u=c(ie);return(await this.execBatch(u)).map(({rows:d,columns:f})=>he(d,f))}}),Object.defineProperty(this,"beginTransaction",{enumerable:!0,configurable:!0,writable:!0,value:async()=>{const c=oe();await this.createQuery({type:"transaction",transactionKey:c,action:"begin"});const u=async y=>{const b=Ne(y);if(b.exec)return this.transactionQueryKeyQueue.push(c),b.exec();const{rows:x,columns:E}=await this.exec(b.sql,b.params,"all",c);return he(x,E)};return{query:u,sql:async(y,...b)=>{const x=je(y,b);return await u(x)},commit:async()=>{await this.createQuery({type:"transaction",transactionKey:c,action:"commit"})},rollback:async()=>{await this.createQuery({type:"transaction",transactionKey:c,action:"rollback"})}}}}),Object.defineProperty(this,"transaction",{enumerable:!0,configurable:!0,writable:!0,value:async c=>ee("exclusive",!1,this.config,async()=>{let u;this.bypassMutationLock=!0;try{u=await this.beginTransaction();const p=await c({sql:u.sql,query:u.query});return await u.commit(),p}catch(p){throw await u?.rollback(),p}finally{this.bypassMutationLock=!1}})}),Object.defineProperty(this,"reactiveQuery",{enumerable:!0,configurable:!0,writable:!0,value:c=>{let u=[],p=!1,d=!1,f=0;const y=Ne(c),b=new Set,x=new Set,E=new Set,w=async()=>{try{const v=++f;if(b.size===0){const m=await this.sql("SELECT name, wr FROM tables_used(?) WHERE type = 'table'",y.sql),T=new Set,P=new Set;if(m.forEach(k=>{typeof k.name=="string"&&(k.wr?P.add(k.name):T.add(k.name))}),T.size===0)throw new Error("The passed SQL does not read any tables.");if(Array.from(P).some(k=>T.has(k)))throw new Error("The passed SQL would mutate one or more of the tables that it reads. Doing this in a reactive query would create an infinite loop.");T.forEach(k=>b.add(k))}const S=y.exec?await y.exec():await this.sql(y.sql,...y.params);v===f&&(u=S,p=!0,x.forEach(m=>m(u)))}catch(v){E.forEach(S=>{S(v instanceof Error?v:new Error(String(v)))})}},L=v=>{v.data.tables.some(S=>b.has(S))&&w()};return{get value(){return u},subscribe:(v,S)=>{if(!this.effectsChannel)throw new Error('This SQLocal instance is not configured for reactive queries. Set the "reactive" option to enable them.');return S||(S=m=>{throw m}),x.add(v),E.add(S),d?p&&v(u):(this.effectsChannel.addEventListener("message",L),d=!0,w()),{unsubscribe:()=>{x.delete(v),E.delete(S),x.size===0&&(this.effectsChannel?.removeEventListener("message",L),d=!1)}}}}}}),Object.defineProperty(this,"createCallbackFunction",{enumerable:!0,configurable:!0,writable:!0,value:async(c,u)=>{await this.createQuery({type:"function",functionName:c,functionType:"callback"}),this.userCallbacks.set(c,u)}}),Object.defineProperty(this,"createScalarFunction",{enumerable:!0,configurable:!0,writable:!0,value:async(c,u)=>{const p=`_sqlocal_func_${c}`,d=()=>{this.proxy[p]=u};this.proxy===globalThis&&d(),await this.createQuery({type:"function",functionName:c,functionType:"scalar"}),this.proxy!==globalThis&&d()}}),Object.defineProperty(this,"createAggregateFunction",{enumerable:!0,configurable:!0,writable:!0,value:async(c,u)=>{const p=`_sqlocal_func_${c}`,d=()=>{this.proxy[`${p}_step`]=u.step,this.proxy[`${p}_final`]=u.final};this.proxy===globalThis&&d(),await this.createQuery({type:"function",functionName:c,functionType:"aggregate"}),this.proxy!==globalThis&&d()}}),Object.defineProperty(this,"getDatabaseInfo",{enumerable:!0,configurable:!0,writable:!0,value:async()=>{const c=await this.createQuery({type:"getinfo"});if(c.type==="info")return c.info;throw new Error("The database failed to return valid information.")}}),Object.defineProperty(this,"getDatabaseFile",{enumerable:!0,configurable:!0,writable:!0,value:async()=>{const c=await this.createQuery({type:"export"});if(c.type==="buffer")return new File([c.buffer],c.bufferName,{type:"application/x-sqlite3"});throw new Error("The database failed to export.")}}),Object.defineProperty(this,"overwriteDatabaseFile",{enumerable:!0,configurable:!0,writable:!0,value:async(c,u)=>{await ee("exclusive",!1,this.config,async()=>{try{this.broadcast({type:"close",clientKey:this.clientKey});const p=await Qe(c,"buffer");await this.createQuery({type:"import",database:p}),typeof u=="function"&&(this.bypassMutationLock=!0,await u()),this.broadcast({type:"reinit",clientKey:this.clientKey,reason:"overwrite"})}finally{this.bypassMutationLock=!1}})}}),Object.defineProperty(this,"deleteDatabaseFile",{enumerable:!0,configurable:!0,writable:!0,value:async c=>{await ee("exclusive",!1,this.config,async()=>{try{this.broadcast({type:"close",clientKey:this.clientKey}),await this.createQuery({type:"delete"}),typeof c=="function"&&(this.bypassMutationLock=!0,await c()),this.broadcast({type:"reinit",clientKey:this.clientKey,reason:"delete"})}finally{this.bypassMutationLock=!1}})}}),Object.defineProperty(this,"destroy",{enumerable:!0,configurable:!0,writable:!0,value:async()=>{await this.createQuery({type:"destroy"}),typeof globalThis.Worker<"u"&&this.processor instanceof Worker&&(this.processor.removeEventListener("message",this.processMessageEvent),this.processor.terminate()),this.queriesInProgress.clear(),this.userCallbacks.clear(),this.reinitChannel.close(),this.effectsChannel?.close(),this.isDestroyed=!0}}),Object.defineProperty(this,Xe,{enumerable:!0,configurable:!0,writable:!0,value:()=>{this.destroy()}}),Object.defineProperty(this,Ze,{enumerable:!0,configurable:!0,writable:!0,value:async()=>{await this.destroy()}});const t=typeof e=="string"?{databasePath:e}:e,{onInit:r,onConnect:o,processor:s,...n}=t,{databasePath:i}=n;this.config=t,this.clientKey=oe();const l=Ye(i,this.clientKey);if(this.reinitChannel=new BroadcastChannel(`_sqlocal_reinit_(${l})`),n.reactive&&(this.effectsChannel=new BroadcastChannel(`_sqlocal_effects_(${l})`)),typeof s<"u")this.processor=s;else if(i==="local"||i===":localStorage:"){const c=new Be("local");this.processor=new Z(c)}else if(i==="session"||i===":sessionStorage:"){const c=new Be("session");this.processor=new Z(c)}else if(typeof globalThis.Worker<"u"&&i!==":memory:")this.processor=new Worker(new URL("/assets/worker-CuIBOSaM.js",import.meta.url),{type:"module"});else{const c=new se;this.processor=new Z(c)}this.processor instanceof Z?(this.processor.onmessage=c=>this.processMessageEvent(c),this.proxy=globalThis):(this.processor.addEventListener("message",this.processMessageEvent),this.proxy=Se(this.processor)),this.processor.postMessage({type:"config",config:{...n,clientKey:this.clientKey,onInitStatements:r?.(ie)??[]}})}}Xe=Symbol.dispose,Ze=Symbol.asyncDispose;const ke="lupmis2.db",Bt="lupmis-db-sync",et=new jt(ke),{sql:h}=et;console.log("[Database] SQLocal instance created for:",ke);const tt=new BroadcastChannel(Bt);let ot=!1,rt,at;new Promise((a,e)=>{rt=a,at=e});const le=new Set;function $t(a){return le.add(a),()=>le.delete(a)}tt.onmessage=a=>{const{type:e,payload:t}=a.data;if(e==="DB_CHANGE")for(const r of le)try{r(t)}catch(o){console.error("[Database] Change listener error:",o)}};function Pe(a,e,t=null){tt.postMessage({type:"DB_CHANGE",payload:{table:a,action:e,id:t,timestamp:Date.now()}});for(const r of le)try{r({table:a,action:e,id:t,timestamp:Date.now(),local:!0})}catch(o){console.error("[Database] Change listener error:",o)}}async function qt(){try{console.log("[Database] Initializing schema...");const a=await h`SELECT sqlite_version() as version`;console.log("[Database] SQLite version:",a[0]?.version),console.log("[Database] Creating locations table..."),await h` CREATE TABLE IF NOT EXISTS locations ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, longitude REAL NOT NULL, latitude REAL NOT NULL, description TEXT, category TEXT DEFAULT 'default', created_at TEXT DEFAULT CURRENT_TIMESTAMP, updated_at TEXT DEFAULT CURRENT_TIMESTAMP, synced INTEGER DEFAULT 0 ) `;const e=await h`SELECT name FROM sqlite_master WHERE type='table' AND name='locations'`;console.log("[Database] Locations table exists:",e.length>0),console.log("[Database] Creating sync_log table..."),await h` CREATE TABLE IF NOT EXISTS sync_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, table_name TEXT NOT NULL, record_id INTEGER NOT NULL, action TEXT NOT NULL, timestamp TEXT DEFAULT CURRENT_TIMESTAMP, synced INTEGER DEFAULT 0 ) `,console.log("[Database] Creating remote_data table..."),await h` CREATE TABLE IF NOT EXISTS remote_data ( key TEXT PRIMARY KEY, data TEXT NOT NULL, fetched_at TEXT DEFAULT CURRENT_TIMESTAMP ) `,console.log("[Database] Creating collector_zones table..."),await h` CREATE TABLE IF NOT EXISTS collector_zones ( id INTEGER PRIMARY KEY, zone_name TEXT, geometry_wkt TEXT, properties TEXT, fetched_at TEXT DEFAULT CURRENT_TIMESTAMP ) `,console.log("[Database] Creating parcels table..."),await h` CREATE TABLE IF NOT EXISTS parcels ( id INTEGER PRIMARY KEY, geometry_wkt TEXT, properties TEXT, status TEXT DEFAULT 'verified', fetched_at TEXT DEFAULT CURRENT_TIMESTAMP ) `;try{await h`SELECT status FROM parcels LIMIT 1`}catch{console.log("[Database] Adding status column to parcels table..."),await h`ALTER TABLE parcels ADD COLUMN status TEXT DEFAULT 'verified'`}console.log("[Database] Creating building_footprints table..."),await h` CREATE TABLE IF NOT EXISTS building_footprints ( id INTEGER PRIMARY KEY, geometry_wkt TEXT, properties TEXT, fetched_at TEXT DEFAULT CURRENT_TIMESTAMP ) `,await h`CREATE INDEX IF NOT EXISTS idx_locations_category ON locations(category)`,await h`CREATE INDEX IF NOT EXISTS idx_locations_synced ON locations(synced)`;const t=await h`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`;console.log("[Database] All tables:",t.map(r=>r.name)),ot=!0,rt(!0),console.log("[Database] ✓ Schema initialized")}catch(a){throw console.error("[Database] ✗ Schema init failed:",a),at(a),a}}async function zt(a,e,t,r={}){const{description:o=null,category:s="default"}=r;console.log("[Database] Adding location:",a,e,t,s);try{const n=await h`SELECT name FROM sqlite_master WHERE type='table' AND name='locations'`;if(console.log("[Database] Table check before insert:",n),n.length===0)throw console.error("[Database] ✗ locations table does not exist!"),new Error("locations table does not exist");console.log("[Database] Executing INSERT..."),await h` INSERT INTO locations (name, longitude, latitude, description, category) VALUES (${a}, ${e}, ${t}, ${o}, ${s}) `,console.log("[Database] INSERT completed");const l=(await h`SELECT last_insert_rowid() as id`)[0]?.id;console.log("[Database] New ID:",l);const c=await h`SELECT * FROM locations WHERE id = ${l}`;if(console.log("[Database] Verify insert:",c),c.length===0)throw console.error("[Database] ✗ Insert verification failed - row not found!"),new Error("Insert verification failed");return await h` INSERT INTO sync_log (table_name, record_id, action) VALUES ('locations', ${l}, 'INSERT') `,Pe("locations","INSERT",l),console.log("[Database] ✓ Location added:",l),{id:l}}catch(n){throw console.error("[Database] ✗ Failed to add location:",n),n}}async function nt(a={}){const{category:e=null,limit:t=1e3}=a;try{const r=await h`SELECT name FROM sqlite_master WHERE type='table' AND name='locations'`;if(console.log("[Database] getLocations - table exists:",r.length>0),r.length===0)return console.warn("[Database] locations table does not exist yet"),[];let o;return e?o=await h` SELECT * FROM locations WHERE category = ${e} ORDER BY created_at DESC LIMIT ${t} `:o=await h` SELECT * FROM locations ORDER BY created_at DESC LIMIT ${t} `,console.log("[Database] getLocations returned",o.length,"rows"),o}catch(r){return console.error("[Database] getLocations error:",r),[]}}async function Gt(){try{return(await h`SELECT COUNT(*) as count FROM locations`)[0]?.count??0}catch(a){return console.error("[Database] getLocationCount error:",a),0}}async function st(a,e){try{const t=JSON.stringify(e);await h` INSERT OR REPLACE INTO remote_data (key, data, fetched_at) VALUES (${a}, ${t}, CURRENT_TIMESTAMP) `,console.log("[Database] ✓ Remote data cached:",a)}catch(t){throw console.error("[Database] ✗ Failed to cache remote data:",a,t),t}}async function it(a){try{const e=await h`SELECT data, fetched_at FROM remote_data WHERE key = ${a}`;if(e.length===0)return null;const t=JSON.parse(e[0].data);return console.log("[Database] ✓ Remote data loaded from cache:",a,"(fetched",e[0].fetched_at+")"),t}catch(e){return console.error("[Database] ✗ Failed to read cached remote data:",a,e),null}}async function Ut(a){try{await h`DELETE FROM collector_zones`;for(const e of a){const t=JSON.stringify(e);await h` INSERT INTO collector_zones (id, zone_name, geometry_wkt, properties, fetched_at) VALUES (${e.colzonenr||e.id}, ${e.colzonename||e.zone_name||""}, ${e.polygon||e.boundary||""}, ${t}, CURRENT_TIMESTAMP) `}console.log("[Database] ✓ Saved",a.length,"collector zones")}catch(e){throw console.error("[Database] ✗ Failed to save collector zones:",e),e}}async function Kt(){try{const a=await h`SELECT properties FROM collector_zones ORDER BY id`;return a.length===0?null:a.map(e=>JSON.parse(e.properties))}catch(a){return console.error("[Database] ✗ Failed to read local collector zones:",a),null}}async function Wt(a){try{await h`DELETE FROM parcels`;for(const e of a){const t=JSON.stringify(e),r=e.polygon||e.boundary||e.geom||e.wkt||"",o=e.id||e.parcelid||e.parcel_id||null;await h` INSERT INTO parcels (id, geometry_wkt, properties, fetched_at) VALUES (${o}, ${r}, ${t}, CURRENT_TIMESTAMP) `}console.log("[Database] ✓ Saved",a.length,"parcels")}catch(e){throw console.error("[Database] ✗ Failed to save parcels:",e),e}}async function Ht(){try{const a=await h`SELECT properties FROM parcels ORDER BY id`;return a.length===0?null:a.map(e=>JSON.parse(e.properties))}catch(a){return console.error("[Database] ✗ Failed to read local parcels:",a),null}}async function Vt(a,e){try{const t=JSON.stringify(e);await h`UPDATE parcels SET properties = ${t} WHERE id = ${a}`,console.log("[Database] ✓ Parcel updated:",a),Pe("parcels","UPDATE",a)}catch(t){throw console.error("[Database] ✗ Failed to update parcel:",a,t),t}}async function Jt(a,e){try{const t=JSON.stringify(e);await h` INSERT INTO parcels (id, geometry_wkt, properties, status, fetched_at) VALUES (NULL, ${a}, ${t}, 'new', CURRENT_TIMESTAMP) `;const o=(await h`SELECT last_insert_rowid() as id`)[0]?.id;return console.log("[Database] ✓ New parcel inserted:",o,"(status: new)"),Pe("parcels","INSERT",o),{id:o}}catch(t){throw console.error("[Database] ✗ Failed to insert new parcel:",t),t}}async function Qt(a){try{if(a.length>0){const e=a[0],t={};for(const[r,o]of Object.entries(e))t[r]=o===null?"null":typeof o;console.log("[Database] First footprint field types:",t)}await h`DELETE FROM building_footprints`;for(const e of a){const t=JSON.stringify(e);let r=e.polygon||e.boundary||e.geom||e.wkt||e.footprint||"";const o=typeof r=="object"?JSON.stringify(r):String(r);let s=e.id||e.footprint_id||e.building_id||null;await h` INSERT INTO building_footprints (id, geometry_wkt, properties, fetched_at) VALUES (${s!==null&&typeof s=="object"?null:s}, ${o}, ${t}, CURRENT_TIMESTAMP) `}console.log("[Database] ✓ Saved",a.length,"building footprints")}catch(e){throw console.error("[Database] ✗ Failed to save building footprints:",e),e}}async function Yt(){try{const a=await h`SELECT properties FROM building_footprints ORDER BY id`;return a.length===0?null:a.map(e=>JSON.parse(e.properties))}catch(a){return console.error("[Database] ✗ Failed to read local building footprints:",a),null}}async function Xt(){return et.getDatabaseFile()}async function Zt(a="lupmis-backup.sqlite3"){const e=await Xt(),t=new Blob([e],{type:"application/x-sqlite3"}),r=URL.createObjectURL(t),o=document.createElement("a");o.href=r,o.download=a,o.click(),URL.revokeObjectURL(r)}async function eo(){return{type:"FeatureCollection",features:(await nt()).map(e=>({type:"Feature",properties:{id:e.id,name:e.name,category:e.category,notes:e.notes,created_at:e.created_at},geometry:{type:"Point",coordinates:[e.lon,e.lat]}}))}}async function Ce(){try{const a=await h` SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name `,e=await Gt();return{ready:ot,databasePath:ke,tables:a.map(t=>t.name),locationCount:e}}catch(a){return{ready:!1,error:a.message}}}async function to(){const a=await h` SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name `;if(a.length===0)return[];const e=a.map(t=>`SELECT '${t.name}' AS name, COUNT(*) AS count FROM "${t.name}"`).join(" UNION ALL ");return h(e)}async function oo(a,e=200){if((await h` SELECT name FROM sqlite_master WHERE type='table' AND name = ${a} `).length===0)throw new Error(`Table "${a}" does not exist`);const r=await h(`SELECT * FROM "${a}" LIMIT ${e}`);return{columns:r.length>0?Object.keys(r[0]):[],rows:r}}async function ro(){console.log("=== DATABASE TEST ===");try{const a=await h`SELECT sqlite_version() as v`;console.log("1. SQLite version:",a[0].v);const e=await h`SELECT name FROM sqlite_master WHERE type='table'`;console.log("2. Tables:",e.map(o=>o.name)),console.log("3. Inserting test row..."),await h`INSERT INTO locations (name, longitude, latitude, category) VALUES ('TEST', -1.0, 7.0, 'test')`;const t=await h`SELECT * FROM locations WHERE name = 'TEST'`;console.log("4. Test row:",t);const r=await h`SELECT COUNT(*) as c FROM locations`;return console.log("5. Total rows:",r[0].c),await h`DELETE FROM locations WHERE name = 'TEST'`,console.log("6. Test row deleted"),console.log("=== TEST PASSED ==="),!0}catch(a){return console.error("=== TEST FAILED ===",a),!1}}typeof window<"u"&&(window.testDatabase=ro,window.dbStatus=Ce);class ao{constructor(e,t={}){this.options=t,this.markerSource=new Q,this.clickCallbacks=[],this.categoryEmojis={default:{emoji:"📍",label:"Default"},water:{emoji:"💧",label:"Water Point"},school:{emoji:"🏫",label:"School"},health:{emoji:"🏥",label:"Health Facility"},market:{emoji:"🏪",label:"Market"},other:{emoji:"📌",label:"Other"}},this.getEmoji=i=>{const l=this.categoryEmojis[i];return l?l.emoji:"📍"},this.getCategoryOptionsHtml=()=>Object.entries(this.categoryEmojis).map(([i,{emoji:l,label:c}])=>``).join(` `),this.createEmojiStyle=(i,l=24)=>new O({text:new Ae({text:i,font:`${l}px sans-serif`,textBaseline:"bottom",textAlign:"center",offsetY:-5})}),this.defaultStyle=this.createEmojiStyle("📍",32),this.selectedStyle=this.createEmojiStyle("📍",42),this.categoryStyles={};for(const[i,{emoji:l}]of Object.entries(this.categoryEmojis))this.categoryStyles[i]=this.createEmojiStyle(l,32);const r=this.createBaseLayers(t.basemap||"osm");this.markersLayer=new F({title:"Markers",source:this.markerSource,style:i=>this.getFeatureStyle(i)}),this.overlayGroup=new q({title:"Overlays"}),this.map=new ut({target:e,layers:[r,this.markersLayer,this.overlayGroup],view:new dt({center:N(t.center||[0,0]),zoom:t.zoom||2,minZoom:t.minZoom||2,maxZoom:t.maxZoom||19})});const o=new wt({collapsed:!0,mouseover:!0,extent:!1,trash:!1,oninfo:null});this.map.addControl(o),this.map.addControl(new pt);const s=new Et({title:"My Location",delay:3e3,zoom:16});this.map.addControl(s),this.geolocationButton=s;const n=new vt({placeholder:"Search location...",typing:300,minLength:3,maxItems:10,collapsed:!0});this.map.addControl(n),n.on("select",i=>{const l=i.search;if(l){const c=parseFloat(l.lon),u=parseFloat(l.lat),p=[c,u],d=N(p);this.navigateTo(c,u,14);const f={coordinate:d,lonLat:p,name:l.display_name||l.name||"Unknown",searchResult:l};this.searchSelectCallbacks.forEach(y=>y(f))}}),this.searchNominatim=n,this.searchSelectCallbacks=[],this.selectedFeature=null,this.createPopup(),this.createInfoPopup(),this.createAddLocationPopup(),this.createParcelEditPopup(),this.createDrawnPolygonPopup(),this.dblClickCallbacks=[],this.editBar=null,this.drawingsSource=null,this.drawingsLayer=null,this.touchCursor=null,this._editBarActive=!1}initEditBar(){this.drawingsSource=new Q,this.drawingsLayer=new F({title:"sketches",source:this.drawingsSource,style:new O({stroke:new A({color:"#f59e0b",width:2.5}),fill:new _({color:"rgba(245,158,11,0.15)"}),image:new H({radius:6,fill:new _({color:"#f59e0b"}),stroke:new A({color:"#fff",width:1.5})})})}),this._drawingsGroup=new q({title:"Drawings",layers:[this.drawingsLayer]});const e=this.map.getLayers(),t=e.getLength()-1;e.insertAt(t,this._drawingsGroup),this._selectInteraction=new ft({condition:ht,filter:(n,i)=>!!i,layers:n=>n instanceof F}),this._selectInteraction.setActive(!1),this.map.addInteraction(this._selectInteraction),this._modifyInteraction=new Tt({features:this._selectInteraction.getFeatures()}),this._modifyInteraction.setActive(!1),this._undoRedo=new xt,this.map.addInteraction(this._undoRedo),this.editBar=new we({source:this.drawingsSource,interactions:{Select:this._selectInteraction,ModifySelect:this._modifyInteraction,DrawPoint:!0,DrawLine:!0,DrawPolygon:!0,DrawRegular:!0,DrawHole:!0,Delete:!0,Info:!0,Transform:!0,Split:!0,Offset:!0}}),this.map.addControl(this.editBar),this._fillColor="#f59e0b";const r=document.createElement("input");r.type="color",r.value=this._fillColor,r.title="Fill colour",r.style.cssText="width:28px;height:28px;border:none;padding:0;cursor:pointer;background:transparent;",r.addEventListener("input",n=>{this._fillColor=n.target.value;const i=this._fillColor,l=parseInt(i.slice(1,3),16),c=parseInt(i.slice(3,5),16),u=parseInt(i.slice(5,7),16);this.drawingsLayer.setStyle(new O({stroke:new A({color:i,width:2.5}),fill:new _({color:`rgba(${l},${c},${u},0.15)`}),image:new H({radius:6,fill:new _({color:i}),stroke:new A({color:"#fff",width:1.5})})})),console.log("[MapView] Fill colour changed to",i)});const o=new Lt({group:!0,controls:[new J({html:'',className:"ol-undo",title:"Undo",handleClick:()=>{this._undoRedo.hasUndo()&&this._undoRedo.undo()}}),new J({html:'',className:"ol-redo",title:"Redo",handleClick:()=>{this._undoRedo.hasRedo()&&this._undoRedo.redo()}}),new J({html:r,className:"ol-colorpicker",title:"Fill colour"}),new J({html:'',className:"ol-save",title:"Save drawings",handleClick:()=>{this.dispatchEditEvent("save")}})]});this.editBar.addControl(o),this.setEditMode(!1),this._drawingsGroup.on("change:visible",()=>{const n=this._drawingsGroup.getVisible();this.setEditMode(n)}),("ontouchstart"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0)&&(this.touchCursor=new St({className:"ol-editbar-cursor"}),this.map.addInteraction(this.touchCursor),this.touchCursor.setActive(!1),console.log("[MapView] Touch device detected — TouchCursor added")),this.drawingsSource.on("addfeature",n=>{const i=n.feature,l=i.getGeometry();if(!l||l.getType()!=="Polygon")return;const c=l.getInteriorPoint().getCoordinates();this.showDrawnPolygonPopup(i,c)}),console.log("[MapView] EditBar initialised with Drawings group, UndoRedo, colour picker")}dispatchEditEvent(e){if(!this._editEventListeners)return;const t=this._editEventListeners[e];t&&t.forEach(r=>r())}onEditEvent(e,t){this._editEventListeners||(this._editEventListeners={}),this._editEventListeners[e]||(this._editEventListeners[e]=[]),this._editEventListeners[e].push(t)}setEditMode(e){this._editBarActive=!!e,this.editBar&&(this.editBar.setVisible(this._editBarActive),this._editBarActive||this.editBar.deactivateControls()),this._selectInteraction&&(this._editBarActive||this._selectInteraction.getFeatures().clear(),this._selectInteraction.setActive(this._editBarActive)),this._modifyInteraction&&this._modifyInteraction.setActive(this._editBarActive),this.touchCursor&&this.touchCursor.setActive(this._editBarActive),console.log("[MapView] Edit mode:",this._editBarActive?"ON":"OFF")}isEditMode(){return this._editBarActive}getDrawingsLayer(){return this.drawingsLayer}getDrawingsSource(){return this.drawingsSource}getEditBar(){return this.editBar}createPopup(){this.popupElement=document.createElement("div"),this.popupElement.className="map-popup",this.popupElement.style.cssText=` position: absolute; background: white; border-radius: 8px; padding: 10px 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.25); font-family: var(--font-body, 'Exo', sans-serif); font-size: 13px; min-width: 150px; max-width: 280px; pointer-events: none; z-index: 1000; border: 1px solid var(--border, #1e1a4b1f); `,this.popup=new K({element:this.popupElement,positioning:"bottom-center",offset:[0,-15],stopEvent:!1}),this.map.addOverlay(this.popup),this.setupHoverPopup()}setupHoverPopup(){let e=null;this.map.on("pointermove",t=>{if(t.dragging){this.hidePopup();return}const r=this.map.forEachFeatureAtPixel(t.pixel,o=>o.get("name")?o:null);r&&r!==e?(e=r,this.showPopup(r,t.coordinate)):!r&&e&&(e=null,this.hidePopup()),this.map.getTargetElement().style.cursor=r?"pointer":""}),this.map.getTargetElement().addEventListener("mouseleave",()=>{this.hidePopup(),e=null})}showPopup(e,t){const r=e.get("name")||"Unnamed",o=e.get("category")||"default",s=e.get("description"),n=e.get("lon"),i=e.get("lat");let c=`
${this.getEmoji(o)} ${this.escapeHtml(r)}
`;const p={water:"#3b82f6",school:"#f59e0b",health:"#ef4444",market:"#8b5cf6",default:"#2d5016",other:"#6b7280"}[o]||"#6b7280";c+=`
${o}
`,s&&(c+=`
${this.escapeHtml(s)}
`),n!==void 0&&i!==void 0&&(c+=`
${Number(n).toFixed(5)}, ${Number(i).toFixed(5)}
`),this.popupElement.innerHTML=c,this.popup.setPosition(t)}hidePopup(){this.popup.setPosition(void 0)}createInfoPopup(){this.infoPopupElement=document.createElement("div"),this.infoPopupElement.className="map-info-popup",this.infoPopupElement.style.cssText=` position: absolute; background: white; border-radius: 10px; padding: 0; box-shadow: 0 4px 16px rgba(0,0,0,0.3); font-family: var(--font-body, 'Exo', sans-serif); font-size: 13px; min-width: 220px; max-width: 320px; z-index: 1001; border: 1px solid var(--border, #1e1a4b1f); overflow: hidden; `,this.infoPopup=new K({element:this.infoPopupElement,positioning:"bottom-center",offset:[0,-10],stopEvent:!0,autoPan:!0,autoPanAnimation:{duration:250}}),this.map.addOverlay(this.infoPopup)}showInfoPopup(e,t,r={}){const{title:o="Feature Info",color:s="#e11d48"}=r,n=e.getProperties(),i=e.getGeometry(),l=i.getType(),c=["geometry","_layerType"];let u="";for(const[d,f]of Object.entries(n))c.includes(d)||f===void 0||f===null||(u+=` ${this.escapeHtml(d)} ${this.escapeHtml(String(f))} `);if(l==="Polygon"||l==="MultiPolygon"){const d=re(i,{projection:"EPSG:3857"}),f=d>1e6?`${(d/1e6).toFixed(2)} km² (${d.toLocaleString("en",{maximumFractionDigits:0})} m²)`:`${d.toLocaleString("en",{maximumFractionDigits:0})} m²`;u+=` area ${f} `}else if(l==="LineString"||l==="MultiLineString"){const d=me(i,{projection:"EPSG:3857"}),f=d>=1e3?`${(d/1e3).toFixed(2)} km (${d.toLocaleString("en",{maximumFractionDigits:0})} m)`:`${d.toLocaleString("en",{maximumFractionDigits:1})} m`;u+=` length ${f} `}else if(l==="Point"){const d=z(i.getCoordinates()),f=d[0].toFixed(6),y=d[1].toFixed(6);u+=` longitude ${f} latitude ${y} `}const p=`
${this.escapeHtml(o)}
${u}
`;this.infoPopupElement.innerHTML=p,this.infoPopup.setPosition(t),this.infoPopupElement.querySelector("#info-popup-close").addEventListener("click",()=>{this.hideInfoPopup()})}hideInfoPopup(){this.infoPopup.setPosition(void 0)}showCircleIntersectionPopup(e,t){const r=e.getGeometry();if(!r||typeof r.getCenter!="function")return;const o=gt(r,64),s=o.getExtent(),n=e.get("_radius")||r.getRadius(),i=[],l=[],c={},u=E=>{const w=E.getGeometry();if(!w)return!1;const L=w.getExtent();return L[2]s[2]||L[3]s[3]?!1:o.intersectsExtent(L)&&this._geometriesIntersect(o,w)},p=(E,w)=>{E.getLayers().forEach(L=>{if(L instanceof q)p(L,L.get("title")||w);else if(L instanceof F&&L.getVisible()){const v=L.get("title")||w||"Unknown",S=L.getSource();if(!S)return;const m=S.getFeaturesInExtent(s);for(const T of m){const P=T.get("_layerType");P==="measure_circle"||P==="measure_circle_radius"||u(T)&&(P==="parcel"?i.push(T):P==="collector_zone"?l.push(T):(c[v]||(c[v]=[]),c[v].push(T)))}}})};p(this.overlayGroup,"Overlays");const d=n>=1e3?`${(n/1e3).toFixed(2)} km`:`${Math.round(n)} m`,f=Math.PI*n*n,y=f>1e6?`${(f/1e6).toFixed(2)} km²`:`${f.toLocaleString("en",{maximumFractionDigits:0})} m²`;let b=` radius ${d} area ${y} `;if(i.length>0&&(b+=` parcels ${i.length} `),l.length>0){const E=l.map(w=>w.get("colzonename")||w.get("zone_name")||w.get("name")||"unnamed");b+=` zones ${l.length} zone names ${E.map(w=>this.escapeHtml(w)).join(", ")} `}for(const[E,w]of Object.entries(c))b+=` ${this.escapeHtml(E)} ${w.length} feature(s) `;i.length===0&&l.length===0&&Object.keys(c).length===0&&(b+=` No intersecting features found `);const x=`
⭕ Circle Analysis
${b}
`;this.infoPopupElement.innerHTML=x,this.infoPopup.setPosition(t),this.infoPopupElement.querySelector("#info-popup-close").addEventListener("click",()=>{this.hideInfoPopup()})}_geometriesIntersect(e,t){const r=t.getType();if(r==="Polygon"||r==="MultiPolygon"){const o=t.getFlatCoordinates(),s=t.getStride();for(let l=0;l `}const n=`
✏️ Edit Parcel
${s}
`;this.parcelEditElement.innerHTML=n,this.parcelEditPopup.setPosition(t),this.parcelEditElement.querySelector(".parcel-edit-close").addEventListener("click",()=>{this.hideParcelEditPopup()}),this.parcelEditElement.querySelector(".parcel-edit-cancel").addEventListener("click",()=>{this.hideParcelEditPopup()});const i=this.parcelEditElement.querySelector(".parcel-edit-form");i.addEventListener("submit",l=>{l.preventDefault();const c=new FormData(i),u={};for(const[p,d]of c.entries())u[p]=d;u._layerType="parcel";for(const[p,d]of Object.entries(u))this._parcelEditFeature.set(p,d);for(const p of this._parcelEditCallbacks)p(this._parcelEditFeature,u);this.hideParcelEditPopup()})}hideParcelEditPopup(){this.parcelEditPopup.setPosition(void 0),this._parcelEditFeature=null}onParcelEdit(e){this._parcelEditCallbacks.push(e)}createDrawnPolygonPopup(){this.drawnPolygonElement=document.createElement("div"),this.drawnPolygonElement.className="map-drawn-polygon-popup",this.drawnPolygonElement.style.cssText=` position: absolute; background: var(--card, #fff); border-radius: var(--radius-xl, 0.75rem); box-shadow: 0 4px 20px rgba(0,0,0,0.2); font-family: var(--font-body, 'Exo', sans-serif); font-size: 13px; min-width: 280px; max-width: 360px; max-height: 420px; z-index: 1002; border: 2px solid var(--success, #006b3f); overflow: hidden; display: flex; flex-direction: column; `,this.drawnPolygonPopup=new K({element:this.drawnPolygonElement,positioning:"bottom-center",offset:[0,-10],stopEvent:!0,autoPan:!0,autoPanAnimation:{duration:250}}),this.map.addOverlay(this.drawnPolygonPopup),this._drawnPolygonCallbacks=[],this._drawnPolygonFeature=null}getParcelAttributeKeys(){const e=["geometry","_layerType"],t=[],r=o=>{t.length>0||o.getLayers().forEach(s=>{if(!(t.length>0)){if(s instanceof q)r(s);else if(s instanceof F){const n=s.getSource();if(!n)return;for(const i of n.getFeatures()){if(i.get("_layerType")!=="parcel")continue;const l=i.getProperties();for(const c of Object.keys(l))e.includes(c)||t.push(c);return}}}})};return r(this.overlayGroup),t}showDrawnPolygonPopup(e,t){this._drawnPolygonFeature=e;const r=this.getParcelAttributeKeys();if(r.length===0){console.warn("[MapView] No parcel attributes found — cannot build form");return}let o="";for(const u of r){const p=this.escapeHtml(u);o+=`
`}const s=e.getGeometry(),n=re(s,{projection:"EPSG:3857"}),l=`
📐 Polygon Attributes
Area: ${n>1e6?`${(n/1e6).toFixed(2)} km²`:`${n.toLocaleString("en",{maximumFractionDigits:0})} m²`}
${o}
`;this.drawnPolygonElement.innerHTML=l,this.drawnPolygonPopup.setPosition(t),this.drawnPolygonElement.querySelector(".drawn-polygon-close").addEventListener("click",()=>{this.hideDrawnPolygonPopup()}),this.drawnPolygonElement.querySelector(".drawn-polygon-cancel").addEventListener("click",()=>{this.hideDrawnPolygonPopup()});const c=this.drawnPolygonElement.querySelector(".drawn-polygon-form");c.addEventListener("submit",u=>{u.preventDefault();const p=new FormData(c),d={};for(const[f,y]of p.entries())d[f]=y;for(const[f,y]of Object.entries(d))this._drawnPolygonFeature.set(f,y);this._drawnPolygonFeature.set("_layerType","parcel");for(const f of this._drawnPolygonCallbacks)f(this._drawnPolygonFeature,d);this.hideDrawnPolygonPopup()})}hideDrawnPolygonPopup(){this.drawnPolygonPopup.setPosition(void 0),this._drawnPolygonFeature=null}onDrawnPolygonSave(e){this._drawnPolygonCallbacks.push(e)}onDblClick(e){return this.dblClickCallbacks.push(e),this.dblClickCallbacks.length===1&&this.map.on("dblclick",t=>{const[r,o]=z(t.coordinate);let s=null;this.map.forEachFeatureAtPixel(t.pixel,n=>(s=n,!0)),s&&(t.preventDefault(),t.stopPropagation());for(const n of this.dblClickCallbacks)n(r,o,s,t);if(s)return!1}),()=>{const t=this.dblClickCallbacks.indexOf(e);t>-1&&this.dblClickCallbacks.splice(t,1)}}escapeHtml(e){if(!e)return"";const t=document.createElement("div");return t.textContent=e,t.innerHTML}createAddLocationPopup(){this.addLocationPopupElement=document.createElement("div"),this.addLocationPopupElement.className="map-add-location-popup",this.addLocationPopupElement.innerHTML=`
➕ Add Location
📍
`,this.addLocationPopup=new K({element:this.addLocationPopupElement,positioning:"bottom-center",offset:[0,-10],stopEvent:!0,autoPan:!0,autoPanAnimation:{duration:250}}),this.map.addOverlay(this.addLocationPopup),this.addLocationCoords=null,this.addLocationPopupElement.querySelector(".add-location-popup-close").addEventListener("click",()=>{this.hideAddLocationPopup()}),this.addLocationCallbacks=[]}showAddLocationPopup(e){const[t,r]=z(e);this.addLocationCoords={lon:t,lat:r};const o=this.addLocationPopupElement.querySelector("#map-location-coords");o.textContent=`${t.toFixed(6)}, ${r.toFixed(6)}`,this.addLocationPopupElement.querySelector("#map-add-location-form").reset(),this.addLocationPopup.setPosition(e)}hideAddLocationPopup(){this.addLocationPopup.setPosition(void 0),this.addLocationCoords=null}onAddLocation(e){if(this.addLocationCallbacks.push(e),this.addLocationCallbacks.length===1){const t=this.addLocationPopupElement.querySelector("#map-add-location-form");t.addEventListener("submit",r=>{if(r.preventDefault(),!this.addLocationCoords)return;const o=new FormData(t),s={name:o.get("name"),category:o.get("category"),description:o.get("description"),lon:this.addLocationCoords.lon,lat:this.addLocationCoords.lat};this.addLocationCallbacks.forEach(n=>n(s)),this.hideAddLocationPopup()})}}createBaseLayers(e){const t=new j({title:"Topographic",type:"base",visible:e==="topo",source:new V({url:"https://{a-c}.tile.opentopomap.org/{z}/{x}/{y}.png",attributions:"Map data: © OpenTopoMap",maxZoom:17,crossOrigin:"anonymous"})}),r=new j({title:"Carto Light",type:"base",visible:e==="carto-light",source:new V({url:"https://{a-c}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",attributions:"© CARTO",maxZoom:19,crossOrigin:"anonymous"})}),o=new j({title:"Carto Dark",type:"base",visible:e==="carto-dark",source:new V({url:"https://{a-c}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",attributions:"© CARTO",maxZoom:19,crossOrigin:"anonymous"})}),s=new j({title:"OSM Cycle map",type:"base",visible:!1,source:new Me({url:"https://tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=ae1339c46dd3446b9c491e7336d38760"})}),n=new j({title:"Satellite",type:"base",visible:e==="satellite",source:new V({url:"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",attributions:"Tiles © Esri",maxZoom:19,crossOrigin:"anonymous"})}),i=new j({title:"Google Sat",type:"base",visible:e==="googlesat",source:new V({url:"http://mt0.google.com/vt/lyrs=y&hl=en&x={x}&y={y}&z={z}&s=Ga",attributions:"Tiles © Google",maxZoom:19,crossOrigin:"anonymous"})}),l=new j({title:"OpenStreetMap",type:"base",visible:e==="osm",source:new Me});return new q({title:"Base Maps",layers:[r,o,n,s,t,i,l]})}getFeatureStyle(e){const t=e.get("category")||"default",r=this.getEmoji(t);if(e===this.selectedFeature)return[new O({image:new H({radius:22,fill:new _({color:"rgba(220, 38, 38, 0.25)"}),stroke:new A({color:"#dc2626",width:3})})}),new O({text:new Ae({text:r,font:"40px sans-serif",textBaseline:"bottom",textAlign:"center",offsetY:-5})})];const o=e.get("style");return o||(this.categoryStyles[t]?this.categoryStyles[t]:this.defaultStyle)}setCategoryStyles(e){for(const[t,r]of Object.entries(e)){r.emoji&&(this.categoryEmojis[t]?(this.categoryEmojis[t].emoji=r.emoji,r.label&&(this.categoryEmojis[t].label=r.label)):this.categoryEmojis[t]={emoji:r.emoji,label:r.label||t});const o=this.getEmoji(t),s=r.fontSize||28;this.categoryStyles[t]=this.createEmojiStyle(o,s)}this.markerSource.changed()}addMarker(e,t,r={}){console.log("[MapView] Adding marker at",e,t,"with properties:",r);const o=new be({geometry:new Ie(N([e,t])),...r});return o.set("lon",e),o.set("lat",t),this.markerSource.addFeature(o),console.log("[MapView] Marker added, total features:",this.markerSource.getFeatures().length),o}addMarkers(e){console.log("[MapView] Adding",e.length,"markers");const t=e.map(r=>new be({geometry:new Ie(N([r.longitude,r.latitude])),id:r.id,name:r.name,description:r.description,category:r.category,lon:r.longitude,lat:r.latitude}));return this.markerSource.addFeatures(t),console.log("[MapView] Markers added, total features:",this.markerSource.getFeatures().length),t}clearMarkers(){this.markerSource.clear(),this.selectedFeature=null}removeMarker(e){if(typeof e=="object")this.markerSource.removeFeature(e);else{const t=this.markerSource.getFeatures().find(r=>r.get("id")===e);t&&this.markerSource.removeFeature(t)}}getMarkers(){return this.markerSource.getFeatures()}findMarker(e){return this.markerSource.getFeatures().find(t=>t.get("id")===e)}selectMarker(e){return typeof e=="object"?this.selectedFeature=e:this.selectedFeature=this.findMarker(e),this.markerSource.changed(),this.selectedFeature}clearSelection(){this.selectedFeature=null,this.markerSource.changed()}zoomTo(e,t,r=15){this.map.getView().animate({center:N([e,t]),zoom:r,duration:500})}fitToMarkers(e=50){const t=this.markerSource.getExtent();t&&t[0]!==1/0&&this.map.getView().fit(t,{padding:[e,e,e,e],duration:500,maxZoom:16})}getCenter(){const e=this.map.getView().getCenter();return z(e)}getZoom(){return this.map.getView().getZoom()}setCenter(e,t){this.map.getView().setCenter(N([e,t]))}setZoom(e){this.map.getView().setZoom(e)}onClick(e){return this.clickCallbacks.push(e),this.clickCallbacks.length===1&&(this._clickTimer=null,this.map.on("dblclick",()=>{this._clickTimer&&(clearTimeout(this._clickTimer),this._clickTimer=null)}),this.map.on("click",t=>{this._clickTimer&&(clearTimeout(this._clickTimer),this._clickTimer=null),!this._editBarActive&&this._selectInteraction&&this._selectInteraction.getFeatures().clear();let r=!1,o=!1,s=null;if(this.map.forEachFeatureAtPixel(t.pixel,l=>{l.get("_layerType")==="parcel"&&(o=!0),l.get("name")&&(s=l),r=!0}),r&&!o&&!s)return;const[n,i]=z(t.coordinate);this._clickTimer=setTimeout(()=>{this._clickTimer=null;let l=null;this.map.forEachFeatureAtPixel(t.pixel,c=>{if(c.get("name"))return l=c,!0});for(const c of this.clickCallbacks)c(n,i,l,t)},300)})),()=>{const t=this.clickCallbacks.indexOf(e);t>-1&&this.clickCallbacks.splice(t,1)}}onPointerMove(e){this.map.on("pointermove",t=>{if(t.dragging)return;const[r,o]=z(t.coordinate);let s=null;this.map.forEachFeatureAtPixel(t.pixel,n=>{if(n.get("name"))return s=n,!0}),this.map.getTargetElement().style.cursor=s?"pointer":"",e(r,o,s,t)})}enableHoverCursor(){}addGeoJSONLayer(e,t,r={},o=null){const{strokeColor:s="#3b82f6",strokeWidth:n=2,fillColor:i="rgba(59,130,246,0.1)"}=r,l=new Q({features:new ce().readFeatures(e,{featureProjection:"EPSG:3857"})}),c=new F({title:t,source:l,style:new O({stroke:new A({color:s,width:n}),fill:new _({color:i})})});return(o||this.overlayGroup).getLayers().push(c),console.log("[MapView] GeoJSON layer added:",t,"→",l.getFeatures().length,"features",o?`(in group "${o.get("title")}")`:""),c}addLayerGroup(e,t,r=""){const o=new q({title:t.trim()});return o.set("layerId",e),o.set("description",r),this.overlayGroup.getLayers().push(o),console.log("[MapView] Layer group added:",t.trim(),"(id:",e+")"),o}getLayerGroup(e){let t=null;return this.overlayGroup.getLayers().forEach(r=>{r.get("layerId")===e&&(t=r)}),t}getLayerGroupByTitle(e){let t=null;return this.overlayGroup.getLayers().forEach(r=>{r.get("title")===e&&(t=r)}),t}getOverlayGroup(){return this.overlayGroup}getMap(){return this.map}getMarkerSource(){return this.markerSource}getMarkersLayer(){return this.markersLayer}updateSize(){this.map.updateSize()}onSearchSelect(e){this.searchSelectCallbacks.push(e)}navigateTo(e,t,r=14,o=500){const s=N([e,t]);this.map.getView().animate({center:s,zoom:r,duration:o})}}class no{constructor(e,t={}){this.map=e,this.options=t,this.measureSource=new Q,this.measureLayer=new F({source:this.measureSource,style:this.getMeasureStyle(),title:"Measurements",zIndex:100}),this.drawSource=new Q,this.drawLayer=new F({source:this.drawSource,style:this.getDrawStyle(),title:"Draw sketches",displayInLayerSwitcher:!1,zIndex:99});const r=this.map.getLayers(),o=r.getLength()-1;r.insertAt(o,this.drawLayer),r.insertAt(o,this.measureLayer),this.activeInteraction=null,this.measureTooltip=null,this.measureTooltipElement=null,this.onMeasureCompleteCallbacks=[],this.onDrawCompleteCallbacks=[]}getMeasureStyle(){return new O({fill:new _({color:"rgba(255, 233, 106, 0.2)"}),stroke:new A({color:"#8B008B",lineDash:[10,10],width:2}),image:new H({radius:5,stroke:new A({color:"#8B008B"}),fill:new _({color:"rgba(255, 233, 106, 0.5)"})})})}getDrawStyle(){return new O({fill:new _({color:"rgba(255, 233, 106, 0.3)"}),stroke:new A({color:"#8B008B",width:2}),image:new H({radius:6,stroke:new A({color:"#8B008B",width:2}),fill:new _({color:"#FFE96A"})})})}formatLength(e){return e>1e3?Math.round(e/1e3*100)/100+" km":Math.round(e*100)/100+" m"}formatArea(e){return e>1e6?Math.round(e/1e6*100)/100+" km²":Math.round(e*100)/100+" m²"}formatCircleExtent(e){const t=Math.PI*e*e;return t>1e6?Math.round(t/1e6*100)/100+" km²":Math.round(t*100)/100+" m²"}createMeasureTooltip(){this.measureTooltipElement&&this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement),this.measureTooltipElement=document.createElement("div"),this.measureTooltipElement.className="measure-tooltip",this.measureTooltip=new K({element:this.measureTooltipElement,offset:[15,0],positioning:"center-left",stopEvent:!1}),this.map.addOverlay(this.measureTooltip)}deactivate(){this.activeInteraction&&(this.map.removeInteraction(this.activeInteraction),this.activeInteraction=null),this.measureTooltip&&(this.map.removeOverlay(this.measureTooltip),this.measureTooltip=null),this.measureTooltipElement&&this.measureTooltipElement.parentNode&&(this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement),this.measureTooltipElement=null)}startCircleMeasure(){this.deactivate(),this.createMeasureTooltip();const e=new G({source:this.measureSource,type:"Circle",style:new O({fill:new _({color:"rgba(255, 233, 106, 0.2)"}),stroke:new A({color:"rgba(139, 0, 139, 0.7)",lineDash:[10,10],width:2}),image:new H({radius:5,stroke:new A({color:"rgba(139, 0, 139, 0.7)"}),fill:new _({color:"rgba(255, 233, 106, 0.5)"})})})});this.activeInteraction=e,this.map.addInteraction(e);let t;return e.on("drawstart",r=>{t=r.feature.getGeometry().on("change",s=>{const n=s.target;if(n instanceof yt){const i=n.getRadius(),l=this.formatCircleExtent(i),u=`${this.formatLength(i)}
${l}`;this.measureTooltipElement.innerHTML=u,this.measureTooltip.setPosition(n.getLastCoordinate())}})}),e.on("drawend",r=>{const o=r.feature,s=o.getGeometry(),n=s.getCenter(),i=s.getRadius();o.set("_layerType","measure_circle"),o.set("_radius",i),o.set("_center",n);const l=new be({geometry:new mt([n,[n[0]+i,n[1]]])});l.set("_layerType","measure_circle_radius"),this.measureSource.addFeature(l),this.measureTooltipElement.className="measure-tooltip measure-tooltip-static",this.measureTooltip.setOffset([0,-7]),this.measureTooltipElement=null,this.createMeasureTooltip(),de(t);const c={type:"circle",center:n,radius:i,area:Math.PI*i*i,feature:o};this.onMeasureCompleteCallbacks.forEach(u=>u(c))}),e}startLineMeasure(){this.deactivate(),this.createMeasureTooltip();const e=new G({source:this.measureSource,type:"LineString",style:this.getMeasureStyle()});this.activeInteraction=e,this.map.addInteraction(e);let t;return e.on("drawstart",r=>{t=r.feature.getGeometry().on("change",s=>{const n=s.target,i=me(n),l=this.formatLength(i);this.measureTooltipElement.innerHTML=l,this.measureTooltip.setPosition(n.getLastCoordinate())})}),e.on("drawend",r=>{const o=r.feature,s=o.getGeometry(),n=me(s);this.measureTooltipElement.className="measure-tooltip measure-tooltip-static",this.measureTooltipElement=null,this.createMeasureTooltip(),de(t);const i={type:"line",length:n,feature:o};this.onMeasureCompleteCallbacks.forEach(l=>l(i))}),e}startAreaMeasure(){this.deactivate(),this.createMeasureTooltip();const e=new G({source:this.measureSource,type:"Polygon",style:this.getMeasureStyle()});this.activeInteraction=e,this.map.addInteraction(e);let t;return e.on("drawstart",r=>{t=r.feature.getGeometry().on("change",s=>{const n=s.target,i=re(n),l=this.formatArea(i);this.measureTooltipElement.innerHTML=l,this.measureTooltip.setPosition(n.getInteriorPoint().getCoordinates())})}),e.on("drawend",r=>{const o=r.feature,s=o.getGeometry(),n=re(s);this.measureTooltipElement.className="measure-tooltip measure-tooltip-static",this.measureTooltipElement=null,this.createMeasureTooltip(),de(t);const i={type:"polygon",area:n,feature:o,coordinate:s.getInteriorPoint().getCoordinates()};this.onMeasureCompleteCallbacks.forEach(l=>l(i))}),e}startDrawPoint(){this.deactivate();const e=new G({source:this.drawSource,type:"Point",style:this.getDrawStyle()});return this.activeInteraction=e,this.map.addInteraction(e),e.on("drawend",t=>{const r={type:"point",feature:t.feature};this.onDrawCompleteCallbacks.forEach(o=>o(r))}),e}startDrawLine(){this.deactivate();const e=new G({source:this.drawSource,type:"LineString",style:this.getDrawStyle()});return this.activeInteraction=e,this.map.addInteraction(e),e.on("drawend",t=>{const r={type:"line",feature:t.feature};this.onDrawCompleteCallbacks.forEach(o=>o(r))}),e}startDrawPolygon(){this.deactivate();const e=new G({source:this.drawSource,type:"Polygon",style:this.getDrawStyle()});return this.activeInteraction=e,this.map.addInteraction(e),e.on("drawend",t=>{const r={type:"polygon",feature:t.feature};this.onDrawCompleteCallbacks.forEach(o=>o(r))}),e}clearMeasurements(){this.measureSource.clear(),document.querySelectorAll(".measure-tooltip-static").forEach(t=>t.parentNode.removeChild(t))}clearDrawings(){this.drawSource.clear()}clearAll(){this.clearMeasurements(),this.clearDrawings()}onMeasureComplete(e){this.onMeasureCompleteCallbacks.push(e)}onDrawComplete(e){this.onDrawCompleteCallbacks.push(e)}createControlBar(e={}){e.position;const t=new we({group:!0,className:"map-tools-bar"}),r=new we({toggleOne:!0,group:!0}),o=new pe({html:'',title:"Measure Circle (radius & area)",className:"measure-circle-btn",onToggle:l=>{l?this.startCircleMeasure():this.deactivate()}});r.addControl(o);const s=new pe({html:'📏',title:"Measure Distance",className:"measure-line-btn",onToggle:l=>{l?this.startLineMeasure():this.deactivate()}});r.addControl(s);const n=new pe({html:'',title:"Measure Area",className:"measure-area-btn",onToggle:l=>{l?this.startAreaMeasure():this.deactivate()}});r.addControl(n);const i=new J({html:'🗑️',title:"Clear Measurements",className:"clear-measure-btn",handleClick:()=>{this.clearMeasurements(),o.setActive(!1),s.setActive(!1),n.setActive(!1)}});return r.addControl(i),t.addControl(r),t}getMeasureLayer(){return this.measureLayer}getDrawLayer(){return this.drawLayer}getMeasureSource(){return this.measureSource}getDrawSource(){return this.drawSource}isActive(){return this.activeInteraction!==null}}let B=null;async function so(){if(!("serviceWorker"in navigator))return console.warn("[PWA] Service Workers not supported"),null;try{return B=await navigator.serviceWorker.register("/sw.js",{scope:"/"}),console.log("[PWA] Service Worker registered:",B.scope),B.addEventListener("updatefound",()=>{const a=B.installing;a.addEventListener("statechange",()=>{a.state==="installed"&&navigator.serviceWorker.controller&&(console.log("[PWA] New version available"),po())})}),B}catch(a){return console.error("[PWA] Service Worker registration failed:",a),null}}let U=null,D=null;function io(a="#install-btn"){if(D=typeof a=="string"?document.querySelector(a):a,!D){console.warn("[PWA] Install button not found:",a);return}D.style.display="none",window.addEventListener("beforeinstallprompt",e=>{e.preventDefault(),U=e,D.style.display="block",console.log("[PWA] Install prompt ready")}),D.addEventListener("click",async()=>{if(!U){lo();return}U.prompt();const{outcome:e}=await U.userChoice;console.log("[PWA] Install prompt outcome:",e),U=null,D.style.display="none"}),window.addEventListener("appinstalled",()=>{console.log("[PWA] App installed"),U=null,D.style.display="none"}),window.matchMedia("(display-mode: standalone)").matches&&(D.style.display="none")}function lo(){const a=/iPad|iPhone|iPod/.test(navigator.userAgent),e=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);let t=`To install this app: `;a?(t+=`1. Tap the Share button (square with arrow) `,t+='2. Scroll down and tap "Add to Home Screen"'):e?(t+=`1. Click File menu `,t+='2. Click "Add to Dock"'):(t+=`1. Click the menu button (three dots) `,t+='2. Click "Install" or "Add to Home Screen"'),alert(t)}let xe=null;const Le=new Set;function co(a="#offline-indicator"){xe=typeof a=="string"?document.querySelector(a):a,ge(!navigator.onLine),window.addEventListener("online",()=>{console.log("[PWA] Back online"),ge(!1),$e(!1)}),window.addEventListener("offline",()=>{console.log("[PWA] Gone offline"),ge(!0),$e(!0)})}function ge(a){xe&&(xe.style.display=a?"block":"none"),document.body.classList.toggle("is-offline",a)}function uo(a){return Le.add(a),a(!navigator.onLine),()=>Le.delete(a)}function $e(a){for(const e of Le)try{e(a)}catch(t){console.error("[PWA] Offline listener error:",t)}}function R(){return navigator.onLine}function po(){confirm("A new version is available. Reload now?")&&fo()}function fo(){B?.waiting&&B.waiting.postMessage({type:"SKIP_WAITING"}),window.location.reload()}async function ho(a={}){const{installButton:e="#install-btn",offlineIndicator:t="#offline-indicator",autoRegisterSW:r=!0}=a;r&&await so(),io(e),co(t),console.log("[PWA] Initialized")}const go="https://api.lupmis4luspa.org/api/spatial_planning",yo={district_id:"1",api_token:"1c46538c712e9b5b"};async function X(a,e={},t={}){const r=`${go}/${a}`,o={...yo,...e};console.log("[RemoteDB] POST",r);try{const s=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(o),...t});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);const n=await s.json();return console.log("[RemoteDB] POST response:",a,"→",typeof n=="object"?`${Array.isArray(n)?n.length+" items":"object"}`:n),n}catch(s){throw console.error("[RemoteDB] POST failed:",a,s),s}}async function mo(){return X("get_district_boundary.php")}async function bo(){return X("get_layers.php")}async function wo(){return X("get_all_collector_zone_per_district.php")}async function Eo(){return X("get_parcels_per_district.php")}async function vo(){return X("get_all_footprint_per_district.php")}let g=null,M=null,C="addLocation";async function qe(){console.log("[App] Initializing..."),await ho({installButton:"#install-btn",offlineIndicator:"#offline-indicator",autoRegisterSW:!0}),g=new ao("map",{center:[-1.5,7.5],zoom:7,basemap:"osm"}),M=new no(g.getMap()),M.onMeasureComplete(e=>{console.log("[MapTools] Measurement complete:",e),e.type==="polygon"&&e.coordinate&&g?.showDrawnPolygonPopup(e.feature,e.coordinate)}),g.onClick((e,t,r,o)=>{if(console.log("[MapClick] Clicked at:",e.toFixed(4),t.toFixed(4)),console.log("[MapClick] currentMode =",C),C==="draw"){console.log("[MapClick] In draw mode, Select interaction handles clicks");return}let s=null;if(g.getMap().forEachFeatureAtPixel(o.pixel,n=>{if(n.get("_layerType")==="parcel")return s=n,!0}),s){console.log("[MapClick] Clicked on parcel → Edit Attributes"),g.showParcelEditPopup(s,o.coordinate);return}C==="addLocation"&&(r?(console.log("[MapClick] Clicked on marker:",r.getId()),g.selectMarker(r),xo(r)):(console.log("[MapClick] Empty space → Add Location popup"),g.clearSelection(),g.showAddLocationPopup(o.coordinate)))}),g.onDblClick((e,t,r,o)=>{if(!r)return;const s=r.get("_layerType");if(console.log("[App] Double-click on feature, _layerType:",s||"none"),s==="measure_circle")g.showCircleIntersectionPopup(r,o.coordinate);else{if(s==="measure_circle_radius")return;s==="collector_zone"?g.showInfoPopup(r,o.coordinate,{title:"Zone Info",color:"#7c3aed"}):s==="parcel"?g.showInfoPopup(r,o.coordinate,{title:"Parcel Info",color:"#0ea5e9"}):g.showInfoPopup(r,o.coordinate,{title:"Feature Info",color:"#e11d48"})}}),g.onAddLocation(async e=>{console.log("[App] Add location from map popup:",e);try{const t=await zt(e.name,e.lon,e.lat,{description:e.description||null,category:e.category||"default"});console.log("[App] Location added:",e.name,"id:",t.id),await ye(),g?.zoomTo(e.lon,e.lat,14),t.id&&g?.selectMarker(t.id),Y("Location added successfully")}catch(t){console.error("[App] Failed to add location:",t),I("Failed to add location: "+t.message)}}),g.onParcelEdit(async(e,t)=>{const r=t.id||t.parcelid||t.parcel_id;if(console.log("[App] Parcel edit saved:",r,t),!r){console.warn("[App] No parcel ID found in updated properties — skipping local save");return}try{await Vt(r,t),Y("Parcel updated locally")}catch(o){console.error("[App] Failed to save parcel update:",o),I("Failed to save parcel: "+o.message)}});const a=new bt;g.onDrawnPolygonSave(async(e,t)=>{console.log("[App] Drawn polygon attributes saved:",t);try{const r=a.writeGeometry(e.getGeometry(),{dataProjection:"EPSG:4326",featureProjection:"EPSG:3857"}),o=await Jt(r,t);console.log("[App] New parcel inserted with id:",o.id),Y("New parcel saved (pending verification)")}catch(r){console.error("[App] Failed to save new parcel:",r),I("Failed to save parcel: "+r.message)}});try{console.log("[App] Initializing database..."),await qt(),console.log("[App] Database ready");const e=await Ce();console.log("[App] Database status:",e),await Ro(),g?.initEditBar(),Io(),Oo(),Do(),Fo()}catch(e){console.error("[App] Database initialization failed:",e),I("Failed to initialize database. Please refresh the page.");return}To(),await ye(),$t(e=>{if(console.log("[App] Database change:",e),e.table==="locations"&&!e.local&&ye(),e.table==="parcels"){const t=document.getElementById("local-data-stats");t&&!t.classList.contains("d-none")&<()}}),uo(e=>{e?console.log("[App] Working offline - data will sync when back online"):(console.log("[App] Back online - syncing data..."),No())}),console.log("[App] Initialized successfully")}function To(){console.log("[initUI] Starting UI initialization...");const a=document.getElementById("export-btn");a&&a.addEventListener("click",ko);const e=document.getElementById("local-data-btn");e&&e.addEventListener("click",()=>lt());const t=document.getElementById("exportGeoJSON-btn");t&&t.addEventListener("click",Po);const r=document.getElementById("status-btn");r&&r.addEventListener("click",Co);const o=document.getElementById("fit-btn");o&&o.addEventListener("click",()=>g?.fitToMarkers());const s=document.getElementById("dock-btn-add-location"),n=document.getElementById("dock-btn-measure-circle"),i=document.getElementById("dock-btn-measure-line"),l=document.getElementById("dock-btn-measure-area"),c=document.getElementById("dock-btn-draw"),u=document.getElementById("dock-btn-clear");console.log("[initUI] Buttons found:",{addLocation:!!s,measureCircle:!!n,measureLine:!!i,measureArea:!!l,draw:!!c,clear:!!u});const p=[s,n,i,l,c],d=(f,y)=>{switch(console.log("[setMode] Changing mode from",C,"to",f),C=f,console.log("[setMode] currentMode is now:",C),p.forEach(b=>{b&&b.classList.toggle("active",b===y)}),M?.deactivate(),f!=="draw"&&g?.setEditMode(!1),f!=="addLocation"&&g?.hideAddLocationPopup(),f){case"measureCircle":M?.startCircleMeasure();break;case"measureLine":M?.startLineMeasure();break;case"measureArea":M?.startAreaMeasure();break;case"draw":g?.setEditMode(!0);break}};s&&s.addEventListener("click",()=>{console.log("[Button] Add Location clicked"),d("addLocation",s)}),n&&n.addEventListener("click",()=>{console.log("[Button] Circle clicked, currentMode is:",C),C==="measureCircle"?d("addLocation",s):d("measureCircle",n)}),i&&i.addEventListener("click",()=>{console.log("[Button] Line clicked, currentMode is:",C),C==="measureLine"?d("addLocation",s):d("measureLine",i)}),l&&l.addEventListener("click",()=>{console.log("[Button] Area clicked, currentMode is:",C),C==="measureArea"?d("addLocation",s):d("measureArea",l)}),c&&c.addEventListener("click",()=>{console.log("[Button] Draw clicked, currentMode is:",C),C==="draw"?d("addLocation",s):d("draw",c)}),u&&u.addEventListener("click",()=>{if(M?.clearMeasurements(),C.startsWith("measure"))switch(M?.deactivate(),C){case"measureCircle":M?.startCircleMeasure();break;case"measureLine":M?.startLineMeasure();break;case"measureArea":M?.startAreaMeasure();break}})}async function ye(){try{console.log("[App] Loading locations...");const a=await nt();console.log("[App] Locations loaded:",a),Lo(a),g&&(g.clearMarkers(),a.length>0&&(g.addMarkers(a),console.log("[App] Added",a.length,"markers to map")));const e=document.getElementById("location-count");e&&(e.textContent=a.length)}catch(a){console.error("[App] Failed to load locations:",a)}}function xo(a){const e=a.get("name"),t=a.get("description"),r=a.get("category"),o=a.get("lon")||a.get("longitude"),s=a.get("lat")||a.get("latitude");console.log("[App] Selected location:",{name:e,description:t,category:r,lon:o,lat:s})}function Lo(a){const e=document.getElementById("locations-list");if(!e)return;const t=document.getElementById("location-count-mobile");if(t&&(t.textContent=a.length),a.length===0){e.innerHTML=`

No locations yet.

Click the map or fill the form above!
`;return}const r={water:"💧",school:"🏫",health:"🏥",market:"🏪",default:"📍",other:"📌"};e.innerHTML=a.map(o=>{const s=r[o.category]||"📍";return`
${s} ${$(o.name)}
${o.latitude.toFixed(5)}, ${o.longitude.toFixed(5)}
${o.category}
${o.description?`${$(o.description)}`:""}
`}).join(""),e.querySelectorAll(".location-item").forEach(o=>{o.addEventListener("click",s=>{s.preventDefault();const n=parseFloat(o.dataset.lon),i=parseFloat(o.dataset.lat),l=parseInt(o.dataset.id);g?.zoomTo(n,i,14),g?.selectMarker(l)})})}async function lt(){const a=document.getElementById("local-data-stats"),e=document.getElementById("local-data-tbody");if(!(!a||!e))try{const t=await to();e.innerHTML=t.map(r=>` ${$(r.name)} ${r.count} `).join(""),a.classList.remove("d-none"),e.querySelectorAll(".table-name-link").forEach(r=>{r.addEventListener("click",o=>{o.preventDefault(),So(r.dataset.table)})})}catch(t){console.error("[App] Failed to load table stats:",t),e.innerHTML='Failed to load',a.classList.remove("d-none")}}async function So(a){const e=document.getElementById("tableContentModalLabel"),t=document.getElementById("table-content-body"),r=document.getElementById("table-content-info");e.textContent=`Table: ${a}`,t.innerHTML=`
Loading...
`,r.textContent="",new Ke(document.getElementById("tableContentModal")).show();try{const{columns:s,rows:n}=await oo(a);if(n.length===0){t.innerHTML='
Table is empty
',r.textContent="0 rows";return}const i=s.map(c=>`${$(c)}`).join(""),l=n.map(c=>`${s.map(p=>{let d=c[p];if(d==null)return'NULL';d=String(d);const f=d.length>120?d.substring(0,120)+"...":d;return`${$(f)}`}).join("")}`).join("");t.innerHTML=`
${i}${l}
`,r.textContent=`${n.length}${n.length>=200?"+":""} row(s), ${s.length} column(s)`}catch(s){console.error("[App] Failed to load table content:",s),t.innerHTML=`
Failed to load: ${$(s.message)}
`}}async function ko(){try{await Zt("lupmis-backup.sqlite3"),Y("Database exported successfully")}catch(a){console.error("[App] Export failed:",a),I("Export failed: "+a.message)}}async function Po(){try{const a=await eo(),e=new Blob([JSON.stringify(a,null,2)],{type:"application/json"}),t=URL.createObjectURL(e),r=document.createElement("a");r.href=t,r.download="locations.geojson",r.click(),URL.revokeObjectURL(t),Y(`Exported ${a.features.length} location(s)`)}catch(a){console.error("[App] GeoJSON Export failed:",a),I("GeoJSON Export failed: "+a.message)}}async function Co(){try{const a=await Ce(),e=document.getElementById("status-content");e&&(e.innerHTML=`
Ready: ${a.ready?"Yes":"No"}
Online: ${R()?"Yes":"Offline"}
Database: ${a.databasePath||"N/A"}
Tables: ${a.tables.map(r=>`${r}`).join("")}
Locations: ${a.locationCount}
`),new Ke(document.getElementById("statusModal")).show()}catch(a){console.error("[App] Failed to get status:",a),I("Failed to get status")}}function ct(a){return a.replace(/^\(+/,"").replace(/\)+$/,"").split(",").map(e=>{const[t,r]=e.trim().split(/\s+/).map(Number);return[t,r]})}function _o(a){return{type:"Polygon",coordinates:a.trim().replace(/^POLYGON\s*\(\s*/i,"").replace(/\s*\)$/,"").split("),(").map(ct)}}function Ao(a){return{type:"MultiPolygon",coordinates:a.trim().replace(/^MULTIPOLYGON\s*\(\s*/i,"").replace(/\s*\)$/,"").split(")),((").map(o=>o.replace(/^\(+/,"").replace(/\)+$/,"").split("),(").map(ct))}}function ue(a){if(!a)return null;const e=a.trim().toUpperCase();return e.startsWith("MULTIPOLYGON")?Ao(a):e.startsWith("POLYGON")?_o(a):(console.warn("[App] Unsupported WKT type:",e.substring(0,30)),null)}function Mo(a){if(!a?.success||!a?.data?.boundary)return console.warn("[App] API response missing success or boundary data"),null;const{boundary:e,districtid:t,district_name:r}=a.data,o=ue(e);return{type:"FeatureCollection",features:[{type:"Feature",properties:{districtid:t,district_name:r},geometry:o}]}}function ze(a){if(!Array.isArray(a)||a.length===0)return null;const e=[];for(const t of a){const r=t.polygon||t.boundary,o=ue(r);if(!o)continue;const s={_layerType:"collector_zone"};for(const[n,i]of Object.entries(t))n==="polygon"||n==="boundary"||(s[n]=i);e.push({type:"Feature",properties:s,geometry:o})}return e.length===0?null:{type:"FeatureCollection",features:e}}async function Io(){const a="district_boundary",t={strokeColor:"#e11d48",strokeWidth:2.5,fillColor:"rgba(225,29,72,0.08)"},r=g?.getLayerGroup(1)||null;function o(n){if(!n)return;const i=n.getLayers(),l=[];i.forEach(c=>{c.get("title")==="District Boundary"&&l.push(c)}),l.forEach(c=>i.remove(c))}function s(n){if(!n||!g)return;const i=n.getSource().getExtent();i&&i[0]!==1/0&&g.getMap().getView().fit(i,{padding:[40,40,40,40],duration:600})}try{const n=await it(a);if(n){console.log("[App] District boundary loaded from local cache");const i=g?.addGeoJSONLayer(n,"District Boundary",t,r);s(i)}if(R()){console.log("[App] Fetching district boundary from API...");const i=await mo(),l=Mo(i);if(!l){console.warn("[App] Could not convert API response to GeoJSON");return}console.log("[App] District boundary:",l.features[0]?.properties?.district_name,"→",l.features[0]?.geometry?.coordinates?.length,"polygon(s)"),await st(a,l),n&&o(r||g?.getOverlayGroup());const c=g?.addGeoJSONLayer(l,"District Boundary",t,r);s(c),console.log("[App] District boundary loaded from API")}else n||console.log("[App] District boundary not available — offline and no local cache")}catch(n){console.error("[App] Failed to load district boundary:",n)}}async function Oo(){const e={strokeColor:"#7c3aed",strokeWidth:1.5,fillColor:"rgba(124,58,237,0.12)"},t=g?.getLayerGroup(1)||null;console.log("[App] loadCollectorZones — adminGroup:",t?t.get("title"):"null");const r={type:"FeatureCollection",features:[]},o=g?.addGeoJSONLayer(r,"Zones",e,t);if(!o){console.warn("[App] Could not create Zones layer");return}o.setVisible(!1),o.on("change:visible",()=>{o.getVisible()&&o.getSource().getFeatures().length===0&&I("No collector zones available locally. Connect to the internet to download zone data.")});function s(n){const i=new ce().readFeatures(n,{featureProjection:"EPSG:3857"});o.getSource().clear(),o.getSource().addFeatures(i)}try{const n=await Kt();if(n){const i=ze(n);i&&(console.log("[App] Collector zones loaded from local cache:",i.features.length,"zones"),s(i))}if(R()){console.log("[App] Fetching collector zones from API...");const i=await wo();if(!i?.success||!Array.isArray(i?.data)){console.warn("[App] getCollectorZones API response invalid:",i);return}const l=i.data;console.log("[App] Collector zones from API:",l.length,"entries"),await Ut(l);const c=ze(l);if(!c){console.warn("[App] Could not convert zones to GeoJSON");return}s(c),console.log("[App] Collector zones updated from API:",c.features.length,"zones")}else n||console.log("[App] Collector zones not available — offline and no local cache")}catch(n){console.error("[App] Failed to load collector zones:",n)}}function Ge(a){if(!Array.isArray(a)||a.length===0)return null;const e=[];for(const t of a){const r=t.polygon||t.boundary||t.geom||t.wkt,o=ue(r);if(!o)continue;const s={_layerType:"parcel"};for(const[n,i]of Object.entries(t))n==="polygon"||n==="boundary"||n==="geom"||n==="wkt"||(s[n]=i);e.push({type:"Feature",properties:s,geometry:o})}return e.length===0?null:{type:"FeatureCollection",features:e}}async function Do(){const e={strokeColor:"#0ea5e9",strokeWidth:1.5,fillColor:"rgba(14,165,233,0.12)"},t=g?.getLayerGroup(4)||null;console.log("[App] loadParcels — landUseGroup:",t?t.get("title"):"null");const r={type:"FeatureCollection",features:[]},o=g?.addGeoJSONLayer(r,"Parcels",e,t);if(!o){console.warn("[App] Could not create Parcels layer");return}o.setVisible(!1),o.on("change:visible",()=>{o.getVisible()&&o.getSource().getFeatures().length===0&&I("No parcels available locally. Connect to the internet to download parcel data.")});function s(n){const i=new ce().readFeatures(n,{featureProjection:"EPSG:3857"});o.getSource().clear(),o.getSource().addFeatures(i)}try{const n=await Ht();if(n){const i=Ge(n);i&&(console.log("[App] Parcels loaded from local cache:",i.features.length,"parcels"),s(i))}if(R()){console.log("[App] Fetching parcels from API...");const i=await Eo();if(!i?.success||!Array.isArray(i?.data)){console.warn("[App] getDistrictParcels API response invalid:",i);return}const l=i.data;console.log("[App] Parcels from API:",l.length,"entries"),l.length>0&&console.log("[App] First parcel keys:",Object.keys(l[0])),await Wt(l);const c=Ge(l);if(!c){console.warn("[App] Could not convert parcels to GeoJSON");return}s(c),console.log("[App] Parcels updated from API:",c.features.length,"parcels")}else n||console.log("[App] Parcels not available — offline and no local cache")}catch(n){console.error("[App] Failed to load parcels:",n)}}function Ue(a){if(!Array.isArray(a)||a.length===0)return null;const e=["polygon","boundary","geom","wkt","footprint"],t=[];for(const r of a){const o=r.polygon||r.boundary||r.geom||r.wkt||r.footprint;let s;if(typeof o=="object"&&o!==null&&o.type?s=o:s=ue(o),!s)continue;const n={_layerType:"building_footprint"};for(const[i,l]of Object.entries(r))e.includes(i)||typeof l=="object"&&l!==null||(n[i]=l);t.push({type:"Feature",properties:n,geometry:s})}return t.length===0?null:{type:"FeatureCollection",features:t}}async function Fo(){const e={strokeColor:"#8b6f47",strokeWidth:1,fillColor:"rgba(139,111,71,0.18)"},t=g?.getLayerGroup(5)||null;console.log("[App] loadBuildingFootprints — physInfraGroup:",t?t.get("title"):"null");const r={type:"FeatureCollection",features:[]},o=g?.addGeoJSONLayer(r,"Building footprints",e,t);if(!o){console.warn("[App] Could not create Building footprints layer");return}o.setVisible(!1),o.on("change:visible",()=>{o.getVisible()&&o.getSource().getFeatures().length===0&&I("No building footprints available locally. Connect to the internet to download footprint data.")});function s(n){const i=new ce().readFeatures(n,{featureProjection:"EPSG:3857"});o.getSource().clear(),o.getSource().addFeatures(i)}try{const n=await Yt();if(n){const i=Ue(n);i&&(console.log("[App] Building footprints loaded from local cache:",i.features.length,"footprints"),s(i))}if(R()){console.log("[App] Fetching building footprints from API...");const i=await vo();if(!i?.success||!Array.isArray(i?.data)){console.warn("[App] getBuildingFootprints API response invalid:",i);return}const l=i.data;console.log("[App] Building footprints from API:",l.length,"entries"),l.length>0&&console.log("[App] First footprint keys:",Object.keys(l[0])),await Qt(l);const c=Ue(l);if(!c){console.warn("[App] Could not convert building footprints to GeoJSON");return}s(c),console.log("[App] Building footprints updated from API:",c.features.length,"footprints")}else n||console.log("[App] Building footprints not available — offline and no local cache")}catch(n){console.error("[App] Failed to load building footprints:",n)}}async function Ro(){const a="layer_categories";function e(t){const r=[...t].sort((o,s)=>s.id-o.id);for(const o of r)g?.addLayerGroup(o.id,o.name,o.description||"");console.log("[App] Created",t.length,"layer groups on map")}try{const t=await it(a);if(t&&(console.log("[App] Layer categories loaded from local cache:",t.length,"entries"),e(t)),R()){console.log("[App] Fetching layer categories from API...");const r=await bo();if(!r?.success||!Array.isArray(r?.data)){console.warn("[App] getLayers API response invalid:",r);return}const o=r.data;if(console.log("[App] Layer categories from API:",o.length,"entries"),await st(a,o),t){const s=g?.getOverlayGroup()?.getLayers();if(s){const n=[];s.forEach(i=>{i.get("layerId")!==void 0&&n.push(i)}),n.forEach(i=>s.remove(i))}}e(o),console.log("[App] Layer categories refreshed from API")}else t||console.log("[App] Layer categories not available — offline and no local cache")}catch(t){console.error("[App] Failed to load layer categories:",t)}}async function No(){if(!R()){console.log("[App] Cannot sync - offline");return}console.log("[App] Sync placeholder - implement based on your backend")}function $(a){const e=document.createElement("div");return e.textContent=a,e.innerHTML}function I(a){const e=document.getElementById("error-message");e?(e.querySelector(".message-text").textContent=a,e.classList.remove("d-none"),setTimeout(()=>{e.classList.add("d-none")},5e3)):console.error(a)}function Y(a){const e=document.getElementById("success-message");e?(e.querySelector(".message-text").textContent=a,e.classList.remove("d-none"),setTimeout(()=>{e.classList.add("d-none")},3e3)):console.log(a)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",qe):qe(); //# sourceMappingURL=index-2WHoRhxp.js.map