@startuml
!define RECTANGLE class

abstract RECTANGLE AbstractCommunicator #palegreen {
    - host: str
    - port: int
    +connect(): Result
    +send(command: String): Result
    +receive(): Result<String>
    +send_and_receive(): Result<String>
    +disconnect(): Result
}

RECTANGLE TelNetCommunicator #palegreen {

}

RECTANGLE WebsocketCommunicator {

}

abstract RECTANGLE AbstractDevice #palegreen {
    +open(): Result
    +close(): Result
    +getConfig(): Result<Configuration>
    -device_id: String
    -communication: AbstractCommunicator
    -manager: DeviceManager
}

RECTANGLE CCDCamera {
    +setup_ccd(): InitData
    +get_acq_data(): Result<AcquisitionData>
    +get_chip_size(): Result<ChipSize>
    +get_chip_temperature(): Result<Temperature>
}

RECTANGLE Monochromator #palegreen {
    +mono_number: int
    +home():
    +is_mono_busy(): Bool
    +get_position(): Position
    +set_position(): Position
    +set_position_no_wait(): Position
    +get_grating_info(): Grating
    +stop_movement()
}

abstract RECTANGLE AbstractMultiDevice {
    +run(): Result
    -devices: List<Device>
}

RECTANGLE RangeScan {
    -scan_start_wl: int
    -scan_stop_wl: int
    -stitching_mode: enum
}

RECTANGLE DeviceManager << (S,#FF7700) Singleton >> #palegreen {
    +communicator: AbstractCommunicator
    +device_list: [AbstractDevice]
    +start_acl(): Result
    +discover_devices(): Result
    +stop_acl(): Result
}

AbstractCommunicator <|-- TelNetCommunicator
AbstractCommunicator <|-- WebsocketCommunicator
AbstractDevice <|-- CCDCamera
AbstractDevice <|-- Monochromator
AbstractMultiDevice <|-- RangeScan
AbstractMultiDevice "2..n" *-- AbstractDevice
AbstractDevice *--> AbstractCommunicator
AbstractDevice <--* "1..n" DeviceManager
DeviceManager *--> AbstractCommunicator

@enduml
