//!wrt $BSPEC:{"icn":"apps/winmp","cpr":"Copyright (C) Windows 96 Team 2023.","dsc":"Windows 96 Multiplayer","frn":"Windows 96 Multiplayer","ver":1,"ssy":"gui"}

const{WindowParams:WindowParams}=w96,{MsgBoxSimple:MsgBoxSimple,Theme:Theme}=w96.ui,{clampNum:clampNum}=w96.util;class Multiplayer96Application extends WApplication{constructor(){super()}async main(t){super.main(t),window._mpactive||(window._mpactive=!0,this._createWindow())}async _createWindow(){this.players={},window._mpactive=!0;var t=new WindowParams;t.title="Windows 96 Multiplayer",t.initialWidth=320,t.initialHeight=270,t.resizable=!0;var e=this.createWindow(t,!0);e.registerWindow(),e.registerAppBar(),e.setHtml('<div>\n        Welcome to Windows 96 Multiplayer. Please enter your server details below (keep this default if you\'re hosting and running the server software locally).\n        <br>\n        <br>\n        <a href="/dl/96mp-v1.0-bin.zip">Download server software</a>\n        </div>\n        <br>\n\n        <span class="bold-noaa">Server IP/Host</span>\n        <input class="w96-textbox ip" type="text" value="ws://127.0.0.1:2020" style="margin-bottom: 12px;">\n\n        <span class="bold-noaa">Nickname (16 chars max)</span>\n        <input class="w96-textbox nick" type="text" value="Anonymouse">\n\n        <span class="status">Status: <span class="bold-noaa">Disconnected</span></span>\n        <div class="bgrp">\n            <button role="host-connect" class="w96-button">Connect as Host</button>\n            <button role="usr-connect" class="w96-button">Connect as User</button>\n            <button role="disconnect" class="w96-button" disabled>Disconnect</button>\n        </div>');const s=e.wndObject.querySelector(".window-html-content");s.classList.add("winmp-app"),this.statusLabel=s.querySelector(".status>.bold-noaa");const i=s.querySelector("input.ip"),o=s.querySelector("input.nick"),n=s.querySelector('button[role="host-connect"]'),r=s.querySelector('button[role="usr-connect"]'),a=s.querySelector('button[role="disconnect"]');this.hostConnectBtn=n,this.userConnectBtn=r,this.disconnectBtn=a,this.nickBox=o,this.hostBox=i,n.onclick=()=>{if(this._nickCheck(o.value)){r.disabled=!0,n.disabled=!0,a.disabled=!0,o.disabled=!0,i.disabled=!0,this.status("Connecting as host...");try{this._createSocket(i.value),this.connectAsHost()}catch(t){this.status(t,"error")}}},r.onclick=()=>{if(this._nickCheck(o.value)){n.disabled=!0,r.disabled=!0,a.disabled=!0,o.disabled=!0,i.disabled=!0,this.status("Connecting...");try{this._createSocket(i.value),this.connectAsUser()}catch(t){this.status(t,"error")}}},a.onclick=()=>this.revertState(),e.onclose=()=>{this.revertState(),this.io&&(this.io.removeAllListeners(),this.io.close(),this.io=null),window._mpactive=!1,this.logArea&&(this.logArea.remove(),this.logArea=null)};const c=document.createElement("div");c.classList.add("wmp-notif"),document.body.appendChild(c),this.logArea=c,e.setWindowIcon(await Theme.getIconUrl("apps/winmp","16x16")),e.show(),e.center()}status(t,e="idle"){this.statusLabel.innerText=t,this.statusLabel.className="bold-noaa "+e}awaitPing(){return new Promise((t=>{const e=setTimeout((()=>t(!1)),1500);this.io.once("_pong",(()=>{t(!0),clearTimeout(e)})),this.io.emit("_ping")}))}connectAsHost(){if(!this.awaitPing())return this.status("Cannot reach server","error"),void this.revertState();this.status("Authenticating..."),this.io.emit("logon",{nick:this.nickBox.value,isHost:!0})}connectAsUser(){if(!this.awaitPing())return this.status("Cannot reach server","error"),void this.revertState();this.status("Authenticating..."),this.io.emit("logon",{nick:this.nickBox.value,isHost:!1})}revertState(){this.hostConnectBtn.disabled=!1,this.userConnectBtn.disabled=!1,this.disconnectBtn.disabled=!0,this.nickBox.disabled=!1,this.hostBox.disabled=!1,this.io&&(this.io.removeAllListeners(),this.io.close(),this.io=null),this.players={},this._usrWindow&&(this._usrWindow.close(),this._usrWindow=null),this.status("Disconnected",""),document.querySelectorAll(".wmp-cursor").forEach((t=>t.remove()))}_createUserWindow(){const t=new WindowParams;t.initialHeight=350,t.initialWidth=400,t.title="96 Multiplayer Control Window",t.resizable=!0,t.draggable=!0,this._usrWindow=this.createWindow(t,!1),this._usrWindow.registerWindow(),this._usrWindow.onclose=()=>this.revertState(),this._usrWindow.setHtml(`<span class="bold-noaa">Server:</span> ${this.hostBox.value}<br><span class="bold-noaa">Nickname:</span> ${this.nickBox.value}<br><br><button class="w96-button" onclick="this.parentElement.requestPointerLock()">Recapture cursor</button>`);const e=this._usrWindow.wndObject.querySelector(".window-html-content");e.classList.add("winmp-usr-window"),e.onclick=()=>{document.pointerLockElement||e.requestPointerLock(),this.io.emit("mouse click")},e.ondblclick=t=>{this.io.emit("mouse dblclick")},e.onmousedown=t=>{this.io.emit("mouse down",t.button)},e.onclick=t=>{this.io.emit("mouse click",t.button)},e.onmouseup=t=>{this.io.emit("mouse up",t.button)},e.onmousemove=t=>{this.io.emit("mouse move",t.movementX,t.movementY,t.button)},this._usrWindow.onshown=()=>{e.requestPointerLock()},this._usrWindow.center(),this._usrWindow.show()}_createSocket(t){this.io&&(this.io.removeAllListeners(),this.io.close(),this.io=null),this.io=io(t),this.io.on("no host",(()=>{MsgBoxSimple.warning("No Host","Please wait for a desktop host to connect first.","OK"),this.status("no host desktop to use as arena.","error"),this.revertState()})),this.io.on("host defined",(()=>{MsgBoxSimple.warning("Already hosted","Somebody is already hosting their desktop.","OK"),this.status("host is already present.","error"),this.revertState()})),this.io.on("welcome user",(t=>{this.disconnectBtn.disabled=!1,this.io.on("disconnect",(()=>{this.status("server closed","error"),this.revertState()})),this.status("Active on "+t.host.nick+"'s desktop.","success"),this._createUserWindow()})),this.io.on("welcome host",(()=>{this.disconnectBtn.disabled=!1,this.io.on("disconnect",(()=>{this.status("server closed","error"),this.revertState()})),this.io.on("player join",(t=>{let e=document.createElement("div");e.classList.add("join-msg"),e.innerText=t.nick+" joined the desktop.",this.logArea.appendChild(e),setTimeout((()=>e.remove()),3e3);const s=document.createElement("div");s.classList.add("wmp-cursor");const i=document.createElement("div");i.classList.add("image"),s.appendChild(i);const o=document.createElement("div");o.classList.add("nick"),o.innerText=t.nick,o.style.backgroundColor="#"+Math.floor(16777215*Math.random()).toString(16),s.appendChild(o),document.body.appendChild(s),this.players[t.id]={id:t.id,nick:t.nick,cursor:s}})),this.io.on("player leave",(t=>{let e=document.createElement("div");e.classList.add("leave-msg"),e.innerText=t.nick+" left the desktop.",this.logArea.appendChild(e),setTimeout((()=>e.remove()),3e3),this.players[t.id].cursor.remove(),this.players[t.id]=null}));let t=document.body;this.io.on("mouse move",((e,s,i,o)=>{const n=clampNum(0,window.innerWidth,this.players[o].cursor.offsetLeft+e),r=clampNum(0,window.innerHeight,this.players[o].cursor.offsetTop+s);this.players[o].cursor.style.left=n+"px",this.players[o].cursor.style.top=r+"px";const a=document.elementFromPoint(n,r);if(t!=a){let e=new MouseEvent("mouseleave",{view:window,bubbles:!0,cancelable:!0,button:i,x:n,y:r,clientX:n,clientY:r});t&&t.dispatchEvent(e),t=a;let s=new MouseEvent("mouseenter",{view:window,bubbles:!0,cancelable:!0,x:n,y:r,clientX:n,clientY:r});a&&a.dispatchEvent(s)}})),this.io.on("mouse dblclick",(t=>{const e=this.players[t].cursor.offsetLeft,s=this.players[t].cursor.offsetTop;var i=new MouseEvent("dblclick",{view:window,bubbles:!0,cancelable:!0,x:e,y:s,clientX:e,clientY:s});const o=document.elementFromPoint(e,s);o&&o.dispatchEvent(i)})),this.io.on("mouse down",((t,e)=>{const s=this.players[t].cursor.offsetLeft,i=this.players[t].cursor.offsetTop,o=document.elementFromPoint(s,i);var n=new MouseEvent("mousedown",{view:window,bubbles:!0,cancelable:!0,button:e,x:s,y:i,clientX:s,clientY:i});o&&o.dispatchEvent(n),document.activeElement!=o&&o.focus()})),this.io.on("mouse up",((t,e)=>{const s=this.players[t].cursor.offsetLeft,i=this.players[t].cursor.offsetTop,o=document.elementFromPoint(s,i);var n=new MouseEvent("mouseup",{view:window,bubbles:!0,cancelable:!0,button:e,x:s,y:i,clientX:s,clientY:i});o&&o.dispatchEvent(n)})),this.io.on("mouse click",((t,e)=>{const s=this.players[t].cursor.offsetLeft,i=this.players[t].cursor.offsetTop,o=document.elementFromPoint(s,i);var n=new MouseEvent("click",{view:window,bubbles:!0,cancelable:!0,button:e,x:s,y:i,clientX:s,clientY:i});o&&o.dispatchEvent(n)})),this.status("Server active - you are hosting","success")}))}_nickCheck(t){return t.length>16?(MsgBoxSimple.warning("Nickname Error","Your nickname must not be longer than 16 characters!","OK"),!1):t.length<1?(MsgBoxSimple.warning("Nickname Error","Please enter a nickname.","OK"),!1):""!=t.trim()||(MsgBoxSimple.warning("Nickname Error","Your nickname must not be empty!","OK"),!1)}}

return await WApplication.execAsync(new Multiplayer96Application(), this.boxedEnv.args, this);