@startuml
skinparam classAttributeIconSize 0
left to right direction

package WashingMachine {
	abstract class WashingMachineBoundary<<abstract>> {
		- requestByteMap: std::unordered_map
		- responseByteMap: std::unordered_map
		+ sendHardwareRequest(HardwareRequest request): hardwareResponse
	}

	abstract class Observable<<abstract>> {
		- listeners: std::vector
		+ subscribe()
		+ poll()
	}

	class SensorHandler<<task>>

	interface SensorListener<<Interface>> {
		+ field: type
		+ update(observable,data)
	}


	class Watervalve<<boundary>>
	class Motor<<boundary>>
	class LED<<boundary>>
	class HeatingUnit<<boundary>>
	class SoapDispenser<<boundary>>
	class Pump<<boundary>> {
		+ getStatus(): bool
	}
	class Door<<boundary>>

	class TemperatureSensor<<boundary>>
	class WaterlevelSensor<<boundary>>


	WashingMachineBoundary  <|--    Watervalve : Extends
	WashingMachineBoundary  <|--    Motor : Extends
	WashingMachineBoundary  <|--    LED : Extends
	WashingMachineBoundary  <|--    HeatingUnit : Extends
	WashingMachineBoundary  <|--    SoapDispenser : Extends
	WashingMachineBoundary  <|--    Pump : Extends
	WashingMachineBoundary  <|--    Door : Extends

	TemperatureSensor       --|>    WashingMachineBoundary : Extends
	WaterlevelSensor        --|>    WashingMachineBoundary : Extends

	Observable              ..|>    TemperatureSensor : Implements
	Observable              ..|>    WaterlevelSensor : Implements

	Observable              <--o "0..*"     SensorHandler
	Observable          "1" o-->            SensorListener
}

class UpdateController<<control>>
class WashingController<<controller>>
class AuthorizationController<<control>>
class WebInterfaceHandler<<thread>>
class SettingsController<<control>>

class WebSocketHandler<<thread>>

class LogController<<control>>
class LogFile<<boundary>>

class WashingProgram<<Object>>
class WashingTask<<Object>>
abstract class WashingInstruction<<Object>>


AuthorizationController   <--o "1"  WebInterfaceHandler
UpdateController      "1" o--> "1"  WebInterfaceHandler
WashingController         <--o "1"  WebInterfaceHandler
WebInterfaceHandler   "1" o->       SettingsController
WebInterfaceHandler   "1" o->       WashingMachineBoundary
WebInterfaceHandler   "1" o->       Observable

WebSocketHandler          <-o "1"   WashingController
LogController             <-o "1"   WashingController
	LogFile               *->       LogController

WashingController     "1" o-->      WashingProgram
WashingProgram     "0..*" o-->      WashingTask
WashingTask           "1" o-->      WashingInstruction
WashingInstruction    "1" o->       WashingMachineBoundary
WashingInstruction    "1" o->       Observable

WashingController         ..|>      SensorListener
@enduml

@startuml
skinparam classAttributeIconSize 0
left to right direction

package WashingMachine {
	abstract class WashingMachineBoundary<<abstract>> {
		- requestByteMap: std::unordered_map
		- responseByteMap: std::unordered_map
		+ sendHardwareRequest(HardwareRequest request): hardwareResponse
	}

	abstract class Observable<<abstract>> {
		- listeners: std::vector
		+ subscribe()
		+ poll()
	}

	interface SensorListener<<Interface>> {
		+ field: type
		+ update(observable,data)
	}
}

class UpdateController<<control>>
class WashingController<<controller>>
class AuthorizationController<<control>>
class WebInterfaceHandler<<thread>>
class SettingsController<<control>>

class WebSocketHandler<<thread>>

class LogController<<control>>
class LogFile<<boundary>>

class WashingProgram<<Object>>
class WashingTask<<Object>>
abstract class WashingInstruction<<Object>>


AuthorizationController   <--o "1"  WebInterfaceHandler
UpdateController      "1" o--> "1"  WebInterfaceHandler
WashingController         <--o "1"  WebInterfaceHandler
WebInterfaceHandler   "1" o->       SettingsController
WebInterfaceHandler   "1" o->       WashingMachineBoundary
WebInterfaceHandler   "1" o->       Observable

