import {HostedByCollectedFrom, Project, RelationResult} from "../../utils/result-preview/result-preview";
import {Context, Measure, Metric, MetricPerDatasource, Reference} from "../../utils/entities/resultLandingInfo";
import {Injectable} from '@angular/core';
import {properties} from "../../../../environments/environment";
import {StringUtils} from "../../utils/string-utils.class";

@Injectable({
  providedIn: 'root'
})
export class ParsingFunctions {
	public eoscSubjects = [
    {label: 'EOSC::Jupyter Notebook', link: 'https://' + (properties.environment != 'production'?'beta.':'') + 'search.marketplace.eosc-portal.eu/search/service?q=*&fq=eosc_if:%22Jupyter%20Notebook%22', value: 'Jupyter Notebook'},
    {label: 'EOSC::RO-crate', link: 'https://' + (properties.environment != 'production'?'beta.':'') + 'search.marketplace.eosc-portal.eu/search/service?q=*&fq=eosc_if:%22RO%5C-crate%22', value: 'RO-crate'},
    {label: 'EOSC::Galaxy Workflow', link: 'https://' + (properties.environment != 'production'?'beta.':'') + 'search.marketplace.eosc-portal.eu/search/service?q=*&fq=eosc_if:%22Galaxy%20Workflow%22', value: 'Galaxy Workflow'},
    {label: 'EOSC::Twitter Data', link: 'https://' + (properties.environment != 'production'?'beta.':'') + 'search.marketplace.eosc-portal.eu/search/service?q=*&fq=eosc_if:%22Twitter%20Data%22', value: 'Twitter Data'},
    {label: 'EOSC::Data Cube', link: 'https://' + (properties.environment != 'production'?'beta.':'') + 'search.marketplace.eosc-portal.eu/search/service?q=*&fq=eosc_if:%22Data%20Cube%22', value: 'Data Cube'}
	]
  public notebookInSubjects: boolean = false;
  private notebookKeyword: string = "eosc jupyter notebook";
  private notebook_label: string = "EOSC";
  private notebook_value: string = "EOSC Jupyter Notebook";
  
  public open = 'open_access';
  public closed = 'closed_access';
  public unknown = 'unknown_access';

  private instanceWithDoiExists: boolean = false;
  
  constructor() {
  }
  
  public ngOnDestroy() {
  }
  
  public parseFundingByProjects(fundedByProjects: Project[], relation: any): Project[] {
    if (fundedByProjects == undefined) {
      fundedByProjects = [];
    }
    
    let fundedByProject: Project = {
      "id": "", "acronym": "", "title": "",
      "funderShortname": "", "funderName": "",
      "funding": "", "code": "", "provenanceAction": "", "validated": false
    };

    if (relation.title != 'unidentified') {
      fundedByProject['id'] = relation['to'].content;
      fundedByProject['acronym'] = relation.acronym;
      fundedByProject['title'] = relation.title;
      fundedByProject['code'] = relation.code;
      if (relation.validated && relation.validated.date) {
        fundedByProject['validated'] = true;
      }
      fundedByProject['provenanceAction'] = relation.provenanceaction;
    } else {
      fundedByProject['id'] = "";
      fundedByProject['acronym'] = "";
      fundedByProject['title'] = "";
      fundedByProject['code'] = "";
      fundedByProject['provenanceAction'] = "";
    }
    
    if (relation.hasOwnProperty("funding")) {
      let funding: { "funderName": string, "funderShortname": string, "stream": string };
      funding = this.parseFundingTrees(relation.funding);
      
      if (funding.funderName) {
        fundedByProject['funderName'] = funding.funderName;
      }
      if (funding.funderShortname) {
        fundedByProject['funderShortname'] = funding.funderShortname;
      }
      if (funding.stream) {
        fundedByProject['funding'] = funding.stream;
      }
    }
    fundedByProjects.push(fundedByProject);
    return fundedByProjects;
  }
  
  // publication & research data : for fundedByProjects | project landing : for funding
  public parseFundingTrees(fundingTree: any): { "funderName": string, "funderShortname": string, "stream": string } {
    let funding: { "funderName": string, "funderShortname": string, "stream": string } = {
      "funderName": "",
      "funderShortname": "",
      "stream": ""
    };
    let length = Array.isArray(fundingTree) ? fundingTree.length : 1;
    
    for (let i = 0; i < length; i++) {
      let fundingData = Array.isArray(fundingTree) ? fundingTree[i] : fundingTree;
      
      if (fundingData.hasOwnProperty("funder")) {
        funding.funderShortname = fundingData['funder'].shortname;
        funding.funderName = fundingData['funder'].name;
      }
      
      funding.stream = this.addFundingLevel0(fundingData, funding.stream);
      
      funding.stream = this.addFundingLevel1(fundingData, funding.stream);
      
      funding.stream = this.addFundingLevel2(fundingData, funding.stream);
    }
    return funding;
  }
  
