From 74263b252ba3550524d50c53015262614c50d014 Mon Sep 17 00:00:00 2001
From: Nathan Schneider <n@nathanschneider.info>
Date: Sat, 31 Jul 2021 00:00:35 -0600
Subject: [PATCH] Shifting minetest interactions to nested functions

---
 modpol/interactions/interactions.lua          |  43 ++++++-
 .../overrides/interactions/interactions.lua   | 106 +++++++++---------
 2 files changed, 91 insertions(+), 58 deletions(-)

diff --git a/modpol/interactions/interactions.lua b/modpol/interactions/interactions.lua
index 397268b..692f2e0 100644
--- a/modpol/interactions/interactions.lua
+++ b/modpol/interactions/interactions.lua
@@ -95,7 +95,6 @@ function modpol.interactions.org_dashboard(user, org_name)
    process:interact(user)
 end
 
--- ===================================================================
 -- Function: modpol.interactions.message
 -- input: user (string), message (string)
 -- output: prints message to CLI
@@ -103,7 +102,6 @@ function modpol.interactions.message(user, message)
    print(user .. ": " .. message)
 end
 
--- ===================================================================
 -- Function: modpol.interactions.text_query
 -- input: User (string), Query (string), func (function)
 --   func input: user input (string)
@@ -114,12 +112,49 @@ function modpol.interactions.text_query(user, query, func)
    func(answer)
 end
 
--- ===================================================================
+-- Function: dropdown_query
+-- input: user (string), label (string), options (table of strings), func(choice) (function)
+--   func input: choice (string)
+-- output: calls func on choice
+function modpol.interactions.dropdown_query(user, label, options, func)
+   -- set up options
+   local options_display = ""
+   local options_number = 0
+   for k,v in ipairs(options) do
+      options_display = options_display .. k .. ". " ..
+         options[k] .. "\n"
+      options_number = options_number + 1
+   end
+   options_display = options_display .. "Select number:"
+   if options_number == 0 then
+      print("Error: No options given for dropdown")
+      return nil      
+   end
+   -- begin displaying
+   print(user .. ": " .. label)
+   print(options_display)
+   -- read input and produce output
+   local answer
+   answer = io.read()
+   answer = tonumber(answer)
+   if answer then
+      if answer >= 1 and answer <= options_number then
+         print("Selection: " .. options[answer])
+         func(options[answer])
+      else
+         print("Error: Not in dropdown range")
+         return nil
+      end
+   else
+      print("Error: Must be a number")
+      return nil
+   end
+end
+
 -- Function: modpol.binary_poll_user(user, question)
 -- Params: user (string), question (string), func (function)
 --   func input: user input (string: y/n)
 -- Output: Applies "func" to user input
--- presents a yes/no poll to a user, returns answer
 function modpol.interactions.binary_poll_user(user, question, func)
    local query = "Poll for " .. user .. " (y/n): ".. question
    local answer
diff --git a/modpol_minetest/overrides/interactions/interactions.lua b/modpol_minetest/overrides/interactions/interactions.lua
index 175a5bb..0ac4bdc 100644
--- a/modpol_minetest/overrides/interactions/interactions.lua
+++ b/modpol_minetest/overrides/interactions/interactions.lua
@@ -16,10 +16,6 @@ minetest.register_on_leaveplayer(function(player)
     _contexts[player:get_player_name()] = nil
 end)
 
--- table of formspec field responses
-local formspec_fields = {}
-
-
 -- UTILITIES
 -- =========
 
@@ -38,7 +34,6 @@ local function formspec_list(array)
    return table.concat(escaped,",")
 end
 
-
 -- DASHBOARDS
 -- ==========
 
@@ -78,18 +73,19 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
       if formname == "modpol:dashboard" then
          local pname = player:get_player_name()
          if nil then
-         -- buttons first
+            -- buttons first
          elseif fields.test_poll then
-            local func_announce_vote = function(vote)
-               modpol.interacts.message(
-                  pname, pname .. " voted " .. vote)
-            end
-            local func_start_poll = function(input)
-               modpol.interactions.binary_poll_user(
-                  pname, input, func_announce_vote)
-            end
+            -- FOR TESTING PURPOSES ONLY
             modpol.interactions.text_query(
-               pname,"Poll question:",func_start_poll)
+               pname,"Poll question:",
+               function(input)
+                  modpol.interactions.binary_poll_user(
+                     pname, input,
+                     function(vote)
+                        modpol.interacts.message(
+                           pname, pname .. " voted " .. vote)
+                  end)
+            end)
          elseif fields.add_org then
             modpol.interactions.add_org(pname, 1)
          elseif fields.remove_org then
