digraph ReservationSystemDiagram {
    graph [
        rankdir=TB,
        splines=ortho,
        label="Lodge Reservation System",
        fontsize=20
    ];

    node [
        shape=record,
        style=filled,
        fillcolor=lightyellow,
        fontname="Helvetica"
    ];

    edge [
        penwidth=1.0,
        fontname="Helvetica"
    ];

    // Class Definitions

    AccomodationManager [label="{AccomodationManager|- accounts: AccountList\l|+ setDataStoreRoot(home: String): void\l+ loadAll(): void\l+ retrieveLoadedAccounts(): List<Account>\l+ retrieveAccount(acct_id: String): Account\l+ AddAccount(acct: Account): void\l+ UpdateAccount(acct: Account): void\l+ newAccount(...): Account\l+ addReservation(account: Account, reservation: Reservation): boolean\l+ findReservation(reservation_number: String): Reservation\l}"];

    AccountList [label="{AccountList|# extends ArrayList<Account>\l+ add(account: Account): boolean\l+ save(acct: Account): void\l+ find(account_number: String): Account\l}"];

 
    HotelReservation [label="{HotelReservation|+ ReservationType(): String\l+ calculatePrice(): float\l+ getPricePerNight(): float\l}"];
    HouseReservation [label="{HouseReservation|+ ReservationType(): String\l+ calculatePrice(): float\l+ getPricePerNight(): float\l}"];
    CabinReservation [label="{CabinReservation|+ ReservationType(): String\l+ calculatePrice(): float\l+ getPricePerNight(): float\l}"];

    DataRepository [label="{DataRepository|- directoryPath: String\l- instance: DataRepository\l+ {static} setDataStoreRoot(path: String): void\l+ {static} getPath(): String\l+ {static} LoadAccount(file: Path): Account\l+ {static} WalkFileSystemTree(...): void\l}"];

    // Data model classes (simplified)
    subgraph cluster_datamodel {
        label = "Data Models";
        style = "dashed";
 
        Address [label="{Address|- street: String\l- city: String\l- state: String\l- zip: String\l}"];
 
        EmailAddress [label="{EmailAddress|- email: String\l}"];

           Account [label="{Account|- account_number: String\l- phone_number: String\l- mailing_address: Address\l- email_address: EmailAddress\l- reservations: AccountReservationList\l|+ add(rsrv: Reservation): boolean\l+ Write(acct: Account): void\l+ findReservation(reservation_number: String): Reservation\l+ checkValid(): boolean\l}"];

    AccountReservationList [label="{AccountReservationList|# extends ArrayList<IReservation>\l+ add(reservation: IReservation): boolean\l+ find(reservation_number: String): Reservation\l}"];

    IReservation [label="{<<interface>>\nIReservation|+ getReservation_number(): String\l+ getAccountNumber(): String\l+ calculatePrice(): float\l+ checkValid(): boolean\l+ ReservationType(): String\l}"];

    Reservation [label="{<<abstract>>\nReservation|- reservation_number: String\l- physical_address: Address\l- reservation_start_date: ZonedDateTime\l- reservation_end_date: ZonedDateTime\l- reservation_status: ReservationStatusEnum\l- price: Float\l# accountNumber: String\l|+ Change(reservation: Reservation, newStatus: ReservationStatusEnum): void\l+ ReservationType(): String\l}"];

    }

    // Relationships

    // Composition / Aggregation
    AccomodationManager -> AccountList [
        arrowhead=odiamond,
        label="manages",
        taillabel="1",
        headlabel="1"
    ];

    AccountList -> Account [
        arrowhead=odiamond,
        label="contains",
        taillabel="1",
        headlabel="0..*"
    ];

    Account -> AccountReservationList [
        arrowhead=odiamond,
        label="has",
        taillabel="1",
        headlabel="1"
    ];

    AccountReservationList -> IReservation [
        arrowhead=odiamond,
        label="contains",
        taillabel="1",
        headlabel="0..*"
    ];

    // Inheritance / Implementation
    Reservation -> IReservation [arrowhead=onormal, style=dashed, label="implements"];
    HotelReservation -> Reservation [arrowhead=empty, label="extends"];
    HouseReservation -> Reservation [arrowhead=empty, label="extends"];
    CabinReservation -> Reservation [arrowhead=empty, label="extends"];

    // Association / Dependency
    AccomodationManager -> DataRepository [arrowhead=vee, style=dashed, label="uses"];
    Account -> Address [
        arrowhead=vee, style=dashed,
        label="has a mailing address",
        taillabel="*",
        headlabel="1"
    ];
    Account -> EmailAddress [
        arrowhead=vee, style=dashed,
        label="has an email",
        taillabel="*",
        headlabel="1"
    ];
    Reservation -> Address [arrowhead=vee, style=dashed, label="has physical & mailing addresses"];
}