  addFundingLevel0(parent: string, fundingStream: string): string {
    if (parent.hasOwnProperty("funding_level_0")) {
      let level0 = parent['funding_level_0'];
      
      fundingStream += (fundingStream) ? " ; " : "";
      fundingStream += level0.name;
    }
    return fundingStream;
  }
  
  addFundingLevel1(parent: string, fundingStream: string): string {
    if (parent.hasOwnProperty("funding_level_1")) {
      let level1 = parent['funding_level_1'];
      
      // For projects' parsing
      if (level1.hasOwnProperty("parent")) {
        fundingStream = this.addFundingLevel0(level1.parent, fundingStream);
      }
      
      fundingStream += (fundingStream) ? " | " : "";
      fundingStream += level1.name;
    }
    return fundingStream;
  }
  
  addFundingLevel2(parent: string, fundingStream: string): string {
    if (parent.hasOwnProperty("funding_level_2")) {
      let level2 = parent['funding_level_2'];
      
      // For projects' parsing
      if (level2.hasOwnProperty("parent")) {
        fundingStream = this.addFundingLevel1(level2.parent, fundingStream);
      }
      
      fundingStream += (fundingStream) ? " | " : "";
      fundingStream += level2.name;
    }
    return fundingStream;
  }
  
  // publication & dataset landing : for collectedFrom
  parseCollectedFrom(collectedFrom: { "name": string, "id": string }[],
                     _collectedFrom: any) {
    let length: number = collectedFrom.length;
    collectedFrom[length] = {"name": "", "id": ""};
    collectedFrom[length]['name'] = _collectedFrom.name;
    collectedFrom[length]['id'] = _collectedFrom.id;
  }
  
  // publication & dataset landing : for downloadFrom
  addPublisherToHostedBy_collectedFrom(hostedBy_collectedFrom: HostedByCollectedFrom[],
                                       publisher: string, journal: string,
                                       identifiers: Map<string, string[]>/*, title: { "name": string, "url": string, "accessMode": string}*/) {
    if (!this.instanceWithDoiExists && publisher && identifiers != null && identifiers.has('doi')) {
      if (hostedBy_collectedFrom == null) {
        hostedBy_collectedFrom = [];
      }
      let available: HostedByCollectedFrom = {
        downloadNames: [],
        downloadUrl: "",
        collectedNamesAndIds: null,
        accessRight: "",
        types: [],
        years: [],
        accessRightIcon: ""
      };
      
      if (journal) {
        available.downloadNames.push(publisher + "/ " + journal['journal']);
      } else {
        available.downloadNames.push(publisher);
      }
      
      available.downloadUrl = properties.doiURL + identifiers.get("doi")[0];
      available.accessRightIcon = this.unknown;
      /*
            if(title != undefined && title['url'] == "") {
              title['url'] = url;
            }
      */
      hostedBy_collectedFrom.push(available);
    }
    return hostedBy_collectedFrom;
  }
  
  // publication & dataset landing : for downloadFrom
  parseDownloadFrom(downloadFrom: Map<string, { "url": string[], "accessMode": string[], "bestAccessMode": string }>, instance: any, url: string) {
    let key: string = instance['hostedby'].name;
    
    if (key) {
      this.addUrlAndAccessMode(downloadFrom, instance, key, url);
    }
  }
  
  // publication & dataset landing : for publishedIn
  parsePublishedIn(publishedIn: Map<string, { "url": string[], "accessMode": string[], "bestAccessMode": string }>, instance: any, result: any, url: string, counter: number): number {
    if (result != null && result.hasOwnProperty("source")) {
      let key: string;
      if (Array.isArray(result.source)) {
        if (counter == result.source.length) {
          counter--;
        }
        key = result['source'][counter];
      } else {
        key = result['source'];
      }
      
      if (key) {
        this.addUrlAndAccessMode(publishedIn, instance, key, url);
        counter++;
      }
    }
    return counter;
  }
  
  // publication & dataset landing : for downloadFrom and publishedIn
  addUrlAndAccessMode(mapStructure: Map<string, { "url": string[], "accessMode": string[], "bestAccessMode": string }>, instance: any, key: string, url: string) {
    if (!mapStructure.has(key)) {
      mapStructure.set(key, {"url": null, "accessMode": null, "bestAccessMode": null});
    }
    
    if (mapStructure.get(key)['url'] == null) {
      mapStructure.get(key)['url'] = new Array<string>();
    }
    
    if (url) {
      mapStructure.get(key)['url'].push(url);
    }
    
    if (mapStructure.get(key)['accessMode'] == null) {
      mapStructure.get(key)['accessMode'] = new Array<string>();
    }
    
    if (instance.hasOwnProperty("accessright")) {
      if (url) {
        mapStructure.get(key)['accessMode'].push(instance['accessright'].classname);
      }
      
      if (this.changeBestAccessMode(mapStructure.get(key)['bestAccessMode'], instance['accessright'])) {
        mapStructure.get(key)['bestAccessMode'] = instance['accessright'].classname;
      }
    } else if (url) {
      mapStructure.get(key)['accessMode'].push("");
    }
  }
  
