### This is an object which tracks the status of the system. ### A timer is an object which keeps track of how long the user has ### spent in a particular class of activity. setOldClass("difftime") setClass("Timer", slots=c(name="character", startTime="POSIXt", totalTime="difftime")) Timer <- function(name) { new("Timer",name=name,startTime=as.POSIXct(NA), totalTime=as.difftime(0,units="secs")) } setMethod("start",c("Timer","POSIXt"), function(timer,time,runningCheck=TRUE) { if (runningCheck && isRunning(timer)) { stop("Timer ",timer@name,"is already running.") } timer@startTime <- as.POSIXct(time) timer}) setMethod("pause",c("Timer","POSIXt"), function(timer,time,runningCheck=TRUE) { if (!isRunning(timer)) { if (runningCheck) stop("Timer ",timer@name,"is not running.") } else { timer@totalTime <- timer@totalTime + as.POSIXct(time) - timer@startTime timer@startTime <- as.POSIXlt(NA) } timer}) setMethod("resume",c("Timer","POSIXt"), function(timer,time) start(timer,time)) setMethod("isRunning","Timer", function(timer) !is.na(timer@startTime) && !is.null(timer@startTime)) setMethod("totalTime","Timer", function(timer) timer@totalTime) setMethod("timeSoFar",c("Timer","POSIXt"), function(timer,time) { if (isRunning(timer)) { timer@totalTime + as.POSIXlt(time) - timer@startTime } else { timer@totalTime }}) setMethod("timeSoFar<-",c("Timer","POSIXt","difftime"), function(timer,time,value) { if (isRunning(timer)) { timer@startTime <- as.POSIXlt(time) } timer@totalTime <- value timer}) setMethod("timeSoFar<-",c("Timer","POSIXt","numeric"), function(timer,time,value) { if (isRunning(timer)) { timer@startTime <- as.POSIXlt(time) } timer@totalTime <- as.difftime(value,units="secs") timer}) setMethod("reset","Timer", function(timer) { timer@startTime <- as.POSIXlt(NA) timer@totalTime <- as.difftime(0,units="secs") timer }) ### ## Serialization. Note timers are not stored directly in database, ## so they don't need IDs setMethod("as.jlist",c("Timer","list"), function(obj,ml, serialize=TRUE) { ml$class <- NULL ## Additional work ml$name <- unbox(ml$name) ml$startTime <- unboxer(ml$startTime) ml$totalTime <- list(time=unboxer(as.numeric(ml$totalTime)), units=unboxer(units(ml$totalTime))) ml }) parseTimer <- function (rec) { if (is.null(rec$totalTime)) { tt <- as.difftime(NA_real_,units="secs") } else { tstring <- rec$totalTime[[pmatch("tim",names(rec$totalTime))]] if (is.null(tstring) || tstring=="NA") tim <- NA_real_ else tim <- as.numeric(tstring) units <- as.character(rec$totalTime$units) tt <- as.difftime(tim,units=units) } if (length(rec$startTime)==0L || is.na(rec$startTime) || (is.character(rec$startTime) && rec$startTime=="NA")) { st <- as.POSIXlt(NA) } else { if (is.list(rec$startTime) && !is.null(rec$startTime[['$date']])) { st <- jsonlite:::parse_date(rec$startTime[['$date']]) } else { st <- as.POSIXlt(ununboxer(rec$startTime)) } } new("Timer",name=ununboxer(rec$name), startTime=st, totalTime=tt) } ############################################################ ### Status -- Maintains state for one user in one context. setClass("Status", slots=c("_id"="character", app="character", uid="character", context="character", oldContext="character", timers="list", flags="list", observables="list", timestamp="POSIXt")) Status <- function (uid,context,timerNames=character(), flags=list(),observables=list(),timestamp=Sys.time(), app="default") { timers <- sapply(timerNames, Timer) new("Status",app=app,uid=uid,context=context,oldContext=context, timers=timers, flags=flags,observables=observables,timestamp=timestamp, "_id"=c(oid=NA_character_)) } setMethod("uid","Status", function(x) x@uid) setMethod("context","Status", function(x) x@context) setMethod("context<-","Status", function(x,value){ x@context <- value x }) setMethod("oldContext","Status", function(x) x@oldContext) setMethod("app","Status", function(x) x@app) setMethod("timestamp","Status", function(x) x@timestamp) setMethod("timer","Status", function(x,name) x@timers[[name]]) setMethod("timer<-","Status", function(x,name,value) { if (!is.null(value) && !is(value,"Timer")) { stop("Attempting to set timer ",name," to non-timer object") } x@timers[[name]] <- value x }) setMethod("setTimer",c("Status","character"), function(x,timerID,time,running,now) { fieldlist <- splitfield(timerID) if (fieldlist[1] != "state" || fieldlist[2] !="timers") stop ("Can only !start and !reset timers: ",timerID) name <- fieldlist[3] if (is.null(timer(x,name))) { timer(x,name) <- Timer(name) } timerTime(x,name,now) <- time timerRunning(x,name,now) <- running x }) setMethod("timerTime",c("Status","character"), function(x,name,now) { if (is.null(x@timers[[name]])) { stop("Did not find a timer named ",name) } tim <- timeSoFar(x@timers[[name]],now) units(tim) <- "secs" tim }) setMethod("timerTime<-", c("Status","character"), function(x,name,now,value){ timeSoFar(timer(x,name),now)<-value x}) setMethod("timerRunning", c("Status","character"), function(x,name,now) { isRunning(timer(x,name)) }) setMethod("timerRunning<-", c("Status","character"), function(x,name,now,value) { if (value == TRUE) { timer(x,name) <- start(timer(x,name),now,FALSE) } else if (value == FALSE) { timer(x,name) <- pause(timer(x,name),now,FALSE) } else { stop ("Trying to set running state of timer ",name," to illogical value.") } x }) setMethod("flag","Status", function(x,name) x@flags[[name]]) setMethod("flag<-","Status", function(x,name,value) { x@flags[[name]] <- value x }) setMethod("obs","Status", function(x,name) x@observables[[name]]) setMethod("obs<-","Status", function(x,name,value) { x@observables[[name]] <- value x }) copyStatus <- function(prototype,uid) { new("Status","_id"=c(oid=NA_character_), uid=uid,context=prototype@context, oldContext=prototype@oldContext, timers=prototype@timers, flags=prototype@flags, observables=prototype@observables, timestamp=prototype@timestamp,app=prototype@app) } splitfield <- function (field) { strsplit(gsub("]","",field),"[.[]")[[1]] } ## !set for timers is treated specially. ## !set: {: