File

src/app/models/gamification-lrs.ts

import { CabriDataService } from "../services/cabri-data.service";
import { LrsService } from "../services/lrs.service";
import { NetworkService } from "../services/network.service";
import { AccountImplService } from "../services/account.Impl.service";
import { Status } from "./proposed-activity";
import { Journey, journeyStatus, JourneysByStatus } from "./journey";
import { LmsService } from "../services/lms.service";
import { NoCategoryStatus } from "./exercices";
import { environment } from "src/environments/environment";
import { format, parse } from "date-fns";
import { AppLanguage } from "./enums/enum-list";
import { AccountService } from "../services/account.service";
import { LocalStorageService, StorageKey } from "../services/local-storage-service";
export class ExerciseStatistics {
	[studentId: string]: {
		[activityId: string]: {
			[category: string]: Array<{
				exerciseId?: number;
				failed?: number;
				passed?: number;
				perGoodAnswers?: number;
				progression?: number;
				passedWithHelp?: number;
				grade?: string;
				journeyId?: number;
				completed?: boolean;
				_id?: string;
				story?: boolean;
			}>;
		};
	};
}

export class LogBookStatistics {
	exerciseid?: number;
	gabarit: string | number;
	mode: string;
	failed?: number;
	passed?: number;
	perGoodAnswers?: number;
	progression?: number;
	parcours_id?: number;
	activityName?: string;
	numberGoodAnswer?: number;
	exerciseName?: string;
	journeyName?: string | null;
	passedWithHelp?: number;
	duration?: string;
	timestamp: { day: number; dayOfWeek: string; month: string; year: number; time: string };
	_id?: string;
}

export class StoredLrsStatements {
	lrs: LrsService;
	lmsService: LmsService;
	cabriService: CabriDataService;
	networkService: NetworkService;
	accountService: AccountService;
	public logBookStatistics: LogBookStatistics[] = new Array();
	public localStorageService: LocalStorageService;
	environment: any;
	constructor(lrs, lmsService, cabriService, networkService, accountService, localStorageService) {
		this.lrs = lrs;
		this.lmsService = lmsService;
		this.cabriService = cabriService;
		this.networkService = networkService;
		this.accountService = accountService;
		this.localStorageService = localStorageService;
		this.environment = environment;
	}