  parseHostedBy_collectedFrom(hostedBy_collectedFrom: HostedByCollectedFrom[],
                              instance: any, url: string, globalAccessRight: string) {
    if (!url) {
      return;
    }
    
    let available: HostedByCollectedFrom = {
      "downloadNames": [],
      "downloadUrl": null,
      "collectedNamesAndIds": new Map(),
      "accessRight": null,
      "accessRightIcon": "",
      "types": [],
      "years": [],
      "license": "",
      "fulltext": "",
      "peerReviewed": null
    };

    if (instance.hasOwnProperty("hostedby")) {
      let downloadNames: Set<string> = new Set();
      let length = Array.isArray(instance['hostedby']) ? instance['hostedby'].length : 1;
      for (let i = 0; i < length; i++) {
        let hostedBy = Array.isArray(instance['hostedby']) ? instance['hostedby'][i] : instance['hostedby'];
        if (hostedBy.name && hostedBy.name != "other resources" && hostedBy.name != "Unknown Repository") {
          downloadNames.add(String(hostedBy.name));
        }
      }
      available.downloadNames = Array.from(downloadNames);
      
      if (available.downloadNames.length == 0) {
        available.downloadNames.push(url.substring(0, 30) + '...');  // substring(from, to);
      }
    }
    
    if (instance.hasOwnProperty("collectedfrom")) {
      let length = Array.isArray(instance['collectedfrom']) ? instance['collectedfrom'].length : 1;
      for (let i = 0; i < length; i++) {
        let collectedFrom = Array.isArray(instance['collectedfrom']) ? instance['collectedfrom'][i] : instance['collectedfrom'];
        if (collectedFrom.name && collectedFrom.id) {
          available.collectedNamesAndIds.set(String(collectedFrom.name), collectedFrom.id);
        }
      }
    }
    
    if (instance.hasOwnProperty("instancetype")) {
      let types: Set<string> = new Set();
      let length = Array.isArray(instance['instancetype']) ? instance['instancetype'].length : 1;
      for (let i = 0; i < length; i++) {
        let instanceType = Array.isArray(instance['instancetype']) ? instance['instancetype'][i] : instance['instancetype'];
        if (instanceType.classname && instanceType.classname.toLowerCase() !== "unknown") {
          types.add(instanceType.classname);
        }
      }
      available.types = Array.from(types);
    }
    
    if (instance.hasOwnProperty("dateofacceptance")) {
      let years: Set<string> = new Set();
      let length = Array.isArray(instance['dateofacceptance']) ? instance['dateofacceptance'].length : 1;
      for (let i = 0; i < length; i++) {
        let dateOfAcceptance = Array.isArray(instance['dateofacceptance']) ? instance['dateofacceptance'][i] : instance['dateofacceptance'];
        let date: string = (dateOfAcceptance) + ""; // transform to string in case it is an integer
        years.add((date && (date).indexOf('-') !== -1) ? date.split('-')[0] : date);
      }
      available.years = Array.from(years);
    }
    
    available['downloadUrl'] = url;
    if (url.includes("doi.org/")) {
      this.instanceWithDoiExists = true;
    }
    
    if (instance.hasOwnProperty("accessright")) {
      let length = Array.isArray(instance['accessright']) ? instance['accessright'].length : 1;
      for (let i = 0; i < length; i++) {
        let accessRight = Array.isArray(instance['accessright']) ? instance['accessright'][i] : instance['accessright'];
        
        if (this.changeBestAccessMode(available.accessRight, accessRight)) {
          available.accessRight = accessRight.classname;
          if (this.changeBestAccessMode(globalAccessRight, accessRight)) {
            globalAccessRight = accessRight.classname;
          }
        }
      }
      
    }

    if (available.accessRight) {
      if (available.accessRight.toLowerCase().indexOf('open') !== -1) {
        available.accessRightIcon = this.open;
      }
      else if (available.accessRight.toLowerCase().indexOf('not available') !== -1) {
        available.accessRightIcon = this.unknown;
      }
      else {
        available.accessRightIcon = this.closed;
      }
    } else {
      available.accessRightIcon = this.unknown;
    }
    
    if (instance.hasOwnProperty("license")) {
      available.license = Array.isArray(instance['license']) ? instance['license'][0] : instance['license'];
    }

    if(instance.hasOwnProperty("fulltext")) {
      available.fulltext = instance['fulltext'];
    }

    if(instance.hasOwnProperty("refereed") && instance.refereed.classname == "peerReviewed") {
      available.peerReviewed = true;
    }
    
    hostedBy_collectedFrom.push(available);
  }
  
