From 35bca4cc31625689343aed75e87b8a4652e7287c Mon Sep 17 00:00:00 2001
From: tobiglaser <76131623+tobiglaser@users.noreply.github.com>
Date: Tue, 26 Jul 2022 12:59:56 +0200
Subject: [PATCH] almost worksheet 3, some weirdness though

---
 CMakeLists.txt              |   9 ++-
 include/BackgroundControl.h |   5 ++
 include/ComHandler.h        |  61 ++++++++++++++++++
 include/ComState.h          |  10 +++
 include/IComListener.h      |  11 ++++
 include/Rover.h             |  12 ++++
 include/RoverHandler.h      |  17 +++++
 src/CommandType.h           |  38 +++++++++++
 src/ControlModel.h          | 121 ++++++++++++++++++++++++++++++++++++
 src/ControlModelRegistry.h  |  45 ++++++++++++++
 src/IControlModelListener.h |   9 +++
 src/testControlModel.cpp    |  41 ++++++++++++
 12 files changed, 377 insertions(+), 2 deletions(-)
 create mode 100644 include/BackgroundControl.h
 create mode 100644 include/ComHandler.h
 create mode 100644 include/ComState.h
 create mode 100644 include/IComListener.h
 create mode 100644 include/Rover.h
 create mode 100644 include/RoverHandler.h
 create mode 100644 src/CommandType.h
 create mode 100644 src/ControlModel.h
 create mode 100644 src/ControlModelRegistry.h
 create mode 100644 src/IControlModelListener.h
 create mode 100644 src/testControlModel.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a2eb145..2b50d64 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,12 +8,17 @@ set(CMAKE_C_STANDARD 17)
 set(CMAKE_CXX_STANDARD 20)
 
 
