/***************************************************************************

    source::worx xtree
    Copyright © 2024-2025 c.holzheuer
    christoph.holzheuer@gmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


#include <QDebug>
#include <QApplication>
#include <QMetaType>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickStyle>
#include <QUrl>
#include <QQmlContext>
#include <QStyleFactory>

#include <xqchildmodel.h>
#include <xqquickwidget.h>

#include <xqmainwindow.h>


using namespace Qt::Literals::StringLiterals;


#include <iostream>
#include <vector>
#include <memory>      // Für std::unique_ptr
#include <iterator>    // Für std::forward_iterator_tag
#include <algorithm>   // Für std::find_if, std::next
#include <cstddef>     // Für std::ptrdiff_t
#include <string>

/**
 * @brief Eine generische Baumstruktur, die als Knoten selbst fungiert.
 *
 * Diese Klasse implementiert einen Baum, bei dem jedes 'Tree'-Objekt
 * einen Knoten im Baum darstellt. Sie verwendet std::unique_ptr
 * für die Verwaltung der Kind-Knoten und ist durch Iteratoren
 * mit STL-Algorithmen kompatibel (Pre-Order-Traversierung).
 *
 * @tparam T Der Typ des zu speichernden Wertes.
 */
template <typename T>
class Tree
{
public:
  // --- Öffentliche Typ-Aliase ---
  using value_type = T;
  using reference = T&;
  using const_reference = const T&;

  // --- Element-Zugriff ---
  value_type value;

  // --- Struktur ---
  // Wir verwenden unique_ptr, um das Eigentum klar zu definieren.
  // Der Elternknoten besitzt seine Kinder.
  std::vector<std::unique_ptr<Tree<T>>> children;

  // Nicht-besitzender Rohzeiger auf den Elternknoten für die Navigation nach oben.
  // Dieser ist für die Iterator-Implementierung entscheidend.
  Tree<T>* parent = nullptr;

  // --- Konstruktoren ---
  explicit Tree(const T& val, Tree<T>* p = nullptr) : value(val), parent(p) {}
  explicit Tree(T&& val, Tree<T>* p = nullptr) : value(std::move(val)), parent(p) {}

  // Verhindere Kopieren, da unique_ptr nicht kopierbar ist (aber verschiebbar).
  Tree(const Tree&) = delete;
  Tree& operator=(const Tree&) = delete;
  // Standard-Move-Konstruktor und -Zuweisung sind in Ordnung.
  Tree(Tree&&) = default;
  Tree& operator=(Tree&&) = default;

  // --- Methoden ---

  /**
     * @brief Fügt ein neues Kind mit einem Wert hinzu (Kopie).
     * @return Ein nicht-besitzender Zeiger auf den neu erstellten Knoten.
     */
  Tree<T>* addChild(const T& val) {
    auto newNode = std::make_unique<Tree<T>>(val, this);
    children.push_back(std::move(newNode));
    return children.back().get();
  }

  /**
     * @brief Fügt ein neues Kind mit einem Wert hinzu (Move).
     * @return Ein nicht-besitzender Zeiger auf den neu erstellten Knoten.
     */
  Tree<T>* addChild(T&& val) {
    auto newNode = std::make_unique<Tree<T>>(std::move(val), this);
    children.push_back(std::move(newNode));
    return children.back().get();
  }

private:
  // --- Private Basis-Iterator-Klasse (Template-Magie zur Vermeidung von Code-Duplizierung) ---
  // Wir definieren einen Template-Iterator, der sowohl für const als auch für non-const funktioniert.
  template <bool IsConst>
  class BaseIterator {
  public:
    // Iterator-Traits (Eigenschaften)
    using iterator_category = std::forward_iterator_tag;
    using difference_type = std::ptrdiff_t;

    // Abhängige Typen: TreeT ist 'const Tree<T>' oder 'Tree<T>'
    using TreeT = std::conditional_t<IsConst, const Tree<T>, Tree<T>>;
    // value_type ist immer T (der Wert, nicht der Knoten)
    using value_type = T;
    using pointer = std::conditional_t<IsConst, const T*, T*>;
    using reference = std::conditional_t<IsConst, const T&, T&>;

  private:
    TreeT* current_node;

  public:
    // Konstruktor
    explicit BaseIterator(TreeT* node) : current_node(node) {}

    // Dereferenzierung
    reference operator*() const { return current_node->value; }
    pointer operator->() const { return &(current_node->value); }

    // Vergleichsoperatoren
    bool operator==(const BaseIterator& other) const {
      return current_node == other.current_node;
    }
    bool operator!=(const BaseIterator& other) const {
      return current_node != other.current_node;
    }