  compareHostedByCollectedFrom(a: HostedByCollectedFrom, b: HostedByCollectedFrom) {
    let retValue: number = 0;
    let firstAccessRight: string = (a.accessRight ? a.accessRight.toLowerCase() : null);
    let secondAccessRight: string = (b.accessRight ? b.accessRight.toLowerCase() : null);

    if (firstAccessRight !== secondAccessRight) {
      if (firstAccessRight === 'open access') {
        retValue = -1;
      } else if (secondAccessRight === 'open access') {
        retValue = 1;
      } else if (firstAccessRight === "open source") {
        retValue = -1;
      } else if (secondAccessRight === "open source") {
        retValue = 1;
      } else if (firstAccessRight === "embargo") {
        retValue = -1;
      } else if (secondAccessRight === "embargo") {
        retValue = 1;
      } else if (firstAccessRight === "restricted") {
        retValue = -1;
      } else if (secondAccessRight === "restricted") {
        retValue = 1;
      } else if (firstAccessRight === "closed access") {
        retValue = -1;
      } else if (secondAccessRight === "closed access") {
        retValue = 1;
      } else if (firstAccessRight === "not available") {
        retValue = -1;
      } else if (secondAccessRight === "not available") {
        retValue = 1;
      }
    }

    if(retValue == 0) {
      let firstFulltext: string = (a.fulltext ? a.fulltext : null);
      let secondFulltext: string = (b.fulltext ? b.fulltext : null);

      if (firstFulltext && !secondFulltext) {
        return -1;
      } else if (!firstFulltext && secondFulltext) {
        return 1;
      }
    } else {
      return retValue;
    }

    return 0;
  }
  
  // publication & dataset landing : for downloadFrom and publishedIn
  changeBestAccessMode(currentAccessMode: string, accessMode: any): boolean {
    if (!accessMode) {
      return false;
    }
    accessMode = accessMode.classid;
    
    switch (currentAccessMode) {
      case null:
        if (accessMode != "UNKNOWN") {
          return true;
        }
        return false;
      case "CLOSED":
        if (accessMode == "OPEN" ||
          accessMode == "OPEN SOURCE" ||
          accessMode == "EMBARGO" ||
          accessMode == "RESTRICTED") {
          return true;
        }
        return false;
      case "RESTRICTED":
        if (accessMode == "OPEN" ||
          accessMode == "OPEN SOURCE" ||
          accessMode == "EMBARGO") {
          return true;
        }
        return false;
      case "EMBARGO":
        if (accessMode == "OPEN" ||
          accessMode == "OPEN SOURCE") {
          return true;
        }
        return false;
      case "OPEN SOURCE":
        if (accessMode == "OPEN") {
          return true;
        }
        return false;
    }
    return false;
  }
  
  // publication & dataset & software & orp landing : for relatedResearchResults
  parseResults(researchResults: RelationResult[], relation, provenanceAction: string, relationName: string): RelationResult[] {
    if (researchResults == undefined) {
      researchResults = [];
    }
    
    let researchResult: RelationResult = {
      name: "",
      id: "",
      date: "",
      percentage: null,
      percentageName: null,
      class: "",
      provenanceAction: provenanceAction,
      relationName: relationName
    };
    
    // researchResult.relationName = relation.to.class;
    
    if (relation['resulttype']) {
      if (relation['resulttype'].classname == "publication") {
        researchResult['class'] = "publication";
      } else if (relation['resulttype'].classname == "dataset") {
        researchResult['class'] = "dataset";
      } else if (relation['resulttype'].classname == "software") {
        researchResult['class'] = "software";
      } else if (relation['resulttype'].classname == "other") {
        researchResult['class'] = "other";
      }
    }
    researchResult['id'] = relation['to'].content;
    if (Array.isArray(relation['title'])) {
      for (let i = 0; i < relation['title'].length; i++) {
        if (relation['title'][i] && relation['title'][i].content) {
          if (!researchResult['name'] || relation['title'][i].classid == "main title") {
            researchResult['name'] = String(relation['title'][i].content);
          }
        }
      }
    } else {
      researchResult['name'] = (relation['title'] && relation['title'].content) ? String(relation['title'].content) : "";
    }
    if (!researchResult['name']) {
      researchResult['name'] = "[no title available]";
    }
    if (relation.hasOwnProperty("dateofacceptance")) {
      var date: string = ((Array.isArray(relation.dateofacceptance)) ? (relation.dateofacceptance[0]) : (relation.dateofacceptance)) + ""; // transform to string in case it is an integer
      researchResult['date'] = (date && (date).indexOf('-') !== -1) ? date.split('-')[0] : date;
    }
    //researchResult['date'] = relation.dateofacceptance.substring(0,4);;
    let percentageName: string;
    if (relation.trust) {
      percentageName = "trust";
    } else if (relation.similarity) {
      percentageName = "similarity";
    }
    if (percentageName) {
      researchResult['percentage'] = Math.round(relation[percentageName] * 100);
      researchResult['percentageName'] = percentageName;
    }
    researchResults.push(researchResult);
    return researchResults;
  }
  
