text: const Express = require("express");
  const ejs = require("ejs");
  const path = require("path");
  const THREE = require("three");
  const { json } = require("express");
  const { stringify } = require("querystring");
  const { log } = require("console");
  const app = Express();
  const server = require('http').createServer(app);
  const escape = require('escape-html');
  
  
  const io = require('socket.io')(server, {
      cors: {
          origin: "http://localhost:3000",
      },
  });
  const port = 3000;
  
  //Template Engine
  app.set('view engine', 'ejs');
  
  //middleware && static files
  app.use(Express.static(__dirname + '/public'));
  app.use(Express.static(__dirname + '/node_modules/three'));
  app.use(Express.static(__dirname + '/node_modules/prng'));
  
  //socket IO
  function socketEvents() {
  
      io.once('connection', client => {
          let isAuth = false;
          let hostClient;
          let roomID;
          let seed;
          let id;
  
          client.on("createRoom", (data) => {
              let customE = ['A', 'B', 'C', 'D', 'E', 'F', 'Q', 'LOL', 'HA', 'COOL', 'R']
              let username = escape(data.username_.trim()).substring(0, 16);
              let roomId = escape(data.roomId_.trim()).substring(0, 16);
              let seed_ = escape(data.seed_);
              id = client.id
              if (seed_ == '') {
  
                  seed_ = Math.floor(Math.random() * 1020100) + customE[Math.floor(Math.random() * customE.length)] + customE[Math.floor(Math.random() * customE.length)];
              }
              seed = seed_;
              let password = escape(data.password_);
  
              if (username == null || username == "" || roomId == "" || roomId == null || username.length < 3 || roomId.length < 3) {
                  return;
              }
  
              //check if room exists
              if (io.sockets.adapter.rooms.get(roomId) == null) {
                  //empty room, first user to connect is host
                  hostClient = client
                  isAuth = true
                  roomID = roomId
              } else {
                  //room exists throw error
                  client.emit("errorRoomExists");
                  return;
  
              }
  
              client.username = username;
              client.password = password;
              client.usercolorid = Math.floor(Math.random() * 5);
              client.usercolor = getColornameByID(client.usercolorid);
              client.join(roomId);
              client.emit("joinLobby", { "username": client.username, "usercolor": client.usercolor, "roomname": roomID });
          })
  
          client.on("joinRoom", (data) => {
              let username = escape(data.username_.trim()).substring(0, 16);
              let roomId = escape(data.roomId_.trim()).substring(0, 16);
              roomID = roomId;
              id = client.id
              let password = escape(data.password_)
              client.password = "";
              if (io.sockets.adapter.rooms.get(roomId) == null) {
                  client.emit("errorRoomDoesntExist");
                  return;
              } else {
                  const clients = io.sockets.adapter.rooms.get(roomId);
  
                  let count = 0;
                  for (const clientId of clients) {
                      const clientSocket = io.sockets.sockets.get(clientId);
  
                      if (count == 0) {
                          count++;
                          if (clientSocket.password != "") {
                              if (password != clientSocket.password) {
                                  client.emit("errorPassword");
                                  return;
                              } else {
                                  client.password = clientSocket.password;
                              }
                          }
                      }
  
                      if (clientSocket.username == username) {
                          client.emit("errorUsernameExists");
                          return;
                      }
                  }
              }
  
              //no pw needed join
              //everything ok
              let aviableColorIds = getValidColorIds(roomId);
              client.username = username;
              client.usercolorid = aviableColorIds[Math.floor(Math.random() * aviableColorIds.length)];
              client.usercolor = getColornameByID(client.usercolorid);
              client.join(roomId);
              client.emit("joinLobby", { "username": client.username, "usercolor": client.usercolor, "roomname": roomID });
  
          })
  
          client.on("loadPlayers", data => {
              const clients = io.sockets.adapter.rooms.get(roomID);
  
              allClients = []
  
              for (const clientId of clients) {
                  const clientSocket = io.sockets.sockets.get(clientId);
  
                  allClients.push({ "clientId": clientSocket.id, "username": clientSocket.username, "usercolor": clientSocket.usercolor })
              }
  
              client.emit("loadPlayers", allClients);
          })
  
          client.on("joinedLobbyPreList", data => {
              let usersInfo = []
              const clients = io.sockets.adapter.rooms.get(roomID);
  
              if (clients != null) {
                  for (const clientId of clients) {
                      const clientSocket = io.sockets.sockets.get(clientId);
                      usersInfo.push({ "username": clientSocket.username, "usercolor": clientSocket.usercolor })
                  }
              } else {
                  usersInfo.push({ "username": client.username, "usercolor": client.usercolor })
              }
  
              io.to(roomID).emit("joinLobbyList", { "users": usersInfo })
          })
  
          client.on("lobbyMessage", (data) => {
              let msg = escape(data.msg.trim()).substring(0, 32);
              if (msg.length <= 1) return
              io.to(roomID).emit("lobbyMessage", { "sys": false, "msg": msg, "username": client.username, "usercolor": client.usercolor });
          })
  
          client.on("lobbyJoinMsg", data => {
              let msg = `User ${data.username} joined the lobby`
              io.to(roomID).emit("lobbyMessage", { "sys": true, "msg": msg });
          })
  
          let timerRunning = false;
  
          let intervalTimer
          client.on("startLobbyTimer", data => {
              let timeCounter = 10;
              let initCounter = 10;
              if (data.timer > 0) {
                  timeCounter = data.timer
                  initCounter = data.timer
              }
  
              if (isAuth) {
                  if (!timerRunning) {
                      //start timer
                      timerRunning = true;
                      io.to(roomID).emit("lobbyMessage", { "sys": true, "msg": "Game is starting soon!" });
                      intervalTimer = setInterval(() => {
                          if (timeCounter <= 5) {
                              io.to(roomID).emit("lobbyMessage", { "sys": true, "msg": "Game Starts in: " + timeCounter });
                          }
                          if (timeCounter <= 0) {
                              //start game
                              clearInterval(intervalTimer);
                              io.to(roomID).emit("joinGame", seed);
                          }
                          timeCounter--;
                      }, 1000);
                  } else {
                      //stop timer
                      clearInterval(intervalTimer);
                      timerRunning = false;
                      timeCounter = initCounter;
                  }
              }
          })
  
          client.on("placeBlock", (position) => {
              if (isAuth) {
                  console.log('server Client');
              }
              io.to(roomID).emit("placeBlock", position);
          })
  
          client.on('disconnect', () => {
              if (isAuth) {
                  disconnectRoom(roomID);
              }
              client.disconnect();
          });
  
          client.on("sendchatmessage", (message) => {
              let msg = escape(message.trim()).substring(0, 64);
              io.to(roomID).emit("receivechatmessage", { "msg": msg, "sender": client.id });
          })
  
      });
  }
  
  async function disconnectRoom(roomId) {
      const sockets = await io.in(roomId).fetchSockets();
      sockets.forEach(element => {
          data = null;
          element.emit('gameclosed', data);
          setTimeout(() => {
              element.leave(roomId);
          }, 50);
      });
  }
  
  function getValidColorIds(roomId) {
      colorIds = [0, 1, 2, 3, 4, 5]
      let filteredAry = []
      const clients = io.sockets.adapter.rooms.get(roomId);
  
      for (const clientId of clients) {
          const clientSocket = io.sockets.sockets.get(clientId);
          filteredAry = colorIds.filter(function(e) { return e !== clientSocket.usercolorid })
      }
  
      return filteredAry;
  }
  
  function getColornameByID(id) {
      switch (id) {
          case 0:
              return "green";
              break;
          case 1:
              return "yellow";
              break;
          case 2:
              return "blue";
              break;
          case 3:
              return "red";
              break;
          case 4:
              return "purple";
              break;
          case 5:
              return "pink";
              break;
  
          default:
              return "white";
              break;
      }
  }
  
  //Home
  app.get('/', (req, res, next) => {
      socketEvents()
      res.render('index');
  });
  
  //Error page
  app.use((req, res) => {
      const data = {
  
      }
      res.status(404).render('error', data);
  });
  
  
  server.listen(port);