module;
#include <print>
#include <iostream>

export module Rect;

// Klassendefinition
export class Rect
{
    short xPos = 0, yPos = 0;        // Position
    short width = 640, height = 480; // Breite und Höhe
  public:
    // ctors
    Rect() = default;
    Rect(short x, short y, short w, short h);
    friend std::ostream& operator << (std::ostream& out, // Ausgabe des Rechtecks
                                      const Rect& obj);
    Rect operator & (const Rect& op2) const;            // Verundet zwei Rechtecke
    auto operator <=>(const Rect& op2) const = default; // Vergleicht zwei Rechtecke
    bool operator !() const;                            // Prüft auf leeres Rechteck ab
    Rect operator ++ (this Rect& self, int);            // Suffix ++
};
// Definition der Memberfunktionen
// 2. Konstruktor
// Erhält als Parameter die Rechteck-Daten als 4 short Werte
Rect::Rect(short x, short y, short w, short h)
{
    xPos = x; yPos = y;
    width = w; height = h;
}
// Verundet zwei Rechtecke
// Das daraus resultierende Rechtecke enthält die Fläche,
// die beiden Rechtecken gemeinsam ist
Rect Rect::operator & (const Rect& op2) const
{
    // Resultierendes Rechteck
    Rect result;
    // Hilfsvariablen
    short end1, end2;
    // Grösste X-Position ist resultierende X-Position
    result.xPos = (op2.xPos>xPos) ? op2.xPos : xPos;
    // X-Positionen der rechten Kante berechnen
    end1 = xPos+width;
    end2 = op2.xPos+op2.width;
    // Kleinste X-Position bestimmte Breite des result. Rechtecks
    result.width = (end1>end2) ? end2-result.xPos : end1-result.xPos;
    // Nun das gleiche Spiel mit der Y-Position und der Höhe
    result.yPos = (op2.yPos>yPos) ? op2.yPos : yPos;
    end1 = yPos+height;
    end2 = op2.yPos+op2.height;
    result.height = (end1>end2) ? end2-result.yPos : end1-result.yPos;
    // Falls keine gemeinsame Fläche vorhanden ist
    // leeres Rechteck setzen
    if ((result.width <= 0) || (result.height <= 0))
    {
        result.width = result.height = 0;
        result.xPos = result.yPos = 0;
    }
    return result;
}
// Prüft ab, ob das Rechteck eine Fläche besitzt
bool Rect::operator ! () const
{
    return ((width == 0) || (height == 0));

}
// Ausgabe der Rechteckdaten
export std::ostream& operator << (std::ostream& out,
                           const Rect& obj)
{
    out << "Rechteck auf (" << obj.xPos << ',' << obj.yPos
    << "), Groesse: (" << obj.width << ',' << obj.height << ")\n";
    return out;
}
// Suffix ++ Operator
Rect Rect::operator ++ (this Rect& self, int)
{
    Rect tmp{self};     // Aktuellen Zustand uebernehmen
    // Nun Rechteck verschieben
    self.xPos++;
    self.yPos++;
    return tmp;         // Vorherigen Zustand zurueckgeben
}