  sortByPercentage(results: RelationResult[]): RelationResult[] {
    if (results) {
      return results.sort(function (a, b) {
        return b["percentage"] - a["percentage"]
      });
    }
    return results;
  }
  
  // publication & dataset landing : for identifiers
  parseIdentifiers(pid: any): Map<string, string[]> {
    let identifiers = new Map<string, string[]>();
    
    if (pid.hasOwnProperty("classid") && pid['classid'] != "") {
      if (pid.classid == "doi" || pid.classid == "pmc" || pid.classid == "handle" || pid.classid == "pmid" || pid.classid == "re3data"
        || pid.classid == "swhid"
        || pid.classid == "ROR" || pid.classid == "ISNI" || pid.classid == "Wikidata" || pid.classid == "FundRef") {
        if (!identifiers.has(pid.classid)) {
          identifiers.set(pid.classid, new Array<string>());
        }
        identifiers.get(pid.classid).push(pid.content + "");
      }
    } else {
      for (let i = 0; i < pid.length; i++) {
        if (pid[i].classid == "doi" || pid[i].classid == "pmc" || pid[i].classid == "handle" || pid[i].classid == "pmid" || pid[i].classid == "re3data"
          || pid[i].classid == "swhid"
          || pid[i].classid == "ROR" || pid[i].classid == "ISNI" || pid[i].classid == "Wikidata" || pid[i].classid == "FundRef") {
          if (!identifiers.has(pid[i].classid)) {
            identifiers.set(pid[i].classid, new Array<string>());
          }
          identifiers.get(pid[i].classid).push(pid[i].content + "");
        }
      }
    }
    return identifiers;
  }
  
  // publication & dataset landing : for subjects and otherSubjects and classifiedSubjects
  parseEoscSubjects(_subjects: any): any[] {
    let eoscSubjectsFound = [];
    let setOfEoscSubjects: Set<string> = new Set();
    
    let subject;
    let length = Array.isArray(_subjects) ? _subjects.length : 1;
    
    for (let i = 0; i < length; i++) {
      subject = Array.isArray(_subjects) ? _subjects[i] : _subjects;
      let content: string = subject.code + "";
      let checkAndAddEoscSubjectResp = this.checkAndAddEoscSubject(setOfEoscSubjects, eoscSubjectsFound, subject, content);
      let found: boolean = checkAndAddEoscSubjectResp["found"];
      if (found) {
        setOfEoscSubjects = checkAndAddEoscSubjectResp["setOfEoscSubject"];
        eoscSubjectsFound = checkAndAddEoscSubjectResp["eoscSubjectsFound"];
      }
    }
    
    return eoscSubjectsFound;
  }
  
