/*
  Sketch: LED_blinken_lassen_objektorientiert
  Zweck: Beispiel für eine einfache objektorientierte Programmierung.
  Datum: 16.04.2024
  Datum: 17.04.2024
  Autor: MIWIS
  Entscheidende Vorteile der objektorientierten Programmierung:
  - Der Programmcode ist besser lesbar.
  - Eine Klasse lässt sich einfach durch Konstruktoren, Attribute und
    neue Methoden erweitern.
  - Eine Klasse kann auf beliebig viele Member angewendet werden.
  - Eine Klasse kann an weitere Klassen vererbt (weitergegeben) werden.
*/

// Let's do it ;-)

// Zuerst definieren wir unsere Klasse, auch Objekt gennant.
// Unsere Klasse soll 2 Konstruktoren, 2 Attribute und 2 Methoden besitzen.
// Unsere Klasse nennen wir LED.
class LED {
    // Hier definieren wir unsere beiden Attribute (Parameter).
    unsigned int LED_Pin;  // Nummer des digitalen Ausgangs
    bool LED_Status;       // Zustand der LED (HIGH oder LOW)

  public:
    // Hier erzeugen wir unseren öffentlichen Konstruktor.
    // Der Konstruktor lässt sich mit einer Funktion vergleichen,
    // ist aber viel mächtiger.
    // Warum, weil sich über den Konstruktor beliebig viele Methoden
    // definieren und Member erzeugen lassen.
    LED(unsigned int PIN_Nummer) {
      // Unsere beiden Attribute werden initialisiert.
      LED_Pin = PIN_Nummer; // wird übergeben
      LED_Status = LOW; // erstmal auf LOW eingestellt
      // Wir verwenden das Attribut LED_Pin in pinMode().
      pinMode(LED_Pin, OUTPUT);
    }

    // Ein weiterer Konstruktor, diesmal mit 2 Parametern
    LED(unsigned int PIN_Nummer, bool PIN_Status) {
      // Unsere beiden Attribute werden initialisiert.
      LED_Pin = PIN_Nummer; // wird übergeben
      LED_Status = PIN_Status; // wird übergeben
      // Wir verwenden das Attribut LED_Pin in pinMode().
      pinMode(LED_Pin, OUTPUT);
      // Wir verwenden die Attribute LED_Pin und LED_Status in digitalWrite().
      digitalWrite(LED_Pin, LED_Status);
    }

    // Hier unsere öffentliche Methode umschalten().
    void umschalten() {
      LED_Status = !LED_Status; // wenn HIGH, dann LOW und umgekehrt
      // Wir verwenden die Attribute LED_Pin und LED_Status in digitalWrite().
      digitalWrite(LED_Pin, LED_Status);
    }

    // Hier unsere öffentliche Methode aus().
    void aus() {
      // Wir verwenden das Attribut LED_Pin in digitalWrite().
      digitalWrite(LED_Pin, LOW);
    }

    // Wir könnten hier beliebig viele weitere Methoden generieren.

}; // Klasse abgeschlossen. Achtung, das Semikolon ist Pflicht.

// Wir wenden unsere Klasse LED auf die beiden digitalen Ausgänge 13 und 7 an.
LED LED_rot(13);
LED LED_blau(7);
// LED_rot und LED_blau besitzen jetzt unsere Klasseneigenschaften.
// Sie werden auch Instanzen oder Objekte der Klasse genannt.
// Dem Konstruktor wurde jeweils ein Parameter (unsigned int PIN_Nummer) übergeben,
// vergleichbar mit einem Setup oder einer Initialisierung.
// Jetzt können wir auf unsere beiden Objekte die in der Klasse LED definierten
// Methoden anwenden. Wie das funktioniert sehen wir im loop().

LED LED_gelb(3, HIGH); // vom zweiten Konstruktor (2 Parameter)

void setup() {
  // wird nicht benötigt
}

void loop() {
  // Wir wenden die Methode umschalten() an.
  LED_rot.umschalten();
  delay(400);
  LED_blau.umschalten();
  delay(800);
  LED_blau.umschalten();
  delay(400);
  LED_rot.umschalten();
  //exit(0);
  // Wir wenden die Methode aus() an.
  delay(800);
  LED_gelb.aus();
  // gelb wird nicht wieder eingeschalten
}

/*
  Erste Aufgabe:
  delay() soll der Methode umschalten() und aus() als Parameter übergeben werden können
  Beispiel:
  LED_rot.umschalten(800);
  LED_blau.aus(2000);

  Zweite Aufgabe:
  Es soll eine Methode entwickelt werden, die den Status der jeweiligen digitalen
  Ausgänge anzeigt.
  Beispiel:
  LED_rot.PIN_Status(); (Ausgabe auf seriellem Monitor)
*/