import { IResourceAction , IResourceActionAttributes , IResourceActionInner , IResourceParamsBase , IResourceRequest , ResourceQueryMappingMethod , ResourceRequestBodyType } from './Declarations' ; export class ResourceHelper { static cleanDataFields : string [ ] = [ '$resolved' , '$promise' , '$abort' , '$resource' ] ; private static isBrowser : boolean | null = null ; static isRunningInBrowser ( ) { if ( this . isBrowser !== null ) { return this . isBrowser ; } try { this . isBrowser = ! ! window ; } catch ( e ) { this . isBrowser = false ; } return this . isBrowser ; } static getRealTypeOf ( data ) { if ( ! data ) { return ResourceRequestBodyType . NONE ; } if ( this . isRunningInBrowser ( ) ) { if ( FormData && data instanceof FormData ) { return ResourceRequestBodyType . FORM_DATA ; } if ( Blob && data instanceof Blob ) { return ResourceRequestBodyType . BLOB ; } } if ( data instanceof ArrayBuffer ) { return ResourceRequestBodyType . ARRAY_BUFFER ; } if ( [ 'string' , 'number' ] . indexOf ( typeof data ) > - 1 ) { return ResourceRequestBodyType . TEXT ; } return ResourceRequestBodyType . JSON ; } static defaults ( dst , src ) { if ( ! dst ) { dst = { } ; } Object . keys ( src ) . forEach ( ( key ) => { if ( dst [ key ] === undefined ) { dst [ key ] = src [ key ] ; } } ) ; return dst ; } static isNullOrUndefined ( value ) { return value === null || value === undefined ; } static cleanData ( obj ) { if ( Array . isArray ( obj ) ) { return this . cleanDataArray ( obj ) ; } else { return this . cleanDataObject ( obj ) ; } } static cleanDataArray ( obj ) { obj = obj . filter ( value => typeof value !== 'function' ) ; return obj ; } static cleanDataObject ( obj ) { const cleanedObj = { } ; for ( const propName in obj ) { if ( typeof obj [ propName ] !== 'function' && this . cleanDataFields . indexOf ( propName ) === - 1 ) { cleanedObj [ propName ] = obj [ propName ] ; } } return cleanedObj ; } static defineReturnDataPropertiesResolvedAbort ( returnData ) { Object . defineProperty ( returnData , '$resolved' , { enumerable : false , configurable : true , writable : true , value : false } ) ; Object . defineProperty ( returnData , '$abort' , { enumerable : false , configurable : true , writable : true , value : ( ) => { } } ) ; } static defineReturnDataPropertiesPromise ( returnData , value ) { Object . defineProperty ( returnData , '$promise' , { enumerable : false , configurable : true , writable : true , value } ) ; } static getRequestOptionsOrThrow ( options ) { const value = this . getResourceActionInnerOrThrow ( options , 'requestOptions' ) ; return value ; } static getResolvedOptionsOrThrow ( options ) { const value = this . getResourceActionInnerOrThrow ( options , 'resolvedOptions' ) ; return value ; } static getActionAttributesOrThrow ( options ) { const value = this . getResourceActionInnerOrThrow ( options , 'actionAttributes' ) ; return value ; } static getActionOptionsOrThrow ( options ) { const value = this . getResourceActionInnerOrThrow ( options , 'actionOptions' ) ; return value ; } static setRequestOptionsUrlParams ( requestOptions , resolvedOptions , actionAttributes , usedInPath ) { if ( ! requestOptions . url ) { throw new Error ( 'setRequestOptionsUrlParams options.requestOptions.url missing' ) ; } const params = this . defaults ( actionAttributes . params , resolvedOptions . params ) ; const pathParams = requestOptions . url . match ( /{([^}]*)}/g ) || [ ] ; for ( const pathParam of pathParams ) { let pathKey = pathParam . substr ( 1 , pathParam . length - 2 ) ; const isMandatory = pathKey [ 0 ] === '!' ; if ( isMandatory ) { pathKey = pathKey . substr ( 1 ) ; } const onlyPathParam = pathKey [ 0 ] === ':' ; if ( onlyPathParam ) { pathKey = pathKey . substr ( 1 ) ; } if ( actionAttributes . query && actionAttributes . query === actionAttributes . params ) { usedInPath [ pathKey ] = true ; } const value = params [ pathKey ] ; if ( onlyPathParam ) { delete params [ pathKey ] ; } requestOptions . url = this . setRequestOptionsUrlParamsNewUrl ( value , isMandatory , pathParam , requestOptions ) ; } } static setRequestOptionsUrlParamsNewUrl ( value , isMandatory , pathParam , requestOptions ) { if ( ! requestOptions . url ) { throw new Error ( 'setRequestOptionsUrlParamsNewUrl requestOptions.url missing' ) ; } if ( this . isNullOrUndefined ( value ) ) { if ( isMandatory ) { const consoleMsg = `Mandatory ${ pathParam } path parameter is missing` ; console . warn ( consoleMsg ) ; throw new Error ( consoleMsg ) ; } return requestOptions . url . substr ( 0 , requestOptions . url . indexOf ( pathParam ) ) ; } return requestOptions . url . replace ( pathParam , value ) ; } static createRequestOptionsFormDataBody ( body , actionOptions ) { const newBody = new FormData ( ) ; Object . keys ( body ) . forEach ( ( key ) => { const value = body [ key ] ; if ( body . hasOwnProperty ( key ) && typeof value !== 'function' ) { const isArrayOfFiles = value instanceof Array && value . reduce ( ( acc , elem ) => acc && elem instanceof File , true ) ; if ( isArrayOfFiles ) { value . forEach ( ( f , index ) => { newBody . append ( `${ key }[${ index }]` , f , f . name ) ; } ) ; } else if ( value instanceof File ) { newBody . append ( key , value , value . name ) ; } else if ( ! actionOptions . rootNode ) { newBody . append ( key , value ) ; } } } ) ; if ( actionOptions . rootNode ) { newBody . append ( actionOptions . rootNode , JSON . stringify ( body ) ) ; } return newBody ; } static appendQueryParams ( query , key , value , queryMappingMethod ? ) { if ( value instanceof Date ) { query [ key ] = value . toISOString ( ) ; return ; } if ( typeof value === 'object' ) { switch ( queryMappingMethod ) { case ResourceQueryMappingMethod . Plain : this . appendQueryParamsMappingMethodPlain ( query , key , value ) ; return ; case ResourceQueryMappingMethod . Bracket : this . appendQueryParamsMappingMethodBracket ( query , key , value , queryMappingMethod ) ; return ; case ResourceQueryMappingMethod . JQueryParamsBracket : this . appendQueryParamsMappingMethodJQueryParamsBracket ( query , key , value , queryMappingMethod ) ; return ; } } query [ key ] = value ; } static appendQueryParamsMappingMethodPlain ( query , key , value ) { if ( Array . isArray ( value ) ) { query [ key ] = value . join ( ',' ) ; } else { if ( value && typeof value === 'object' ) { if ( value instanceof Date ) { value = value . toISOString ( ) ; } else { value = JSON . stringify ( value ) ; } } query [ key ] = value ; } } static appendQueryParamsMappingMethodBracket ( query , key , value , queryMappingMethod ) { for ( const k in value ) { if ( value . hasOwnProperty ( k ) ) { this . appendQueryParams ( query , `${ key }[${ k }]` , value [ k ] , queryMappingMethod ) ; } } } static appendQueryParamsMappingMethodJQueryParamsBracket ( query , key , value , queryMappingMethod ) { for ( const k in value ) { if ( value . hasOwnProperty ( k ) ) { let path = `${ key }[${ k }]` ; if ( Array . isArray ( value ) && typeof value [ k ] !== 'object' ) { path = `${ key }[]` ; } this . appendQueryParams ( query , path , value [ k ] , queryMappingMethod ) ; } } } /**
     * Creates new abort method from subscription
     */ static createNewAbortMethod ( options ) { if ( options . returnData && options . subscription ) { const abort = options . returnData . abort ; options . returnData . abort = ( ) => { if ( abort ) { abort ( ) ; } if ( options . subscription ) { options . subscription . unsubscribe ( ) ; options . subscription = null ; } } ; } } private static getResourceActionInnerOrThrow ( options , param ) { if ( options [ param ] ) { return options [ param ] ; } throw new Error ( 'getResourceActionInnerOrThrow options.' + param + ' missing' ) ; } }