import { map , share } from 'rxjs/operators' ; import { Emission } from '../shared/emission' ; import { Control } from '../pin/control' ; import { Pin } from '../pin/pin' ; import group from '../pin/group' ; import _map from '../pin/map' ; import filter , { block } from '../pin/filter' ; import pipe from '../pin/pipe' ; import { Agent } from './agent' ; /**
 *
 * Denotes a token specifying an event sequence.
 * Each token can at each step either accept a new emission,
 * and can complete on a list of emissions.
 *
 */ export interface SequenceToken { param val param list accepts ( val , list ) : boolean ; param list complete ( list ) : boolean ; } param min param max export function range ( min , max ? ) { return < SequenceToken > { accepts ( _ , list ) { return max === undefined || list . length < max ; } , complete ( list ) { return list . length >= min ; } } ; } param c export function count ( c ) { return range ( c , c ) ; } /**
 *
 * Sequence token denoting an event that may or may not happen (multiple times).
 *
 */ export const maybesome = range ( 0 ) ; /**
 *
 * Sequence token denoting an event that happens at least once.
 *
 */ export const some = range ( 1 ) ; export type SequenceTokenIndicator = number | '*' | '+' | SequenceToken ; /**
 *
 * Represents [sequence](https://connective.dev/docs/sequence) agents.
 *
 */ export class Sequence extends Agent { readonly tokens : SequenceToken [ ] ; private _control : Control ; private _relay : Pin ; public _seq : Emission [ ] [ ] ; private _head = 0 ; param tokens constructor ( tokens ) { super ( { inputs : tokens . map ( ( _ , index ) => index . toString ( ) ) , outputs : [ 'out' ] } ) ; this . _control = new Control ( ) ; this . _relay = new Pin ( ) ; this . tokens = tokens . map ( t => { if ( typeof t == 'number' ) return count ( t ) ; if ( t === '+' ) return some ; if ( t === '*' ) return maybesome ; return t ; } ) ; tokens . forEach ( ( _ , index ) => { this . in ( index ) . to ( pipe ( map ( e => { this . _take ( e , index , true ) ; return e ; } ) ) ) . to ( this . _relay ) ; } ) ; this . reset ( ) ; } private _take ( emission , index , retry = false ) { if ( index == this . _head ) { if ( this . tokens [ index ] . accepts ( emission , this . _seq [ index ] ) ) this . _seq [ index ] . push ( emission ) ; else { this . reset ( ) ; if ( retry ) this . _take ( emission , index ) ; } } else { if ( index < this . _head ) { this . reset ( ) ; this . _take ( emission , index ) ; } else { if ( this . _seek ( index ) ) this . _take ( emission , index , retry ) ; else { this . reset ( ) ; if ( this . _seek ( index ) ) this . _take ( emission , index , retry ) ; } } } } private _seek ( index ) { for ( let i = this . _head ; i < index ; i ++ ) if ( ! this . tokens [ i ] . complete ( this . _seq [ i ] ) ) return false ; this . _head = index ; return true ; } private get _complete ( ) : boolean { return this . _seq . every ( ( e , index ) => this . tokens [ index ] . complete ( e ) ) ; } protected reset ( ) { this . _seq = this . tokens . map ( _ => [ ] ) ; this . _head = 0 ; return this ; } protected createOutput ( label ) { this . checkOutput ( label ) ; return group ( this . _control . to ( _map ( ( ) => this . reset ( ) ) ) . to ( block ( ) ) , this . _relay . to ( filter ( ( ) => this . _complete ) ) ) . to ( pipe ( map ( ( ) => { let _vals = this . _seq . map ( _comp => ( _comp . length == 1 ) ? ( _comp [ 0 ] . value ) : ( _comp . map ( _ => _ . value ) ) ) ; let _emission = Emission . from ( this . _seq . reduce ( ( all , list ) => all . concat ( list ) , [ ] ) , ( this . tokens . length == 1 ) ? _vals [ 0 ] : _vals ) ; return _emission ; } ) , share ( ) ) ) ; } protected createEntries ( ) { return ( this . signature . inputs || [ ] ) . map ( i => this . in ( i ) ) ; } protected createExits ( ) { return [ this . output ] ; } public clear ( ) { this . reset ( ) ; this . _control . clear ( ) ; this . _relay . clear ( ) ; return super . clear ( ) ; } /**
     *
     * Resets the sequence being tracked when receiving emissions
     * on `.control`.
     *
     */ public get control ( ) { return this . _control ; } /**
     *
     * Shortcut for `.out('out')`, which will emit completed sequences.
     * [Read this](https://connective.dev/docs/sequence#signature) for more details.
     *
     */ public get output ( ) { return this . out ( 'out' ) ; } } param tokens export function sequence ( ... tokens ) { return new Sequence ( tokens ) ; } export default sequence ;