import { HttpClient , HttpHeaders } from '@angular/common/http' ; import { forkJoin , Observable , of } from 'rxjs' ; import { Schema } from './schema' ; import { map , publishReplay , refCount , switchMap } from 'rxjs/operators' ; import jsonata from 'jsonata' ; /**
 * class backing a select / autocomplete option
 */ export interface Choice { /**
     * select value
     */ value : any ; /**
     * display name
     */ name : string ; } /**
 * interface for choice handlers for select / autocomplete choices
 */ export interface ChoiceHandler { /**
     * loads the choices
     */ load ( value , schema ) : Observable < Choice [ ] > ; /**
     * user typed in autocomplete field
     */ filter ( value , schema , current , choices ) : Observable < Choice [ ] > ; /**
     * return a single choice (i.e. convert value to Choice)
     */ choice ( value , schema ) : Observable < Choice > ; /**
     * delay between keystrokes before new data is loaded
     */ debounceTime ( ) : number ; } /**
 * default implementation that handles choices based on schema fields.
 * can be overriden via schema.displayWith
 */ export class DefaultChoiceHandler implements ChoiceHandler { param http constructor ( private http ) { } /**
     * http cache for REST request on config/Table (i.e. schema requests)
     */ cache : Observable < Choice [ ] > ; /**
     * load choices
     */ load ( value , schema ) { if ( ! this . cache ) { if ( schema . choices ) { const arr = [ ] ; for ( const s of schema . choices ) { arr . push ( this . choice ( s , schema ) ) ; } this . cache = forkJoin ( arr ) ; } else if ( schema . choicesUrl ) { this . cache = this . getChoices ( schema . choicesUrl , schema . choicesUrlArgs , schema . choicesVerb ) . pipe ( switchMap ( res => { if ( schema . jsonata ) { res = jsonata ( schema . jsonata ) . evaluate ( res ) ; if ( ! Array . isArray ( res ) ) { res = [ res ] ; } } const obs = [ ] ; for ( const r of res ) { obs . push ( this . choice ( r , schema ) ) ; } return forkJoin ( obs ) ; } ) , publishReplay ( 1 ) , refCount ( ) ) ; } } return this . cache ; } /**
     * filter after keystroke
     */ filter ( value , schema , current , choices ) { return choices . pipe ( map ( arr => { if ( ! current ) { return arr ; } const res = arr . filter ( i => this . include ( i , current ) ) ; return res ; } ) ) ; } /**
     * called from filter, intended to allow subclasses to easily change filter algorithm
     */ include ( i , current ) { return ( '' + i . name ) . toLowerCase ( ) . includes ( ( '' + current ) . toLowerCase ( ) ) ; } /**
     * default choice implementation: just reuse value as name
     * check for localName
     */ choice ( value , schema ) { if ( schema . displayWith === 'localName' ) { for ( const delimiter of [ '/' , '#' , ':' , '.' ] ) { const parts = value . split ( delimiter ) ; if ( parts . length > 1 ) { if ( parts [ parts . length - 1 ] === '' ) { return of ( { value , name : parts [ parts . length - 2 ] } ) ; } else { return of ( { value , name : parts [ parts . length - 1 ] } ) ; } } } return of ( { value , name : value } ) ; } if ( schema . jsonata ) { if ( typeof value === 'object' ) { return of ( value ) ; } else { return of ( { value , name : value } ) ; } } if ( schema . displayWithChoices ) { return of ( { value , name : schema . displayWithChoices [ schema . choices . indexOf ( value ) ] } ) ; } return of ( { value , name : value } ) ; } /**
     * handle GET / POST
     */ getChoices ( url , args , verb ) { if ( verb === 'GET' ) { return this . http . get < any [ ] > ( url , args ) ; } else { return this . http . post < any [ ] > ( url , args , { headers : new HttpHeaders ( { 'Content-Type' : 'application/json' , } ) } ) ; } } /**
     * default: no delay
     */ debounceTime ( ) { return 0 ; } }