WebSocketHandler          <-o "1"   WashingController
WashingController     "1" o->       LogController
	LogController         *->       LogFile

WashingController     "1" o-->      WashingProgram
WashingProgram     "0..*" o-->      WashingTask
WashingTask           "1" o-->      WashingInstruction
WashingInstruction    "1" o->       WashingMachineBoundary
WashingInstruction    "1" o->       Observable

WashingController         ..|>      SensorListener
@enduml

@startuml
skinparam classAttributeIconSize 0
left to right direction

package WashingMachine {
	abstract class WashingMachineBoundary<<abstract>> {
		- requestByteMap: std::unordered_map
		- responseByteMap: std::unordered_map
		+ sendHardwareRequest(HardwareRequest request): hardwareResponse
	}

	abstract class Observable<<abstract>> {
		- listeners: std::vector
		+ subscribe()
		+ poll()
	}

	class SensorHandler<<task>>

	interface SensorListener<<Interface>> {
		+ field: type
		+ update(observable,data)
	}

	class Watervalve<<boundary>>
	class Motor<<boundary>>
	class LED<<boundary>>
	class HeatingUnit<<boundary>>
	class SoapDispenser<<boundary>>
	class Pump<<boundary>> {
		+ getStatus(): bool
	}
	class Door<<boundary>>

	class TemperatureSensor<<boundary>>
	class WaterLevelSensor<<boundary>>


	WashingMachineBoundary  <|--    WaterValve : Extends
	WashingMachineBoundary  <|--    Motor : Extends
	WashingMachineBoundary  <|--    LED : Extends
	WashingMachineBoundary  <|--    HeatingUnit : Extends
	WashingMachineBoundary  <|--    SoapDispenser : Extends
	WashingMachineBoundary  <|--    Pump : Extends
	WashingMachineBoundary  <|--    Door : Extends

	TemperatureSensor       <|--    WashingMachineBoundary : Extends
	WaterLevelSensor        <|--    WashingMachineBoundary : Extends

	Observable              ..|>    TemperatureSensor : Implements
	Observable              ..|>    WaterLevelSensor : Implements

	Observable              <--o "0..*"     SensorHandler
	Observable          "1" o-->            SensorListener
}
@enduml
@startuml
skinparam classAttributeIconSize 0
'left to right direction'

