-- Lua startup file for SMAUG Fuss 
--   Written by Nick Gammon
--   5th July 2007

os.setlocale ("", "time")

-- get directory, file names
systeminfo = mud.system_info ()

-- table of event handlers
-- each module can use table.insert to insert their own handler
handlers = {
    saving = {},        -- saving is special - we only open the file once
    reconnected = {},   -- reconnected is special - first we load player state
    }

function MakeHandler (name)
  return function (...)
    for _, f in ipairs (handlers [name]) do
      f (...)  -- call each handler
    end -- for
  end -- anonymous function
end -- MakeHandler
   
-- install handlers into handlers table AFTER this code
for _, name in ipairs {
  "new_player", 
  "entered_game",
  "speech",
  "entered_room",
  "killed_mob",
  "got_object",
  "lost_object",
  "looking",
  "char_update",
  "act",
  "give",
  "bribe",
  "buy",
  "wear",
  "drop",
  "repair",
  "advance_level",
  "use",
  } do
  _G [name] = MakeHandler (name)  -- make a function handler
  handlers [name] = {}  -- make empty handlers table
end -- for loop

-- we will require from Lua directory
package.path = systeminfo.LUA_DIR .. "?.lua"

require "tprint"
require "serialize"

-- -----------------------------------------------------------------------------
--        Sending functions - leave up here in case modules need them
-- -----------------------------------------------------------------------------

-- send to character, concats multiple arguments, appends cr/newline
function send (...)
  mud.send_to_char (table.concat {...} .. "\n\r")
end -- send

-- formatted send (first argument is 'string.format' style)
function fsend (s, ...)
  mud.send_to_char (string.format (s, ...) .. "\n\r")
end -- send

-- send to character, concats multiple arguments, does not append cr/newline
function send_nocr (...)
  mud.send_to_char (table.concat {...})
end -- send_nocr

-- install other stuff here (like task system)

tasks_module = require "tasks"  -- module
task = tasks_module.task -- command handler

whereis_module = require "whereis" -- module
whereis = whereis_module.whereis  -- command handler

-- standard loading/saving of state file
function get_file_name ()
local charinfo = mud.character_info ()
  return systeminfo.PLAYER_DIR .. 
        string.lower (string.sub (charinfo.name, 1, 1)) .. 
        "/" ..
        charinfo.name ..
        ".lua"
end -- get_file_name

-- called to save a player
function saving ()
local charinfo = mud.character_info ()
local fname = get_file_name ()

   local f = assert (io.open (fname, "w"))
   f:write (os.date ("-- Saved at: %c\n\n"))
   f:write (string.format ("-- Extra save file for %s\n\n", charinfo.name))

   for _, func in ipairs (handlers.saving) do
      func (f)  -- call each handler to write to this file
   end -- for
   
   f:close ()

end -- saving

function reconnected (name)

  local fname = get_file_name ()
  local f = loadfile (fname)
  
  if f then
    f ()  -- execute it
  else
    io.stderr:write ("Warning - no state file: " .. fname)
  end 
   
  for _, func in ipairs (handlers.reconnected) do
    func (name)  -- call each handler to let them know
  end -- for
  
end -- reconnected

-- -----------------------------------------------------------------------------
--         HELPER FUNCTIONS
-- -----------------------------------------------------------------------------

-- trim leading and trailing spaces from a string
function trim (s)
  return (string.gsub (s, "^%s*(.-)%s*$", "%1"))
end -- trim

-- round "up" to absolute value, so we treat negative differently
--  that is, round (-1.5) will return -2
function round (x)
  if x >= 0 then
    return math.floor (x + 0.5)
  end  -- if positive

  return math.ceil (x - 0.5)
end -- function round

function convert_time_helper (secs)

  -- handle negative numbers
  local sign = ""
  if secs < 0 then
    secs = math.abs (secs)
    sign = "-"
  end -- if negative seconds
  
  -- weeks
  if secs >= (60 * 60 * 24 * 6.5) then
    return sign .. round (secs / (60 * 60 * 24 * 7)), "w"
  end -- 6.5 or more days
  
  -- days
  if secs >= (60 * 60 * 23.5) then
    return sign .. round (secs / (60 * 60 * 24)), "d"
  end -- 23.5 or more hours
  
  -- hours
  if secs >= (60 * 59.5) then
   return sign .. round (secs / (60 * 60)), "h"
  end -- 59.5 or more minutes
  
  -- minutes
  if secs >= 59.5 then
   return sign .. round (secs / 60), "m"
  end -- 59.5 or more seconds
  
  -- seconds
  return sign .. round (secs), "s"    
end -- function convert_time_helper

-- eg. 4m
function convert_time (secs)
  local n, u = convert_time_helper (secs)
  return n .. " " .. u 
end -- function convert_time

time_units = {
  w = "week",
  d = "day",
  h = "hour",
  m = "minute",
  s = "second"
  }
  
-- eg. 4 minutes
function convert_time_long (secs)
  local n, u = convert_time_helper (secs)
  local long_units = time_units [u]
  local s = ""
  if math.abs (n) ~= 1 then
    s = "s"
  end -- if not 1
  return n .. " " .. long_units .. s
end -- function convert_time_long

function capitalize (s)
  return string.upper (string.sub (s, 1, 1)) .. string.sub (s, 2)
end -- capitalize 

-- substitutions in descriptions
function fix_description (char_info, s, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  local t = {
    ["$n"] = char_info.name,   -- $n = name
    ["$c"] = string.lower (mud.class ()),  -- $c = class
    ["$r"] = string.lower (mud.race ()),   -- $r = race
    
    -- some way to include a $ symbol
    ["$$"] = "$",
    
    -- argument substitution
    ["$1"] = a1 or "$1",
    ["$2"] = a2 or "$2",
    ["$3"] = a3 or "$3",
    ["$4"] = a4 or "$4",
    ["$5"] = a5 or "$5",
    ["$6"] = a6 or "$6",
    ["$7"] = a7 or "$7",
    ["$8"] = a8 or "$8",
    ["$9"] = a9 or "$9",
    }
    
  return (string.gsub (s, "$[%a%d$]", t))
end -- fix_description

function heading (title, colour)
  local hyphens = math.floor ((76 - #title) / 2)
  send (colour or "&Y", ("-"):rep (hyphens), " ", title, " ", ("-"):rep (hyphens))
end -- heading

-- a line of hyphens
function hyphens ()
  send (("-"):rep (79))
end -- hyphens

