Yrkki/cv-generator-fe

View on GitHub
src/app/services/classifier/classifier.service.ts

Summary

Maintainability
A
0 mins
Test Coverage
// 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 { AccomplishmentClassifiableService } from '../accomplishment-classifiable/accomplishment-classifiable.service';

import { Accomplishment } from '../../interfaces/cv/accomplishment';
import { ClassifierKind } from '../../enums/classifier-kind.enum';
import { OntologyEntry } from '../../interfaces/ontology-entry/ontology-entry';

import { UiService } from '../../services/ui/ui.service';
import { PersistenceService } from '../../services/persistence/persistence.service';
import { OntologyService } from '../ontology/ontology.service';

import { Go } from '../../enums/go.enum';

/**
 * Classifier connection service.
 * ~extends {@link AccomplishmentClassifiableService}
 */
@Injectable({
  providedIn: 'root'
})
export class ClassifierService extends AccomplishmentClassifiableService {
  /** ClassifierKind values getter. */
  public get ClassifierKindValues() {
    return Object.values(ClassifierKind).filter((_) => !isNaN(Number(_))) as ClassifierKind[];
  }

  /** Subservice. */
  public get subService() {
    return {
      /** Classifier kind. */
      classifierKind: this.classifierKind,
      /** Defaults. */
      defaultKind: ClassifierKind.Strong,
      /** Prefix for fully qualified names, getter. */
      get prefix() { return 'classifier'; },
      /** Fully qualified name, used to prefix other identifiers, getter. */
      get full() { return this.prefix + ClassifierKind[this.classifierKind]; },
      /** Persistence name getter. */
      get sFull() { return this.full + 's'; },
      /** Index name getter. */
      get indexFull() { return this.full + 'Index'; },
      /** Next direction getter. */
      get nextDirection() { return ['ᐸᐸ', 'ᐸ', 'ᐳ']; },
    };
  }

  /**
   * Constructs the Classifier service.
   * ~constructor
   *
   * @param uiService The ui service injected dependency.
   * @param persistenceService The persistence service injected dependency.
   * @param ontologyService The ontology service injected dependency.
   */
  constructor(
    public readonly uiService: UiService,
    public override readonly persistenceService: PersistenceService,
    public readonly ontologyService: OntologyService,
  ) {
    super(persistenceService);
  }

  /**
   * Whether accomplishment is of type specified.
   *
   * @param accomplishment The accomplishment to test.
   * @param accomplishmentType The accomplishment type to test.
   *
   * @returns whether accomplishment is of the type specified.
   */
  protected override isOfType(accomplishment: Accomplishment, accomplishmentType: string) {
    if ([
      ClassifierKind.Direct,
      ClassifierKind.Classic
    ].includes(this.classifierKind)) {
      return super.isOfType(accomplishment, accomplishmentType);
    }

    return this.isOfOntologyType(accomplishment, accomplishmentType);
  }

  /**
   * Whether accomplishment is of ontology type specified.
   *
   * @param accomplishment The accomplishment to test.
   * @param accomplishmentType The accomplishment ontology type to test.
   *
   * @returns whether accomplishment is of the ontology type specified.
   */
  private isOfOntologyType(accomplishment: Accomplishment, accomplishmentType: string) {
    const ontology = this.ontologyService.ontology;
    const ontologyEntry = ontology.find((_) => _.Entity === accomplishment.Platform) as OntologyEntry;
    switch (this.classifierKind) {
      case ClassifierKind.Explicit: return accomplishmentType === accomplishment.Platform;
      case ClassifierKind.Strong: return ontologyEntry?.category === accomplishmentType;
      case ClassifierKind.Medium: return ontologyEntry?.path.includes(accomplishmentType);
      case ClassifierKind.Weak: return ontologyEntry?.displayPath.includes(accomplishmentType);
      default: return false;
    }
  }

  /** Floored division modulo operation getter. */
  private clamp(n: number, m: number) {
    if (m === 0) { return n; }

    const d = n % m;
    return d < 0 ? d + m : d;
  }

  /** Next potential field. */
  private nextPotentialField(classifierKind: number, classifierKindNext = Go.Forward) {
    if (classifierKindNext === Go.Home) {
      classifierKind = this.subService.defaultKind;
    } else {
      const nudgedPotentialField = this.nudgePotentialField(classifierKind, classifierKindNext);
      classifierKind = nudgedPotentialField.classifierKind;
    }
    classifierKind = this.clamp(classifierKind, this.ClassifierKindValues.length);
    return { classifierKind };
  }

  /** Nudge potential field to next adjacent one, raw. */
  private nudgePotentialField(classifierKind: number, classifierKindNext = Go.Forward) {
    if (classifierKindNext === Go.Back) {
      classifierKind--;
    } else if (classifierKindNext === Go.Forward) {
      classifierKind++;
    }
    return { classifierKind };
  }

  /** Next. */
  public next(event: MouseEvent, classifierKindNext = Go.Forward) {
    const nextPotentialField = this.nextPotentialField(this.classifierKind, classifierKindNext);
    this.classifierKind = nextPotentialField.classifierKind;
    event.stopPropagation();
  }

  /** Next title. */
  public nextTitle(classifierKindNext = Go.Forward) {
    const nextPotentialField = this.nextPotentialField(this.classifierKind, classifierKindNext);
    const tokens = [
      this.uiService.uiText('Click here to change classification method from'),
      ClassifierKind[this.classifierKind].toLowerCase(),
      this.uiService.uiText('to'),
      ClassifierKind[nextPotentialField.classifierKind].toLowerCase(),
    ];
    return tokens.join(' ');
  }
}