import {ChangeDetectorRef, Component, ElementRef, Inject, Input, Renderer2, ViewChild} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {DOCUMENT, Location} from '@angular/common';
import {Meta, Title} from '@angular/platform-browser';
import {EnvProperties} from '../openaireLibrary/utils/properties/env-properties';
import {CommunityService} from "../openaireLibrary/connect/community/community.service";
import {ConfigurationService} from '../openaireLibrary/utils/configuration/configuration.service';
import {PiwikService} from '../openaireLibrary/utils/piwik/piwik.service';
import {ZenodoCommunitiesService} from '../openaireLibrary/connect/zenodoCommunities/zenodo-communities.service';
import {Session, User} from '../openaireLibrary/login/utils/helper.class';
import {StatisticsForDashboardComponent} from '../statistics/statistics.component';
import {StringUtils} from '../openaireLibrary/utils/string-utils.class';
import {SearchCommunityDataprovidersService} from "../openaireLibrary/connect/contentProviders/searchDataproviders.service";
import {SearchCommunityProjectsService} from "../openaireLibrary/connect/projects/searchProjects.service";
import {SearchResearchResultsService} from "../openaireLibrary/services/searchResearchResults.service";
import {RouterHelper} from "../openaireLibrary/utils/routerHelper.class";
import {SEOService} from "../openaireLibrary/sharedComponents/SEO/SEO.service";
import {UserManagementService} from "../openaireLibrary/services/user-management.service";
import {SearchCustomFilter} from "../openaireLibrary/searchPages/searchUtils/searchUtils.class";
import {FetchResearchResults} from "../openaireLibrary/utils/fetchEntitiesClasses/fetchResearchResults.class";
import {ErrorCodes} from "../openaireLibrary/utils/properties/errorCodes";
import {Subscription} from "rxjs";
import {properties} from "../../environments/environment";
import {ConnectHelper} from "../openaireLibrary/connect/connectHelper";
import {Filter} from "../openaireLibrary/searchPages/searchUtils/searchHelperClasses.class";
import {OpenaireEntities} from '../openaireLibrary/utils/properties/searchFields';

@Component({
  selector: 'community',
  templateUrl: 'community.component.html',
  styles: [
    `
      #mytabs .uk-tab::before {
          border-bottom: none;
      }
      #mytabs::before {
          content: "";
          position: absolute;
          bottom: 0;
          left: 0;
          right: 0;
          border-bottom: 1px solid #eaeaea;
      }
    `
  ]
})

export class CommunityComponent {
  public url: string = null;

  public projectTotal = null;
  public contentProviderTotal = null;

  public projectsCalculated: boolean = false;
  public contentProvidersCalculated: boolean = false;

  params: any = {};
  properties: EnvProperties = properties;

  public errorCodes: ErrorCodes = new ErrorCodes();
  // Request results of each tab only the one time (first time tab is clicked)
  private reloadPublications: boolean = true;
  private reloadDatasets: boolean = true;
  private reloadSoftware: boolean = true;
  private reloadOrps: boolean = true;
  private reloadFeaturedDatasets: boolean = true;

  // Variables for publications, research data, projects, content providers, related content providers tabs
  public fetchPublications: FetchResearchResults;
  public fetchDatasets: FetchResearchResults;
  public fetchSoftware: FetchResearchResults;
  public fetchOrps: FetchResearchResults;
  public fetchFeaturedDatasets: FetchResearchResults;
  public searchNumber: number = 5;

  @Input() communityId = null;
  public community = null;

  public portal = null;

  public showLoading: boolean = true;
  masterZenodoCommunity = null;
  zenodoCommunityIdS = [];
  showAllDescription = false;
  public thresholdDescription: number = 500;
  public descriptionDiff: number = 100;

  page = 1;
  size = 5;

  subscribers: number = 0;

  subs: Subscription[] = [];

  displayedAllSubjects = [];
  displayedSubjects = [];
  displayedSdg = [];
  displayedFos = [];

  @ViewChild(StatisticsForDashboardComponent) statistics: StatisticsForDashboardComponent = null;
  public activeTab = "summary";
  public show: string = 'overview';
  public analyticsActiveTab: string = "";
  public analyticsChecked: boolean = false;

  searchLinkToResults: string = null;

