import {emitter} from '../../src/util/emitter'; import {DocChangeInfo, FlowEventType} from '../../src/models/ext_models'; const KPM_SEND_TIMEOUT_THRESHOLD: number = 90000; export class ChangeWatch { public receivedOpenEvent:boolean = false; public receivedSaveEvent:boolean = false; public receivedSingleDeleteEvent:boolean = false; public receivedSingleCharacterAddEvent:boolean = false; public receivedReplacementEvent:boolean = false; public receivedMultiAddEvent:boolean = false; public receivedMultiDeleteEvent:boolean = false; public receivedUnfocusEvent:boolean = false; public receivedKpmEventCounter:number = 0; public kpm_payload: any | undefined = undefined; constructor() { emitter.on('editor_flow_data', (data: any) => { this.kpm_payload = data.project_change_info; switch (data.flow_event_type) { case FlowEventType.OPEN: this.receivedOpenEvent = true; break; case FlowEventType.SAVE: this.receivedSaveEvent = true; break; case FlowEventType.UNFOCUS: this.receivedUnfocusEvent = true; break; case FlowEventType.CHANGE: if (data.project_change_info) { const docs_changed = data.project_change_info.docs_changed; Object.keys(docs_changed).forEach((key: string) => { const docChangeInfo: DocChangeInfo = docs_changed[key]; if (docChangeInfo.changeType === 'singleDelete') { this.receivedSingleDeleteEvent = true; } else if (docChangeInfo.changeType === 'singleAdd') { this.receivedSingleCharacterAddEvent = true; } else if (docChangeInfo.changeType === 'replacement') { this.receivedReplacementEvent = true; } else if (docChangeInfo.changeType === 'multiAdd') { this.receivedMultiAddEvent = true; } else if (docChangeInfo.changeType === 'multiDelete') { this.receivedMultiDeleteEvent = true; } }); } break; case FlowEventType.KPM: this.receivedKpmEventCounter += 1; break; } }); } public reset() { this.receivedOpenEvent = false; this.receivedSaveEvent = false; this.receivedUnfocusEvent = false; this.receivedSingleDeleteEvent = false; this.receivedSingleCharacterAddEvent = false; this.receivedReplacementEvent = false; this.receivedMultiAddEvent = false; this.receivedMultiDeleteEvent = false; this.kpm_payload = undefined; this.receivedKpmEventCounter = 0; } public getKpmStats() { let charactersAdded = 0; let keystrokes = 0; let charactersDeleted = 0; let aiCharactersAdded = 0; let aiCharactersReverted = 0; let aiLinesReverted = 0; let aiLinesAdded = 0; let linesAdded = 0; let linesDeleted = 0; let autoIndents = 0; let changeTypes: string[] = []; if (this.kpm_payload?.docs_changed) { Object.keys(this.kpm_payload.docs_changed).forEach((key: string) => { charactersAdded += this.kpm_payload.docs_changed[key].charactersAdded; keystrokes += this.kpm_payload.docs_changed[key].keystrokes; charactersDeleted += this.kpm_payload.docs_changed[key].charactersDeleted; linesAdded += this.kpm_payload.docs_changed[key].linesAdded; linesDeleted += this.kpm_payload.docs_changed[key].linesDeleted; aiCharactersAdded += this.kpm_payload.docs_changed[key].aiCharactersAdded; aiLinesAdded += this.kpm_payload.docs_changed[key].aiLinesAdded; aiLinesReverted += this.kpm_payload.docs_changed[key].aiLinesReverted; aiCharactersReverted += this.kpm_payload.docs_changed[key].aiCharactersReverted; autoIndents += this.kpm_payload.docs_changed[key].autoIndents; changeTypes.push(this.kpm_payload.docs_changed[key].changeType); }); } return { payload: this.kpm_payload, charactersAdded, keystrokes, charactersDeleted, aiCharactersAdded, aiLinesAdded, linesAdded, linesDeleted, changeTypes, aiCharactersReverted, aiLinesReverted, autoIndents }; } public hasValidStartAndEnd() { let valid = true if (this.kpm_payload?.docs_changed) { const rangeMap: any = {}; Object.keys(this.kpm_payload.docs_changed).forEach((key: string) => { const end = this.kpm_payload.docs_changed[key].end; const start = this.kpm_payload.docs_changed[key].start; if (!start || !end) { valid = false; } else if (end - start > KPM_SEND_TIMEOUT_THRESHOLD) { valid = false; } else if (Object.keys(rangeMap).length) { // check to see if this start time is found between any other // start and end time ranges Object.keys(rangeMap).forEach(start => { const ranges = rangeMap[start]; if (ranges[0] < end && ranges[1] > end) { valid = false; } }); } rangeMap[start] = [start, end]; }); } return valid; } }