import { NONE, NOOP_SUBSCRIBER, sendEndInTx, sendNextInTx, Subscriber, Subscription } from "./_core"
import { Dispatcher, MCSNode } from "./_dispatcher"
import * as Sym from "./_symbols"
import { Transaction } from "./_tx"
import { is } from "./_util"
import { HKT, Observable } from "./Observable"
export class Property extends Observable implements HKT> {
public [Sym.HKT]!: Property
protected __isProperty!: true
constructor(d: PropertyDispatcher) {
super(d)
}
}
export function isProperty(x: any): x is Property {
return is(x, Property)
}
export class PropertyDispatcher extends Dispatcher {
protected has: boolean = false
protected val: T = NONE
protected ended: boolean = false
public subscribe(subscriber: Subscriber, order: number): Subscription {
return this.ended === true
? new PropertyEndedSubscription(this, subscriber)
: super.subscribe(subscriber, order)
}
public activate(subscriber: Subscriber, initialNeeded: boolean): void {
const isLateActivation = this.active
super.activate(subscriber, initialNeeded)
const noSourceInitialDuringFirstActivation = !isLateActivation && !this.has
if (
this.active &&
(isLateActivation || noSourceInitialDuringFirstActivation) &&
initialNeeded
) {
this.replayState(subscriber)
}
}
public dispose(node: MCSNode): void {
super.dispose(node)
if (this.active === false) {
this.has = false
}
}
public next(tx: Transaction, val: T): void {
this.has = true
this.sink.next(tx, (this.val = val))
}
public end(tx: Transaction): void {
this.ended = true
this.sink.end(tx)
}
public replayState(subscriber: Subscriber): void {
const { val, ended } = this
if (val !== NONE) {
sendNextInTx(subscriber, val)
}
if (ended === true) {
sendEndInTx(subscriber)
}
}
}
class PropertyEndedSubscription implements Subscription {
constructor(private d: PropertyDispatcher, private s: Subscriber) {}
public activate(initialNeeded: boolean): void {
this.d.replayState(this.s)
}
public dispose(): void {
this.s = NOOP_SUBSCRIBER
}
public reorder(order: number): void {
// noop
}
}