// GridTracker Copyright © 2021 GridTracker.org
// All rights reserved.
// See LICENSE for more information.

var g_gtEngineInterval = null;
var g_chatRecvFunctions = {
  uuid: gtChatSetUUID,
  list: gtChatNewList,
  info: gtChatUpdateCall,
  drop: gtChatRemoveCall,
  mesg: gtChatMessage,
  o: gtSpotMessage
};

var ChatState = Object();
ChatState.none = -1;
ChatState.idle = 0;
ChatState.connect = 1;
ChatState.connecting = 2;
ChatState.connected = 3;
ChatState.status = 4;
ChatState.closed = 5;
ChatState.error = 6;

var g_gtStateToFunction = {
  "-1": gtSetIdle,
  0: gtCanConnect,
  1: gtConnectChat,
  2: gtConnecting,
  3: gtChatSendUUID,
  4: gtStatusCheck,
  5: gtInError,
  6: gtClosedSocket
};

var g_gtChatSocket = null;
var g_gtFlagPins = Object();
var g_gtMessages = Object();
var g_gtUnread = Object();
var g_gtIdToCid = Object();
var g_gtCallsigns = Object();
var g_gtSentAwayToCid = Object();

var g_gtState = ChatState.none;
var g_gtStatusCount = 0;
var g_gtStatusTime = 500;
var g_gtMaxChatMessages = 100;
var g_gtNeedUsersList = true;

var g_gtLiveStatusUpdate = false;

var myChatId = 0;

var myRoom = 0;
var g_gtChatlistChangeCount = 0;
var g_gtCurrentMessageCount = 0;

function gtConnectChat()
{
  if (g_gtChatSocket != null)
  {
    // we should start over
    g_gtState = ChatState.error;
    return;
  }

  var rnd = parseInt(Math.random() * 10) + 18360;
  try
  {
    g_gtState = ChatState.connecting;
    g_gtChatSocket = new WebSocket("ws://oams.space:" + rnd);
  }
  catch (e)
  {
    g_gtState = ChatState.error;
    return;
  }

  g_gtChatSocket.onopen = function ()
  {
    g_gtState = ChatState.connected;
  };

  g_gtChatSocket.onmessage = function (evt)
  {
    if (g_appSettings.gtShareEnable == true)
    {
      var jsmesg = false;
      try
      {
        jsmesg = JSON.parse(evt.data);
      }
      catch (err)
      {
        // bad message, dumping client
        g_gtState = ChatState.error;
        return;
      }
      if (typeof jsmesg.type == "undefined")
      {
        g_gtState = ChatState.error;
        return;
      }

      if (jsmesg.type in g_chatRecvFunctions)
      {
        g_chatRecvFunctions[jsmesg.type](jsmesg);
      }
      else
      {
        g_gtState = ChatState.error;
      }
    }
  };

  g_gtChatSocket.onerror = function ()
  {
    g_gtState = ChatState.error;
  };

  g_gtChatSocket.onclose = function ()
  {
    g_gtState = ChatState.closed;
  };
}

function gtConnecting() {}

function gtInError()
{
  closeGtSocket();
}

function gtChatSendClose()
{
  msg = Object();
  msg.type = "close";
  msg.uuid = g_appSettings.chatUUID;

  sendGtJson(JSON.stringify(msg));
}

function closeGtSocket()
{
  if (g_gtChatSocket != null)
  {
    gtChatSendClose();

    if (g_gtChatSocket.readyState != WebSocket.CLOSED) g_gtChatSocket.close();

    if (g_gtChatSocket.readyState === WebSocket.CLOSED)
    {
      g_gtChatSocket = null;
      g_gtState = ChatState.none;
    }
  }
  else g_gtState = ChatState.none;
}

function gtClosedSocket()
{
  g_gtChatSocket = null;
  g_gtState = ChatState.none;
}

function gtCanConnect()
{
  g_gtState = ChatState.connect;
}

function gtSetIdle()
{
  g_gtStatusCount = 0;
  g_gtNeedUsersList = true;
  g_gtState = ChatState.idle;
  g_lastGtStatus = "";
}

function gtStatusCheck()
{
  if (g_gtStatusCount > 0)
  {
    g_gtStatusCount--;
  }
  if (g_gtStatusCount == 0 || g_gtLiveStatusUpdate == true)
  {
    if (g_gtLiveStatusUpdate == true)
    {
      g_gtLiveStatusUpdate = false;
    }
    else
    {
      g_lastGtStatus = "";
      g_gtStatusCount = g_gtStatusTime;
    }
    gtChatSendStatus();
  }
  if (g_gtNeedUsersList == true)
  {
    g_gtNeedUsersList = false;
    gtChatGetList();
  }
}