package WashingMachine{
    Class WaterLevelController<<Controller>>{
        +WaterLevelController(&pump : Pump, waterValve : WaterValve&)
        +virtual void setWaterLevel(waterLevel : int)
        +virtual void update(newVal : int)
        #virtual void main()

        -&pump : Pump
        -&waterValve : WaterValve
        -targetWaterLevel : RTOS::pool<int>
        -targetWaterLevelUpdated : RTOS::flag
        -latestWaterLevel : RTOS::pool<int>
        -waterLevelUpdated : RTOS::flag
    }
    Interface WaterLevelRegulator<<Interface>>{
        +virtual void setWaterLevel(waterLevel : int)
    }
    Class TemperatureController<<Controller>>{
        +TemperatureController(heat : HeatingUnit&)
        +virtual void setTemperature(heatLevel : int)
        +virtual void update(newVal : int)
        #virtual void main()
        -&heat : HeatingUnit
        -targetTemperature : RTOS::pool<int>
        -targetTemperatureUpdated : RTOS::flag
        -latestTemperature : RTOS::pool<int>
        -temperatureUpdated : RTOS::flag
    }
    Interface TemperatureRegulator<<Interface>>{
        +virtual void setTemperature(temperature : int)
    }
    Class UARTHandler{
        +UARTHandler(&serial : LibSerial)
        +void SendMessage(m : UARTMessage)
        -void main()
        -InputBuffer : RTOS::channel<UARTMessage, 64>
        -timer : RTOS::timer
        -OutputBuffer : std::queue<UARTMessage>
    }
    Class UARTMessage << (S,#FF00FF) Struct>>{
        requestByte : uint8_t
        commandByte : uint8_t
        sender: UARTUser*
    }
    Class UARTUser{
        #replyPool : RTOS::pool<uint8_t>
        #virtual void main()
        +UARTUser(priority : unsigned int, name : const char*)
        +virtual void receiveReply(replyByte : uint8_t)
        +virtual uint8_t getReplyPoolContents()
    }
    Abstract Observable <<Abstract>>{
        +void subscribe(listener : SensorListener*)
        +virtual int poll(referenceUser : UARTUser*)
        #void updateAll(newVal : int)
        -listeners : std::vector<SensorListeners*>
    }
    Class SensorHandler{
        +SensorHandler()
        +void addSensor()
        #virtual void main()
        #sensors : std::vector<Observable*>
    }
    Interface SensorListener <<Interface>>{
        +virtual void update(newVal : int)
    }
    Class SignalLed <<Boundary>>{
        +SignalLed(uart: UARTHandler&)
        +SignalLedState getStatus(referenceUser : UARTUser*)
        +void set(status : SignalLedState, referenceUser : UARTUser*)
        +void toggle(referenceUser : UARTUser*)
        -uart: UARTHandler&
    }
    Class SoapDispenser <<Boundary>>{
        +SoapDispenser(uart: UARTHandler&)
        +SoapDispenserState getState(referenceUser : UARTUser*)
        +void set(state : SoapDispenserState, referenceUser : UARTUser*)
        +void toggle(*referenceUser UARTUser)
        -uart: UARTHandler&
    }
    Class WaterValve <<Boundary>>{
        +WaterValve(uart: UARTHandler&)
        +WaterValveState getState(referenceUser : UARTUser*)
        +void set(state WaterValveState, referenceUser : UARTUser*)
        +void toggle(referenceUser : UARTUser*)
        -uart: UARTHandler&
    }
    Class Door <<Boundary>>{
        +Door(uart: UARTHandler&)
        +DoorState getState(referenceUser : UARTUser*)
        +void set(state : DoorState, referenceUser : UARTUser*)
        +void toggle(referenceUser : UARTUser*)
        -uart: UARTHandler&
    }
    Class HeatingUnit <<Boundary>>{
        +HeatingUnit(uart: UARTHandler&)
        +HeatingUnitState getState(referenceUser : UARTUser*)
        +void set(state : HeatingUnitState, referenceUser : UARTUser*)
        +void toggle(referenceUser : UARTUser*)
        -uart: UARTHandler&
    }
    Class Motor <<Boundary>>{
        +Motor(uart: UARTHandler&)
        +int getRPM(referenceUser : UARTUser*)
        +void setRPM(rpm : int, referenceUser : UARTUser*)
        -uart: UARTHandler&
    }
    Class Pump <<Boundary>>{
        +Pump(uart: UARTHandler&)
        +PumpState getState (referenceUser : UARTUser*)
        +void set(state : PumpState, referenceUser : UARTUser*)
        +void toggle(referenceUser : UARTUser*)
        -uart: UARTHandler&
    }
    Class TemperatureSensor <<Boundary>>{
        +TemperatureSensor(uart: UARTHandler&)
        +int poll(referenceUser : UARTUser*)
        -uart: UARTHandler&
    }
    Class WaterLevelSensor <<Boundary>>{
        +WaterLevelSensor(uart: UARTHandler&)
        +int poll(referenceUser : UARTUser*)
        -uart: UARTHandler&
    }
    Class WashingMachine{
        +WashingMachine(uart: UARTHandler&)
        +Door &getDoor()
        +HeatingUnit &getHeatingUnit()
        +Motor &getMotor()
        +Pump &getPump()
        +SignalLed &getSignalLed()
        +SoapDispenser &getSoapDispenser()
        +TemperatureSensor &getTemperatureSensor()
        +WaterLevelSensor &getWaterLevelSensor()
        +WaterValve &getWaterValve()
        -uart : UARTHandler&
        -door : Door
        -heatingUnit : HeatingUnit
        -motor : Motor
        -pump : Pump
        -signalLed : SignalLed
        -soapDispenser : SoapDispenser
        -temperatureSensor : TemperatureSensor
        -waterLevelSensor : WaterLevelSensor
        -waterValve : WaterValve

    }
    Class EventGenerator{
        +void wait(user : RTOS::task*)
        #bool notify()
        #void notifyAll()
        -blocked{} : std::queue<RTOS::task*>
    }

    enum SignalLedState<<Enumeration>>{
        LED_ON
        LED_OFF
    }
    enum SoapDispenserState{
        SOAP_OPEN
        SOAP_CLOSED
    }
    enum WaterValveState{
        VALVE_OPEN
        VALVE_CLOSED
    }
    enum DoorState{
        DOOR_OPENED
        DOOR_UNLOCKED_CLOSED
        DOOR_LOCKED
    }
    enum HeatingUnitState{
        HEATINGUNIT_ON
        HEATINGUNIT_OFF
    }
    enum PumpState{
        PUMP_ON
        PUMP_OFF
    }

    WaterLevelRegulator --|> EventGenerator :Extends
    TemperatureRegulator --|> EventGenerator : Extends

    UARTMessage -- UARTHandler
    SignalLed -- SignalLedState
    SoapDispenser -- SoapDispenserState
    WaterValve -- WaterValveState
    Door -- DoorState
    HeatingUnit -- HeatingUnitState
    Pump -- PumpState

    UARTUser <|-- UARTHandler : Extends
    WashingMachine *-- SignalLed
    WashingMachine *-- SoapDispenser
    WashingMachine *-- WaterValve
    WashingMachine *-- Door
    WashingMachine *-- HeatingUnit
    WashingMachine *-- Motor
    WashingMachine *-- Pump
    WashingMachine *-- TemperatureSensor
    WashingMachine *-- WaterLevelSensor

	Observable <-o SensorHandler
	Observable o-- SensorListener

	WaterLevelSensor --|> Observable : Extends
	TemperatureSensor --|> Observable : Extends

    UARTHandler o-- WashingMachine
    UARTHandler o-- SignalLed
    UARTHandler o-- SoapDispenser
    UARTHandler o-- WaterValve
    UARTHandler o-- Door
    UARTHandler o-- HeatingUnit
    UARTHandler o-- Motor
    UARTHandler o-- Pump
    UARTHandler o-- TemperatureSensor
    UARTHandler o-- WaterLevelSensor
}