  searchLinkToProjects: string = null;
  searchLinkToDataProviders: string = null;
  searchLinkToAdvancedResults: string = null;
  shareInZenodoPage: string = null;
  public routerHelper: RouterHelper = new RouterHelper();
  private user: User;
  selectedEntity = 'result';
  selectedEntitySimpleUrl;
  selectedEntityAdvancedUrl;
  resultTypes: Filter = {
    values: [],
    filterId: "type",
    countSelectedValues: 0,
    filterType: 'checkbox',
    originalFilterId: "",
    valueIsExact: true,
    title: "Type",
    filterOperator: "or"
  };
  showPublications: boolean = false;
  showDatasets: boolean = false;
  showSoftware: boolean = false;
  showOrp: boolean = false;
  showProjects: boolean = false;
  showDataProviders: boolean = false;
  keyword: string = "";
  customFilter;
  placeholderText = "Search by title, author, abstract, DOI, orcid... ";
  resultsQuickFilter: { filter: Filter, selected: boolean, filterId: string, value: string } = {
    filter: null,
    selected: true,
    filterId: "resultbestaccessright",
    value: "Open Access"
  };
  disableSelect: boolean = true;
  openaireEntities= OpenaireEntities;

  constructor(
    private element: ElementRef,
    private route: ActivatedRoute,
    private _router: Router,
    private location: Location,
    private _meta: Meta,
    private _title: Title,
    private _piwikService: PiwikService,
    private config: ConfigurationService,
    private _communityService: CommunityService,
    private _searchCommunityDataprovidersService: SearchCommunityDataprovidersService,
    private _searchCommunityProjectsService: SearchCommunityProjectsService,
    private _searchResearchResultsService: SearchResearchResultsService,
    private _zenodoCommunitieService: ZenodoCommunitiesService,
    private seoService: SEOService,
    private userManagementService: UserManagementService,
    private _renderer2: Renderer2,
    private cdr: ChangeDetectorRef,
    @Inject(DOCUMENT) private _document: Document) {

    var description = "OpenAIRE - Connect, Community Dashboard, research community";
    var title = "OpenAIRE - Connect";
    this._meta.updateTag({content: description}, "name='description'");
    this._meta.updateTag({content: description}, "property='og:description'");
    this._meta.updateTag({content: title}, "property='og:title'");
    this._title.setTitle(title);

    this.fetchPublications = new FetchResearchResults(this._searchResearchResultsService);
    this.fetchDatasets = new FetchResearchResults(this._searchResearchResultsService);
    this.fetchSoftware = new FetchResearchResults(this._searchResearchResultsService);
    this.fetchOrps = new FetchResearchResults(this._searchResearchResultsService);
    this.fetchFeaturedDatasets = new FetchResearchResults(this._searchResearchResultsService);

  }

