--[[ a card consists of a base note, a card type, a creation timestamp, and a list of prompts timestamps are seconds from the Unix epoch ]] local Card = {} Card.__index = Card function Card:new(ctable) local o = { note = "", ct = "bmc", created = os.time(), pr = {} } setmetatable(o, self) for k, v in pairs(ctable) do if o[k] then o[k] = v end end return o end function Card:__tostring() return string.format("\"%s\" (%s), %d (%d)", self.note, self.ct, #self.pr, self.created) end --[[ extracts `Card`s from a record-based deck returns a table of `Card`s ]] function Card:fromrecs(recs, conf) local ret = {} for i, rec in ipairs(recs) do local bn if rec.PromptText then bn = rec.PromptText[1] end if rec.BaseNote then bn = rec.BaseNote[1] end if bn then local cc = Card:new({ note = bn, ct = (rec.CardType or {})[1], created = (rec.Created or {})[1] }) if cc.ct == "bmc" then local m, n = cc.note:find("{[^}]+}") local ctr = 1 while m do table.insert(cc.pr, Prompt:new({ card = cc, ind = m, time = tonumber((rec.LastReview or {})[ctr]), delay = tonumber((rec.LastDelay or {})[ctr]), succ = tonumber((rec.Successes or {})[ctr]), fail = tonumber((rec.Failures or {})[ctr]), ease = tonumber((rec.Ease or {})[ctr]), })) m, n = cc.note:find("{[^}]+}", n) ctr = ctr + 1 end table.insert(ret, cc) elseif cc.ct == "cys" then local m = cc.note:find(";;.") local ctr = 1 local segs = {} while m do table.insert(segs, m + 2) m = cc.note:find(";;.", m + 2) end for i, m in ipairs(segs) do table.insert(cc.pr, Prompt:new({ card = cc, ind = { segs[i == 1 and #segs or i - 1], m }, time = tonumber((rec.LastReview or {})[ctr]), delay = tonumber((rec.LastDelay or {})[ctr]), succ = tonumber((rec.Successes or {})[ctr]), fail = tonumber((rec.Failures or {})[ctr]), ease = tonumber((rec.Ease or {})[ctr]), })) ctr = ctr + 1 end table.insert(ret, cc) elseif cc.ct == "pwc" then local m = cc.note:find(";;") local ctr = 1 local segs = {} while m do table.insert(segs, m + 2) m = cc.note:find(";;", m + 2) end for i, m in ipairs(segs) do local p = cc.note:find(";;", m) or #cc.note local b = cc.note:find("{[^}]+}", m) if b and b < p then for j, n in ipairs(segs) do if i ~= j then table.insert(cc.pr, Prompt:new({ card = cc, ind = { n, m }, time = tonumber((rec.LastReview or {})[ctr]), delay = tonumber((rec.LastDelay or {})[ctr]), succ = tonumber((rec.Successes or {})[ctr]), fail = tonumber((rec.Failures or {})[ctr]), ease = tonumber((rec.Ease or {})[ctr]), })) ctr = ctr + 1 end end end end table.insert(ret, cc) elseif cc.ct == "seq" then local m, n = cc.note:find(";;") local ctr = 1 while m do table.insert(cc.pr, Prompt:new({ card = cc, ind = n + 1, time = tonumber((rec.LastReview or {})[ctr]), delay = tonumber((rec.LastDelay or {})[ctr]), succ = tonumber((rec.Successes or {})[ctr]), fail = tonumber((rec.Failures or {})[ctr]), ease = tonumber((rec.Ease or {})[ctr]), })) m, n = cc.note:find(";;", n) ctr = ctr + 1 end table.insert(ret, cc) else print("error: unsupported card type " .. cc.ct) end end end return ret end --[[ serialises a `Card` to a record returns a table mapping labels to value-lists ]] function Card:torec() local ret = { BaseNote = { self.note }, CardType = { self.ct }, Created = { self.created }, LastReview = {}, LastDelay = {}, Successes = {}, Failures = {}, Ease = {} } for i, pr in ipairs(self.pr) do ret.LastReview[i] = pr.time ret.LastDelay[i] = pr.delay ret.Successes[i] = pr.succ ret.Failures[i] = pr.fail ret.Ease[i] = pr.ease end return ret end return Card