digraph "Reservation System" {
    // General graph settings
    graph [
        rankdir="TB",
        splines=ortho,
        nodesep=1.0,
        ranksep=1.0,
        fontname="Arial",
        fontsize=12
    ];

    // General node and edge settings
    node [
        shape=record,
        style=filled,
        fillcolor=lightyellow,
        fontname="Arial",
        fontsize=10
    ];
    edge [
        fontname="Arial",
        fontsize=9
    ];

    // Packages
    subgraph cluster_reservationsystem {
        label="lodge.reservationsystem";
        style=filled;
        color=lightgrey;

        AccomodationManager [label="{AccomodationManager|+ AccomodationManager(String)\l+ loadAll(): void\l+ retrieveAccount(String): Account\l+ retrieveLoadedAccounts(): AccountList\l+ newAccount(String, Address, EmailAddress): Account\l+ AddAccount(Account): void\l+ UpdateAccount(Account): void\l+ addReservation(Account, Reservation): boolean\l+ showReservationList(): void\l}"];
        DataRepository [label="{DataRepository (Singleton)|- directoryPath: String\l- instance: DataRepository\l|+ getInstance(): DataRepository\l+ setDataStoreRoot(path: String)\l+ getPath(): String\l+ Reservation(type: String): Reservation\l+ WalkFileSystemTree(manager: AccomodationManager, rootDir: Path)\l+ LoadAccount(file: Path): Account\l- loadReservationRefList(rdr: JsonReader, ac: Account)\l- loadReservation(ac: Account, type: String, num: String)\l}"];
        HotelReservation [label="{HotelReservation|+ HotelReservation(physicalAddress: Address)\l}"];
        HouseReservation [label="{HouseReservation|+ HouseReservation(physicalAddress: Address)\l}"];
        CabinReservation [label="{CabinReservation|+ CabinReservation(physicalAddress: Address)\l}"];
    }

    subgraph cluster_datamodel {
        label="lodge.datamodel";
        style=filled;
        color=lightblue;

        IReservation [label="<<interface>>\nIReservation"];
        Reservation [label="{Reservation|+ Reservation()\l+ Reservation(physicalAddress: Address)\l+ Change(rsrv: Reservation, status: ReservationStatusEnum)\l+ update(rsrv: Reservation)\l+ calculatePrice(): float\l+ getPricePerNight(): float\l+ ReservationType(): String\l}"];
        Account [label="{Account|+ Account()\l+ add(rsrv: Reservation)\l+ findReservation(reservationNumber: String): Reservation\l+ getAllReservations(): Iterator<IReservation>\l}"];
        Address [label="{Address|+ Address(street: String, city: String, state: String, zip: String)\l}"];
        EmailAddress [label="{EmailAddress|+ EmailAddress(email: String)\l}"];
        ReservationStatusEnum [label="<<enum>>\nReservationStatusEnum|DRAFT\lCOMPLETED\lCANCELED\l"];
        KitchenTypeEnum [label="<<enum>>\nKitchenTypeEnum|NONE\lPARTIAL\lFULL\l"];
        DuplicateObjectException [label="<<exception>>\nDuplicateObjectException"];
    }
    
    subgraph cluster_test {
        label="lodge (Test)";
        style=filled;
        color=honeydew;
        TestReservations [label="{TestReservations|+ main(args: String[])\l}"];
    }


    // Relationships
    AccomodationManager -> Account [label="manages"];
    AccomodationManager -> Reservation [label="manages"];
    AccomodationManager -> DataRepository [label="uses"];
    
    DataRepository -> AccomodationManager [label="uses"];
    DataRepository -> Reservation [label="creates"];
    DataRepository -> HotelReservation [label="creates"];
    DataRepository -> HouseReservation [label="creates"];
    DataRepository -> CabinReservation [label="creates"];
    DataRepository -> Account [label="loads/updates"];
    
    TestReservations -> AccomodationManager [label="uses"];
    TestReservations -> Account [label="uses"];
    TestReservations -> HotelReservation [label="creates"];
    TestReservations -> HouseReservation [label="creates"];
    TestReservations -> CabinReservation [label="creates"];

    Account -> IReservation [label="contains 0..*"];
    Account -> Address [label="has mailing"];
    Account -> EmailAddress [label="has"];
    
    Reservation -> IReservation [style=dashed, arrowhead=empty, label="implements"];
    Reservation -> Address [label="has physical/mailing"];
    Reservation -> ReservationStatusEnum;
    Reservation -> KitchenTypeEnum;

    HotelReservation -> Reservation [style=dashed, arrowhead=empty, label="extends"];
    HouseReservation -> Reservation [style=dashed, arrowhead=empty, label="extends"];
    CabinReservation -> Reservation [style=dashed, arrowhead=empty, label="extends"];

    // Exceptions
    edge [color=red, style=dashed, arrowhead=open];
    AccomodationManager -> DuplicateObjectException [label="<<throws>>"];
    AccomodationManager -> Exception [label="<<throws>>"];
    DataRepository -> IOException [label="<<throws>>"];
}