  public ngOnInit() {
    this.searchLinkToResults = this.properties.searchLinkToResults;
    this.searchLinkToProjects = this.properties.searchLinkToProjects;
    this.searchLinkToDataProviders = this.properties.searchLinkToDataProviders;
    this.searchLinkToAdvancedResults = this.properties.searchLinkToAdvancedResults;
    this.shareInZenodoPage = this.properties.shareInZenodoPage;
    this.url = properties.domain + properties.baseLink + this._router.url;
    this.seoService.createLinkForCanonicalURL(this.url, false);
    this._meta.updateTag({content: this.url}, "property='og:url'");
    this.subs.push(this.userManagementService.getUserInfo().subscribe(user => {
      this.user = user;
    }));
    this.customFilter = new SearchCustomFilter("Community", "communityId", this.communityId, "");
    this.subs.push(this._communityService.getCommunityAsObservable().subscribe(
      community => {
        this.community = community;
        if(community && !ConnectHelper.isPrivate(community, this.user)) {
          this.displayedSubjects = community.subjects;
          this.displayedSdg = community.sdg;
          this.displayedFos = community.fos;
          this.displayedSubjects.forEach(element => {
            this.displayedAllSubjects.push({value: element, type: 'resultsubject'});
          });
          this.displayedSdg.forEach(element => {
            this.displayedAllSubjects.push({value: element, type: 'sdg'});
          });
          this.displayedFos.forEach(element => {
            this.displayedAllSubjects.push({value: element, type: 'fos'});
          });
          if (community.description != null && (community.description.length - this.thresholdDescription <= this.descriptionDiff)) {
            this.thresholdDescription = community.description.length;
          }

          if (this.properties.environment == "development") {
            this.params = {communityId: community.communityId};
          }
          this._meta.updateTag({content: community.description}, "name='description'");
          this._meta.updateTag({content: community.description}, "property='og:description'");
          this._meta.updateTag({content: community.title}, "property='og:title'");
          this._title.setTitle(community.title);
          this.subs.push(this._piwikService.trackView(this.properties, community.title).subscribe());
          if (this.community.zenodoCommunity) {
            this.subs.push(this._zenodoCommunitieService.getZenodoCommunityById(this.properties, this.properties.zenodoCommunities + this.community.zenodoCommunity).subscribe(
              result => {
                this.masterZenodoCommunity = result;
              },
              error => {
                this.handleError("Error getting Master Zenodo community with id: " + this.community.zenodoCommunity, error);
              }
            ));
          }
          this.zenodoCommunityIdS = this.community.otherZenodoCommunities;
        }
      }));

    this.countResearchResults("publication");
    this.countResearchResults("dataset");
    this.countResearchResults("software");
    this.countResearchResults("other");
    if(this.communityId == "enermaps"){
      this.countResearchResults("dataset", "enermaps::selection" );
    }

    this.subs.push(this._searchCommunityProjectsService.countTotalProjects(this.properties, this.communityId).subscribe(
      projectTotal => {
        this.projectTotal = projectTotal;
      },
      error => {
        this.handleError("Error getting number of projects for community with id: " + this.communityId, error);
      },
      () => {
        this.projectsCalculated = true;
      }
    ));

    this.subs.push(this._searchCommunityDataprovidersService.countTotalDataproviders(this.properties, this.communityId).subscribe(
      contentProviderTotal => {
        this.contentProviderTotal = contentProviderTotal;
        //console.log(contentProviderTotal);
      },
      error => {
        this.handleError("Error getting number of content providers for community with id: " + this.communityId, error);
      },
      () => {
        this.contentProvidersCalculated = true;
      }
    ));
    this.subs.push(this.config.portalAsObservable.subscribe(
      res => {
        this.portal = res;

        // loading twitter widget script conditionally
        if (properties.environment == "development") {
          if (this.portal && this.portal.twitterAccount) {
            let script = this._renderer2.createElement('script');
            script.charset = "utf-8";
            script.src = "https://platform.twitter.com/widgets.js";
            this._renderer2.appendChild(this._document.body, script);
          }
        }
      },
      error => {
        //console.log(error)
        this.handleError("Error getting community with id: " + this.communityId, error);
      }
    ));
    this.subs.push(this.config.portalAsObservable.subscribe(data => {
      if (data) {
        var showEntity = {};
        for (var i = 0; i < data['entities'].length; i++) {
          showEntity["" + data['entities'][i]["pid"] + ""] = data['entities'][i]["isEnabled"];
        }
        this.showPublications = !!showEntity["publication"];
        this.showDatasets = !!showEntity["dataset"];
        this.showSoftware = !!showEntity["software"];
        this.showOrp = !!showEntity["orp"];
        this.showProjects = !!showEntity["project"];
        this.showDataProviders = !!showEntity["datasource"];
        this.resultTypes.values = [];
        if (this.showPublications) {
          this.resultTypes.values.push({
            name: this.openaireEntities.PUBLICATIONS,
            id: "publications",
            selected: false,
            number: 0
          });
        }
        if (this.showDatasets) {
          this.resultTypes.values.push({
            name: this.openaireEntities.DATASETS,
            id: "datasets",
            selected: false,
            number: 0
          });
        }
        if (this.showSoftware) {
          this.resultTypes.values.push({
            name: this.openaireEntities.SOFTWARE,
            id: "software",
            selected: false,
            number: 0
          });
        }
        if (this.showOrp) {
          this.resultTypes.values.push({name: this.openaireEntities.OTHER, id: "other", selected: false, number: 0});
        }
      }
    }));
  }

