#ifndef VIRTUALTREEADAPTER_H
#define VIRTUALTREEADAPTER_H

#include <memory>

#include <QAbstractItemModel>

#include <QTreeView>

class VirtualModelAdapter;

class VirtualTreeModel : public QAbstractItemModel {
  Q_OBJECT

private:
  struct InternalNode;
  class VirtualTreeModelPrivate;

private:
  VirtualModelAdapter *m_adapter;
  VirtualTreeModelPrivate *m_model;
  // we need mutable nodes to allow lazy loading
  mutable InternalNode *m_root;
  int m_updating;
  bool m_syncing;

private:
  InternalNode &getNode(const QModelIndex &index) const;
  InternalNode *getItemNode(void *item) const;
  QModelIndex getIndex(const InternalNode &node, int column = 0) const;

  void syncNodeList(InternalNode &node, void *parent);
  void syncTree();

public:
  explicit VirtualTreeModel(VirtualModelAdapter *adapter, QObject *parent = nullptr);
  ~VirtualTreeModel();

public:
  QVariant data(const QModelIndex &index, int role) const override;
  QModelIndex index(int row, int column,
                    const QModelIndex &parent = QModelIndex()) const override;
  QModelIndex parent(const QModelIndex &index) const override;
  int rowCount(const QModelIndex &parent = QModelIndex()) const override;
  int columnCount(const QModelIndex &parent = QModelIndex()) const override;
  bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;

public:
  void *getItem(const QModelIndex &index) const;
  QModelIndex getItemModelIndex(void *item) const;

  VirtualModelAdapter *setModelAdapter(VirtualModelAdapter *adapter);
  VirtualModelAdapter *getModelAdapter() const;

  // tree is updating that means items in internal nodes may be invalid
  bool isUpdating() const;
  void beginUpdate();
  void endUpdate();
  void queuedUpdate();

private slots:
  void doQueuedUpdate();
};

#endif // VIRTUALTREEADAPTER_H
