src/app/services/count-cache/count-cache.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 { ModelModel } from '../../model/model/model.model';
import { UiService } from '../../services/ui/ui.service';
import { ChartService } from '../../services/chart/chart.service';
import { TagCloudProcessorService } from '../../services/tag-cloud-processor/tag-cloud-processor.service';
import { Indexable } from '../../interfaces/indexable';
import { Language } from '../../interfaces/cv/language';
import { Project } from '../../interfaces/project/project';
/**
* A count cache service.
*/
@Injectable({
providedIn: 'root'
})
export class CountCacheService {
/** Aggregation count cache. */
/** Aggregation count cache getter. */
public get countCache() { return this.model.countCache; }
/** Aggregation count cache setter. */
public set countCache(value) { this.model.countCache = value; }
/** Frequencies cache. */
/** Frequencies cache getter. */
public get frequenciesCache() { return this.model.frequenciesCache; }
/** Frequencies cache setter. */
public set frequenciesCache(value) { this.model.frequenciesCache = value; }
/** Project period decrypted. */
public decryptedPeriod: Indexable = {};
/** Filtered getter. */
public get filtered() { return this.model.filtered; }
/**
* Constructs the count cache service.
* ~constructor
*
* @param uiService The UI service injected dependency.
* @param tagCloudProcessorService The tag cloud processor service injected dependency.
* @param model The model injected dependency.
* @param chartService The chart service injected dependency.
*/
constructor(
public readonly uiService: UiService,
private readonly tagCloudProcessorService: TagCloudProcessorService,
private readonly model: ModelModel,
private readonly chartService: ChartService,
) {
}
/**
* Gets the project period decrypted for a project
*
* @param project The project index
*/
public getDecryptedProjectPeriod(project: Project): string {
const period = 'Period';
return this.decryptedPeriod[project[period]];
}
/**
* One person team project indicator.
*
* @param project The project index
*/
public getProjectIsOnePersonTeam(project: Project): boolean {
const teamSize = 'Team size';
return project[teamSize] === 1;
}
/** Calculates the count cache and refreshes project charts. */
public calcCountCache(propertyNames: string[]) {
this.calcCountCacheProper(propertyNames);
if (propertyNames.length === 0 || propertyNames.includes('Project')) {
this.chartService.refreshCharts();
}
}
/** Calculates the count cache for the property types registered and refreshes the clients. */
// eslint-disable-next-line max-lines-per-function
private calcCountCacheProper(propertyNames: string[]) {
// if (propertyNames.length === 0) {
propertyNames = ['Project', 'Language', 'Accomplishment', 'Publication'];
// }
this.countCache = {};
this.calcCountCacheProjectsFrequencies(propertyNames);
if (propertyNames.includes('Language')) {
this.calcFrequencies(this.filtered.Languages, 'Language');
}
if (propertyNames.includes('Accomplishment')) {
this.calcFrequencies(this.filtered.Certifications, 'Certification');
this.calcFrequencies(this.filtered.Courses, 'Name');
this.calcFrequencies(this.filtered.Organizations, 'Organization');
this.calcFrequencies(this.filtered.HonorsAndAwards, 'Honor and Award');
this.calcFrequencies(this.filtered.Volunteering, 'Volunteering');
this.calcFrequencies(this.filtered.InterestsAndHobbies, 'Interest and Hobby');
this.calcFrequencies(this.filtered.Vacation, 'Vacation');
}
if (propertyNames.includes('Publication')) {
this.calcFrequencies(this.filtered.Publications, 'Title');
}
if (propertyNames.includes('Project')) {
this.calcCountCacheProjects();
}
}
/** Preprocesses the project frequencies. */
private calcCountCacheProjectsFrequencies(propertyNames: string[]) {
if (propertyNames.includes('Project')) {
for (const propertyName of [
'Project',
'Client', 'Country', 'Industry', 'Project type', 'System type',
'Platform', 'Architecture', 'Languages and notations', 'IDEs and Tools', 'Methodology and practices',
'Role', /* 'Responsibilities', */ 'Team size', 'Position', 'Reference'
]) {
this.calcFrequencies(this.filtered.Projects, propertyName);
}
this.calcFrequencies(this.filtered.Projects, 'Responsibilities', undefined, true);
}
}
/** Calculates the count cache for the projects. */
private calcCountCacheProjects() {
// calc sections start project and count cache
let i = 0;
let lastPeriod = '';
const propertyName = 'New Period';
for (const project of this.filtered.Projects) {
const period = this.getDecryptedProjectPeriod(project);
if (period === lastPeriod) {
project[propertyName] = '';
} else {
project[propertyName] = period;
this.countCache[lastPeriod] = i;
lastPeriod = period;
i = 0;
}
i++;
}
this.countCache[lastPeriod] = i;
}
/**
* Checkes if the section toggle state is collapsed.
*
* @param propertyName The name of the property to process.
*
* @returns Whether the section toggle state is collapsed.
*/
public checkToggleCollapsed(propertyName?: string): boolean {
// if (this.persistenceService.getToggle(propertyName)['content-class'] === 'collapse') {
// this.countCache[propertyName] = 0;
// this.frequenciesCache[propertyName] = [];
// return true;
// }
return false;
}
/**
* Calculates a splitter and then delegates to a service to calculate the frequency of occurrence of any value parts
* in a collection objects' property based on that 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. Optional.
* @param ai Whether to apply lexical analysis euristics when parsing each value encountered. Optional.
*
* @description
* Also updates count and caches result.
*/
private calcFrequencies(collection: any, propertyName: string, splitter: string = ', ', ai: boolean = false) {
const frequenciesCacheKey = this.frequenciesCacheKey(collection, propertyName);
const key = frequenciesCacheKey.key;
propertyName = frequenciesCacheKey.propertyName;
if (this.checkToggleCollapsed()) { return; }
this.countCache[key] = 0;
const entries = this.tagCloudProcessorService.calcFrequencies(collection, propertyName, splitter, ai);
if ((typeof entries === 'undefined')) {
return;
}
this.updateCount(key, entries.length);
this.frequenciesCache[key] = entries;
}
/**
* Calculates a frequencies cache key.
*
* @param collection The collection of objects to process.
* @param propertyName The name of the property to process.
*
* @returns FrequenciesCacheKey calculated and modified propertyName.
*/
private frequenciesCacheKey(collection: any, propertyName: string) {
let key = propertyName;
if (['Language', 'Certification', 'Organization', 'Honor and Award', 'Volunteering',
'Interest and Hobby', 'Vacation', 'Project'].includes(propertyName)) {
if (propertyName === 'Language') {
collection.forEach((_: Language) => {
_.Name = _.Language;
_.Strength = _.Share;
});
} else if (propertyName === 'Project') {
collection.forEach((_: Project) => {
_.Name = _['Project name'];
_.Strength = Number(this.getProjectIsOnePersonTeam(_));
});
}
key = propertyName;
propertyName = 'Name';
}
return { key, propertyName };
}
/**
* Updates an entity's count.
*
* @param propertyName The name of the property to process.
* @param count The new count.
*/
private updateCount(propertyName: string, count: number) {
if (propertyName === '' || typeof propertyName === 'undefined') {
return;
}
if (typeof this.countCache[propertyName] !== 'number') {
this.countCache[propertyName] = 0;
}
this.countCache[propertyName] += count;
const entities = this.model.entities;
if (!entities?.[propertyName]) {
return;
}
const parentEntity = entities[propertyName].parent;
this.updateCount(parentEntity, count);
}
}