@startuml uc16
title "Use Case #16: Receive Message"

'Styling goes here
hide footbox
skinparam stereotypePosition bottom
skinparam sequenceMessageAlign direction
skinparam sequence {
	LifeLineBorderColor #Silver
	LifeLineBackgroundColor #Gainsboro
}

'Add a legend plus styling
skinparam legend {
	backgroundColor #GhostWhite
	entrySeparator #GhostWhite
}

legend top
	<#GhostWhite,#GhostWhite>|	|= __Legend__ |
	|<#red> | Sender|
	|<#silver> | Server|
	|<#blue> | Receiver|
endlegend

'Setup the objects involved here
actor ReceivingUser as u <<Actor>> #blue
boundary ReceiverConversationWindow as rcw <<Boundary>> #blue
control ReceiverConversationManager as rcm <<Control>> #blue
control ChatRouter as cr <<Control>> #silver
control WebsocketHandler as ws <<Control>> #silver
control DatabaseManager as db <<Control>> #silver
'boundary SenderDevice as sd <<Boundary>>

'Setup persistent objects here
activate u
activate cr
activate ws
activate db
'activate sd

'--- FLOW OF CONTROL STARTS HERE ---
'Case 1: The recipient is online
group Recipient Already In Convo Window (Online)
	'If the receiving user is online, then messages are pulled in immediately.
	activate rcm
	activate rcw
	ws -> rcm: wsMessage(ws, recvId, em)
	rnote over rcw
	The message is pulled in and
	processed; see next section
	below the "enter convo" case.
	end note
end
deactivate rcw
deactivate rcm

...

'Case 2: The recipient is offline
group Recipient Enters In Convo Window (Offline)
	'The user enters the conversation.
	u -> rcw: Receiving user \nopens conversation
	activate rcw
	rnote over rcm,rcw
	"Use Case #10: Enter Conversation" is called
	to populate the conversation window with saved
	messages and re-initialize the session manager
	for this conversation.
	end note
	activate rcm

	'The recipient’s device makes a request for unread messages.
	rcm -> cr: POST /api/conversations/:roomId/receive \n\tjson::{recvId}

	'The server dequeues the unread messages from the receiver's queue and sends them down to the receiver in an array, from oldest to newest.
	cr -> db: recvId.messageQueue.peekAll(roomId, em) \n\t -> EMessage[] msgs
	db --> cr: return: msgs
	cr --> rcm: RESP json::{success, msgs}

	'The receiver's device begins processing each message
	rnote over rcw
	Each message is processed using
	the below flow of control.
	end note
end

...

'The recipient’s device decrypts the message and updates the ratchet state. 
rcm -> rcm: seshKey.decrypt(em)\n -> Message msg
rcm -> rcm: updateSessionState()
rcm -> rcw: onSuccessfulReceive(msg)

'The recipient reads the message that was sent to them.
rcw -> u: received message is displayed \nin the chat room

'The recipient’s device sends a read receipt to the server to be delivered to the sender, if enabled
rcm -> cr: POST /api/conversations/:roomId/receive_ack \n\tjson::{em.id}
group Recipient Has Read Receipts On
	cr -> ws: wsMessage(ws, recvId, read_receipt, em.id)
end

'The server removes the message from the queue and securely erases it.
cr -> db: recvId.messageQueue.eject(roomId, em.id)
'--- FLOW OF CONTROL ENDS HERE   ---

@enduml
