import {Injectable} from '@angular/core'; import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import {BehaviorSubject, from, Observable, of, Subscriber, throwError, zip} from 'rxjs'; import {AutoCompleteValue} from '../../searchPages/searchUtils/searchHelperClasses.class'; import {EnvProperties} from '../properties/env-properties'; import {catchError, map} from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class ISVocabulariesService { private vocabularies: Map> = new Map>(); private provenanceActionVocabulary: BehaviorSubject<{}> = new BehaviorSubject(null); private subjectsVocabulary: BehaviorSubject = new BehaviorSubject(null); private relationsVocabulary: BehaviorSubject = new BehaviorSubject(null); private subscriptions = []; private vocabulariesPromises: Map> = new Map>(); constructor(private http: HttpClient) {} ngOnDestroy() { this.clearSubscriptions(); } clearSubscriptions() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscriber) { subscription.unsubscribe(); } }); } getVocabularyByType(field: string, entity: string, properties: EnvProperties): Observable { let file = ""; let vocabulary = ""; if (field == "lang") { vocabulary = "dnet:languages.json"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } else if (field == "type" && (entity == "publication")) { vocabulary = "dnet:publication_resource.json"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } else if (field == "type" && (entity == "dataset")) { vocabulary = "dnet:dataCite_resource.json"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } else if (field == "type" && (entity == "software" || entity == "other")) { return of([]); } else if (field == "type" && entity == "result" ) { return zip(this.getVocabularyFromService("dnet:publication_resource.json", properties),this.getVocabularyFromService("dnet:dataCite_resource.json", properties)); } else if (field == "access" && (entity == "publication" || entity == "dataset" || entity == "software" || entity == "other" || entity == "result")) { vocabulary = "dnet:access_modes.json"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } else if ((field == "type") && (entity == "dataprovider" || entity == "service")) { vocabulary = "dnet:datasource_typologies.json"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } else if (field == "compatibility" && (entity == "dataprovider" || entity == "service")) { vocabulary = "dnet:datasourceCompatibilityLevel.json"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } else if (field == "country") { vocabulary = "dnet:countries.json"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } else if (field == "fos") { vocabulary = "fos"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } else if (field == "sdg") { vocabulary = "sdg"; return this.getVocabularyFromServiceAsync(vocabulary, properties); } return null; } getVocabularyFromServiceAsync(vocabularyName: string, properties: EnvProperties) { if(!this.vocabularies.has(vocabularyName)) { this.vocabularies.set(vocabularyName, new BehaviorSubject(null)); if(!this.vocabulariesPromises.has(vocabularyName)) { this.vocabulariesPromises.set(vocabularyName, new Promise(resolve => { this.subscriptions.push(this.getVocabularyFromService(vocabularyName, properties).subscribe( vocabularyRes => { this.vocabularies.get(vocabularyName).next(vocabularyRes); resolve(); }, error => { this.vocabularies.get(vocabularyName).next(null); resolve(); } )); })); } } return from(this.getAsync(vocabularyName)); } async getAsync(vocabularyName: string): Promise { await this.vocabulariesPromises.get(vocabularyName); return this.vocabularies.get(vocabularyName).getValue(); } getVocabularyFromService(vocabularyName: string, properties: EnvProperties): Observable { let url = properties.vocabulariesAPI + vocabularyName; if(vocabularyName == 'fos' || vocabularyName == 'sdg'){ return this.getLocalVocabularyFromService(vocabularyName, properties); } return this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) //.map(res => res.json()) .pipe(map(res => res['terms'])) .pipe(map(res => this.parse(res, vocabularyName))) .pipe(catchError(this.handleError)); } getLocalVocabularyFromService(vocabularyName: string, properties: EnvProperties): Observable { if(vocabularyName == "sdg"){ return this.getSDGs(properties) .pipe(map(res => res['sdg'])) .pipe(map(res => this.parseSDGs(res))) .pipe(catchError(this.handleError)); }else if( vocabularyName == "fos"){ return this.getFos(properties) .pipe(map(res => res['fos'])) .pipe(map(res => this.parseFOS(res))) .pipe(catchError(this.handleError)); } } getFos(properties: EnvProperties): Observable { let url = "/assets/common-assets/vocabulary/fos.json"; return this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) } getSDGs(properties: EnvProperties): Observable { let url = "/assets/common-assets/vocabulary/sdg.json"; return this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) } parseSDGs(data: any): AutoCompleteValue[] { var array: AutoCompleteValue[] = [] for (var i = 0; i < data.length; i++) { var value: AutoCompleteValue = new AutoCompleteValue(); value.id = data[i].id;//data[i].code; value.label = data[i].id; array.push(value); } return array; } parseFOS(data: any): AutoCompleteValue[] { let array: AutoCompleteValue[] = [] for (let fos of data) { let value: AutoCompleteValue = new AutoCompleteValue(); value.id = fos.id;//data[i].code; value.label = fos.label; array.push(value); if(fos.children) { for (let fos2 of fos.children) { let value: AutoCompleteValue = new AutoCompleteValue(); value.id = fos2.id;//data[i].code; value.label = fos2.label; array.push(value); if(fos2.children) { for (let fos3 of fos2.children) { let value: AutoCompleteValue = new AutoCompleteValue(); value.id = fos3.id;//data[i].code; value.label = fos3.label; array.push(value); } } } } } return array; } parse(data: any, vocabularyName: string): AutoCompleteValue[] { var array: AutoCompleteValue[] = [] for (var i = 0; i < data.length; i++) { var value: AutoCompleteValue = new AutoCompleteValue(); value.id = data[i].englishName;//data[i].code; if (vocabularyName == 'dnet:countries.json') { //use Country code instead of country name value.id = data[i].code; } value.label = data[i].englishName; array.push(value); } return array; } getProvenanceActionVocabulary(properties: EnvProperties): Observable { let vocabulary = "dnet:provenanceActions.json"; return from(this.getProvenanceActionVocabularyFromServiceAsync(vocabulary, properties)); } async getProvenanceActionVocabularyFromServiceAsync (vocabularyName: string, properties: EnvProperties): Promise<{}> { if(!this.provenanceActionVocabulary || !this.provenanceActionVocabulary.getValue()) { await new Promise(resolve => { this.subscriptions.push(this.getProvenanceActionVocabularyFromService(vocabularyName, properties).subscribe( vocabularyRes => { this.provenanceActionVocabulary.next(vocabularyRes); resolve(); }, error => { this.provenanceActionVocabulary.next(null); resolve(); } )); }); // this.clearSubscriptions(); } return this.provenanceActionVocabulary.getValue(); } getProvenanceActionVocabularyFromService (vocabularyName: string, properties: EnvProperties): any { let url = properties.vocabulariesAPI+vocabularyName; return this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) .pipe(map(res => res['terms'])) .pipe(map(res => this.parseProvenanceActionVocabulary(res))); } parseProvenanceActionVocabulary(terms: any) { var provenanceActionVocabulary: {} = {}; for(let term of terms) { provenanceActionVocabulary[term.code] = term.englishName; } return provenanceActionVocabulary; } getSubjectsVocabulary(properties: EnvProperties): Observable { let vocabulary = "dnet:subject_classification_typologies.json"; return from(this.getSubjectsVocabularyFromServiceAsync(vocabulary, properties)); } async getSubjectsVocabularyFromServiceAsync (vocabularyName: string, properties: EnvProperties): Promise<{}> { if(!this.subjectsVocabulary || !this.subjectsVocabulary.getValue()) { await new Promise(resolve => { this.subscriptions.push(this.getSubjectsVocabularyFromService(vocabularyName, properties).subscribe( vocabularyRes => { // console.log(vocabularyRes); this.subjectsVocabulary.next(vocabularyRes); resolve(); }, error => { this.subjectsVocabulary.next(null); resolve(); } )); }); // this.clearSubscriptions(); } return this.subjectsVocabulary.getValue(); } getSubjectsVocabularyFromService (vocabularyName: string, properties: EnvProperties): any { let url = properties.vocabulariesAPI+vocabularyName; return this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) .pipe(map(res => res['terms'])) // .pipe(map(res => res.code)) .pipe(map(res => this.parseSubjectsVocabulary(res))); } parseSubjectsVocabulary(terms: any) { var subjectsVocabulary: {} = {}; for(let term of terms) { if(term.code != "keyword") { subjectsVocabulary[term.code] = term.englishName; } } return subjectsVocabulary; } getRelationsVocabulary(properties: EnvProperties): Observable { let vocabulary = "dnet:relation_relClass.json"; return from(this.getRelationsVocabularyFromServiceAsync(vocabulary, properties)); } async getRelationsVocabularyFromServiceAsync (vocabularyName: string, properties: EnvProperties): Promise<{}> { if(!this.relationsVocabulary || !this.relationsVocabulary.getValue()) { await new Promise(resolve => { this.subscriptions.push(this.getRelationsVocabularyFromService(vocabularyName, properties).subscribe( vocabularyRes => { this.relationsVocabulary.next(vocabularyRes); resolve(); }, error => { this.relationsVocabulary.next(null); resolve(); } )); }); } return this.relationsVocabulary.getValue(); } getRelationsVocabularyFromService (vocabularyName: string, properties: EnvProperties): any { let url = properties.vocabulariesAPI+vocabularyName; return this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) .pipe(map(res => res['terms'])) .pipe(map(res => this.parseRelationsVocabulary(res))); } parseRelationsVocabulary(terms: any) { var relationsVocabulary: {} = {}; for(let term of terms) { if(term.code != "keyword") { relationsVocabulary[term.code] = term.englishName; } } return relationsVocabulary; } private handleError(error: HttpErrorResponse) { // in a real world app, we may send the error to some remote logging infrastructure // instead of just logging it to the console console.log(error); return throwError(error || 'Server error'); } }