  // publication & dataset landing : for subjects and otherSubjects and classifiedSubjects
  parseAllSubjects(_subjects: any, vocabulary: any): [string[], Map<string, string[]>, Map<string, string[]>, string[], string[],] {
    // let eoscSubjectsFound = [];
    let subjects: string[];
    let otherSubjects: Map<string, string[]>;
    let classifiedSubjects: Map<string, string[]>;
    let fos: string[];
    let sdg: string[];
    
    let setOfEoscSubjects: Set<string> = new Set();
    
    let subject;
    let length = Array.isArray(_subjects) ? _subjects.length : 1;
    
    for (let i = 0; i < length; i++) {
      subject = Array.isArray(_subjects) ? _subjects[i] : _subjects;
      if (subject.classid != "") {
        if (subject.classid == "keyword") {
          let content: string = subject.content + "";
          // let checkAndAddEoscSubjectResp = this.checkAndAddEoscSubject(setOfEoscSubjects, eoscSubjectsFound, subject, content);
          // let found: boolean = checkAndAddEoscSubjectResp["found"];
          // if(found) {
          //   setOfEoscSubjects = checkAndAddEoscSubjectResp["setOfEoscSubject"];
          // eoscSubjectsFound = checkAndAddEoscSubjectResp["eoscSubjectsFound"];
          // } else {
          if (subjects == undefined) {
            subjects = new Array<string>();
          }
          subjects.push(content);
          // }
        } else if (!vocabulary || vocabulary[subject.classid] || subject.classid === "SDG" || subject.classid === "FOS") {
          // if (subject.inferred && subject.inferred == true) {
          if (subject.classid === "SDG") {
            if (sdg == undefined) {
              sdg = new Array<string>();
            }
            sdg.push(subject.content + "");
          } else if (subject.classid === "FOS") {
            if (fos == undefined) {
              fos = new Array<string>();
            }
            fos.push(subject.content + "");
          } else {
            if (classifiedSubjects == undefined) {
              classifiedSubjects = new Map<string, string[]>();
            }
            
            let content: string = subject.content + "";
            // let checkAndAddEoscSubjectResp = this.checkAndAddEoscSubject(setOfEoscSubjects, eoscSubjectsFound, subject, content);
            // let found: boolean = checkAndAddEoscSubjectResp["found"];
            // if(found) {
            //   setOfEoscSubjects = checkAndAddEoscSubjectResp["setOfEoscSubject"];
            //   eoscSubjectsFound = checkAndAddEoscSubjectResp["eoscSubjectsFound"];
            // } else {
            if (!classifiedSubjects.has(subject.classname)) {
              classifiedSubjects.set(subject.classname, new Array<string>());
            }
            classifiedSubjects.get(subject.classname).push(content);
            // }
          }
        } else {
          let content: string = subject.content + "";
          // let checkAndAddEoscSubjectResp = this.checkAndAddEoscSubject(setOfEoscSubjects, eoscSubjectsFound, subject, content);
          // let found: boolean = checkAndAddEoscSubjectResp["found"];
          // if(found) {
          //   setOfEoscSubjects = checkAndAddEoscSubjectResp["setOfEoscSubject"];
          //   eoscSubjectsFound = checkAndAddEoscSubjectResp["eoscSubjectsFound"];
          // } else {
          let classname: string = subject.classname + "";
          if (subjects == undefined) {
            subjects = new Array<string>();
          }
          subjects.push(content);
          // }
        }
      }
    }
    return [subjects, otherSubjects, classifiedSubjects, fos, sdg];
  }
  
  checkAndAddEoscSubject(setOfEoscSubjects: Set<string>, eoscSubjectsFound, subject, content) {
    let found: boolean = false;
    
    if (!setOfEoscSubjects.has(content)) {
      // looping through our declared array
      this.eoscSubjects.forEach(item => {
        if (content && content == item.label) {
          found = true;
          eoscSubjectsFound.push(item);
          setOfEoscSubjects.add(content);
        }
      });
    }
    return {"found": found, "setOfEoscSubject": setOfEoscSubjects, "eoscSubjectsFound": eoscSubjectsFound};
  }
  
  parseContexts(_contexts: any): Context[] {
    let contexts = new Array<Context>();
    
    let position = 0;
    let labels = "";
    let context;
    let length = Array.isArray(_contexts) ? _contexts.length : 1;
    for (let i = 0; i < length; i++) {
      let numOfCategories: number = 0;  // count categories with label
      context = Array.isArray(_contexts) ? _contexts[i] : _contexts;
      
      if (context.label && context.hasOwnProperty("type") && (context['type'] == "community" || context['type'] == "ri")) {
        if (context.hasOwnProperty("category")) {
          let category;
          let length2 = Array.isArray(context['category']) ? context['category'].length : 1;
          for (let z = 0; z < length2; z++) {
            let numOfConcepts: number = 0;  // count category concepts with label
            category = Array.isArray(context['category']) ? context['category'][z] : context['category'];
            if (category.label && category.hasOwnProperty("concept")) {
              let categoryConcept;
              let length1 = Array.isArray(category['concept']) ? category['concept'].length : 1;
              for (let j = 0; j < length1; j++) {
                categoryConcept = Array.isArray(category['concept']) ? category['concept'][j] : category['concept'];
                
                // initalize if there is concept label or this is the last concept of the category and there were no concepts
                // otherwise we could have multiple entries for the same category but without concepts
                if (categoryConcept.label || (numOfConcepts == 0 && j == (length1 - 1))) {
                  contexts[position] = {
                    "labelContext": "", "idContext": "",
                    "labelCategory": "", "idCategory": "",
                    "labelConcept": "", "idConcept": ""
                  };
                  contexts[position]['labelContext'] = context.label;
                  contexts[position]['idContext'] = context.id;
                  contexts[position]['labelCategory'] = category.label;
                  contexts[position]['idCategory'] = category.id;
                  contexts[position]['labelConcept'] = categoryConcept.label ? categoryConcept.label : null;
                  contexts[position]['idConcept'] = categoryConcept.label ? categoryConcept.id : null;
                  
                  position++;
                  numOfConcepts++;
                }
              }
            } else if (category.label || (numOfCategories == 0 && z == (length2 - 1))) {
              contexts[position] = {
                "labelContext": "", "idContext": "",
                "labelCategory": "", "idCategory": "",
                "labelConcept": "", "idConcept": ""
              };
              contexts[position]['labelContext'] = context.label;
              contexts[position]['idContext'] = context.id;
              contexts[position]['labelCategory'] = category.label ? category.label : null;
              contexts[position]['idCategory'] = category.label ? category.id : null;
              contexts[position]['labelConcept'] = null;
              contexts[position]['idConcept'] = null;
              position++;
              numOfCategories++;
            }
          }
        } else {
          contexts[position] = {
            "labelContext": "", "idContext": "",
            "labelCategory": "", "idCategory": "",
            "labelConcept": "", "idConcept": ""
          };
          contexts[position]['labelContext'] = context.label;
          contexts[position]['idContext'] = context.id;
          contexts[position]['labelCategory'] = null;
          contexts[position]['idCategory'] = null;
          contexts[position]['labelConcept'] = null;
          contexts[position]['idConcept'] = null;
          contexts[position]['new'] = false;
          position++;
        }
      }
    }
    return contexts;
  }
  