@@ -230,7 +226,7 @@ end)
 -- Function: modpol.interactions.message
 -- input: message (string)
 -- output
-modpol.interactions.message = function(user, message)
+function modpol.interactions.message(user, message)
    minetest.chat_send_player(user, message)
 end
 
@@ -261,8 +257,8 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
          local pname = player:get_player_name()
          local input = fields.input
          minetest.close_formspec(pname, formname)
-         if _contexts[pname]["text_query_func"] then
-            local func = _contexts[pname]["text_query_func"]
+         local func = _contexts[pname]["text_query_func"]
+         if func then
             func(input)
          else
             modpol.interactions.message(pname, "text_query: " .. input)
@@ -272,8 +268,10 @@ end)
 
 
 -- Function: dropdown_query
--- input: user (string), label (string), options (table of strings)
-function modpol.interactions.dropdown_query(user, label, options)
+-- input: user (string), label (string), options (table of strings), func (function)
+--    func input: choice (string)
+-- output: calls func on user choice
+function modpol.interactions.dropdown_query(user, label, options, func)
    -- set up formspec
    local formspec = {
       "formspec_version[4]",
@@ -285,15 +283,24 @@ function modpol.interactions.dropdown_query(user, label, options)
    local formspec_string = table.concat(formspec, "")
    -- present to players
    minetest.show_formspec(user, "modpol:dropdown_query", formspec_string)
+   -- put func in _contexts
+   _contexts[user] = {}
+   _contexts[user]["dropdown_query_func"] = func
 end
 -- receive fields
 minetest.register_on_player_receive_fields(function (player, formname, fields)
       if formname == "modpol:dropdown_query" then
          local pname = player:get_player_name()
-         if _contexts[pname] then
-            _contexts[pname](fields.input)
-         end
+         local choice = fields.input
          minetest.close_formspec(pname, formname)
+         local func = _contexts[pname]["dropdown_query_func"]
+         if not choice then
+            -- no choice, do nothing
+         elseif func then
+            func(choice)
+         else
+            modpol.interactions.message(pname, "dropdown_query: " .. choice)
+         end
       end
 end)
 
@@ -363,47 +370,38 @@ function modpol.interactions.binary_poll_org(initiator, org)
 end
 
 -- Function: modpol.interactions.add_org
--- TESTING PURPOSES. SHOULD BE DEPRICATED
+-- TODO: NEEDS TO BE MADE INTO A REQUEST
 -- input: initator (user string), base_org_id (ID)
 -- output: interaction begins
-function modpol.interactions.add_org(initiator, base_org_id)
-   -- start formspec
-   modpol.interactions.text_query(initiator, "Org name:")
-   -- set user's context to followup function
-   _contexts[initiator] = function(input)
-      if input then
-         local base_org = modpol.orgs.get_org(base_org_id)
-         local result = base_org:add_org(input, initiator)
-         if result then
-            local message = input .. " created"
-            modpol.interactions.message(initiator, message)
-         end
-      end
-      _contexts[initiator] = nil
-      modpol.interactions.dashboard(initiator)
-   end
+function modpol.interactions.add_org(user, base_org_id)
+   modpol.interactions.text_query(
+      user,"Org name:",
+      function(input)
+         local base_org = modpol.orgs.get_org(1)
+         local result = base_org:add_org(input, user)
+         local message = input .. " created"
+         modpol.interactions.message(user, message)
+         modpol.interactions.dashboard(user)
+   end)
 end
 
 -- Function: modpol.interactions.remove_org
+-- TODO: NEEDS TO BE MADE INTO A REQUEST
 -- input: initator (user string)
 -- output: interaction begins
-function modpol.interactions.remove_org(initiator)
+function modpol.interactions.remove_org(user)
    -- start formspec
    local orgs_list = modpol.orgs.list_all()
    local label = "Choose an org to remove:"
-   modpol.interactions.dropdown_query(initiator, label, orgs_list)
-   -- set user's context to followup function
-   _contexts[initiator] = function(input)
-      if input then
-         local target_org = modpol.orgs.get_org(input)
-         local result = target_org:delete()
-         if result then
+   modpol.interactions.dropdown_query(
+      user, label, orgs_list,
+      function(input)
+         if input then
+            local target_org = modpol.orgs.get_org(input)
+            local result = target_org:delete()
             local message = input .. " deleted"
-            modpol.interactions.message(initiator, message)
+            modpol.interactions.message(user, message)
          end
-      end
-      _contexts[initiator] = nil
-      modpol.interactions.dashboard(initiator)
-   end
+         modpol.interactions.dashboard(user)
+   end)
 end
-