/* pk-hserver.pk - Hyperlinks server Poke infrastructure.  */

/* Copyright (C) 2020, 2021, 2022, 2023, 2024, 2025, 2026 Jose E.
 * Marchesi */

/* This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/* Hostname where the hserver listens for connections.  This variable
   is initialized in pk-hserver.c */
var hserver_hostname = "";

/* Port where the hserver listens for connections.  */
var hserver_port = 0;

/* The hserver maintains a table with tokens.  Each hyperlink uses its
   own unique token, which is included in the payload and checked upon
   connection.  */

var hserver_max_tokens = 128;
var hserver_cur_token = 0U;

type HServer_Callback = ()void;

type HServer_Token =
  struct
  {
    int<32> used_p;
    int<32> id;
    uint<8> kind;
    string cmd;
    HServer_Callback function;
  };

var hserver_tokens = HServer_Token[hserver_max_tokens]();

/* Get the kind of a given token.  */
fun hserver_token_kind = (int<32> token) uint<8>:
{
  var index = token % hserver_max_tokens;
  return hserver_tokens[index].kind;
}

/* Get the command associated with a given token.  */
fun hserver_token_cmd = (int<32> token) string:
{
  var index = token % hserver_max_tokens;
  return hserver_tokens[index].cmd;
}

/* Get the function associated with a given token.  */
fun hserver_token_function = (int<32> token) HServer_Callback:
{
  var index = token % hserver_max_tokens;
  return (hserver_tokens[index].function);
}

/* Determine whether a given token exists.  */
fun hserver_token_p = (int<32> token) int<32>:
{
  var index = token % hserver_max_tokens;
  return hserver_tokens[index].used_p;
}

/* Allocate and get a random token.  */
fun hserver_get_token = uint<32>:
{
  var index = hserver_cur_token % hserver_max_tokens;

  /* Note how tokens expire at some point if the capacity of
     hserver_tokens is exceeded.  */
  hserver_tokens[index].used_p = 1;
  hserver_tokens[index].id = hserver_cur_token;

  return hserver_cur_token++;
}

/* Build a hserver hyperlink.  */

fun hserver_make_hyperlink = (uint<8> kind,
                              string cmd = "",
                              HServer_Callback function = lambda void: {}) string:
{
  if (!(kind in ['i','e','c']))
    raise E_inval;

  var token = hserver_get_token;
  var index = token % hserver_max_tokens;

  hserver_tokens[index].kind = kind;
  hserver_tokens[index].cmd = cmd;
  (hserver_tokens[index].function) = (function);

  return ("app://"
          + hserver_hostname
          + ":"
          + ltos (hserver_port)
          + "/"
          + ltos (token));
}

/* Print an hserver-served hyperlink.  */

fun hserver_print_hl = (uint<8> kind, string str, string cmd,
                        HServer_Callback function = lambda void: {}) void:
{
  var url = hserver_make_hyperlink (kind, cmd, (function));

  term_begin_class ("hyperlink");
  term_begin_hyperlink (url, "");
  print str;
  term_end_hyperlink;
  term_end_class ("hyperlink");
}
