import {
  AfterViewInit,
  ChangeDetectorRef,
  Component,
  ElementRef,
  Inject,
  OnDestroy,
  OnInit,
  PLATFORM_ID,
  QueryList,
  ViewChild,
  ViewChildren
} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {Meta, Title} from '@angular/platform-browser';
import {EnvProperties} from '../openaireLibrary/utils/properties/env-properties';
import {PiwikService} from '../openaireLibrary/utils/piwik/piwik.service';
import {ErrorCodes} from '../openaireLibrary/utils/properties/errorCodes';
import {ErrorMessagesComponent} from '../openaireLibrary/utils/errorMessages.component';
import {HelperService} from "../openaireLibrary/utils/helper/helper.service";
import {SEOService} from "../openaireLibrary/sharedComponents/SEO/SEO.service";
import {RefineFieldResultsService} from "../openaireLibrary/services/refineFieldResults.service";
import {NumberUtils} from "../openaireLibrary/utils/number-utils.class";
import {SearchResearchResultsService} from "../openaireLibrary/services/searchResearchResults.service";
import {StakeholderService} from "../openaireLibrary/monitor/services/stakeholder.service";
import {LocalStorageService} from "../openaireLibrary/services/localStorage.service";
import {Stakeholder, StakeholderEntities, StakeholderInfo} from "../openaireLibrary/monitor/entities/stakeholder";
import {User} from "../openaireLibrary/login/utils/helper.class";
import {UserManagementService} from "../openaireLibrary/services/user-management.service";
import {properties} from "../../environments/environment";
import {Subscriber} from "rxjs";
import {QuickContactService} from '../openaireLibrary/sharedComponents/quick-contact/quick-contact.service';
import {IDeactivateComponent} from "../openaireLibrary/utils/can-exit.guard";
import {OpenaireEntities} from "../openaireLibrary/utils/properties/searchFields";
import {isPlatformServer} from '@angular/common';
import {LayoutService} from '../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service';

@Component({
  selector: 'home',
  templateUrl: 'home.component.html',
  styleUrls: ['home.component.less']
})
export class HomeComponent implements OnInit, OnDestroy, AfterViewInit, IDeactivateComponent {
  public pageTitle = "OpenAIRE | Monitor";
  public description = "OpenAIRE - Monitor, A new era of monitoring research. Open data. Open methodologies. Work together with us to view, understand and visualize research statistics and indicators.";
  public stakeholders: StakeholderInfo[] = [];
  public stakeholdersSlider: {
    stakeholders: StakeholderInfo[][];
    funders: StakeholderInfo[][];
    ris: StakeholderInfo[][];
    organizations: StakeholderInfo[][];
  };
  public selected: Stakeholder = null;
  public pageContents = null;
  public divContents = null;
  // Message variables
  public status: number;
  public loading: boolean = true;
  public errorCodes: ErrorCodes;
  public properties: EnvProperties = properties;
  public openaireEntities = OpenaireEntities;
	public stakeholderEntities = StakeholderEntities;
  public directLink: boolean = true;
  public publicationsSize: any = null;
  public datasetsSize: any = null;
  public softwareSize: any = null;
  public otherSize: any = null;
  public fundersSize: any = null;
  private errorMessages: ErrorMessagesComponent;
  private subscriptions = [];
  private mutationObserver: MutationObserver;
  private user: User;
  @ViewChildren('scrolling_element') elements: QueryList<ElementRef>;
  @ViewChild('contact') contact: ElementRef;
	isMobile: boolean = false;
	isServer: boolean;
  
