import { Vertex , Source } from "./Vertex" ; import * as Collections from 'typescript-collections' ; import { Stream , StreamWithSend } from "./Stream" ; import { StreamSink } from "./StreamSink" ; import { Cell } from "./Cell" ; import { CellSink } from "./CellSink" ; import { Transaction } from "./Transaction" ; /**
 * An interface for implementations of FRP timer systems.
 */ export abstract class TimerSystemImpl { return abstract setTimer ( t , callback ) ; /**
     * Return the current clock time.
     */ abstract now ( ) ; } let nextSeq = 0 ; class Event { constructor ( t , sAlarm ) { this . t = t ; this . sAlarm = sAlarm ; this . seq = ++ nextSeq ; } t : number ; sAlarm : StreamWithSend < number > ; seq : number ; } export class TimerSystem { constructor ( impl ) { Transaction . run ( ( ) => { this . impl = impl ; this . tMinimum = 0 ; const timeSnk = new CellSink < number > ( impl . now ( ) ) ; this . time = timeSnk ; this . time . listen ( ( t ) => { } ) ; Transaction . onStart ( ( ) => { const t = this . tMinimum = Math . max ( this . tMinimum , impl . now ( ) ) ; while ( true ) { let ev = null ; if ( ! this . eventQueue . isEmpty ( ) ) { let mev = this . eventQueue . minimum ( ) ; if ( mev . t <= t ) { ev = mev ; } } if ( ev != null ) { timeSnk . send ( ev . t ) ; Transaction . run ( ( ) => ev . sAlarm . send_ ( ev . t ) ) ; } else break ; } timeSnk . send ( t ) ; } ) ; } ) ; } private impl : TimerSystemImpl ; private tMinimum : number ; /**
     * A cell giving the current clock time.
     */ time : Cell < number > ; private eventQueue : Collections . BSTree < Event > = new Collections . BSTree < Event > ( ( a , b ) => { if ( a . t < b . t ) return - 1 ; if ( a . t > b . t ) return 1 ; if ( a . seq < b . seq ) return - 1 ; if ( a . seq > b . seq ) return 1 ; return 0 ; } ) ; /**
     * A timer that fires at the specified time, which can be null, meaning
     * that the alarm is not set.
     */ at ( tAlarm ) { let current = null , cancelCurrent = null , active = false , tAl = null , sampled = false ; const sAlarm = new StreamWithSend < number > ( null ) , updateTimer = ( ) => { if ( cancelCurrent !== null ) { cancelCurrent ( ) ; this . eventQueue . remove ( current ) ; } cancelCurrent = null ; current = null ; if ( active ) { if ( ! sampled ) { sampled = true ; tAl = tAlarm . sampleNoTrans__ ( ) ; } if ( tAl !== null ) { current = new Event ( tAl , sAlarm ) ; this . eventQueue . add ( current ) ; cancelCurrent = this . impl . setTimer ( tAl , ( ) => { this . tMinimum = Math . max ( this . tMinimum , tAl ) ; Transaction . run ( ( ) => { } ) ; } ) ; } } } ; sAlarm . setVertex__ ( new Vertex ( "at" , 0 , [ new Source ( tAlarm . getVertex__ ( ) , ( ) => { active = true ; sampled = false ; Transaction . currentTransaction . prioritized ( sAlarm . getVertex__ ( ) , updateTimer ) ; const kill = tAlarm . getStream__ ( ) . listen_ ( sAlarm . getVertex__ ( ) , ( oAlarm ) => { tAl = oAlarm ; sampled = true ; updateTimer ( ) ; } , false ) ; return ( ) => { active = false ; updateTimer ( ) ; kill ( ) ; } ; } ) ] ) ) ; return sAlarm ; } }