@startuml Gestire Compiti Cucina
skinparam Style strictuml
skinparam classAttributeIconSize 0
skinparam linetype polyline
skinparam linetype ortho

title DCD

namespace KitchenTaskManagement {
    ' GRASP Controller dei Compiti
    class KitchenTaskManager{
        --<b>event sender methods</b>--
        +addReceiver(er: kitchenTaskReceiver)
        +removeReceiver(er: kitchenTaskReceiver)
        -notifySheetCreate(s: SummarySheet)
        -notifyAddExtraDuty(kd: KitchenDuty)
        -notifyDeleteExtraDuty(kd: KitchenDuty)
        -notifyEditTask(t: Task)
        -notifyCreatedKitchenJob(j: KitchenJob)
        -notifyDeletedKitchenJob(j: KitchenJob)
        -notifyEditKitchenJob(j: KitchenJob)
        --<b>operation methods</b>--
        + createSummarySheet(event: Event, service: Service)
        + editTask(task: Task, newAmount: int, newDuration: int)
        + sortTask(task: Task, position: int)
        + addExtraDuty(kd: KitchenDuty)
        + deleteExtraDuty(kd: KitchenDuty)
        + createKitchenJob(cook: Cook, task: Task, turn: KitchenTurn, amount: int, estimatedDuration: Duration)
        + deleteKitchenJob(task: Task, job: KitchenJob)
        + assignCook(job: KitchenJob, user: User)
    }

    class "KitchenTaskEventReceiver \n {interface}" as KitchenTaskReceiver{
        --
        +<i>updateSheetCreate(s: SummarySheet)</i>
        +<i>updateAddExtraDuty(kd: KitchenDuty)</i>
        +<i>updateDeleteExtraDuty(kd: KitchenDuty)</i>
        +<i>updateEditTask(t: Task)</i>
        +<i>updateCreatedKitchenJob(j: KitchenJob)</i>
        +<i>updateDeletedKitchenJob(j: KitchenJob)</i>
        +<i>updateEditKitchenJob(j: KitchenJob)</i>
    }

    ' Compito
    class Task{
        - amount: int
        - estimatedDuration: Duration
        - toDo: boolean
        --
        + create(kitchenDuty: KitchenDuty)
        + editDetails(newAmount: int, newDuration: int, newToDo: boolean)
        + addKitchenJob(cook: Cook, turn: KitchenTurn, amount: int, estimatedDuration: Duration)
        + deleteKitchenJob(job: KitchenJob)
        + deleteAllKitchenJobs()

    }

    ' Foglio Riepilogativo
    class SummarySheet {
        + create(menu: Menu)
        + addExtraDuty(kd: KitchenDuty)
        + deleteExtraDuty(kd: KitchenDuty)
        + deleteAllTasks()
    }

    ' Incarico
    class KitchenJob {
        - amount: int
        - estimatedDuration: Duration
        --
        + create(cook: Cook, turn: KitchenTurn, amount: int, estimatedDuration: Duration)
        + edit(amount: int, estimatedDuration: Duration)
        + assignCook(user: User)
    }

    KitchenTaskManager --> "0..1" SummarySheet: currentSheet
    KitchenTaskManager -> "0..n" KitchenTaskReceiver: eventReceivers
    SummarySheet --> "1..n" Task: tasks
    SummarySheet --> "0..n" RecipeManagement.KitchenDuty: extraDuties
    Task -> "0..n" KitchenJob: jobs
    Task -left-> "0..1" RecipeManagement.KitchenDuty: optionalDuty
    KitchenJob --> "0..1"  UserManagement.User: cook
    KitchenJob --> "1" TurnManagement.KitchenTurn: turn
}

namespace TurnManagement {
    ' Turno di Cucina
    class KitchenTurn {
        - startDate: LocalDate
        - endDate: LocalDate
        - complete: boolean
        --
        + getDuration(): Duration
        + hasUserEnoughTime(user: User, duration: Duration): boolean
        + freeTime(user: User, durationToFree: Duration)
        + takeTime(user: User, durationToTake: Duration)
    }

    ' Classe utilitaria suggerita dalle Prof; questa diventerà parte di una HashMap
    class TimeKeeper {
        - usedTime: Duration
        + create(user: User, startDuration: Duration)
    }

    class ServiceTurn

    class Turn{
        - day: LocalDate
        -startHour: Instant
        -endHour: Instant
    }

    class TurnManager

    class ServiceJob{
        -role: char
    }

    KitchenTurn -> "0..n" TimeKeeper: assignedCooks
    TimeKeeper -> UserManagement.User: cook
    TurnManager -> "0..n" KitchenTurn: turns
    ServiceTurn -|> Turn
    KitchenTurn -|> Turn
    ServiceJob -> "1" ServiceTurn: turn
    ServiceJob -> "0..n" UserManagement.User: worker
}

namespace RecipeManagement {
    ' Mansione di Cucina
    class KitchenDuty {
        - name: String
        - instructions: String
        - resultingAmount: int
        - constantConcreteActivityTime: Duration
        - variableConcreteActivityTime: Duration
        {abstract} List<KitchenDuty> getSubDuties()
    }

    ' Ricetta
    class Recipe {
        -name
    }

    ' Preparazione
    class Preparation{

    }

    class RecipeManager{
        --<b>event sender methods</b>--
        --<b>operation methods</b>--
        +getRecipeBook(): ArrayList<Recipe>
    }

    Recipe -left|> KitchenDuty
    Recipe -up> "0..n" Preparation: subDuties
    Preparation -left|> KitchenDuty
    KitchenDuty --> "1" UserManagement.User: author
    RecipeManager-->"0..n" Recipe: recipes
}