  constructor(
    private route: ActivatedRoute,
    private _router: Router,
    private _meta: Meta,
    private _title: Title,
    private _piwikService: PiwikService,
    private _stakeholderService: StakeholderService,
    private localStorageService: LocalStorageService,
    private userManagementService: UserManagementService,
    private helper: HelperService,
    private seoService: SEOService,
    private _refineFieldResultsService: RefineFieldResultsService,
    private _searchResearchResultsService: SearchResearchResultsService,
    private quickContactService: QuickContactService,
		private layoutService: LayoutService,
		private cdr: ChangeDetectorRef,
		@Inject(PLATFORM_ID) private platform: any) {
    this._meta.updateTag({content: this.description}, "name='description'");
    this._meta.updateTag({content: this.description}, "property='og:description'");
    this._meta.updateTag({content: this.pageTitle}, "property='og:title'");
    this._title.setTitle(this.pageTitle);
    this.errorCodes = new ErrorCodes();
    this.errorMessages = new ErrorMessagesComponent();
    this.status = this.errorCodes.LOADING;
		this.isServer = isPlatformServer(this.platform);
    this.quickContactService.setDisplay(false);
  }
  
  public ngOnInit() {
    let url = this.properties.domain + this.properties.baseLink + this._router.url;
    this.seoService.createLinkForCanonicalURL(url, false);
    this._meta.updateTag({content: url}, "property='og:url'");
    this.subscriptions.push(this._piwikService.trackView(this.properties, "OpenAIRE Monitor").subscribe());
    this.getNumbers();
    this.subscriptions.push(this.localStorageService.get().subscribe(value => {
      this.directLink = value;
    }));
    this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
      this.user = user;
      this.getStakeholders();
    }));
		this.layoutService.isMobile.subscribe(isMobile => {
			this.isMobile = isMobile;
			this.cdr.detectChanges();
		});
  }
  
  canExit(): boolean {
    this.clear();
    return true;
  }
  
  ngOnDestroy() {
    this.quickContactService.setDisplay(true);
    this.clear();
  }
  
  clear() {
    this.subscriptions.forEach(value => {
      if (value instanceof Subscriber) {
        value.unsubscribe();
      } else if (value instanceof IntersectionObserver || value instanceof MutationObserver) {
        value.disconnect();
      }
    });
    if(this.mutationObserver) {
      this.mutationObserver.disconnect();
    }
  }
  
  ngAfterViewInit() {
    if(typeof window !== "undefined") {
      this.createObservers();
    }
  }
  
  createObservers() {
    let options = {
      root: null,
      rootMargin: '200px',
      threshold: 1.0
    };
    let intersectionObserver = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        this.quickContactService.setDisplay(!entry.isIntersecting);
      });
    }, options);
		if(this.contact) {
			intersectionObserver.observe(this.contact.nativeElement);
		}
   this.mutationObserver = new MutationObserver(entries => {
      entries.forEach(entry => {
        if (entry.attributeName === 'style') {
          let opacities: number[] = this.elements.map(element => +element.nativeElement.style.opacity);
          let active: number = opacities.indexOf(Math.max(...opacities));
          this.elements.forEach((element, index) => {
            if (index === active) {
              element.nativeElement.classList.remove('uk-disabled');
            } else {
              element.nativeElement.classList.add('uk-disabled');
            }
          })
        }
      })
    });
    this.elements.changes.subscribe(() => {
      this.elements.forEach(element => {
        this.mutationObserver.observe(element.nativeElement, {attributes: true});
      });
    });
    this.subscriptions.push(intersectionObserver);
  }
  
  private getPageContents() {
    this.subscriptions.push(this.helper.getPageHelpContents(this.properties, 'monitor', this._router.url).subscribe(contents => {
      this.pageContents = contents;
    }));
  }
  
  private getDivContents() {
    this.subscriptions.push(this.helper.getDivHelpContents(this.properties, 'monitor', this._router.url).subscribe(contents => {
      this.divContents = contents;
    }));
  }
  
  getNumbers() {
    this.subscriptions.push(this._refineFieldResultsService.getRefineFieldsResultsByEntityName(["funder"], "project", this.properties).subscribe(
      data => {
        if (data[1].length > 0 && data[1][0].filterId == "funder" && data[1][0].values) {
          this.fundersSize = NumberUtils.roundNumber(data[1][0].values.length);
        }
      },
      err => {
        //console.log(err);
        this.handleError("Error getting 'funder' field results of projects", err);
      }));
    
    this.subscriptions.push(this._searchResearchResultsService.numOfSearchResults("publication", "", this.properties).subscribe(
      data => {
        if (data && data > 0) {
          this.publicationsSize = NumberUtils.roundNumber(data);
        }
      },
      err => {
        //console.log(err);
        this.handleError("Error getting number of publications", err);
      }
    ));
    
    this.subscriptions.push(this._searchResearchResultsService.numOfSearchResults("dataset", "", this.properties).subscribe(
      data => {
        if (data && data > 0) {
          this.datasetsSize = NumberUtils.roundNumber(data);
        }
      },
      err => {
        //console.log(err);
        this.handleError("Error getting number of research data", err);
      }
    ));
    
    this.subscriptions.push(this._searchResearchResultsService.numOfSearchResults("software", "", this.properties).subscribe(
      data => {
        if (data && data > 0) {
          this.softwareSize = NumberUtils.roundNumber(data);
        }
      },
      err => {
        this.handleError("Error getting number of software data", err);
      }
    ));
    
    this.subscriptions.push(this._searchResearchResultsService.numOfSearchResults("other", "", this.properties).subscribe(
      data => {
        if (data && data > 0) {
          this.otherSize = NumberUtils.roundNumber(data);
        }
      },
      err => {
        this.handleError("Error getting number of software data", err);
      }
    ));
    
    
  }
  
  public getStakeholders() {
    this.loading = true;
    this.status = this.errorCodes.LOADING;
    this.subscriptions.push(this._stakeholderService.getStakeholders(this.properties.monitorServiceAPIURL).subscribe(
      stakeholders => {
        if (!stakeholders || stakeholders.length == 0) {
          this.status = this.errorCodes.NONE;
        } else {
          this.stakeholders = StakeholderInfo.toStakeholderInfo(stakeholders, this.user);
          this.sort(this.stakeholders);
          this.stakeholders = this.publicStakeholders.concat(this.privateStakeholders);
          this.stakeholdersSlider = {
            stakeholders: this.stakeholderSlider(this.stakeholders),
            funders: this.stakeholderSlider(this.funders),
            ris: this.stakeholderSlider(this.ris),
            organizations: this.stakeholderSlider(this.organizations)
          };
        }
        this.loading = false;
      },
      error => {
        this.status = this.handleError("Error getting stakeholders", error);
        this.loading = false;
      }
    ));
  }
  
  private sort(results: StakeholderInfo[]) {
    results.sort((left, right): number => {
      if (left.name > right.name) {
        return 1;
      } else if (left.name < right.name) {
        return -1;
      } else {
        return 0;
      }
    })
  }
  
  public stakeholderSlider(stakeholders: StakeholderInfo[], size: number = 6): StakeholderInfo[][] {
    let slider: StakeholderInfo[][] = [];
    for (let i = 0; i < (stakeholders.length / size); i++) {
      slider.push(stakeholders.slice(i * size, ((i + 1) * size)));
    }
    return slider;
  }
  
  get publicStakeholders(): StakeholderInfo[] {
    return this.stakeholders.filter(stakeholder => stakeholder.visibility === "PUBLIC");
  }
  
  get privateStakeholders(): StakeholderInfo[] {
    return this.stakeholders.filter(stakeholder => stakeholder.visibility !== "PUBLIC");
  }
  
  get funders(): StakeholderInfo[] {
    if (this.stakeholders) {
      return this.stakeholders.filter(stakeholder => stakeholder.type === "funder");
    } else {
      return [];
    }
  }
  
  get ris(): StakeholderInfo[] {
    if (this.stakeholders) {
      return this.stakeholders.filter(stakeholder => stakeholder.type === "ri");
    } else {
      return [];
    }
  }
  
  get organizations(): StakeholderInfo[] {
    if (this.stakeholders) {
      return this.stakeholders.filter(stakeholder => stakeholder.type === "organization");
    } else {
      return [];
    }
  }
  
  private handleError(message: string, error): number {
    let code = "";
    if (!error.status) {
      code = error.code;
    } else {
      code = error.status;
    }
    console.error("Home Component: " + message, error);
    return this.errorMessages.getErrorCode(code);
  }
}