-add_executable("Info3_Praktikum-test"
+add_executable("Test_Command_List"
 src/testCommandList.cpp 
 )
+# Add include directory
+target_include_directories("Test_Command_List" PUBLIC include/)
 
+add_executable("Test_Control_Model"
+src/testControlModel.cpp 
+)
 # Add include directory
-target_include_directories("Info3_Praktikum-test" PUBLIC include/)
+target_include_directories("Test_Control_Model" PUBLIC include/)
 
 
 add_executable("Class-Member-Variable-demo"
diff --git a/include/BackgroundControl.h b/include/BackgroundControl.h
new file mode 100644
index 0000000..938308d
--- /dev/null
+++ b/include/BackgroundControl.h
@@ -0,0 +1,5 @@
+#pragma once
+
+class BackgroundControl
+{
+};
diff --git a/include/ComHandler.h b/include/ComHandler.h
new file mode 100644
index 0000000..a973c57
--- /dev/null
+++ b/include/ComHandler.h
@@ -0,0 +1,61 @@
+#pragma once
+#include "IComListener.h"
+#include "ComState.h"
+#include "BackgroundControl.h"
+#include "commandlib.h"
+#include "Rover.h"
+#include <memory>
+#include <vector>
+
+
+class ComHandler
+{
+private:
+    std::optional<IComListener *> comListener;
+    BackgroundControl backgroundControl;
+    ComHandler() {}
+
+public:
+    static ComHandler &getInstance();
+    void registerComListener(IComListener *cl);
+    void unregisterComListener(IComListener *cl);
+    bool start(std::vector<std::shared_ptr<Command>> commands, std::optional<Rover> rover);
+    bool stop() { return true; }
+};
+
+ComHandler& ComHandler::getInstance()
+{
+    static ComHandler instance = ComHandler();
+    return instance;
+}
+
+void ComHandler::registerComListener(IComListener *cl)
+{
+    comListener = cl;
+}
+
+void ComHandler::unregisterComListener(IComListener *cl)
+{
+    if (comListener == cl)
+        comListener.reset();
+}
+
+bool ComHandler::start(std::vector<std::shared_ptr<Command>> commands, std::optional<Rover> rover)
+{
+    if (rover)
+    {
+        //* Funtionality unknown
+        std::cout << "Many robot, such wow!\nSimuliere stattdessen:\n";
+        start(commands, std::nullopt);
+    }
+    else
+    {
+        std::cout << "Simuliere Ausführung durch Listeneraufrufe.\n";
+        for (auto &&i : commands)
+        {
+            if (comListener)
+                comListener.value()->commandPerformed(i, ComState::connection_error);
+        }
+    }
+    return rover ? true : false;
+}
\ No newline at end of file
diff --git a/include/ComState.h b/include/ComState.h
new file mode 100644
index 0000000..39f4493
--- /dev/null
+++ b/include/ComState.h
@@ -0,0 +1,10 @@
+#pragma once
+
+enum class ComState
+{
+    connection_error,
+    rover_finish_ICommand,
+    rover_in_use,
+    rover_running_ICommand,
+    send_ICommand
+};
diff --git a/include/IComListener.h b/include/IComListener.h
new file mode 100644
index 0000000..57fcf06
--- /dev/null
+++ b/include/IComListener.h
@@ -0,0 +1,11 @@
+#pragma once
+#include "commandlib.h"
+#include "ComState.h"
+#include <optional>
+#include <memory>
+
+class IComListener
+{
+public: 
+    virtual void commandPerformed(std::optional<std::shared_ptr<Command>>, ComState _state) = 0;
+};
\ No newline at end of file
diff --git a/include/Rover.h b/include/Rover.h
new file mode 100644
index 0000000..cde39cc
--- /dev/null
+++ b/include/Rover.h
@@ -0,0 +1,12 @@
+#pragma once
+#include <string>
+
+class Rover
+{
+private:
+    std::string id;
+
+public:
+    std::string getId() { return id; }
+    std::string toString() { return getId(); }
+};
\ No newline at end of file
diff --git a/include/RoverHandler.h b/include/RoverHandler.h
new file mode 100644
index 0000000..102121c
--- /dev/null
+++ b/include/RoverHandler.h
@@ -0,0 +1,17 @@
+#pragma once
+#include <vector>
+#include "Rover.h"
+
+class RoverHandler
+{
+public:
+    /**
+     * @brief Dummy/Placeholder not implemented!
+     * Maybe don't use References, so nobody has to guarantee any lifetimes.
+     * @returns an empty Vector or - in future - a Vector of Rover references.
+     */
+    static inline std::vector<Rover> getFreeRover()
+    {
+        return std::vector<Rover>();
+    };
+};
\ No newline at end of file
diff --git a/src/CommandType.h b/src/CommandType.h
new file mode 100644
index 0000000..c091d35
--- /dev/null
+++ b/src/CommandType.h
@@ -0,0 +1,38 @@
+#pragma once
+#include "Command.h"
+#include "Gear.h"
+#include "Direction.h"
+#include "Pause.h"
+#include <memory>
+#include <string>
+
+class CommandType 
+{
+private:
+    std::string name;
+
+public:
+    CommandType(std::string _name);
+
+    std::string getName() { return name; }
+    std::string toString() { return getName(); }
+    std::shared_ptr<Command> createInstance();
+};
+
+CommandType::CommandType(std::string _name)
+{
+    name = _name;
+}
+
+
+std::shared_ptr<Command> CommandType::createInstance()
+{
+    if (name == IGear::gear)
+        return std::make_shared<Gear>(0, 0);
+    else if (name == IDirection::direction)
+        return std::make_shared<Direction>(0);
+    else if (name == IPause::pause)
+        return std::make_shared<Pause>(0);
+    else
+        return nullptr;
+}
diff --git a/src/ControlModel.h b/src/ControlModel.h
new file mode 100644
index 0000000..37b54d2
--- /dev/null
+++ b/src/ControlModel.h
@@ -0,0 +1,121 @@
+#pragma once
+#include <iostream>
+#include <array>
+#include "commandlib.h"
+#include "IComListener.h"
+#include "ControlModelRegistry.h"
+#include "CommandType.h"
+#include "CommandListOWN.h"
+#include "Rover.h"
+#include "RoverHandler.h"
+#include "ComHandler.h"
+#include "ComState.h"
+
+class ControlModel : public ControlModelRegistry, IComListener
+{
+private:
+    ControlModel();
+    ~ControlModel();
+    std::array<CommandType, 3> cT = {
+        CommandType(IDirection::direction),
+        CommandType(IGear::gear),
+        CommandType(IPause::pause)};
+    CommandList list;
+    std::optional<Rover> selectedRover;
+
+public:
+    static ControlModel& getInstance();
+    void commandPerformed(std::optional<std::shared_ptr<Command>> _command, ComState _state);
+    bool start();
+    bool stop();
+
+    // Possible Lifetime concerns
+    CommandList &getCommandList() { return list; }
+    // Possible Lifetime concerns
+    std::array<CommandType, 3> &getCommandTypes() { return cT; }
+
+    void setSelectedRover()
+    {
+        //? is RoverHandler static? Where does it belong? ControlModel?
+        std::vector<Rover> rovers = RoverHandler::getFreeRover();
+        if (!rovers.empty())
+            selectedRover = rovers.front();
+    }
+
+    std::optional<std::string> getSelectedRoverId() 
+    {
+    if (selectedRover)
+        return selectedRover.value().getId();
+    else
+        return std::nullopt;
+    }
+};
+
+ControlModel::ControlModel()
+{
+    ComHandler::getInstance().registerComListener(this);
+}
+
+ControlModel::~ControlModel()
+{
+    ComHandler::getInstance().unregisterComListener(this);
+}
+
+ControlModel& ControlModel::getInstance()
+{
+    static ControlModel instance = ControlModel();
+    return instance;
+}
+
+void ControlModel::commandPerformed(std::optional<std::shared_ptr<Command>> _command, ComState _state)
+{
+    std::string commandPart = "";
+    if (_command)
+        commandPart = _command.value()->getConfig();
+    else
+        commandPart = "no Command";
+
+    std::string statePart = "";
+    switch (_state)
+    {
+    case ComState::connection_error:
+        statePart = "Connection Error";
+        break;
+    case ComState::rover_finish_ICommand:
+        statePart = "Rover finish ICommand";
+        break;
+    case ComState::rover_in_use:
+        statePart = "Rover in Use";
+        break;
+    case ComState::rover_running_ICommand:
+        statePart = "Rover running ICommand";
+        break;
+    case ComState::send_ICommand:
+        statePart = "Send ICommand";
+        break;
+    default:
+        statePart = "";
+        break;
+    }
+    notifyMessageChanged("Command: " + commandPart + " - State: " + statePart);
+}
+
+bool ControlModel::start()
+{
+    std::vector<std::shared_ptr<Command>> commands;
+    uint size = list.getSize();
+    //0 is root element
+    // iterator would help greatly with of by one errors
+    for (int i = 1; i <= size; ++i) 
+    {
+        //? Wie hier was sammeln und übergeben?
+        commands.push_back(list.getCommand(i));
+    }
+
+    return ComHandler::getInstance().start(commands, selectedRover);
+}
+
+bool ControlModel::stop()
+{
+    return ComHandler::getInstance().stop();
+}
\ No newline at end of file
diff --git a/src/ControlModelRegistry.h b/src/ControlModelRegistry.h
new file mode 100644
index 0000000..7cb01e2
--- /dev/null
+++ b/src/ControlModelRegistry.h
@@ -0,0 +1,45 @@
+#pragma once
+#include "IControlModelListener.h"
+#include <string>
+#include <memory>
+#include <vector>
+
+class ControlModelRegistry
+{
+private:
+    //? maybe should be https://en.cppreference.com/w/cpp/memory/weak_ptr
+    std::vector<std::shared_ptr<IControlModelListener>> registry;
+
+public:
+    void addControlModelListener(std::shared_ptr<IControlModelListener> _listener);
+    void removeControlModelListener(std::shared_ptr<IControlModelListener> _listener);
+    void notifyMessageChanged(std::string _message);
+    void notifyRoverChanged();
+};
+
+void ControlModelRegistry::addControlModelListener(std::shared_ptr<IControlModelListener> _listener)
+{
+    registry.push_back(_listener);
+}
+
+void ControlModelRegistry::removeControlModelListener(std::shared_ptr<IControlModelListener> _listener)
+{
+    // https://en.cppreference.com/w/cpp/container/vector/erase2
+    std::erase(registry, _listener);
+}
+
+void ControlModelRegistry::notifyMessageChanged(std::string _message)
+{
+    for (auto &&i : registry)
+    {
+        i->messageUpdated(_message);
+    }
+}
+
+void ControlModelRegistry::notifyRoverChanged()
+{
+    for (auto &&i : registry)
+    {
+        i->roverUpdated();
+    }
+}
\ No newline at end of file
diff --git a/src/IControlModelListener.h b/src/IControlModelListener.h
new file mode 100644
index 0000000..51c6bb9
--- /dev/null
+++ b/src/IControlModelListener.h
@@ -0,0 +1,9 @@
+#pragma once
+#include <string>
+
+class IControlModelListener
+{
+public:
+    virtual void messageUpdated(std::string _message) = 0;
+    virtual void roverUpdated() = 0;
+};
\ No newline at end of file
diff --git a/src/testControlModel.cpp b/src/testControlModel.cpp
new file mode 100644
index 0000000..53d1957
--- /dev/null
+++ b/src/testControlModel.cpp
@@ -0,0 +1,41 @@
+#include <iostream>
+
+#include "Gear.h"
+#include "Direction.h"
+#include "Pause.h"
+#include "IControlModelListener.h"
+#include "ControlModel.h"
+
+class Listener : public IControlModelListener
+{
+    void messageUpdated(std::string _message)
+    {
+        std::cout << "Got Message: " << _message << '\n';
+    }
+    void roverUpdated()
+    {
+        std::cout << "Rover was updated\n";
+    }
+};
+
+int main()
+{
+    ControlModel &model = ControlModel::getInstance();
+    std::shared_ptr<Listener> listener = std::make_shared<Listener>();
+    model.addControlModelListener(listener);
+
+    
+    std::shared_ptr<Command> a = model.getCommandTypes()[0].createInstance();
+    std::cout << a->getConfig() << '\n';
+    //! model.getCommandList().add(a);
+    //  model.getCommandList().add(model.getCommandTypes()[0].createInstance());
+    //  model.getCommandList().add(model.getCommandTypes()[1].createInstance());
+    //  model.getCommandList().add(model.getCommandTypes()[2].createInstance());
+    model.getCommandList().add(Gear(1, 1.0));
+    model.getCommandList().add(Direction(30));
+    model.getCommandList().add(Pause(0.5));
+
+    model.start();
+
+    model.setSelectedRover();
+}
\ No newline at end of file
-- 
GitLab