    // --- Inkrement (Kernlogik der Pre-Order-Traversierung) ---
    // (Präfix-Version: ++it)
    BaseIterator& operator++() {
      if (!current_node) {
        return *this; // Bereits am Ende
      }

      // 1. Priorität: Gehe zum ersten Kind (Tiefensuche)
      if (!current_node->children.empty()) {
        current_node = current_node->children.front().get();
        return *this;
      }

      // 2. Priorität: Gehe zum nächsten Geschwisterknoten oder gehe nach oben
      while (current_node) {
        // Wenn wir zur Wurzel zurückgekehrt sind und keine Geschwister haben, sind wir fertig.
        if (!current_node->parent) {
          current_node = nullptr; // Ende erreicht
          return *this;
        }

        TreeT* parent_node = current_node->parent;

        // Finde den aktuellen Knoten in der Kind-Liste des Elternteils
        auto it = std::find_if(parent_node->children.begin(), parent_node->children.end(),
                               [this](const auto& child_ptr) {
                                 return child_ptr.get() == current_node;
                               });

        // Finde das nächste Geschwister
        auto next_sibling_it = std::next(it);

        if (next_sibling_it != parent_node->children.end()) {
          // 2a. Nächstes Geschwister gefunden
          current_node = next_sibling_it->get();
          return *this;
        }

        // 2b. Kein nächstes Geschwister, gehe eine Ebene nach oben
        // Die Schleife wird mit dem parent_node wiederholt
        current_node = parent_node;
      }

      return *this; // Sollte jetzt nullptr sein
    }

    // (Postfix-Version: it++)
    BaseIterator operator++(int) {
      BaseIterator temp = *this;
      ++(*this);
      return temp;
    }
  };

public:

  // --- Öffentliche Iterator-Typen ---
  using iterator = BaseIterator<false>;
  using const_iterator = BaseIterator<true>;

  // --- Iterator-Methoden (STL-Kompatibilität) ---
  iterator begin() { return iterator(this); }
  iterator end()   { return iterator(nullptr); }

  const_iterator begin() const { return const_iterator(this); }
  const_iterator end() const   { return const_iterator(nullptr); }

  const_iterator cbegin() const { return const_iterator(this); }
  const_iterator cend() const   { return const_iterator(nullptr); }
};



class Interface
{

  virtual int moo() = 0;


};


class Aspect
{

  virtual int moo()
  {
    qDebug() << " --- Aspect moo";
    return 42;
  }

};


class DoWork : public Interface, public Aspect
{

};



int firz(int argc, char *argv[])
{
  QApplication app(argc, argv);

  // hat am wenigsten darstellungfehler (alternative: fusion)
  QQuickStyle::setStyle("Imagine");



  XQMainWindow window;


    // 1. Baum erstellen
    // Der Benutzer erstellt den Wurzelknoten direkt.
    Tree<std::string> root("Root");

    // Kinder hinzufügen. Die addChild-Methode gibt einen Zeiger
    // auf den neuen Knoten zurück, sodass wir sie verketten können.
    auto* a = root.addChild("A");
    auto* b = root.addChild("B");
    auto* c = root.addChild("C");

    // Enkelkinder hinzufügen
    a->addChild("A1");
    a->addChild("A2");

    auto* b1 = b->addChild("B1 (suche mich)");

    c->addChild("C1");
    c->addChild("C2");
    c->addChild("C3");

    b1->addChild("B1.1");

    /*
     * Der Baum sieht nun so aus (Pre-Order):
     * 1. Root
     * 2.  A
     * 3.    A1
     * 4.    A2
     * 5.  B
     * 6.    B1 (suche mich)
     * 7.      B1.1
     * 8.  C
     * 9.    C1
     * 10.   C2
     * 11.   C3
    */

  // 2. Verwendung mit Range-Based 'for' (dank begin/end)
  std::cout << "--- Pre-Order Traversierung (Range-based for) ---" << std::endl;
  for (const std::string& value : root) {
    std::cout << value << " -> ";
  }
  std::cout << "end" << std::endl;


  // 3. Verwendung mit <algorithm> (z.B. std::find_if)
  std::cout << "\n--- STL std::find_if ---" << std::endl;

  // Finde den ersten Knoten, dessen Wert "B1 (suche mich)" ist.
  // Wir verwenden cbegin/cend, da wir den Baum nicht ändern wollen.
  auto found_it = std::find_if(root.cbegin(), root.cend(), [](const std::string& val) {
    return val == "B1 (suche mich)";
  });

  if (found_it != root.cend()) {
    // *found_it gibt den Wert (std::string) zurück
    std::cout << "Gefunden: " << *found_it << std::endl;
  }
  else
  {
    std::cout << "Nicht gefunden." << std::endl;
  }

  // 4. Verwendung mit <numeric> (z.B. std::count_if)
  std::cout << "\n--- STL std::count_if ---" << std::endl;
  int count = std::count_if(root.cbegin(), root.cend(), [](const std::string& val)
  {
    return val.length() > 5; // Zähle alle Strings mit mehr als 5 Zeichen
  });

  std::cout << "Knoten mit > 5 Zeichen: " << count << std::endl;

  return 0;

}


int main(int argc, char *argv[])
{

  QApplication app(argc, argv);

  // hat am wenigsten darstellungfehler (alternative: fusion)
  QQuickStyle::setStyle("Imagine");


  XQMainWindow window;
  window.show();

  return app.exec();

}

