@startuml
skinparam Style strictuml

collections UI

participant "kitchentaskMgr: KitchenTaskManager" as ktm
participant "ktr: KitchenTaskEventReceiver" as ktr
participant "job: KitchenJob" as job
participant "job.turn: KitchenTurn" as turn
participant "assignedCooks: ArrayList<TimeKeeper>" as cooks

UI -> ktm: assignCook(user, job)
activate ktm
alt user == null || !user.isCook() || Date.now() > job.turn.endDate
    UI <<-- job: throw UseCaseLogicException
else job.cook == user
    UI <- ktm: job
else
    ktm -> turn: hasUserEnoughTime(user, job.estimatedDuration)
    activate turn

    turn -> cooks: get(job.cook)
    activate cooks
    return time

    turn -> turn: enoughTime = (startDate + time.usedTime + job.estimatedDuration) <= endDate

    return enoughTime
    deactivate turn

    alt !enoughTime
        UI <<-- job: throw TaskException
    else
        alt job.cook != null
            ktm -> turn: freeTime(job.cook, job.estimatedDuration)
            activate turn
            turn -> cooks: get(job.cook)
            activate cooks
            return time

            turn -> turn: time.usedTime -= job.estimatedDuration

            ' se per caso liberando del tempo ci accorgiamo che il TimeKeeper è vuoto, cancelliamolo.
            alt time.usedTime == 0
                turn -> cooks: remove(job.cook)
            ' altrimenti aggiorniamo il tempo.
            else
                turn -> cooks: update(job.cook, time)
            end
            deactivate turn
        end

        ktm -> turn: takeTime(user, job.estimatedDuration)
        activate turn

        participant "time: TimeKeeper" as newTime

        ' potrebbe trattarsi del primo incarico assegnato all cuoco in questo turno.
        alt !assignedCooks.contains(user)
            turn -> newTime**: create(user, job.estimatedDuration)
            activate newTime
            turn <<-- newTime: time
            deactivate newTime

            turn -> cooks: add(time)
            activate cooks
            deactivate cooks
        else
            turn -> cooks: get(user)
            activate cooks
            return time

            turn -> turn: time.usedTime += job.estimatedDuration

            turn -> cooks: add(time)
            activate cooks
            deactivate cooks
        end
        deactivate turn

        ktm -> job: assignCook(user)
        activate job
        job -> job: this.cook = user
        ktm <- job: job
        deactivate job

        |||
        ktm -> ktm: notifyEditKitchenJob(job)
        activate ktm
        loop ""for all"" ktr ""in"" eventReceivers
            ktm -> ktr : updateEditKitchenJob(job)
            activate ktr
            deactivate ktr
        end
        deactivate ktm

        UI <- ktm: job
        end
deactivate ktm
end
@enduml