function sendGtJson(json)
{
  if (g_gtChatSocket != null)
  {
    if (g_gtChatSocket.readyState === WebSocket.OPEN)
    {
      g_gtChatSocket.send(json);
    }
    else
    {
      if (g_gtChatSocket.readyState === WebSocket.CLOSED)
      {
        g_gtState = ChatState.closed;
      }
    }
  }
  else g_gtState = ChatState.closed;
}

var g_lastGtStatus = "";

function gtChatSendStatus()
{
  var msg = Object();
  msg.type = "status";
  msg.uuid = g_appSettings.chatUUID;

  msg.call = myDEcall;
  msg.grid = myRawGrid;
  msg.freq = myRawFreq;
  msg.mode = myMode;
  msg.band = myBand;
  msg.src = "GT";
  msg.canmsg = g_appSettings.gtMsgEnable == true;
  msg.o = g_appSettings.gtSpotEnable == true ? 1 : 0;
  msg = JSON.stringify(msg);

  if (msg != g_lastGtStatus)
  {
    sendGtJson(msg);
    g_lastGtStatus = msg;
  }
}

function gtChatSendSpots(spotsObject)
{
  var msg = Object();
  msg.type = "o";
  msg.uuid = g_appSettings.chatUUID;
  msg.o = spotsObject;
  msg = JSON.stringify(msg);
  sendGtJson(msg);
}

function gtChatRemoveCall(jsmesg)
{
  var id = jsmesg.id;
  if (id in g_gtIdToCid)
  {
    var cid = g_gtIdToCid[id];
    if (cid in g_gtFlagPins)
    {
      delete g_gtFlagPins[cid].ids[id];
      if (Object.keys(g_gtFlagPins[cid].ids).length == 0)
      {
        if (g_gtFlagPins[cid].pin != null)
        {
          // remove pin from map here
          if (g_layerSources.gtflags.hasFeature(g_gtFlagPins[cid].pin))
          { g_layerSources.gtflags.removeFeature(g_gtFlagPins[cid].pin); }
          delete g_gtFlagPins[cid].pin;
          g_gtFlagPins[cid].pin = null;
        }
        g_gtFlagPins[cid].live = false;
        notifyNoChat(cid);
        if (!(cid in g_gtMessages))
        {
          delete g_gtCallsigns[g_gtFlagPins[cid].call];
          delete g_gtFlagPins[cid];
        }

        updateChatWindow();
      }
    }
    delete g_gtIdToCid[id];
  }
}

function gtChatUpdateCall(jsmesg)
{
  var id = jsmesg.id;
  var cid = jsmesg.cid;

  if (cid in g_gtFlagPins)
  {
    g_gtFlagPins[cid].ids[id] = true;
    // Did they move grid location?
    if (g_gtFlagPins[cid].pin != null)
    {
      // remove pin from map here
      if (g_layerSources.gtflags.hasFeature(g_gtFlagPins[cid].pin))
      { g_layerSources.gtflags.removeFeature(g_gtFlagPins[cid].pin); }
      delete g_gtFlagPins[cid].pin;
      g_gtFlagPins[cid].pin = null;
    }
  }
  else
  {
    g_gtFlagPins[cid] = Object();
    g_gtFlagPins[cid].pin = null;

    g_gtFlagPins[cid].ids = Object();
    g_gtFlagPins[cid].ids[id] = true;
  }
  g_gtIdToCid[jsmesg.id] = jsmesg.cid;

  g_gtFlagPins[cid].cid = jsmesg.cid;
  g_gtFlagPins[cid].call = jsmesg.call;
  g_gtFlagPins[cid].grid = jsmesg.grid;
  g_gtFlagPins[cid].freq = jsmesg.freq;
  g_gtFlagPins[cid].band = jsmesg.band;
  g_gtFlagPins[cid].mode = jsmesg.mode;
  g_gtFlagPins[cid].src = jsmesg.src;
  g_gtFlagPins[cid].canmsg = jsmesg.canmsg;
  g_gtFlagPins[cid].o = jsmesg.o;
  g_gtFlagPins[cid].dxcc = callsignToDxcc(jsmesg.call);
  g_gtFlagPins[cid].live = true;
  // Make a pin here
  if (g_gtFlagPins[cid].pin == null)
  {
    makeGtPin(g_gtFlagPins[cid]);
    if (g_gtFlagPins[cid].pin != null)
    { g_layerSources.gtflags.addFeature(g_gtFlagPins[cid].pin); }
  }
  g_gtChatlistChangeCount++;
  g_gtCallsigns[g_gtFlagPins[cid].call] = cid;
  updateChatWindow();
}

function gtChatGetList()
{
  msg = Object();
  msg.type = "list";
  msg.uuid = g_appSettings.chatUUID;

  sendGtJson(JSON.stringify(msg));
}