  private searchPublications(page: number, size: number) {
    this.setActiveTab("publication");

    if (this.reloadPublications &&
      (this.fetchPublications.searchUtils.status == this.errorCodes.LOADING ||
        (this.fetchPublications.searchUtils.status == this.errorCodes.DONE && this.fetchPublications.searchUtils.totalResults > 0)
      )
    ) {
      this.fetchPublications.getResultsForCommunity("publication", this.communityId, page, size, this.properties);
    }
    this.reloadPublications = false;
  }

  private searchDatasets(page: number, size: number) {
    this.setActiveTab("dataset");

    if (this.reloadDatasets &&
      (this.fetchDatasets.searchUtils.status == this.errorCodes.LOADING ||
        (this.fetchDatasets.searchUtils.status == this.errorCodes.DONE && this.fetchDatasets.searchUtils.totalResults > 0)
      )
    ) {
      this.fetchDatasets.getResultsForCommunity("dataset", this.communityId, page, size, this.properties);
    }
    this.reloadDatasets = false;
  }

  private searchSoftware(page: number, size: number) {
    this.setActiveTab("software");

    if (this.reloadSoftware &&
      (this.fetchSoftware.searchUtils.status == this.errorCodes.LOADING ||
        (this.fetchSoftware.searchUtils.status == this.errorCodes.DONE && this.fetchSoftware.searchUtils.totalResults > 0)
      )
    ) {
      this.fetchSoftware.getResultsForCommunity("software", this.communityId, page, size, this.properties);
    }
    this.reloadSoftware = false;
  }

  private searchOrps(page: number, size: number) {
    this.setActiveTab("other");

    if (this.reloadOrps &&
      (this.fetchOrps.searchUtils.status == this.errorCodes.LOADING ||
        (this.fetchOrps.searchUtils.status == this.errorCodes.DONE && this.fetchOrps.searchUtils.totalResults > 0)
      )
    ) {
      this.fetchOrps.getResultsForCommunity("other", this.communityId, page, size, this.properties);
    }
    this.reloadOrps = false;
  }
  private searchFeaturedDatasets(page: number, size: number) {
    this.setActiveTab("enermaps");
    if (this.reloadFeaturedDatasets &&
      (this.fetchFeaturedDatasets.searchUtils.status == this.errorCodes.LOADING ||
        (this.fetchFeaturedDatasets.searchUtils.status == this.errorCodes.DONE && this.fetchFeaturedDatasets.searchUtils.totalResults > 0)
      )
    ) {
      this.fetchFeaturedDatasets.getAllResultsForCommunity("dataset", this.communityId, page, size, this.properties, "enermaps::selection");
      // console.log(this.fetchFeaturedDatasets);
    }
    this.reloadFeaturedDatasets = false;
  }

  private countResearchResults(resultType: string, contextId = null) {
    let fetch: FetchResearchResults;

    if (resultType == "publication") {
      fetch = this.fetchPublications;
    } else if (resultType == "dataset" && !contextId) {
      fetch = this.fetchDatasets;
    } else if (resultType == "software") {
      fetch = this.fetchSoftware;
    } else if (resultType == "other") {
      fetch = this.fetchOrps;
    } else if (resultType == "dataset" && contextId) {
      fetch = this.fetchFeaturedDatasets;
      this.fetchFeaturedDatasets.getAllResultsForCommunity("dataset", this.communityId, 0, 0, this.properties, contextId);
      return;
    }
    fetch.getNumForCommunity(resultType, this.communityId, this.properties, contextId);
  }

  public ngOnDestroy() {
    for (let sub of this.subs) {
      sub.unsubscribe();
    }
    this.fetchPublications.clearSubscriptions();
    this.fetchDatasets.clearSubscriptions();
    this.fetchOrps.clearSubscriptions();
    this.fetchSoftware.clearSubscriptions();
    this.fetchFeaturedDatasets.clearSubscriptions();
  }

  isEntityEnabled(entity: string) {
    return this.portal.entities.some(x => x['pid'] == entity && x['isEnabled'] === true);
  }

  isRouteEnabled(route: string) {
    return this.portal.pages.some(x => x['route'] == route && x['isEnabled'] === true);
  }

  showInvite() {
    return this.isManager();
  }