	/**
	 *	Start Journeys
	 */
	async getStoredJourneys(forCurrentUser: boolean): Promise<any> {
		return new Promise<any>(async resolve => {
			let allJourneysByStatus: JourneysByStatus[] = new Array();
			const allJourneysByProgressStatus: JourneysByStatus[] = new Array();
			const statement = [
				{
					$match: {
						timestamp: {
							$gte: {
								$dte: "2021-01-27T19:30:00.000Z"
							}
						}
					}
				},
				{
					$match: {
						$and: [
							{
								"statement.verb.id": {
									$nin: [
										"https://xapi.mathia.education/verbs/initialized",
										"https://xapi.mathia.education/verbs/finished"
									]
								}
							},
							{
								"statement.context.extensions.https://xapi&46;mathia&46;education/extensions/mode_jeu": {
									$in: ["entraînement", "bilan"]
								}
							},
							{
								"statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_etape": {
									$nin: [null]
								}
							},
							{
								"statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id_session": {
									$nin: [null]
								}
							},
							{
								"statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_session_id": {
									$nin: [null]
								}
							},
							{
								"statement.actor.account.name": {
									$in: forCurrentUser ? [this.accountService.team[0]?.id] : this.accountService.allStudents.map(s => s.id)
								}
							}
						]
					}
				},
				{
					$project: {
						search: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_session_id",
						userId: "$statement.actor.account.name",
						id_session: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id_session",
						recommandation: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/recommandation",
						remediation: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/remediation",
						id_assignation: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/assignation_id",
						id: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_id",
						bilanAutoFinished: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/fin_automatique",
						timestamp: "$statement.stored",
						step: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_etape",
						exerciseid: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id",
						completed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/completed"] }, 1, 0] },
						isCompetition: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/is_competition",
						bilanCompleted: {
							$cond: [
								{
									$and: [
										{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/completed"] },
										{ $eq: ["$statement.object.definition.type", "https://xapi.mathia.education/objectType/journey"] }
									]
								},
								1,
								0
							]
						},
						timeToAnswer: "$metadata.https://learninglocker&46;net/result-duration.seconds",
						question: "$statement.object.definition.description.en-US",
						award: {
							$switch: {
								branches: [
									{
										case: { $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed"] },
										then: "shooting"
									},
									{
										case: { $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-with-help"] },
										then: "normal"
									},
									{
										case: { $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-on-retry"] },
										then: "normal"
									},
									{ case: { $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/failed"] }, then: "moon" }
								],
								default: 0
							}
						},
						passed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed"] }, 1, 0] },
						skippedExerciseId: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/exercice_passe_id",
						passedRetry: {
							$cond: [
								{
									$or: [
										{
											$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-with-help"]
										},
										{
											$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-on-retry"]
										}
									]
								},
								1,
								0
							]
						}
					}
				},
				{
					$group: {
						_id: "$search",
						userId: { $first: "$userId" },
						recommandation: { $first: "$recommandation" },
						remediation: { $first: "$remediation" },
						bilanAutoFinished: { $first: "$bilanAutoFinished" },
						isCompetition: { $first: "$isCompetition" },
						allAskedQuestions: {
							$push: {
								id_session: "$id_session",
								step: "$step",
								exerciseId: "$exerciseid",
								completed: "$completed",
								vTimer: "$timeToAnswer",
								question: "$question",
								award: "$award",
								timestamp: "$timestamp",
								bilanCompleted: "$bilanCompleted",
								skippedExerciseId: "$skippedExerciseId",
								passed: { $sum: { $add: ["$passed", "$passedRetry"] } }
							}
						},
						timestamp: { $first: "$timestamp" },
						assignationId: { $first: "$id_assignation" },
						id: { $first: "$id" }
					}
				},
				{
					$sort: {
						timestamp: -1
					}
				}
			];

			let allUserJourneys;
			try {
				if (this.lmsService.allJourneysLrsProgression && forCurrentUser && !this.lmsService.needRefreshStudentJourneysData) {
					// change player
					allUserJourneys = this.lmsService.allJourneysLrsProgression;
				} else {
					// first time no data / need update user statistics
					allUserJourneys = await this.lrs.request(statement);
				}
				if (this.lmsService.needRefreshStudentJourneysData) {
					// new activity is made so reload data
					const currentUserJourneys = this.lmsService.allJourneysLrsProgression.filter(j => {
						return Number(j.userId) === Number(this.accountService.team[0].id);
					});

					// get ony new items where the elements does not exist in global saved journey progression
					const diffToSave = allUserJourneys.filter(item1 => {
						return currentUserJourneys.findIndex(item2 => item2.timestamp === item1.timestamp) === -1;
					});

					// get first index in global array that that student items start
					const firstElementIndex = this.lmsService.allJourneysLrsProgression.findIndex(globalJ => {
						return globalJ.userId === this.accountService.team[0].id;
					});

					// add in global items the elements that does not yet exist in order to update array
					this.lmsService.allJourneysLrsProgression.splice(firstElementIndex, 0, ...diffToSave);
				}
				this.lmsService.needRefreshStudentJourneysData = false;
				this.localStorageService.set(StorageKey.journeysProgression, allUserJourneys);
			} catch {
				allUserJourneys = await this.localStorageService.get(StorageKey.journeysProgression);
			} finally {
				if (!forCurrentUser) {
					resolve(allUserJourneys);
				} else {
					if (allUserJourneys) {
						this.lmsService.storeLrsJourneysProgression = allUserJourneys;
						if (forCurrentUser) {
							// filter and keep only user's journey from all
							allUserJourneys = allUserJourneys.filter(journey => {
								return journey.userId === this.accountService.team[0].id;
							});
						}
						if (allUserJourneys.length === 0) {
							allJourneysByStatus = new Array();
							const toDo = new Array();
							let lastAdventureJourney: Array<any>;
							this.lmsService.userJourneysByAssignation.forEach(data => {
								toDo.push(Object.assign(data, { journeyStatus: 2 }));
							});

							if (toDo.length > 0 || this.lmsService.allJourneys.length > 0) {
								const allStatuses = {
									[this.lmsService.getStatusAsIndex(journeyStatus.toDo)]: { opened: false, items: toDo },
									[this.lmsService.getStatusAsIndex(journeyStatus.allJourneys)]: {
										opened: false,
										items: this.lmsService.allJourneys
									}
								};
								allJourneysByStatus.push(allStatuses);

								if (toDo.length > 0) {
									lastAdventureJourney = new Array();
									// assignation journey offer first in adventure mode
									const lastAdventureJourneyObj = {
										[this.lmsService.getStatusAsIndex(journeyStatus.inProgress)]: {
											opened: false,
											items: new Array(toDo[0])
										}
									};
									lastAdventureJourney.push(lastAdventureJourneyObj);
								}
							}

							resolve({ journeysByStatus: allJourneysByStatus, recommandedJourneyByStatus: lastAdventureJourney });
							return;
						}
						const recommandedJourneys = new Array();
						const notRecommandedJourneys = new Array();
						let lastMadeJourney: Journey;
						allUserJourneys = allUserJourneys.map(journey => {
							journey.allAskedQuestions = journey.allAskedQuestions.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
							const resultUserJourneys: Journey = this.lmsService.userJourneysByAssignation.find(userJourney => {
								return +userJourney.id === +journey.id;
							});
							const resultAllJourneys: Journey = this.lmsService.allJourneys.find(userJourney => {
								return +userJourney.id === +journey.id;
							});
							
							/**
							 * TODO : 
							 * Competition journey's: 
							 */
							let result;
							if (resultUserJourneys || resultAllJourneys) {
								if (resultUserJourneys && resultUserJourneys.assignationId) {
									result = resultUserJourneys;
								} else {
									result = resultAllJourneys;
								}

							}

							// if (!result) {
							// 	console.log("resultUserJourneys", resultUserJourneys)
							// 	console.log("result", result)
							// 	return;
							// }
							/** Ajouter les exercices d'un parcours dans le parcours */
							if (result) {
								if (result.exercises?.length > 0) {
									// all statuses set to notDone
									result.exercises.forEach((exercise, index) => {
										result.exercises[index].status = Status.notDone;
									});
								}
								journey.exercises = result.exercises;
								journey.bilan = result.bilan;
								journey.title = result.title;
								journey.level = result.level;
								journey.difficulty = result.difficulty;
								journey.assignation = result.assignation;
								journey.level = result.level;
								journey = { ...result, ...journey };
								// avoid circular dependancies when the object is copied
								journey.lmsService = null;
								journey.cabriService = null;
							}
							// Sur toutes les questions posées au cours d'un parcours garder celles
							//  qui ont été accomplie et les questions auxquelles l'élève a répondu
							journey.allAskedQuestions = journey.allAskedQuestions.filter(question => {
								return typeof question.award === "string" || question.completed === 1;
							});
							const proposedActivity = journey.allAskedQuestions.filter(question => {
								return typeof question.award === "string";
							});
							const passed = proposedActivity.filter(question => {
								return question.passed > 0;
							});
							journey.totalQuestions = proposedActivity.length;
							journey.passed = passed.length;

							// Calculer le taux des bonnes réponses dans un parcours
							let correctAnswers;
							if (journey.bilanAutoFinished) {
								correctAnswers = 100;
							} else {
								correctAnswers = Math.floor((passed.length / proposedActivity.length) * 100);
							}
							journey.correctAnswers = correctAnswers;

							if (journey.completed) {
								journey.progression = 100;
							} else {
								journey.progression = proposedActivity.length;
							}

							if (!journey.remediation) {
								if (!journey.recommandation) {
									notRecommandedJourneys.push(journey);
								} else {
									recommandedJourneys.push(journey);
								}
							}

							if (!lastMadeJourney) {
								lastMadeJourney = JSON.parse(JSON.stringify(journey));
							}
							const j = new Journey(this.cabriService, this.lmsService, journey.id, journey.educationalLevel, null, journey.title, journey.difficulty, false, false);
							for(const key in journey){
								try{
									j[key] = journey[key];
								} catch(e){
									console.error("key error", key);
								}
							}
							j.lmsService = null;
							j.cabriService = null;
							// avoid circular dependency when we copy the full class
							return j;
						}) as Journey[];
						// const response = allUserJourneys.filter(journey => {
						// 	return journey.id == 127768;
						// })
						// console.log("response", response)
						// Retourne un tableau associatif en clé l'identifiant de l'exercice
						const notRecommanded = await this.studentJourneyInfos(allUserJourneys, allJourneysByStatus);
						const resultRecommanded = await this.studentRecommandedJourneys(recommandedJourneys, allJourneysByProgressStatus);
						if (notRecommanded.journeysByStatus && Array.isArray(notRecommanded.journeysByStatus)) {
							// if assignation journey exist so force to do assignated journey in the adventure map
							const firstAssignationJourneyToDo =
								notRecommanded.journeysByStatus[0][this.lmsService.getStatusAsIndex(journeyStatus.toDo)]?.items[0];
							if (firstAssignationJourneyToDo) {
								const lastAdventureJourneyOffered =
									resultRecommanded.journeysByStatus[0][this.lmsService.getStatusAsIndex(journeyStatus.inProgress)];
								lastAdventureJourneyOffered.items[0] = firstAssignationJourneyToDo;
							}
						}

						lastMadeJourney = this.changeLastJourneyExerciseStatus(lastMadeJourney);
						let competitionTracesJourneys = allUserJourneys.filter(journey => journey.isCompetition);
						competitionTracesJourneys = this.changeLastCompetitionJourneyExerciseStatus(competitionTracesJourneys);
						const journeysProgression = {
							journey: notRecommanded.journey,
							journeysByStatus: notRecommanded.journeysByStatus,
							recommandedJourney: resultRecommanded.journey,
							recommandedJourneyByStatus: resultRecommanded.journeysByStatus,
							lastMadeJourney,
							competitionTracesJourneys
						};
						resolve(journeysProgression);
					} else {
						resolve(false);
					}
				}
			}
		});
	}

	/**
	 * Change exercises status for the first exercise
	 */
	changeLastJourneyExerciseStatus(lastMadeJourney: Journey) {
		if (lastMadeJourney?.exercises) {
			lastMadeJourney.idSession = lastMadeJourney._id;
			const userJourneysExercise = lastMadeJourney.allAskedQuestions.filter(startedExercise => {
				return lastMadeJourney.exercises.some(exercises => {
					return startedExercise.completed === 1 && exercises.step === startedExercise.step;
				});
			});
			if (userJourneysExercise.length > 0) {
				if (userJourneysExercise.length >= lastMadeJourney.exercises.length) {
					lastMadeJourney.completed = true;
				} else {
					lastMadeJourney.completed = false;
				}
				// change status to done when allAksedQuestions match with exercise id contained in journey exercises id
				lastMadeJourney.exercises.forEach(exercises => {
					const statusToChange = userJourneysExercise.find(startedExercise => {
						return exercises.step === startedExercise.step;
					});

					if (statusToChange) {
						exercises.status = Status.done;
						exercises.skippedExerciseId = statusToChange.skippedExerciseId;
						exercises.skip = exercises.skippedExerciseId ? true : false;
					}
				});
			}
		}

		return lastMadeJourney;
	}


			/**
	 * Change exercises status for the first exercise
	 */
	changeLastCompetitionJourneyExerciseStatus(competitionJourneys: Journey[]) {
		competitionJourneys.forEach(journey => {
			if (journey?.exercises) {
				journey.idSession = journey._id;
				const userJourneysExercise = journey.allAskedQuestions.filter(startedExercise => {
					return journey.exercises.some(exercises => {
						return startedExercise.completed === 1 && exercises.step === startedExercise.step;
					});
				});
				if (userJourneysExercise.length > 0) {
					if (userJourneysExercise.length >= journey.exercises.length) {
						journey.completed = true;
					} else {
						journey.completed = false;
					}
					// change status to done when allAksedQuestions match with exercise id contained in journey exercises id
					journey.exercises.forEach(exercises => {
						const statusToChange = userJourneysExercise.find(startedExercise => {
							return exercises.step === startedExercise.step;
						});

						if (statusToChange) {
							exercises.status = Status.done;
							exercises.skippedExerciseId = statusToChange.skippedExerciseId;
							exercises.skip = exercises.skippedExerciseId ? true : false;
						}
					});
				}
			}
		});

		return competitionJourneys;
	}

	async studentRecommandedJourneys(arr, journeysByStatus): Promise<{ journey: Journey; journeysByStatus: JourneysByStatus[] }> {
		return new Promise<{ journey: Journey; journeysByStatus: JourneysByStatus[] }>(resolve => {
			// Retourne un tableau associatif en clé l'identifiant de l'exercice
			const newJourney: Journey = arr.reduce((res, curr) => {
				if (res[curr.id]) {
					res[curr.id].push({
						idSession: curr._id,
						...curr
					});
				} else {
					Object.assign(res, {
						[curr.id]: [
							{
								idSession: curr._id,
								...curr
							}
						]
					});
				}
				return res;
			}, {});

			const statusProgression = new Array();
			const lastMadeJourneyByIds = {};
			// tslint:disable-next-line: forin
			for (const key in newJourney) {
				// keep last statement in each array of journeys already filtered by date
				if (newJourney.hasOwnProperty(key)) {
					// Modifier le statut de l'exercice s'il a été accompli
					newJourney[key].find(dataByJourney => {
						if (dataByJourney.exercises) {
							const userJourneysExercise = dataByJourney.allAskedQuestions.filter(startedExercise => {
								return dataByJourney.exercises.some(exercises => {
									return startedExercise.completed === 1 && exercises.step === startedExercise.step;
								});
							});
							if (userJourneysExercise.length > 0) {
								if (userJourneysExercise.length >= dataByJourney.exercises.length) {
									dataByJourney.completed = true;
								} else {
									dataByJourney.completed = false;
								}
								// change status to done when allAksedQuestions match with exercise id contained in journey exercises id
								const dataByJourneyExercises = JSON.parse(JSON.stringify(dataByJourney.exercises));
								dataByJourneyExercises.forEach(exercises => {
									const statusToChange = userJourneysExercise.find(startedExercise => {
										return exercises.step === startedExercise.step;
									});
									if (statusToChange) {
										exercises.status = Status.done;
										exercises.skippedExerciseId = statusToChange.skippedExerciseId;
										exercises.skip = exercises.skippedExerciseId ? true : false;
									}
								});
								dataByJourney.exercises = dataByJourneyExercises;
							}
						}
					});
					if (!lastMadeJourneyByIds[key]) {
						lastMadeJourneyByIds[key] = newJourney[key];
					}
				}
			}

			const allJourneysMade = new Array();
			for (const key in lastMadeJourneyByIds) {
				if (lastMadeJourneyByIds.hasOwnProperty(key) && lastMadeJourneyByIds[key][0]) {
					// const items = Object.values(lastMadeJourneyByIds).sort((a: any, b: any) => a.timestamp.localeCompare(b.timestamp));
					lastMadeJourneyByIds[key].forEach(cj => {
						allJourneysMade.push(cj);
					});
				}
			}
			const orderAscByTimestamp = allJourneysMade.sort((a: any, b: any) => {
				return a.timestamp.localeCompare(b.timestamp);
			});
			for (const key in lastMadeJourneyByIds) {
				// keep last statement in each array of journeys already filtered by date
				if (lastMadeJourneyByIds.hasOwnProperty(key)) {
					if (lastMadeJourneyByIds[key][0]?.exercises) {
						const inProgressJourney = lastMadeJourneyByIds[key][0].exercises.some(exercise => {
							return exercise.status === Status.notDone;
						});
						// if one exercise of journey has been done starting from another index that 0 so pass status to done for previous exercises
						if (inProgressJourney) {
							// indexes that exercise has been done
							const indexes = lastMadeJourneyByIds[key][0].exercises
								.map((elm, idx) => {
									if (elm.status === Status.done) {
										return idx;
									}
								})
								.filter(uNdefined => uNdefined !== undefined);
							if (indexes.length > 0) {
								// get last index of an exercise done
								const maxOfIndex = Math.max(...indexes);
								for (let i = 0; i <= maxOfIndex; i++) {
									// change all exercises status to done until the last index of done
									lastMadeJourneyByIds[key][0].exercises[i].status = Status.done;
								}
							}
						}
					}
				}
			}

			if (orderAscByTimestamp[orderAscByTimestamp.length - 1]?.exercises) {
				const allDone = orderAscByTimestamp[orderAscByTimestamp.length - 1].exercises.every(exercise => {
					return exercise.status === Status.done;
				});

				if (!allDone) {
					statusProgression.push(orderAscByTimestamp[orderAscByTimestamp.length - 1]);
				}
			}

			const progressStatus: JourneysByStatus = {
				[this.lmsService.getStatusAsIndex(journeyStatus.inProgress)]: { opened: false, items: statusProgression }
			};
			if (Object.keys(progressStatus).length > 0) {
				journeysByStatus.push(progressStatus);
			}
			// En cours
			resolve({ journey: newJourney, journeysByStatus });
		});
	}

	async studentJourneyInfos(arr, journeysByStatus): Promise<{ journey: Journey; journeysByStatus: JourneysByStatus[] }> {
		return new Promise<{ journey: Journey; journeysByStatus: JourneysByStatus[] }>(resolve => {
			// Retourne un tableau associatif en clé l'identifiant de l'exercice
			const newJourney: Journey = arr.reduce((res, curr) => {
				if (res[curr.id]) {
					res[curr.id].push({
						idSession: curr._id,
						...curr
					});
				} else {
					Object.assign(res, {
						[curr.id]: [
							{
								idSession: curr._id,
								...curr
							}
						]
					});
				}
				return res;
			}, {});
			const statusCompleted = new Array();
			const statusProgression = new Array();
			const statusToDo = new Array();

			// tslint:disable-next-line: forin
			for (const key in newJourney) {
				if (newJourney.hasOwnProperty(key)) {
					// Modifier le statut de l'exercice s'il a été accompli
					newJourney[key].find(dataByJourney => {
						if (dataByJourney.exercises) {
							const userJourneysExercise = dataByJourney.allAskedQuestions.filter(startedExercise => {
								return dataByJourney.exercises.some(exercises => {
									return startedExercise.completed === 1 && exercises.step === startedExercise.step;
								});
							});

							// keeping all completed journeys
							if (userJourneysExercise.length > 0) {
								const lastItem = userJourneysExercise[userJourneysExercise?.length - 1];
								// change status to done when allAksedQuestions match with exercise id contained in journey exercises id
								const dataByJourneyExercises = JSON.parse(JSON.stringify(dataByJourney.exercises));
								const indexFound = dataByJourneyExercises.findIndex(ex => {
									return ex.step === lastItem.step;
								});

								dataByJourney.completed = indexFound === dataByJourneyExercises.length - 1 ? true : false;

								for (let i = 0; i <= indexFound; i++) {
									dataByJourneyExercises[i].status = Status.done;
								}

								dataByJourneyExercises.forEach((exercises, index) => {
									const statusToChange = userJourneysExercise.find(startedExercise => {
										return exercises.step === startedExercise.step;
									});

									if (statusToChange) {
										exercises.skippedExerciseId = statusToChange.skippedExerciseId;
										exercises.skip = exercises.skippedExerciseId ? true : false;
									}
								});

								dataByJourney.exercises = dataByJourneyExercises;
							}
						}
					});
				}
				if (newJourney[key][0]) {
					const tempLastJourneyMade = newJourney[key][0];
					let exerciseEnumProgression;
					try{
						exerciseEnumProgression = JSON.parse(JSON.stringify(newJourney[key]));
					} catch(err){
						// debugger;
						console.error(err);
					}
					exerciseEnumProgression = exerciseEnumProgression.sort((a, b) => b.correctAnswers - a.correctAnswers);
					if (exerciseEnumProgression[0].bilan) {
						// Mode diagnostique terminé
						const completedBilan = exerciseEnumProgression.find(bilanJourney => {
							return bilanJourney.allAskedQuestions.find(bilanQuestion => {
								return bilanQuestion.bilanCompleted === 1;
							});
						});

						if (completedBilan) {
							const journey = this._transformNestyJourneyAsClass(
								completedBilan,
								tempLastJourneyMade,
								this.lmsService.getStatusAsIndex(journeyStatus.completed)
							);
							statusCompleted.push(journey);
						}
					}
					const completedFarthestJourney = exerciseEnumProgression.find(data => {
						return data.completed;
					});
					tempLastJourneyMade.farthest = false;
					newJourney[key] = new Array();
					const forAllJourneys = this.lmsService.allJourneys.find(journey => {
						return Number(journey.id) === Number(tempLastJourneyMade.id);
					});
					const forUserJourney = this.lmsService.userJourneysByAssignation.find(journey => {
						return Number(journey.id) === Number(tempLastJourneyMade.id);
					});

					if (forUserJourney || forAllJourneys) {
						if (tempLastJourneyMade && !tempLastJourneyMade.recommandation) {
							if (!tempLastJourneyMade.completed && !tempLastJourneyMade.bilan) {
								if (tempLastJourneyMade.allAskedQuestions.length > 0) {
									const temp = JSON.parse(JSON.stringify(tempLastJourneyMade));
									const journey = this._transformNestyJourneyAsClass(
										temp,
										tempLastJourneyMade,
										this.lmsService.getStatusAsIndex(journeyStatus.inProgress)
									);
									statusProgression.push(journey);
								}
							} else if (tempLastJourneyMade.bilan) {
								if (tempLastJourneyMade.allAskedQuestions.length > 0) {
									const bilan = tempLastJourneyMade.allAskedQuestions.find(bilanQuestion => {
										return bilanQuestion.bilanCompleted === 1;
									});

									if (!bilan) {
										const temp = JSON.parse(JSON.stringify(tempLastJourneyMade));
										const journey = this._transformNestyJourneyAsClass(
											temp,
											tempLastJourneyMade,
											this.lmsService.getStatusAsIndex(journeyStatus.inProgress)
										);
										statusProgression.push(journey);
									}
								}
							}
						}

						newJourney[key].push(tempLastJourneyMade);
						if (completedFarthestJourney) {
							// Parcours déjà terminé
							const completedCopy = JSON.parse(JSON.stringify(completedFarthestJourney));
							completedFarthestJourney.farthest = true;
							if (!completedCopy.bilan) {
								const journey = this._transformNestyJourneyAsClass(
									completedCopy,
									tempLastJourneyMade,
									this.lmsService.getStatusAsIndex(journeyStatus.completed)
								);
								statusCompleted.push(journey);
							}
							newJourney[key].push(completedFarthestJourney);
						} else {
							// Parcours à faire
								let needToDo = true;
								if(exerciseEnumProgression[0].bilan){
									// for bilan journeys can't determine if all ex were done 
									// due to the adaptative learning
									const exist = statusCompleted.some(data => {
										return data.id == exerciseEnumProgression[0].id;
									});
									if(exist){
										needToDo = false;
									}
								}
								if(needToDo){
									const exerciseEnumCopy = JSON.parse(JSON.stringify(exerciseEnumProgression[0]));
									const currentJourney = this.lmsService.userJourneysByAssignation.find(j => {
										return j.id === exerciseEnumCopy.id;
									});

									if (currentJourney) {
										const journey = this._transformNestyJourneyAsClass(
											exerciseEnumCopy,
											tempLastJourneyMade,
											this.lmsService.getStatusAsIndex(journeyStatus.toDo)
										);
										statusToDo.push(journey);
									}
								}
							newJourney[key].push(exerciseEnumProgression[0]);
						}
					}
				}
			}
			// En cours
			const inProcessing = this._addNewStatus(statusProgression, this.lmsService.getStatusAsIndex(journeyStatus.inProgress));
			// A faire
			const toDo = this._addNewStatus(statusToDo, this.lmsService.getStatusAsIndex(journeyStatus.toDo));

			if (toDo?.value) {
				// assignation journey atteibute assignationId for lrs journey
				toDo.value.forEach(lrsAssignatedJ => {
					const currAssignatedJourney = this.lmsService.userJourneysByAssignation.find(userAssignatedJ => {
						return +userAssignatedJ.id === +lrsAssignatedJ.id;
					});

					if (currAssignatedJourney?.assignationId) {
						lrsAssignatedJ.assignationId = currAssignatedJourney.assignationId;
					}
				});
			}
			// // Terminé
			const completed = this._addNewStatus(statusCompleted, this.lmsService.getStatusAsIndex(journeyStatus.completed));
			const listOfStatuses = statusProgression.concat(statusToDo, statusCompleted);
			let toDoNotInLrs = new Array();
			// A faire qui n'est pas stocké dans lrs
			toDoNotInLrs = this._checkLrsNotIncludedJourney(this.lmsService.userJourneysByAssignation, listOfStatuses);
			const allStatuses: JourneysByStatus = {
				[this.lmsService.getStatusAsIndex(journeyStatus.inProgress)]: { opened: false, items: inProcessing.value },
				[this.lmsService.getStatusAsIndex(journeyStatus.toDo)]: { opened: false, items: toDo.value.concat(toDoNotInLrs) },
				[this.lmsService.getStatusAsIndex(journeyStatus.completed)]: { opened: false, items: completed.value },
				[this.lmsService.getStatusAsIndex(journeyStatus.allJourneys)]: { opened: false, items: this.lmsService.allJourneys }
			};

			if (Object.keys(allStatuses).length > 0) {
				journeysByStatus.push(allStatuses);
			}
			resolve({ journey: newJourney, journeysByStatus });
		});
	}
	/**
	 * Add status to nesty journey considered as simple object and convert it to a real class with it's own functions
	 */
	private _transformNestyJourneyAsClass(journeyWithoutClass: Journey, journeyWithClass: Journey, status: string) {
		// add status to nesty journey
		// let nestyJourneyStatus = Object.assign(journeyWithoutClass, { journeyStatus: status });
		journeyWithoutClass.journeyStatus = status;
		// nesty journey as real class
		let realJourneyAsClass = { ...journeyWithClass, ...journeyWithoutClass };
		return this._recoverModelRequirements(realJourneyAsClass);
	}

	/**
	 * Add requirements in order to access to class functions
	 */
	private _recoverModelRequirements(journey: any) {
		if (!journey.lmsService) {
			journey.lmsService = this.lmsService;
		}
		if (!journey.cabriService) {
			journey.cabriService = this.cabriService;
		}
		return journey;
	}

	private _checkLrsNotIncludedJourney(array, status) {
		const notIncludedLrs = new Array();
		array.forEach(data => {
			const posIndex = status.findIndex(allJourney => {
				return data.id === allJourney.id;
			});

			if (posIndex === -1) {
				// All journeys
				notIncludedLrs.push(data);
			}
		});

		return notIncludedLrs;
	}

	private _addNewStatus(status, key: string) {
		let statusItems;
		let value = new Array();
		if (status.length === 0) {
			statusItems = {
				key: value
			};
		} else {
			value = status;
			statusItems = {
				key: value
			};
		}
		return { key, value };
	}

	/**
	 * Start statistics by competencies
	 */
	getExercisesProgression(lang: string) {
		return new Promise(async (resolve, reject) => {
			let studentIds: Array<string>;
			studentIds = this.accountService.allStudents.map(currStudent => {
				return currStudent.id;
			});
			const statement = [
				{
					$match: {
						timestamp: {
							$gte: {
								$dte: "2021-01-01T08:09:00.000Z"
							}
						}
					}
				},
				{
					$match: {
						$and: [
							{
								"statement.verb.id": {
									$nin: [
										"https://xapi.mathia.education/verbs/initialized",
										"https://xapi.mathia.education/verbs/finished"
									]
								}
							},
							// {
							// 	"statement.context.extensions.https://xapi&46;mathia&46;education/extensions/kidaia": {
							// 		$in: this.environment.kidaia ? [true] : [null, false]
							// 	}
							// },
							{
								"statement.actor.account.name": {
									$in: studentIds
								}
							}
						]
					}
				},
				{
					$project: {
						search: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id_session",
						userId: "$statement.actor.account.name",
						story: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/story",
						exerciseid: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id",
						journeyId: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_id",
						mode: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/mode_jeu",
						completed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/completed"] }, 1, 0] },
						perGoodAnswers: "$statement.context.extensions.https://xapi&46;mathia&46;education/pourcentage_bonnes_reponses",
						failed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/failed"] }, 1, 0] },
						passedWithHelp: {
							$cond: [
								{
									$or: [
										{
											$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-on-retry"]
										},
										{
											$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-with-help"]
										}
									]
								},
								1,
								0
							]
						},
						passed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed"] }, 1, 0] }
					}
				},
				{
					$group: {
						_id: "$search",
						userId: { $first: "$userId" },
						perGoodAnswers: { $sum: "$perGoodAnswers" },
						exerciseid: { $first: "$exerciseid" },
						journeyId: { $first: "$journeyId" },
						story: { $first: "$story" },
						completed: { $sum: "$completed" },
						mode: { $first: "$mode" },
						passed: { $sum: "$passed" },
						passedWithHelp: { $sum: "$passedWithHelp" },
						failed: { $sum: "$failed" }
					}
				},
				{
					$sort: {
						timestamp: -1
					}
				}
			];

			let allExStatistics;
			try {
				allExStatistics = (await this.lrs.request(statement)) as any;
				// Directly storing LRS response traces which facilitates array management when an activity is completed
				this.localStorageService.set(StorageKey.getExercisesProgression, allExStatistics);
			} catch (err) {
				allExStatistics = await this.localStorageService.get(StorageKey.getExercisesProgression);
			} finally {
				if (allExStatistics) {
					allExStatistics.forEach(exercise => {
						if (exercise.completed >= 1) {
							exercise.progression = 100;
						}
						if (exercise.perGoodAnswers > 100) {
							exercise.perGoodAnswers = 100;
						}

						if (exercise.mode === "défi" && exercise.perGoodAnswers <= 100) {
							// défi eliminated directly so earned one moon by session
							exercise.failed = 1;
						}
					});

					const getStatistics = this._defineExerciseStatistics(allExStatistics, lang);
					this.lmsService.exerciseStatistics = getStatistics;
					this.lmsService.exerciseStatisticsLoaded.next(true);
					resolve(getStatistics);
				} else {
					reject(true);
				}
			}
		});
	}

	/**
	 * Return exercise id as key with progression as percentage with corresponding mode
	 */
	private _defineExerciseStatistics(arr, lang: string): ExerciseStatistics {
		const statistics: ExerciseStatistics = {};
		arr.forEach(exercise => {
			if (!isNaN(exercise.progression)) {
				const currentExercise = this.cabriService.exercices.getExercise(exercise.exerciseid);
				if (currentExercise) {
					let allExCategories = new Array();

					if (currentExercise.categories.length > 0) {
						if (lang === AppLanguage.EN) {
							const result = this.cabriService.exercices.allCategories.filter(category => {
								let found = false;
								Object.entries(currentExercise.categoriesObject).forEach(([key, value]) => {
									if (Number(key) === Number(category.term_id)) {
										found = true;
									}
								});
								return found;
							});
							if (result?.length > 0) {
								result.forEach(category => {
									if(category?.name){
										allExCategories.push(category.name);
									}
								});
							} else {
								console.error("no any category no reason");
							}
						} else {
							allExCategories = currentExercise.categories
						}
					} else {
						allExCategories = new Array(NoCategoryStatus.label);
					}
					const activity = this.cabriService.activities.find(activity => {
						return activity.id === currentExercise.gabarit;
					});
					if (activity !== undefined) {
						if (exercise.exerciseid === 124 || exercise.exerciseid === 125 || exercise.exerciseid === 126) {
							// decouverte des solides with no question so avoid to have 0 as percent
							exercise.perGoodAnswers = 100;
						}

						allExCategories.forEach(cat => {
							if (
								statistics[exercise.userId] &&
								statistics[exercise.userId][activity.id] &&
								statistics[exercise.userId][activity.id][cat]
							) {
								statistics[exercise.userId][activity.id][cat].push({
									progression: exercise.progression,
									perGoodAnswers: Math.floor(exercise.perGoodAnswers),
									exerciseId: exercise.exerciseid,
									completed: exercise.completed >= 1 ? true : false,
									_id: exercise._id,
									passed: exercise.passed,
									passedWithHelp: exercise.passedWithHelp,
									failed: exercise.failed,
									grade: currentExercise.classe,
									journeyId: exercise.journeyId,
									story: exercise.story
								});
	
							} else {
								// first time define object item
								if (!statistics[exercise.userId]) {
									(statistics[exercise.userId] as any) = {
										[activity.id]: {
											[cat]: {}
										}
									};
								} else if (!statistics[exercise.userId][activity.id]) {
									(statistics[exercise.userId][activity.id] as any) = {
										[cat]: {}
									};
								}
	
								statistics[exercise.userId][activity.id][cat] = [
									{
										progression: exercise.progression,
										perGoodAnswers: Math.floor(exercise.perGoodAnswers),
										exerciseId: exercise.exerciseid,
										_id: exercise._id,
										completed: exercise.completed >= 1 ? true : false,
										passed: exercise.passed,
										passedWithHelp: exercise.passedWithHelp,
										failed: exercise.failed,
										grade: currentExercise.classe,
										journeyId: exercise.journeyId,
										story: exercise.story
									}
								];
							}
						});
					}
				}
			}
		});
		// descending sort by progression
		for (const userId in statistics) {
			if (userId) {
				for (const activityId in statistics[userId]) {
					if (activityId) {
						for (const category in statistics[userId][activityId]) {
							if (category) {
								statistics[userId][activityId][category] = statistics[userId][activityId][category].sort((a, b) => {
									return b.perGoodAnswers - a.perGoodAnswers;
								});
							}
						}
					}
				}
			}
		}
		return statistics;
	}

	/**
	 * Start LogBook
	 */
	async nbU() {
		return new Promise((resolve, reject) => {
			const statement = [
				{
					$match: {
						$and: [
							{
								"statement.verb.id": {
									$in: ["https://xapi.mathia.education/verbs/initialized"]
								}
							}
						]
					}
				},
				{
					$project: {
						userid: "$statement.actor.account.name",
						mydate: {
							$dateToString: {
								format: "%d-%m-%Y",
								date: {
									$toDate: "$statement.timestamp"
								}
							}
						}
					}
				},
				{
					$group: {
						_id: {
							userid: "$userid",
							mydate: "$mydate"
						}
					}
				},
				{
					$group: {
						_id: "$_id.mydate",
						nbuser: {
							$sum: 1
						}
					}
				},
				{
					$project: {
						_id: 0,
						date: "$_id",
						nbuser: 1
					}
				},
				{
					$sort: {
						date: 1
					}
				}
			];

			this.lrs
				.request(statement)
				.then(async (initilized: any) => {
					console.log("Nombre élève", initilized);

					resolve(this.logBookStatistics);
				})
				.catch(err => {
					reject(true);
				});
		});
	}
	/**
	 * Start LogBook
	 //statistiques exercices terminés*/
	async exercicescompleted() {
		return new Promise((resolve, reject) => {
			const statement = [
				{
					$match: {
						$and: [
							{
								"statement.verb.id": {
									$in: ["https://xapi.mathia.education/verbs/completed"]
								}
							}
						]
					}
				},
				{
					$project: {
						sessionid: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id_session",
						mydate: {
							$dateToString: {
								format: "%d-%m-%Y",
								date: {
									$toDate: "$statement.timestamp"
								}
							}
						}
					}
				},
				{
					$group: {
						_id: {
							sessionid: "$sessionid",
							mydate: "$mydate"
						}
					}
				},
				{
					$group: {
						_id: "$_id.mydate",
						nbsession: {
							$sum: 1
						}
					}
				},
				{
					$project: {
						_id: 0,
						date: "$_id",
						nbsession: 1
					}
				},

				{
					$sort: {
						date: 1
					}
				}
			];

			this.lrs
				.request(statement)
				.then(async (initilized: any) => {
					console.log("Exercices termine", initilized);
					resolve(this.logBookStatistics);
				})
				.catch(err => {
					reject(true);
				});
		});
	}
	//requete parcours terminé par un utilisateur
	async parcourscompleted(cabriService: CabriDataService, journeys: Journey[]) {
		return new Promise((resolve, reject) => {
			const statement = [
				{
					$match: {
						timestamp: {
							$gte: {
								$dte: "2021-01-01T08:09:00.000Z"
							}
						}
					}
				},
				{
					//on cherche à avoir le nombre de parcours terminé par un utilisateur
					$match: {
						$and: [
							// {
							// 	"statement.actor.account.name": {
							// 		$in: ["1"]
							// 	}
							// },
							{
								"statement.verb.id": {
									$in: ["https://xapi.mathia.education/verbs/completed"]
								}
							},
							{
								"statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_session_id": {
									$nin: [null]
								}
							}
							// {
							// 	"statement.context.extensions.https://xapi.mathia.education/extensions/codeclasse":{
							// 		$nin: ["61103","60662"]
							// 	}
							// }
						]
					}
				},
				{
					$project: {
						parcours: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_session_id",
						search: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id",
						nomparcoursen: "$statement.object.definition.description.en-US"
						//passed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed"] }, 1, 0] }
					}
				},
				{
					$group: {
						_id: "$search",
						idparcours: { $sum: "$parcours" },
						nomparcours: { $first: "$nomparcoursen" }
						//numberPassed: { $sum: "$passed" }
					}
				},
				{
					$sort: {
						timestamp: -1
					}
				}
			];

			this.lrs
				.request(statement)
				.then(async (sessionExercises: Array<LogBookStatistics>) => {
					console.info("parcours terminée", sessionExercises);
				})
				.catch(err => {
					console.log("ERR2");
					reject(true);
				});
		});
	}
	//requette nombre de classe
	async nombredeclasse() {
		return new Promise((resolve, reject) => {
			const statement = [
				{
					//on cherche à avoir le nombre de code classe
					$match: {
						$and: [
							{
								"statement.verb.id": {
									$in: ["https://xapi.mathia.education/verbs/initialized"]
								}
							}
						]
					}
				},
				{
					$project: {
						codeid: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/codeclasse",
						mydate: {
							$dateToString: {
								format: "%d-%m-%Y",
								date: {
									$toDate: "statement.timestamp"
								}
							}
						}
					}
				},
				{
					$group: {
						_id: {
							codeid: "$codeid",
							mydate: "$mydate"
						}
					}
				},
				{
					$group: {
						_id: "$_id.mydate",
						nbcodeid: {
							$sum: 1
						}
					}
				},
				{
					$project: {
						_id: 0,
						date: "$_id",
						nbcodeid: 1
					}
				},
				{
					$sort: {
						date: 1
					}
				}
			];
			// ];
			this.lrs
				.request(statement)
				.then(async (initilized: any) => {
					console.log("Nombre de classe", initilized);

					resolve(this.logBookStatistics);
				})
				.catch(err => {
					reject(true);
				});
		});
	}

	/**
	 * Start LogBook
	 */
	async getLogBook(cabriService: CabriDataService, journeys: Journey[], lang: string) {
		return new Promise((resolve, reject) => {
			if (this.logBookStatistics.length > 0) {
				resolve(this.logBookStatistics);
				return;
			}
			const statement = [
				{
					$match: {
						timestamp: {
							$gte: {
								$dte: "2021-01-01T08:09:00.000Z"
							}
						}
					}
				},
				{
					$match: {
						$and: [
							{
								"statement.verb.id": {
									$in: ["https://xapi.mathia.education/verbs/completed"]
								}
							},
							{
								"statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id_activite": {
									$nin: ["2"]
								}
							},
							// {
							// 	"statement.context.extensions.https://xapi&46;mathia&46;education/extensions/kidaia": {
							// 		$in:  [true]
							// 	}
							// },
							{
								"statement.actor.account.name": {
									$in: [this.accountService.team[0].id]
								}
							}
						]
					}
				},
				{
					$project: {
						search: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id_session",
						parcours_id: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_id",
						exerciseid: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id",
						parcours_session_id:
							"$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/parcours_session_id",
						mode: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/mode_jeu",
						timestamp: "$statement.stored",
						perGoodAnswers: "$statement.context.extensions.https://xapi&46;mathia&46;education/pourcentage_bonnes_reponses",
						failed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/failed"] }, 1, 0] },
						failedOnFirstAttempt: {
							$cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/failed-on-first-attempt"] }, 1, 0]
						},
						passedWithHelp: {
							$cond: [
								{
									$or: [
										{
											$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-on-retry"]
										},
										{
											$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-with-help"]
										}
									]
								},
								1,
								0
							]
						},
						passed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed"] }, 1, 0] },
						duration: "$metadata.https://learninglocker&46;net/result-duration.seconds"
					}
				},
				{
					$group: {
						_id: "$search",
						perGoodAnswers: { $first: "$perGoodAnswers" },
						exerciseid: { $first: "$exerciseid" },
						timestamp: { $first: "$timestamp" },
						parcours_id: { $first: "$parcours_id" },
						mode: { $first: "$mode" },
						passed: { $sum: "$passed" },
						passedWithHelp: { $sum: "$passedWithHelp" },
						failed: { $sum: "$failed" },
						failedOnFirstAttempt: { $sum: "$failedOnFirstAttempt" },
						duration: { $first: "$duration" }
					}
				},
				{
					$sort: {
						timestamp: -1
					}
				}
			];

			this.lrs
				.request(statement)
				.then(async (sessionExercises: Array<LogBookStatistics>) => {
					sessionExercises.forEach(exercise => {
						exercise.duration = this.secondsToHms(exercise.duration);
						// let perGoodAnswer: number;
						exercise.perGoodAnswers = Math.floor(exercise.perGoodAnswers);
						const currentExercise = cabriService.exercices.getExercise(exercise.exerciseid);
						let journeyName;
						if (exercise.parcours_id) {
							// get journay title
							const currentJourney = journeys.find(currJourney => {
								return currJourney.id === exercise.parcours_id;
							});
							if (currentJourney) {
								journeyName = currentJourney.title;
							}
						}
						if (currentExercise) {
							const exerciseNameSplitted = currentExercise.name.split("-");
							if (exerciseNameSplitted.length > 0) {
								let activityName;
								const activity = cabriService.activities.find(activitiy => {
									return Number(activitiy.id) === Number(currentExercise.gabarit);
								});
								if (activity.name) {
									// get activity name
									activityName = activity.name;
								}
								let exerciseNameWithoutId;
								if (exerciseNameSplitted[1]) {
									exerciseNameWithoutId = exerciseNameSplitted[1].trim();
								} else {
									exerciseNameWithoutId = exerciseNameSplitted[0].trim();
								}
								if (lang === AppLanguage.FR) {
									/** Convert lrs timestamp to local timezone to get locale hour */
									// iso -> Date
									const startTime = new Date(String(exercise.timestamp));
									// date -> iso8601
									exercise.timestamp = new Date(
										startTime.getTime() - startTime.getTimezoneOffset() * 60000
									).toISOString() as any;
								}
								exercise.timestamp = this._getDate(exercise.timestamp);
								// statistic final
								this.logBookStatistics.push({
									...exercise,
									exerciseName: exerciseNameWithoutId,
									journeyName,
									activityName,
									perGoodAnswers: exercise.perGoodAnswers
								});
							}
						}
					});

					this.logBookStatistics = this.logBookStatistics.reverse();
					resolve(this.logBookStatistics);
				})
				.catch(err => {
					reject(true);
				});
		});
	}

	secondsToHms(d) {
		d = Number(d);
		const h = Math.floor(d / 3600);
		const m = Math.floor((d % 3600) / 60);
		const s = Math.floor((d % 3600) % 60);

		const hDisplay = h > 0 ? h + (h == 1 ? " " + $localize` heure ` + " " : " " + $localize` heures ` + " ") : "";
		const mDisplay = m > 0 ? m + (m == 1 ? " " + $localize` minute ` + " " : " " + $localize` minutes ` + " ") : "";
		const sDisplay = s > 0 ? s + (s == 1 ? " " + $localize` seconde` : " " + $localize` secondes`) : "";
		let et = "";
		if (mDisplay && sDisplay) {
			et = " " + $localize`et ` + " ";
		}

		return hDisplay + mDisplay + et + sDisplay;
	}

	private _getDate(timestampIso8601): { day: number; dayOfWeek: string; month: string; year: number; time: string } {
		const date = parse(timestampIso8601, "yyyy-MM-dd'T'HH:mm:ss'.'SSS'Z'", new Date());
		return this._getCompleteDate(date);
	}

	private _getCompleteDate(dateJS: Date) {
		const date = format(dateJS, "dd/MM/yyyy");
		const time = format(dateJS, "HH:mm");
		const dateSplitted = date.split("/");
		const tabMois = new Array(
			$localize`janvier`,
			$localize`février`,
			$localize`mars`,
			$localize`avril`,
			$localize`mai`,
			$localize`juin`,
			$localize`juillet`,
			$localize`août`,
			$localize`septembre`,
			$localize`octobre`,
			$localize`novembre`,
			$localize`décembre`
		);
		const indexDayOfWeek = Number(format(dateJS, "i"));
		const tabJour = new Array(
			$localize`:Week day logbook text:Le lundi`,
			$localize`:Week day logbook text:Le mardi`,
			$localize`:Week day logbook text:Le mercredi`,
			$localize`:Week day logbook text:Le jeudi`,
			$localize`:Week day logbook text:Le vendredi`,
			$localize`:Week day logbook text:Le samedi`,
			$localize`:Week day logbook text:Le dimanche`
		);
		return {
			month: tabMois[Number(dateSplitted[1]) - 1],
			day: Number(dateSplitted[0]),
			dayOfWeek: tabJour[indexDayOfWeek - 1],
			year: Number(dateSplitted[2]),
			time
		};
	}

	/**
	 * END LogBook
	 */

	updatePerGoodAnswerStatements(http) {
		const statement = [
			{
				$match: {
					timestamp: {
						$gte: {
							$dte: "2021-01-27T19:30:00.000Z"
						}
					}
				}
			},
			{
				$match: {
					$and: [
						{
							"statement.verb.id": {
								$nin: ["https://xapi.mathia.education/verbs/finished", "https://xapi.mathia.education/verbs/initialized"]
							}
						}
					]
				}
			},
			{
				$project: {
					id: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/id_session",
					failed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/failed"] }, 1, 0] },
					modeJeu: "$statement.context.extensions.https://xapi&46;mathia&46;education/extensions/mode_jeu",
					passedWithHelp: {
						$cond: [
							{
								$or: [
									{
										$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-on-retry"]
									},
									{
										$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed-with-help"]
									}
								]
							},
							1,
							0
						]
					},
					failedOnFirstAttempt: {
						$cond: [
							{
								$and: [
									{
										$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/failed-on-first-attempt"]
									}
								]
							},
							1,
							0
						]
					},
					passed: { $cond: [{ $eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/passed"] }, 1, 0] },
					fieldExist: {
						$cond: [
							{
								$gt: ["$statement.context.extensions.https://xapi&46;mathia&46;education/pourcentage_bonnes_reponses", null]
							},
							true,
							false
						]
					},
					isCompleted: {
						$cond: [
							{
								$eq: ["$statement.verb.id", "https://xapi.mathia.education/verbs/completed"]
							},
							true,
							false
						]
					}
				}
			},
			{
				$group: {
					_id: "$id",
					isCompleted: { $first: "$isCompleted" },
					modeJeu: { $first: "$modeJeu" },
					fieldExist: { $first: "$fieldExist" },
					passed: { $sum: "$passed" },
					failedOnFirstAttempt: { $sum: "$failedOnFirstAttempt" },
					failed: { $sum: "$failed" },
					passedWithHelp: { $sum: "$passedWithHelp" }
				}
			},
			{
				$sort: {
					timestamp: -1
				}
			}
		];

		this.lrs
			.request(statement)
			.then(async (request: any) => {
				const notExistingFieldRequest = [];
				request.forEach(elem => {
					if (elem.isCompleted && !elem.fieldExist) {
						let perTotalGoodAnswer;
						let perTotalWrongAnswer;
						perTotalGoodAnswer =
							((elem.passed + elem.passedWithHelp) / (elem.passed + elem.passedWithHelp + elem.failed)) * 100;
						elem.perGoodAnswer = perTotalGoodAnswer;
						if (elem.modeJeu === "défi") {
							perTotalWrongAnswer =
								(elem.failedOnFirstAttempt / (elem.passed + elem.failedOnFirstAttempt + elem.failed)) * 100;
						} else {
							perTotalWrongAnswer = (elem.failed / (elem.passed + elem.passedWithHelp + elem.failed)) * 100;
						}

						if (isNaN(perTotalWrongAnswer) || isNaN(perTotalGoodAnswer)) {
							if (isNaN(perTotalWrongAnswer)) {
								perTotalWrongAnswer = 0;
							}

							if (isNaN(perTotalGoodAnswer)) {
								perTotalGoodAnswer = 0;
							}
						}

						const finalElement = {
							id: elem._id,
							perTotalGoodAnswer,
							perTotalWrongAnswer
						};
						notExistingFieldRequest.push(finalElement);
					}
				});

				const items = notExistingFieldRequest.slice(0, 3);
				// items[0].id = "16196066543626473oyl5pc";
				// items[1].id = "16196185255886473kewvgq";
				// items[2].id = "161961865769764737hnrh3";
				http.post(`http://127.0.0.1:8000/search`, { statements: JSON.stringify(items) }).subscribe({
					next: res => {
						console.log("resultLrs", res);
					},
					error: err => {
						console.log("error search", err);
					}
				});
			})
			.catch(err => {});
	}
}

results matching ""

    No results matching ""