Event class

Zig Zichterman [03-04-16 - 20:47]
Event class
Filename
GuildGoldDeposits.lua
diff --git a/GuildGoldDeposits.lua b/GuildGoldDeposits.lua
index 2473940..40af458 100644
--- a/GuildGoldDeposits.lua
+++ b/GuildGoldDeposits.lua
@@ -21,6 +21,10 @@ GuildGoldDeposits.retry_ct   = { 0, 0, 0, 0, 0 }
 GuildGoldDeposits.max_retry_ct = 3
 GuildGoldDeposits.max_day_ct = 30 -- how many days to store in SavedVariables

+                        -- Latches true when responding to the very first
+                        -- "Save Data Now" event so that we don't spin forever.
+GuildGoldDeposits.debug_brakes = false
+
 local TIMESTAMPS_CLOSE_SECS = 10

 -- Indices into the 3-element "event" split.
@@ -28,6 +32,69 @@ local I_TIMESTAMP = 1
 local I_AMOUNT    = 2
 local I_USER      = 3

+-- Event ---------------------------------------------------------------------
+-- One row in our savedVariables history
+--
+-- Knows how to convert to/from string
+-- Knows how to convert from GetGuildEventInfo().
+-- Named fields instead of table indices.
+--
+local Event = {}
+
+-- If this is a gold deposit, return a row. If not, return nil.
+function Event:FromInfo(event_type, since_secs, user, amount)
+    if event_type ~= GUILD_EVENT_BANKGOLD_ADDED then return nil end
+    o = { time   = GetTimeStamp() - since_secs
+        , user   = user
+        , amount = amount
+        }
+    setmetatable(o, self)
+    self.__index = self
+    return o
+end
+
+function Event:FromString(str)
+    ts, amt, user = GuildGoldDeposits:split(str)
+    o = { time   = ts
+        , amount = amt
+        , user   = user
+        }
+    setmetatable(o, self)
+    self.__index = self
+    return o
+end
+
+function Event:ToString()
+                        -- tab-delimited fields
+                        -- date     seconds since the epoch
+                        -- amount
+                        -- user     unquoted, can contain all sorts of
+                        --          noise but unlikely to contian a
+                        --          tab character.
+                        --
+                        -- using tostring() here so that this function can work
+                        -- when debugging nil event elements.
+    return tostring(self.time)
+            .. '\t' .. tostring(self.amount)
+            .. '\t' .. tostring(self.user)
+end
+
+-- Do these events "match"?
+--
+-- User and amount must be exact.
+-- Time must be within N seconds.
+function Event.Match(a, b)
+    -- d("em f=" .. a:ToString())
+    -- d("em s=" .. b:ToString())
+                        -- ### Eventually this needs to short-circuit
+                        -- ### Leaving it inefficient for now nur zum Debuggen.
+    m1 =  math.abs(a.time - b.time) < TIMESTAMPS_CLOSE_SECS
+    m2 = a.amount == b.amount
+    m3 = a.user   == b.user
+    -- d("em m=" .. tostring(m1) .. " " .. tostring(m2) .. " " .. tostring(m3))
+    return m1 and m2 and m3
+end
+
 -- Init ----------------------------------------------------------------------

 function GuildGoldDeposits.OnAddOnLoaded(event, addonName)
@@ -48,6 +115,17 @@ function GuildGoldDeposits:Initialize()
     EVENT_MANAGER:UnregisterForEvent(self.name, EVENT_ADD_ON_LOADED)
 end

+-- Return false only once.
+-- Avoids infinite invocations.
+function GuildGoldDeposits:BrakesOn()
+    if self.debug_brakes then
+        return true
+    else
+        self.debug_brakes = true
+        return false
+    end
+end
+
 -- UI ------------------------------------------------------------------------

 function GuildGoldDeposits.ref_cb(guild_index)
@@ -294,18 +372,16 @@ end
 -- Now that all data from the ESO server is loaded into the ESO client,
 -- extract gold deposits and write to savedVars.
 function GuildGoldDeposits:ServerDataComplete(guild_index)
+    if self:BrakesOn() then return end
+
     guildId = GetGuildId(guild_index)
     guild_name = self.guild_name[guild_index]
     event_ct = GetNumGuildEvents(guildId, GUILD_HISTORY_BANK)
     --self:SetStatus(guild_index, "scanning events: " .. event_ct .. " ...")
     for i = 1, event_ct do
         t, s, u, a = GetGuildEventInfo(guildId, GUILD_HISTORY_BANK, i)
-        if t == GUILD_EVENT_BANKGOLD_ADDED then
-            event = { type = t
-                    , time = GetTimeStamp() - s
-                    , user = u
-                    , amount = a
-                    }
+        event = Event:FromInfo(t, s, u, a)
+        if event then
             self:RecordEvent(guild_index, event)
         end
     end