  isManager() {
    if (!this.user) {
      return false;
    }
    var email = this.user.email;
    var index = -1;
    if (email && this.community != null && this.community.managers != null) {
      index = this.community.managers.indexOf(email);
    }
    return Session.isPortalAdministrator(this.user) || Session.isCommunityCurator(this.user) || index != -1;
  }

  private handleError(message: string, error) {
    console.error("Community (component): " + message, error);
  }

  getSearchPlaceHolder() {
    var entities = [];
    if (this.isEntityEnabled("publication")) {
      entities.push("publications");
    }
    if (this.isEntityEnabled("dataset")) {
      entities.push("research data");
    }
    if (this.isEntityEnabled("software")) {
      entities.push("software");
    }
    if (this.isEntityEnabled("orp")) {
      entities.push("other research products");
    }
    return "Search" + ((entities.length > 0) ? (" for " + entities.join(', ') + "...") : "");
  }

  countOtherGraphs() {
    var count = 0;
    if (this.statistics && this.statistics.allowedEntities) {
      for (var entity of this.statistics.allowedEntities) {
        if (this.statistics.statisticsSum[entity].total > 0 && this.statistics.allowedCharts[entity].length > 0 && this.activeTab != entity) {
          count += this.statistics.allowedCharts[entity].length;
        }
      }
    }
    return count;
  }

  createParams(param) {
    return StringUtils.quote(StringUtils.URIEncode(param));
  }

  private setActiveTab(entityType: string) {
    if (entityType == "other") {
      this.activeTab = "orp";
    } else {
      this.activeTab = entityType;
    }
  }

  public getParamsForSearchLink(type: string = "") {
    if (type) {
      return this.routerHelper.createQueryParams(['type', 'qf', 'sortBy'], [type, 'false', 'resultdateofacceptance,descending']);
    } else {
      return {};
    }
  }

  private getEntityName(entityType: string, plural: boolean, full: boolean): string {
    if (entityType == "publication") {
      return "publication" + (plural ? "s" : "");
    } else if (entityType == "dataset") {
      return (full ? "research data" : ("dataset" + (plural ? "s" : "")));
    } else if (entityType == "software") {
      return "software";
    } else if (entityType == "other") {
      return (full ? ("other research product" + (plural ? "s" : "")) : "other");
    }
  }

  public buildProjectsTooltip(): string {
    let tooltipContent: string = "<div>";

    if (this.projectTotal != null && this.projectTotal > 0 && this.isEntityEnabled('project') && this.isRouteEnabled(this.searchLinkToProjects)) {
      tooltipContent += "<span class='uk-text-bold'>Projects</span>";
    }

    tooltipContent += " have been selected as relevant for your community by the gateway curators.";
    tooltipContent += "</div>";

    return tooltipContent;
  }

  public buildContentProvidersTooltip(): string {
    let tooltipContent: string = "<div>";
    
    if (this.contentProviderTotal != null && this.contentProviderTotal > 0 && this.isEntityEnabled('datasource') && this.isRouteEnabled(this.searchLinkToDataProviders)) {
      tooltipContent += "<span class='uk-text-bold'>Content Providers</span>";
    }

    tooltipContent += " have been selected as relevant for your community by the gateway curators.";
    tooltipContent += "</div>";

    return tooltipContent;
  }

  public buildZenodoCommunitiesTooltip(): string {
    let tooltipContent: string = "<div>";

    tooltipContent += "<span class='uk-text-bold'>Zenodo</span> is a catch-all repository for OpenAIRE.";
    tooltipContent += "<div class='uk-margin-small-top'>A <span class='uk-text-bold'>Zenodo Community</span> is created and curated by Zenodo users.</div>";
    tooltipContent += "</div>";
    
    return tooltipContent;
  }

  entityChanged($event) {
    this.selectedEntity = $event.entity;
    this.selectedEntitySimpleUrl = $event.simpleUrl;
    this.selectedEntityAdvancedUrl = $event.advancedUrl;
    if (this.selectedEntity == 'result') {
      this.placeholderText = "Search by title, author, abstract, DOI, orcid... ";
    } else if (this.selectedEntity == 'project') {
      this.placeholderText = "Search by project title, grant id, funder...";
    } else if (this.selectedEntity == 'dataprovider') {
      this.placeholderText = "Search by name...";
    } else {
      this.placeholderText = "Search community content";
    }
  }