package washingInstructions{
    Class WashingInstruction{
        +virtual void execute(user : UARTUser*)
    }
    Class AddSoapInstruction{
        +AddSoapInstruction(&dispenser : SoapDispenser)
        +virtual void execute(user : UARTUser*)
        -dispenser : SoapDispenser&
    }
    Class SetDoorLockInstruction{
        +SetDoorLockInstruction(&door : Door, lock : DoorState)
        +virtual void execute(user : UARTUser*)
        -door : Door&
        -lock : DoorState
    }
    Class SetRPMInstruction{
        +SetRPMInstruction(&motor : Motor, rpm : int)
        +virtual void execute(user : UARTUser*)
        -motor : Motor&
        -rpm : int
    }
    Class SetTemperatureInstruction{
        +SetTemperatureInstruction(&temperatureRegulator : TemperatureRegulator, temperature : int)
        +virtual void execute(user : UARTUser*)
        -temperatureRegulator : TemperatureRegulator&
        -temperature : int
    }
    Class SetWaterLevelInstruction{
        +SetWaterLevelInstruction(&waterRegulator : WaterLevelRegulator, waterLevel : int)
        +virtual void execute(user : UARTUser*)
        -waterRegulator : WaterLevelRegulator&
        -waterLevel : int
    }
    Class WaitTimeInstruction{
        +WaitTimeInstruction(time : unsigned int)
        +virtual void execute(user : UARTUser*)
        -time : unsigned int
    }
    Class WaitTemperatureInstruction{
        +WaitTemperatureInstruction(&regulator : TemperatureRegulator)
        +virtual void execute(user : UARTUser*)
        -regulator : TemperatureRegulator&
    }
    Class WaitWaterLevelInstruction{
        +WaitWaterLevelInstruction(&water : WaterLevelRegulator)
        +virtual void execute(user : UARTUser*)
        -water : WaterLevelRegulator&
    }
}
    Class LogController<<Controller>>{
        +LogController(log : std::ostream*)
        +void logCurrentProgram(program : std::string)
        +void logCurrentStep(step : int)
        +void logProgramStopped()
        +log : std::ostream*
    }
    Class WashingController<<Controller>>{
        +WashingController(log : LogController&)
        +void start(program : WashingProgram&)
    }
    Class WashingProgram{
        +void addTask(task : WashingTask)
        +void execute (uartUser : UARTUser*, logController : LogController*)
        +void execute (uartUser : UARTUser*, logController : LogController*, resumeFrom : int)
        -tasks : std::vector<WashingTask>
    }
    Class WashingTask{
        +void addInstruction(instruction : WashingInstruction*)
        +void execute(referenceUser : UARTUser*)
        -instructions{} : std::vector<WashingInstruction*>
    }
    Class SwirliListener{
        +void onTextMessage(s : const string&, ws : WebSocket*)
        +void onClose(ws : WebSocket*)
        +bool packetsAvailable()
        +std::shared_ptr<WebSocketPacket> getPacket()
        -packetQueue : std::queue<std::shared_ptr<WebSocketPacket>>
        -pQMutex : std::mutex
    }
    Class WebInterfaceHandler{
        +WebInterfaceHandler(washingMachine : WashingMachine*, swirliListener : SwirliListener*)
        -washingMachine : WashingMachine&
        -listener : SwirliListener&
        -timer : RTOS::timer
        -void main()
    }
    Class WebSocketHandler{
        +WebSocketHandler(port : int, web : WebInterfaceHandler&, listener : SwirliListener&)
        +void runServer()
        +std::thread spawnWebSocketHandler()
        +void sendMessage()
        -port : int
        -listener : SwirliListener&
    }
    Class WebSocketPacket{
        +WebSocketPacket(json : const char*, ws : WebSocket*)
        +rapidjson::Document &getDoc()
        +WebSocket * getWebSocket()
        -doc : rapidjson::Document
        -ws : WebSocket*
    }

    WaitWaterLevelInstruction o-- WaterLevelRegulator
    WaitTemperatureInstruction o-- TemperatureRegulator

    WebInterfaceHandler o-- WashingMachine
    WebInterfaceHandler o-- SwirliListener

    SwirliListener o-- WebSocketPacket

    WebSocketHandler o-- WebInterfaceHandler
    WebSocketHandler o-- SwirliListener


    WaterLevelController o-- Pump
    WaterLevelController o-- WaterValve
    WaterLevelController o-- SensorListener
    WaterLevelController o-- UARTUser
    WaterLevelRegulator <|-- WaterLevelController : Extends

    TemperatureController o-- HeatingUnit
    TemperatureController o-- SensorListener
    TemperatureController o-- UARTUser
    TemperatureRegulator <|-- TemperatureController : Extends

    UARTUser --o WashingInstruction
    WashingProgram o- WashingTask
    WashingTask o- WashingInstruction
    WashingController o- WashingProgram
    LogController -o WashingController

    WashingInstruction <|-- AddSoapInstruction :Extends
    WashingInstruction <|-- SetDoorLockInstruction :Extends
    WashingInstruction <|-- SetRPMInstruction :Extends
    WashingInstruction <|-- SetTemperatureInstruction :Extends
    WashingInstruction <|-- SetWaterLevelInstruction :Extends
    WashingInstruction <|-- WaitTimeInstruction :Extends
    WashingInstruction <|-- WaitWaterLevelInstruction : Extends
    WashingInstruction <|-- WaitTemperatureInstruction : Extends

    AddSoapInstruction o-- SoapDispenser
    SetDoorLockInstruction o-- Door
    SetRPMInstruction o-- Motor
    SetTemperatureInstruction o--- TemperatureController
    SetWaterLevelInstruction o--- WaterLevelController
@enduml