function redrawPins()
{
  clearGtFlags();
  for (cid in g_gtFlagPins)
  {
    if (g_gtFlagPins[cid].pin != null)
    {
      delete g_gtFlagPins[cid].pin;
      g_gtFlagPins[cid].pin = null;
    }

    makeGtPin(g_gtFlagPins[cid]);

    if (g_gtFlagPins[cid].pin != null)
    { g_layerSources.gtflags.addFeature(g_gtFlagPins[cid].pin); }
  }
}

function makeGtPin(obj)
{
  try
  {
    if (obj.pin)
    {
      if (g_layerSources.gtflags.hasFeature(obj.pin))
      { g_layerSources.gtflags.removeFeature(obj.pin); }
      delete obj.pin;
      obj.pin = null;
    }

    if (typeof obj.grid == "undefined" || obj.grid == null) return;

    if (obj.grid.length != 4 && obj.grid.length != 6) return;

    if (validateGridFromString(obj.grid, null) == false) return;

    if (
      g_appSettings.gtFlagImgSrc == 2 &&
      (obj.mode != myMode || obj.band != myBand)
    )
    { return; }

    var LL = squareToLatLongAll(obj.grid);
    var myLonLat = [
      LL.lo2 - (LL.lo2 - LL.lo1) / 2,
      LL.la2 - (LL.la2 - LL.la1) / 2
    ];

    obj.pin = iconFeature(ol.proj.fromLonLat(myLonLat), g_gtFlagIcon, 100);
    obj.pin.key = obj.cid;
    obj.pin.isGtFlag = true;
    obj.pin.size = 1;
  }
  catch (e) {}
}

function gtChatNewList(jsmesg)
{
  clearGtFlags();

  for (var cid in g_gtFlagPins)
  {
    g_gtFlagPins[cid].live = false;
    if (!(cid in g_gtMessages))
    {
      delete g_gtFlagPins[cid];
    }
  }

  for (var key in jsmesg.data.calls)
  {
    var cid = jsmesg.data.cid[key];
    var id = jsmesg.data.id[key];
    if (id != myChatId)
    {
      if (cid in g_gtFlagPins)
      {
        g_gtFlagPins[cid].ids[id] = true;
      }
      else
      {
        g_gtFlagPins[cid] = Object();
        g_gtFlagPins[cid].ids = Object();
        g_gtFlagPins[cid].ids[id] = true;
        g_gtFlagPins[cid].pin = null;
      }

      g_gtIdToCid[id] = cid;
      g_gtFlagPins[cid].call = jsmesg.data.calls[key];
      g_gtFlagPins[cid].grid = jsmesg.data.grid[key];
      g_gtFlagPins[cid].freq = jsmesg.data.freq[key];
      g_gtFlagPins[cid].band = jsmesg.data.band[key];
      g_gtFlagPins[cid].mode = jsmesg.data.mode[key];
      g_gtFlagPins[cid].src = jsmesg.data.src[key];
      g_gtFlagPins[cid].cid = cid;
      g_gtFlagPins[cid].canmsg = jsmesg.data.canmsg[key];
      g_gtFlagPins[cid].o = jsmesg.data.o[key];
      g_gtFlagPins[cid].dxcc = callsignToDxcc(g_gtFlagPins[cid].call);
      g_gtFlagPins[cid].live = true;
      g_gtCallsigns[g_gtFlagPins[cid].call] = cid;
      makeGtPin(g_gtFlagPins[cid]);
      if (g_gtFlagPins[cid].pin != null)
      { g_layerSources.gtflags.addFeature(g_gtFlagPins[cid].pin); }
    }
  }
  g_gtChatlistChangeCount++;

  updateChatWindow();
}

function appendToHistory(cid, jsmesg)
{
  if (!(cid in g_gtMessages))
  {
    g_gtMessages[cid] = Object();
    g_gtMessages[cid].history = Array();
  }

  g_gtMessages[cid].history.push(jsmesg);
  while (g_gtMessages[cid].history.length > g_gtMaxChatMessages)
  {
    g_gtMessages[cid].history.shift();
  }
}

function htmlEntities(str)
{
  return String(str)
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");
}

function gtChatMessage(jsmesg)
{
  if (g_appSettings.gtMsgEnable == true)
  {
    var cid = jsmesg.cid;
    jsmesg.when = Date.now();
    try
    {
      jsmesg.msg = new Buffer.from(jsmesg.msg, "base64").toString("utf8"); // eslint-disable-line new-cap
      jsmesg.msg = htmlEntities(jsmesg.msg);
    }
    catch (e)
    {
      jsmesg.msg = "Corrupt message recieved";
    }

    if (jsmesg.call != null && jsmesg.call != "" && jsmesg.call != "NOCALL")
    {
      appendToHistory(cid, jsmesg);
      g_gtUnread[cid] = true;
      g_gtCurrentMessageCount++;

      if (newChatMessage(cid, jsmesg) == false) alertChatMessage();

      if (g_msgSettings.msgAwaySelect == 1 && !(cid in g_gtSentAwayToCid))
      {
        g_gtSentAwayToCid[cid] = true;
        gtSendMessage(
          "Away message [ " + g_msgSettings.msgAwayText + " ]",
          cid
        );
      }
    }
  }
}