@@ -316,8 +392,8 @@ function GuildGoldDeposits:ServerDataComplete(guild_index)
     self:SetStatus(guild_index, "scanned events: " .. event_ct
                    .. "  gold deposits: " .. found_ct)
     self.savedVariables.history[guild_name]
-        = self:MergeHistories( self.event_list[guild_index]
-                             , self.savedVariables.history[guild_name])
+         = self:MergeHistories( self.event_list[guild_index]
+                              , self.savedVariables.history[guild_name])
 end

 function GuildGoldDeposits:RecordEvent(guild_index, event)
@@ -325,7 +401,7 @@ function GuildGoldDeposits:RecordEvent(guild_index, event)
         self.event_list[guild_index] = {}
     end
     t = self.event_list[guild_index]
-    table.insert(t, self:EventToString(event))
+    table.insert(t, event:ToString())
 end

 -- Merging saved and fetched history -----------------------------------------
@@ -336,24 +412,24 @@ function GuildGoldDeposits:MergeHistories(fetched, saved)
     -- Where in "saved" does "fetch" end?

                         -- No saved events? Just use whatever we fecthed.
-    if 0 == #saved then
-        return fetched
-    end
+                        -- If we fetched nothing at all, retain saved
+                        -- unchanged. If nothing saved, return fetch unchanged.
+                        -- Don't even bother to strip older events. Something's
+                        -- probably gone wrong (or the guild has gone very,
+                        -- very, quiet).
+    if 0 == #fetched  then return saved end
+    if 0 == #saved    then return fetched end
+
                         -- Create a short list of the last few fetched events.
                         -- We'll scan saved for these events to match up the
                         -- two lists.
     last_rows = self:LastRows(fetched, 5)
     f_events = {}
     for i,f_row in ipairs(last_rows) do
-        f_event = self:StringToEvent(f_row)
+        f_event = Event:FromString(f_row)
         table.insert(f_events, f_event)
-        d("f_event["..#f_events.."]: " .. f_row)
+        --d("mh f_event["..#f_events.."]: " .. f_event:ToString())
     end
-                        -- If we fetched nothing at all, retain saved
-                        -- unchanged. Don't even bother to strip older events.
-                        -- Something's probably gone wrong (or the guild has
-                        -- gone very, very, quiet).
-    if 0 == #f_events then return fetched end

     s_i_found = self:Find(f_events, saved)
     if not s_i_found then
@@ -373,8 +449,7 @@ end
 -- Return nil if not found.
 function GuildGoldDeposits:Find(f_events, saved)
     if (0 == #f_events) or (0 == #saved) then return nil end
-    --for i = 1,#saved
-    do
+    for i = 1,#saved do
         i=#saved
         if self:PatternMatch(i, f_events, saved) then
             return i - #f_events + 1
@@ -391,13 +466,13 @@ function GuildGoldDeposits:PatternMatch(s_i, f_events, saved)
         s_ii    = s_i - i
         f_ii    = #f_events - i
         s_row   = saved[s_ii]
-        s_event = self:StringToEvent(saved[s_i - i])
+        s_event = Event:FromString(saved[s_i - i])
         f_event = f_events[f_ii]
-        match   = self:EventsMatch(f_event, s_event)
+        match   = Event.Match(f_event, s_event)
         d("pm " ..tostring(match)
             .. " s_i:" .. s_i
             .." i:"..i
-            .." f_ii:"..f_ii.." "..self:EventToString(f_event)
+            .." f_ii:"..f_ii.." "..f_event:ToString()
             .." s_ii:"..s_ii.." "..s_row
             )
         if not match then return false end
@@ -411,26 +486,11 @@ function GuildGoldDeposits:LastRows(list, ct)
     r = {}
     for i = math.min(ct, #list),1,-1 do
         list_i = #list-i+1
-        d("lr list[" .. list_i .."] " ..tostring(list[list_i]))
         table.insert(r, list[list_i])
     end
     return r
 end

--- Do these rows "match"?
---
--- User and amount must be exact.
--- Time must be within N seconds.
-function GuildGoldDeposits:EventsMatch(f_event, s_event)
-    d("f=" .. self:EventToString(f_event))
-    d("s=" .. self:EventToString(s_event))
-    m1 =  math.abs(f_event.time - s_event.time) < TIMESTAMPS_CLOSE_SECS
-    m2 = f_event.amount == s_event.amount
-    m3 = f_event.user   == s_event.user
-    d("m=" .. tostring(m1) .. " " .. tostring(m2) .. " " .. tostring(m3))
-    return m1 and m2 and m3
-end
-
 -- Postamble -----------------------------------------------------------------

 EVENT_MANAGER:RegisterForEvent( GuildGoldDeposits.name