  goTo(simple: boolean) {
    let url = (simple) ? this.selectedEntitySimpleUrl : this.selectedEntityAdvancedUrl;
    let parameterNames = [];
    let parameterValues = [];

    if (this.selectedEntity == "result" && this.resultsQuickFilter && this.resultsQuickFilter.selected) {
      parameterNames.push(this.resultsQuickFilter.filterId);
      parameterValues.push('"'+ encodeURIComponent(this.resultsQuickFilter.value)+'"');
    }

    if (this.keyword.length > 0) {
      parameterNames.push("fv0");
      parameterValues.push(this.keyword);
      parameterNames.push("f0");
      parameterValues.push("q");
    }
    this._router.navigate([url], {queryParams: this.routerHelper.createQueryParams(parameterNames, parameterValues)});
  }

  public countSubscribersEvent($event) {
    this.subscribers = $event.value;
  }

  public checkStatistics(type: string) {
    return !!(this.isEntityEnabled(type)
      && this.statistics && this.statistics.statisticsDisplay && this.statistics.statisticsDisplay.isActive
      && this.statistics.statisticsSum && this.statistics.statisticsSum[type] && this.statistics.statisticsSum[type].total > 0
      &&
      (this.statistics.statisticsDisplay.entities[type].numbers.map['total']['showInMonitor']
        || this.statistics.statisticsDisplay.entities[type].numbers.map['project']['showInMonitor']
        || this.statistics.statisticsDisplay.entities[type].numbers.map['open']['showInMonitor']
        || this.statistics.statisticsDisplay.entities[type].numbers.map['closed']['showInMonitor']
        || this.statistics.statisticsDisplay.entities[type].numbers.map['embargo']['showInMonitor']
        || this.statistics.statisticsDisplay.entities[type].numbers.map['restricted']['showInMonitor']
        || (this.statistics.allowedEntitiesMode['showInMonitor']
          && this.statistics.allowedChartsMode['showInMonitor'][type]
          && this.statistics.allowedChartsMode['showInMonitor'][type].length > 0)));
  }

  public initializeAnalyticsActiveTab() {
    if (!this.analyticsChecked) {
      if (this.checkStatistics("publication")) {
        this.analyticsActiveTab = "publication";
      } else if (this.checkStatistics("dataset")) {
        this.analyticsActiveTab = "dataset";
      } else if (this.checkStatistics("software")) {
        this.analyticsActiveTab = "software";
      } else if (this.checkStatistics("orp")) {
        this.analyticsActiveTab = "orp";
      }
    }
  }

  public showAnalyticsTab() {
    this.initializeAnalyticsActiveTab();
    return this.analyticsActiveTab;
  }

  public onSelectActiveTab(activeTabId) {
    if (this.activeTab != "activaTabId") {   // tab really changed
      if (activeTabId == 'summary') {
        this.activeTab = 'summary';
      } else if (activeTabId == 'publications') {
        this.show = 'overview';
        this.searchPublications(1, this.searchNumber);
      } else if (activeTabId == 'datasets') {
        this.show = 'overview';
        this.searchDatasets(1, this.searchNumber);
      } else if (activeTabId == 'software') {
        this.show = 'overview';
        this.searchSoftware(1, this.searchNumber);
      } else if (activeTabId == 'other') {
        this.show = 'overview';
        this.searchOrps(1, this.searchNumber);
      } else if (activeTabId == 'analytics') {
        this.show = 'analysis';
        this.activeTab = 'analytics';
        this.analyticsChecked = true;
      } else if (activeTabId == 'mapping') {
        this.show = 'mapping';
        this.activeTab = 'mapping';
      } else if (activeTabId == 'enermaps') {
        this.show = 'enermaps';
        this.activeTab = 'enermaps';
        this.searchFeaturedDatasets(1, this.fetchFeaturedDatasets.searchUtils.totalResults);
      } else if (activeTabId == 'twitter') {
        this.show = 'twitter';
        this.activeTab = 'twitter';
      }
    }
  }
  isPrivate(){
    return ConnectHelper.isPrivate(this.community, this.user);
  }

  disableSelectChange(event: boolean) {
    this.disableSelect = event;
    this.cdr.detectChanges();
  }

  public updatePage(event) {
    this.page = event.value;
  }
}
