class Vector3 {
  constructor(init = {}, ptr = undefined) {
    this._size = 12;
    this._ptr = ptr.buffer || new ArrayBuffer(this._size);
    this._data = new DataView(this._ptr);
    for (const key of Object.keys(init)) {
      this[key] = init[key];
    }
  }
  get x() {
    return this._data.getFloat32(0, true);
  }
  get y() {
    return this._data.getFloat32(4, true);
  }
  get z() {
    return this._data.getFloat32(8, true);
  }
  set x(v) {
    this._data.setFloat32(0, v, true);
  }
  set y(v) {
    this._data.setFloat32(4, v, true);
  }
  set z(v) {
    this._data.setFloat32(8, v, true);
  }
  get bytes() {
    return new Uint8Array(this._ptr);
  }
}

class Camera3D {
  constructor(init = {}, ptr = undefined) {
    this._size = 44;
    this._ptr = ptr.buffer || new ArrayBuffer(this._size);
    this._data = new DataView(this._ptr);
    for (const key of Object.keys(init)) {
      this[key] = init[key];
    }
  }
  get position() {
    return new Vector3({}, new Uint8Array(this._ptr.slice(0, 12)));
  }
  get target() {
    return new Vector3({}, new Uint8Array(this._ptr.slice(12, 24)));
  }
  get up() {
    return new Vector3({}, new Uint8Array(this._ptr.slice(24, 36)));
  }
  get fovy() {
    return this._data.getFloat32(36, true);
  }
  get projection() {
    return this._data.getInt32(40, true);
  }
  set position(v) {
    this._data.set(v.bytes(), 0);
  }
  set target(v) {
    this._data.set(v.bytes(), 12);
  }
  set up(v) {
    this._data.set(v.bytes(), 24);
  }
  set fovy(v) {
    return this._data.setFloat32(36, v, true);
  }
  set projection(v) {
    return this._data.setInt32(40, v, true);
  }
  get bytes() {
    return new Uint8Array(this._ptr);
  }
}

var decoder = new TextDecoder("utf-8");
var port = 8089;
var ws = require("ws");
var wss = new ws.WebSocketServer({ port: port });
console.log("WebSocket server listening on ws://localhost:" + port + "/");
wss.on("connection", function (ws) {
  console.log("Client connected!");
  ws.on("message", function (message, isBinary) {
    if (!isBinary) {
      var text = decoder.decode(new Uint8Array(message).buffer);
      console.log("received TEXT: " + text.length + " characters:");
      console.log('  "' + text + '"');
    } else {
      const camera = new Camera3D({}, new Uint8Array(message));
      console.log(camera.position.x, camera.position.y, camera.position.z);
      console.log(camera.target.x, camera.target.y, camera.target.z);
      console.log(camera.up.x, camera.up.y, camera.up.z);
      console.log(camera.fovy);
      console.log(camera.projection);
      console.log(camera.bytes);

      ws.send(camera.bytes, { binary: true }); // Echo back the received message
    }
  });
});