function gtSendMessage(message, who)
{
  msg = Object();
  msg.type = "mesg";
  msg.uuid = g_appSettings.chatUUID;
  msg.cid = who;
  msg.msg = new Buffer.from(message).toString("base64"); // eslint-disable-line new-cap
  sendGtJson(JSON.stringify(msg));
  msg.msg = htmlEntities(message);
  msg.id = 0;
  msg.when = Date.now();
  appendToHistory(who, msg);
}

function gtChatSendUUID()
{
  var msg = Object();
  msg.type = "uuid";
  if (g_appSettings.chatUUID != "") msg.uuid = g_appSettings.chatUUID;
  msg.call = myDEcall;
  msg.ver = gtShortVersion;

  sendGtJson(JSON.stringify(msg));
}

function gtChatSetUUID(jsmesg)
{
  g_appSettings.chatUUID = jsmesg.uuid;
  myChatId = jsmesg.id;

  gtChatSendStatus();

  g_gtState = ChatState.status;
}

function gtChatStateMachine()
{
  if (
    g_appSettings.gtShareEnable == true &&
    g_mapSettings.offlineMode == false
  )
  {
    var now = timeNowSec();
    g_gtStateToFunction[g_gtState]();

    if (Object.keys(g_gtUnread).length > 0 && now % 2 == 0)
    {
      msgImg.style.webkitFilter = "invert(1)";
    }
    else msgImg.style.webkitFilter = "";

    if (
      g_msgSettings.msgFrequencySelect > 0 &&
      Object.keys(g_gtUnread).length > 0
    )
    {
      if (now - g_lastChatMsgAlert > g_msgSettings.msgFrequencySelect * 60)
      {
        alertChatMessage();
      }
    }
  }
  else
  {
    closeGtSocket();
    g_gtChatlistChangeCount = 0;
    g_lastGtStatus = "";
  }
}

function gtSpotMessage(jsmesg)
{
  addNewOAMSSpot(jsmesg.cid, jsmesg.db);
}

function gtChatSystemInit()
{
  g_gtEngineInterval = setInterval(gtChatStateMachine, 1000);
}

function showGtFlags()
{
  if (g_appSettings.gtFlagImgSrc > 0)
  {
    if (g_mapSettings.offlineMode == false)
    {
      redrawPins();
      g_layerVectors.gtflags.setVisible(true);
    }
    else
    {
      g_layerVectors.gtflags.setVisible(false);
    }
  }
  else g_layerVectors.gtflags.setVisible(false);
}

function clearGtFlags()
{
  g_layerSources.gtflags.clear();
}

function toggleGtMap()
{
  g_appSettings.gtFlagImgSrc += 1;
  g_appSettings.gtFlagImgSrc %= 3;
  gtFlagImg.src = g_gtFlagImageArray[g_appSettings.gtFlagImgSrc];
  if (g_spotsEnabled == 1 && g_receptionSettings.mergeSpots == false) return;
  if (g_appSettings.gtFlagImgSrc > 0)
  {
    redrawPins();
    g_layerVectors.gtflags.setVisible(true);
  }
  else
  {
    g_layerVectors.gtflags.setVisible(false);
  }
}

function notifyNoChat(id)
{
  if (g_chatWindowHandle != null)
  {
    try
    {
      g_chatWindowHandle.window.notifyNoChat(id);
    }
    catch (e) {}
  }
}

function updateChatWindow()
{
  if (g_chatWindowHandle != null)
  {
    try
    {
      g_chatWindowHandle.window.updateEverything();
    }
    catch (e) {}
  }
}

function newChatMessage(id, jsmesg)
{
  var hasFocus = false;
  if (g_msgSettings.msgActionSelect == 1) showMessaging();

  if (g_chatWindowHandle != null)
  {
    try
    {
      hasFocus = g_chatWindowHandle.window.newChatMessage(id, jsmesg);
    }
    catch (e) {}
    updateChatWindow();
  }
  return hasFocus;
}

var g_lastChatMsgAlert = 0;

function alertChatMessage()
{
  if (g_msgSettings.msgAlertSelect == 1)
  {
    // Text to speech
    speakAlertString(g_msgSettings.msgAlertWord);
  }
  if (g_msgSettings.msgAlertSelect == 2)
  {
    // Audible
    playAlertMediaFile(g_msgSettings.msgAlertMedia);
  }
  g_lastChatMsgAlert = timeNowSec();
}
