src/app/services/entities/entities.service.ts
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2018 Georgi Marinov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import { Injectable } from '@angular/core';
import { GeneralTimelineService } from '../../services/general-timeline/general-timeline.service';
import { ModelModel } from '../../model/model/model.model';
import { UiService } from '../../services/ui/ui.service';
import { ExcelDateFormatterService } from '../excel-date-formatter/excel-date-formatter.service';
import { Indexable } from '../../interfaces/indexable';
/**
* A entities service.
*/
@Injectable({
providedIn: 'root'
})
export class EntitiesService {
/** Entities getter delegate. */
public get entities() { return this.model.entities; }
/**
* Constructs the entities service.
* ~constructor
*
* @param generalTimelineService The general timeline service injected dependency.
* @param uiService The UI service injected dependency.
* @param excelDateFormatterService The Excel date formatter service injected dependency.
* @param model The model injected dependency.
*/
constructor(
public readonly generalTimelineService: GeneralTimelineService,
public readonly uiService: UiService,
private readonly excelDateFormatterService: ExcelDateFormatterService,
public readonly model: ModelModel,
) {
}
/** Formatted count value. */
public getCountValueFormatted(key: string): string {
if (!key) { return ''; }
const countValue = this.getCountValue(key);
return countValue > 0 ? `(${countValue})` : '';
}
/** Count cache, aggregation or fixed collection length value. */
public getCountValue(key: string): number {
const cache = this.model.countCache;
// amend specific fixed count
this.model.countCache['Reference architecture'] = 2;
let cacheValue = cache[key];
if (cacheValue > 0) { return cacheValue; }
cacheValue = this.aggregateCountValue(key);
if (cacheValue > 0) { return cacheValue; }
return 0;
}
/** Count aggregation value. */
// eslint-disable-next-line max-lines-per-function
private aggregateCountValue(key: string): number {
switch (key) {
case this.entities['Curriculum Vitae']?.key:
return this.getCountValue(this.entities['Personal Data'].key)
+ this.getCountValue(this.entities.Background.key)
+ this.getCountValue(this.entities.Accomplishments.key);
case this.entities.Background?.key:
return this.getCountValue(this.entities['Professional Experience'].key)
+ this.getCountValue(this.entities.Education.key);
case this.entities.Accomplishments?.key:
return this.getCountValue(this.entities.Languages.key)
+ this.getCountValue(this.entities.Certifications.key)
+ this.getCountValue(this.entities.Courses.key)
+ this.getCountValue(this.entities.Organizations.key)
+ this.getCountValue(this.entities['Honors and Awards'].key)
+ this.getCountValue(this.entities.Volunteering.key)
+ this.getCountValue(this.entities['Interests and Hobbies'].key)
+ this.getCountValue(this.entities.Vacation.key)
+ this.getCountValue(this.entities.Publications.key);
default:
['Index', 'List', 'Chart', 'Map'].forEach((_) => { key = key.replace(new RegExp(' ' + _, 'g'), ''); });
return this.getFixedOrCacheCountValue(key);
}
}
/** Fixed collection length or count cache value. */
private getFixedOrCacheCountValue(key: string): number {
switch (key) {
case this.entities['Personal Data']?.key:
return this.model.cv['Personal data']?.length;
case this.entities.Education?.key:
// return this.model.filtered.Education.length;
return this.model.cv.Education?.length;
case this.entities['Professional Experience']?.key:
// return this.model.filtered['Professional Experience'].length;
return this.model.cv['Professional experience']?.length;
default:
return this.getCountValueProjects(key);
}
}
/** Fixed collection length or count cache value for project sections. */
private getCountValueProjects(key: string): number {
switch (key) {
case this.entities.Projects?.key:
case this.entities['Project Portfolio']?.key:
return this.model.filtered.Projects.length;
default:
return this.getCountValueProjectSubsections(key);
}
}
/** Fixed collection length or count cache value for project portfolio sections. */
private getCountValueProjectSubsections(key: string): number {
switch (key) {
case 'Gantt':
case this.entities.Contributions?.key:
case this.entities.List?.key:
case this.entities.Index?.key:
return this.model.filtered.Projects.length;
default:
return this.getCountValueFooter(key);
}
}
/** Fixed collection length or count cache value for footer sections. */
private getCountValueFooter(key: string): number {
switch (key) {
case this.entities['General Timeline']?.key:
// case this.entities['General Timeline Map']?.key:
return this.model.filtered.TimelineEvents.length;
case this.entities.Navigation?.key:
return Object.values(this.entities).filter((_) => _.class !== '').length;
default:
break;
}
return this.model.countCache[this.entities[key]?.cacheKey ?? key];
}
/**
* Calculates the number of items in an aggregation string based on a splitter character/string.
*
* @param collection The collection of objects to process.
* @param propertyName The name of the property to process.
* @param splitter The splitter character/string.
*
* @returns The number of items in an aggregation string.
*/
public count(collection: Indexable[], propertyName: string, splitter: string = ', '): number {
const aggregate = this.aggregate(collection, propertyName, splitter);
const matches = aggregate.match(new RegExp(this.uiService.frequenciesDivider, 'g'));
return matches ? matches.length + 1 : aggregate.length > 0 ? 1 : 0;
}
/**
* Aggregates the value parts in a collection objects' property based on a splitter character/string.
*
* @param collection The collection of objects to process.
* @param propertyName The name of the property to process.
* @param splitter The splitter character/string.
*
* @description
* For a given object property name in the collection of objects, extracts the values, concatenates them with the splitter
* and filters out the blank ones and the repetitions.
*
* @returns A string with the aggregated values.
*/
private aggregate(collection: Indexable[], propertyName: string, splitter: string = ', '): string {
if ((typeof collection === 'undefined')) {
return '';
}
let aggregation = '';
for (const property of collection) {
let propertyValue = property[propertyName];
propertyValue = this.excelDateFormatterService.formatDates(['From', 'To'], propertyName, propertyValue);
aggregation = aggregation.concat(propertyValue, splitter);
}
const arr = aggregation.split(splitter);
aggregation = arr
.filter((item: string, pos: number) => item !== '' && arr.indexOf(item) === pos)
.join(' ' + this.uiService.frequenciesDivider + ' ');
return aggregation;
}
}