  public static getEnermapsConceptId(contexts: any): string {
    let enermapsconcepts = contexts.filter(c => {
      return c.idCategory == "enermaps::selection" && c.idConcept
    });
    return enermapsconcepts && enermapsconcepts.length > 0 ? enermapsconcepts[0].idConcept.split("enermaps::selection::")[1] : null;
    // return "hotmaps_heat_tot_curr_density"
  }
  
  parseTypes(types: string[], uniqueTypes: Set<string>, instance: any) {
    if (instance && instance.hasOwnProperty("instancetype") && instance['instancetype'].classname) {
      if (!uniqueTypes.has(instance['instancetype'].classname)) {
        types.push(instance['instancetype'].classname);
        uniqueTypes.add(instance['instancetype'].classname);
      }
    }
  }
  
  parseLanguages(_languages: any) {
    var languages = new Array<string>();
    
    if (!Array.isArray(_languages)) {
      if (_languages.classname != "Undetermined" && _languages.classname) {
        languages.push(_languages.classname);
      }
    } else {
      for (let i = 0; i < _languages.length; i++) {
        if (_languages[i].classname != "Undetermined" && _languages[i].classname) {
          languages.push(_languages[i].classname);
        }
      }
    }
    return languages;
  }
  
  parseCountries(_countries: any) {
    var countries = new Array<string>();
    
    if (!Array.isArray(_countries)) {
      if (_countries.classname != "Undetermined" && _countries.classname) {
        countries.push(_countries.classname);
      }
    } else {
      for (let i = 0; i < _countries.length; i++) {
        if (_countries[i].classname != "Undetermined" && _countries[i].classname) {
          countries.push(_countries[i].classname);
        }
      }
    }
    return countries;
  }
  
  parseProgrammingLanguages(_pLanguages) {
    var pLanguages = new Array<string>();
    
    if (!Array.isArray(_pLanguages)) {
      if (_pLanguages.classname != "Undetermined" && _pLanguages.classname) {
        pLanguages.push(_pLanguages.classname);
      }
    } else {
      for (let i = 0; i < _pLanguages.length; i++) {
        if (_pLanguages[i].classname != "Undetermined" && _pLanguages[i].classname) {
          pLanguages.push(_pLanguages[i].classname);
        }
      }
    }
    return pLanguages;
  }
  
  parseReferences(citations: any): Reference[] {
    let references: Reference[] = [];
    citations = Array.isArray(citations) ? citations : [citations];
    citations.forEach(citation => {
      let reference: Reference = {name: null, ids: []};
      if (citation.rawText) {
        reference.name = citation.rawText;
      }
      if (citation.id) {
        let ids: any[] = Array.isArray(citation.id) ? citation.id : [citation.id];
        ids.forEach(id => {
          reference.ids.push({
            type: id.type,
            value: id.value,
            trust: id.confidenceLevel
          });
        });
      }
      references[citation.position - 1] = reference;
    });
    return references;
  }
  
  static parseRelCanonicalId(record, type) {
    try {
      if (record["result"]["metadata"]["oaf:entity"][("oaf:" + type)]["children"] && record["result"]["metadata"]["oaf:entity"][("oaf:" + type)]["children"][type]) {
        for (let child of record["result"]["metadata"]["oaf:entity"][("oaf:" + type)]["children"][type]) {
          return child["objidentifier"];
        }
      }
    } catch (e) {
      // console.error(e);
    }
    return record["result"]["header"]["dri:objIdentifier"];
    
  }
  