namespace EventManagement {
    ' Servizio
    class Service {
        -offsetDay: int
        -startHour: Instant
        -endHour: Instant
        -typology: String
        -place: String
        -diners: int
        -state: String
        --
        + getMenu(): Menu
        + addSummarySheet(sheet: SummarySheet)
    }

    class MacroEvent {
        - notes: String
        - customer: String
        --
        +setDefaultEvent(event: Event)
        +addEvent(startDate: LocalDate)
        +changeFrequency(frequency: EventFrequency)
    }

    class "EventEventReceivers \n {interface}" as EventEventReceivers{
        +<i>updateCreateEvent(ev: Event)</i>
        +<i>updateCancelEvent(ev: Event)</i>
        +<i>updateEditEvent(ev: Event)</i>
        +<i>updateDeleteEvent(ev: Event)</i>
    }

    class EventManager{
        --<b>event sender methods</b>--
        +addReceiver(er: EventEventReceivers)
        +removeReceiver(er: EventEventReceivers)
        -notifyCreateEvent(ev: Event)
        -notifyEditEvent(ev: Event)
        -notifyCancelEvent(ev: Event)
        -notifyDeleteEvent(ev: Event)
        --<b>operation methods</b>--
        + createEvent(startDate: LocalDate)
        + cancelEvent(ev: Event)
        + deleteEvent(ev: Event)
        + editEventDetails(event: Event, frequency: EventFrequency, startDate: LocalDate)
    }

    class EventFrequency{
        -offsetGiorniOccorrenza: int
        -numeroOccorrenzePreviste: int
        -numeroOccorrenzeAvvenute: int
    }

    class Patch

    class AdditionPatch

    class RemovalPatch

    ' Evento
    class Event {
        - state: String
        - dateStart: LocalDate
        --
        + isActive(): boolean
        + containsService(s:Service): boolean
        + editDetails(startDate: LocalDate)
        + delete()
    }
    Event --> "1..n" Service: "services"
    Event -left> "1" UserManagement.User: "assignedChef"
    Service -up> "0..1" MenuManagement.Menu: menu
    RemovalPatch -|> Patch
    AdditionPatch -|> Patch
    AdditionPatch --> "1" RecipeManagement.kitchenDuty: duty
    RemovalPatch -> "1" MenuManagement.MenuItem : menuItem
    Service ->  "0..n" Patch: patches
    MacroEvent -> "0..1" EventFrequency: frequency
    Service -> "0..n" TurnManagement.ServiceJob: serviceJobs
    MacroEvent -> "1" UserManagement.User: organizer
    MacroEvent -> "1" Event: defaultEvent
    MacroEvent -> "1..n" Event: events
    Event -> "1" MacroEvent: macroEvent
    EventManager -> "0..n" EventEventReceivers: eventReceivers
    Service -> "0..1" KitchenTaskManagement.SummarySheet: sheet
}

namespace UserManagement {
    ' Utente
    class User {
        + isChef(): boolean
        + isCook(): boolean
    }

    class UserManager {
        --<b>event sender methods</b>--
        --<b>operation methods</b>--
        +getCurrentUser(): User
    }

    UserManager -> "0..1" User: currentUser
}

namespace MenuManagement {
    class Menu{
        -title: String
        -published: boolean
        -inUse: boolean
        -features: String[]
        -featureValues: boolean[]
        --
        +create(owner: User, title: String, features: String[])
        +addSection(name: String)
        +addItem(r: Recipe, sec?: Section, desc?: String)
        +isOwner(user: User): boolean
        +isinUse(): boolean
        +hasSection(sec: Section): boolean
        +sectionsSize(): int
        +moveSection(sec: Section, pos: int)
    }

    ' Sezione
    class Section{
        name: String
        --
        +create(name: String)
        +create(sec: Section)
        +addItem(mi: MenuItem)
    }

    ' Voce (del menù)
    class MenuItem{
        description: String
        --
        +create(rec: Recipe, desc?: String)
        +create(mi: MenuItem)
    }

    class "MenuEventReceiver \n {interface}" as MenuEventReceiver{
        --
        +//updateSectionAdded(m: Menu, sec: Section)//
        +//updateMenuItemAdded(m: Menu, mi:MenuItem)//
        +//updateMenuCreated(m: Menu)//
        +//updateMenuDeleted(m: Menu)//
        +//updateSectionsRearranged(m: Menu)//
    }

    class MenuManager{
        - menuFeatures: String[]
        --<b>event sender methods</b>--
        +addReceiver(er: MenuEventReceiver)
        +removeReceiver(er: MenuEventReceiver)
        -notifySectionAdded(sec: Section)
        -notifyMenuItemAdded(mi: MenuItem)
        -notifyMenuCreated(m: Menu)
        -notifyMenuDeleted(m: Menu)
        -notifySectionsRearranged(m: Menu)
        --<b>operation methods</b>--
        +defineSection(name: String)
        +insertItem(r: Recipe, sec?: Section, desc?: String)
        +createMenu(title: String): Menu
        +getRecipeBook():ArrayList<Recipe>
    }

    MenuManager ->"0..n" MenuEventReceiver: eventReceivers
    MenuManager--left> "0..1" Menu: currentMenu
    Section -left> "0..n" MenuItem: sectionItems
    Menu --> "0..n" Section: sections
    Menu -> "0..n" MenuItem: freeItems
    Menu -> "1" UserManagement.User: owner
    MenuItem -> RecipeManagement.Recipe: itemRecipe
}

namespace GeneralModule {
    UseCaseLogicException --|> Exception
    EventException --|> Exception
}
@enduml