import { Subject } from "../observe/Observable"; import { Observer } from "../observe/Observer"; import { JsonAPI } from "../singleton/JsonAPI"; import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel"; import { ChatModelHelper } from "./ChatModelHelper"; import log = require("loglevel"); import { ObserverData } from "../observe/ObserverData"; import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel"; import moment = require("moment"); interface Params { userName: string; data: ChatMessageViewModel[]; op: string; } export class ChatModel implements Subject { /** * @type {Observer[]} List of subscribers. In real life, the list of * subscribers can be stored more comprehensively (categorized by event * type, etc.). */ private readonly _observers: Observer[] = []; private readonly _messagePageMap: Map; private readonly _messagesMap: Map; private readonly _chatModelHelper: ChatModelHelper; constructor(chatModelHelper: ChatModelHelper) { this._messagePageMap = new Map(); this._messagesMap = new Map(); this._chatModelHelper = chatModelHelper; } /** * The subscription management methods. */ public attach(observer: Observer): void { log.info("Subject: Attached an observer."); this._observers.push(observer); } public detach(observer: Observer): void { const observerIndex = this._observers.indexOf(observer); this._observers.splice(observerIndex, 1); log.info("Subject: Detached an observer."); } private storeUserMessages( username: string, messages: ChatMessageViewModel[], op: string ) { switch (op) { case "clear": this._messagesMap.set(username, []); break; case "page": this._messagesMap.set( username, messages.concat(this.getStoredUserMessages(username)) ); break; // case "page": this._messagesMap.set(username, messages); case "new": this._messagesMap.set( username, this.getStoredUserMessages(username).concat(messages) ); break; case "update": this._messagesMap.set( username, this.getStoredUserMessages(username).concat(messages) ); break; default: new Error("Invalid option"); } } private getStoredUserMessages(username: string): ChatMessageViewModel[] { let temp = this._messagesMap.get(username); if (temp == null) return []; else { return temp; } } /** * Trigger an update in each subscriber. */ public notify(p: Params): void { log.info("Subject: Notifying observers..."); switch (p.op) { case "clear": { const od: ObserverData = { data: [], op: "clear", }; for (const observer of this._observers) { observer.update(od); } } break; case "new": { const od: ObserverData = { data: p.data, op: p.op, }; for (const observer of this._observers) { observer.update(od); } } break; case "page": { const od: ObserverData = { data: p.data, op: p.op, }; for (const observer of this._observers) { observer.update(od); } } break; case "update": { const od: ObserverData = { data: p.data, op: p.op, }; for (const observer of this._observers) { observer.update(od); } } break; default: { log.error("error"); } } } public someBusinessMethod(chatMessageList: ChatMessageViewModel[]): void {} public clear(): void { log.info("Clearing model"); this._messagePageMap.set(JsonAPI.contactName!, 0); this.storeUserMessages(JsonAPI.contactName!, Array(), "clear"); this.notify({ userName: "", data: [], op: "clear" }); } public async getMessages( aVm: ActiveUserViewModel, op: string ): Promise { if (this._messagePageMap.get(aVm.userName!) == null) this._messagePageMap.set(aVm.userName!, 0); const pageNumber = this._messagePageMap.get(aVm.userName!); const cVMs = await this._chatModelHelper.getMessages( aVm.userName!, aVm.passphrase, pageNumber!, aVm.lastMessageTime!, op ); let cVMsFiltered = Array(); if (cVMs != null && cVMs.length != 0) { log.info("Subject: My state has just changed"); const existingMessages = this.getStoredUserMessages(aVm.userName!); log.debug("existing message:"); log.debug(existingMessages); log.debug("new messages:"); log.debug(cVMs); // filter duplicates cVMsFiltered = cVMs.filter((c) => { const res = existingMessages.filter((m) => { if (moment(c.messageTime).isSame(moment(m.messageTime))) return true; }); if (res.length > 0) return false; return true; }); if (op == "update") { // update the active user last message text and times for each user const lastMessage = cVMsFiltered[cVMsFiltered.length - 1]; cVMsFiltered.forEach((v) => { if (v.fromUser == aVm.userName) { aVm.lastMessageTime = lastMessage.messageTime; aVm.lastMessageText = lastMessage.message.slice(0, 15) + "..."; } }); } else { this._messagePageMap.set( aVm.userName!, this._messagePageMap.get(aVm.userName!)! + 1 ); } this.storeUserMessages(aVm.userName!, cVMsFiltered, op); this.notify({ userName: aVm.userName!, data: cVMsFiltered, op: op }); } return cVMsFiltered; } public async isPassphraseValid( passphrase: string, userName: string ): Promise { let valid = await this._chatModelHelper.isPassphraseValid( passphrase, userName ); return valid; } }