  parseDescription(description, stripHTML: boolean = false): string {
    let abstracts = [];
    if (!Array.isArray(description)) {
      abstracts = [description ? String(description) : ""];
    } else {
      abstracts = description.map(x => String(x));
    }
    try {
      abstracts = abstracts.map(x => StringUtils.HTMLToString(x));
    } catch (e) {
    }
    abstracts = abstracts.sort((a, b) => b.length - a.length);
    if (stripHTML) {
      return abstracts.join(' ');
    } else {
      return abstracts.length > 0 ? ('<p>' + abstracts.join('</p> <p>') + '</p>') : abstracts.join(' ');
    }
  }
  
  parseMeasures(elements: any[]): Measure {
    if (elements && elements.length) {
      let bip: Metric[] = [];
      let counts: Metric[] = [];
      let countsPerDatasource: MetricPerDatasource[] = [];
      let measure: Measure = {};

      let datasourcePosition: Map<string, number> = new Map<string, number>();

      let views: number = 0;
      let downloads: number = 0;
      elements.forEach(element => {
        if (element.id == 'views') {
          views += element.count;
          let datasourceId = element.datasource;
          if(datasourceId) {
            if(datasourcePosition.has(element.datasource)) {
              countsPerDatasource[datasourcePosition.get(element.datasource)].views = element.count;
            } else {
              datasourcePosition.set(element.datasource, countsPerDatasource.length);
              countsPerDatasource.push({"datasourceId": element.datasource.split("||")[0], "datasourceName": element.datasource.split("||")[1], "views": element.count, "downloads": 0})
            }
          }
          // measure.views = element.count;
        }
        if (element.id == 'downloads') {
          downloads += element.count;
          let datasourceId = element.datasource;
          if(datasourceId) {
            if(datasourcePosition.has(element.datasource)) {
              countsPerDatasource[datasourcePosition.get(element.datasource)].downloads = element.count;
            } else {
              datasourcePosition.set(element.datasource, countsPerDatasource.length);
              countsPerDatasource.push({"datasourceId": element.datasource.split("||")[0], "datasourceName": element.datasource.split("||")[1], "views": 0, "downloads": element.count})
            }
          }
          // measure.downloads = element.count;
        }
        if (element.id == 'influence_alt' || element.id == 'citation_count') {
          bip.push({name: 'citations', icon: 'cite', value: element.score, order: 2});
          // measure.citations = element.score;
        }
        if (element.id == 'popularity') {
          let metric: Metric = {name: 'popularity', icon: 'fire', value: null, order: 3};
          if (element.class == 'C1') {
            metric.value = 'Top 0.01%';
          } else if (element.class == 'C2') {
            metric.value = 'Top 0.1%';
          } else if (element.class == 'C3') {
            metric.value = 'Top 1%';
          } else if (element.class == 'C4') {
            metric.value = 'Top 10%';
          } else {
            metric.value = 'Average';
          }
          // measure.popularity = metric.value;
          bip.push(metric);
        }
        if (element.id == 'influence') {
          let metric: Metric = {name: 'influence', icon: 'landmark', value: null, order: 4};
          if (element.class == 'C1') {
            metric.value = 'Top 0.01%';
          } else if (element.class == 'C2') {
            metric.value = 'Top 0.1%';
          } else if (element.class == 'C3') {
            metric.value = 'Top 1%';
          } else if (element.class == 'C4') {
            metric.value = 'Top 10%';
          } else {
            metric.value = 'Average';
          }
          // measure.influence = metric.value;
          bip.push(metric);
        }
        if (element.id == 'impulse') {
          let metric: Metric = {name: 'impulse', icon: 'rocket', value: null, order: 5};
          if (element.class == 'C1') {
            metric.value = 'Top 0.01%';
          } else if (element.class == 'C2') {
            metric.value = 'Top 0.1%';
          } else if (element.class == 'C3') {
            metric.value = 'Top 1%';
          } else if (element.class == 'C4') {
            metric.value = 'Top 10%';
          } else {
            metric.value = 'Average';
          }
          // measure.impulse = metric.value;
          bip.push(metric);
        }
      });

      if(views > 0) {
        counts.push({name: 'views', icon: 'visibility', value: views, order: 0});
      }
      if(downloads > 0) {
        counts.push({name: 'downloads', icon: 'download', value: downloads, order: 1});
      }
      if(countsPerDatasource && countsPerDatasource.length > 0) {
        measure.countsPerDatasource = countsPerDatasource;
      }

      measure.bip = bip.sort((a, b) => a.order - b.order);
      measure.counts = counts.sort((a, b) => a.order - b.order);
      return measure;
    }
    return null;
  }
}
