#ifndef SCHEMATIC_SELECTION_H
#define SCHEMATIC_SELECTION_H

#include <vector>
#include <QRect>

#include "component.h"
#include "wire.h"
#include "painting.h"
#include "diagram.h"
#include "wirelabel.h"
#include "marker.h"
#include "node.h"

struct SchematicSelection {
  QRect bounds;
  std::vector<Component*> components;
  std::vector<Wire*> wires;
  std::vector<Painting*> paintings;
  std::vector<Diagram*> diagrams;
  std::vector<WireLabel*> labels;
  std::vector<Marker*> markers;
  std::vector<Node*> nodes;
  // isolatedNodes, i.e. not owned by component/wire
  // NOTE: they are also in @nodes, so don't use this for counting etc.
  std::vector<Node*> isoNodes;

  // Return whether the selection is empty
  bool isEmpty() const {
    return components.empty() &&
      wires.empty() &&
      paintings.empty() &&
      diagrams.empty() &&
      labels.empty() &&
      markers.empty() &&
      nodes.empty();
  }
  // Valid checks if we are not empty and has a valid boundary
  bool isValid() const {
    return !isEmpty() && bounds.isValid() && !bounds.isEmpty();
  }

  // Return total amount of elements selected
  std::size_t count() const {
    return components.size() +
      wires.size() +
      paintings.size() +
      diagrams.size() +
      labels.size() +
      markers.size() +
      nodes.size();
  }

  // Clear selection
  void clear() {
    components.clear();
    wires.clear();
    paintings.clear();
    diagrams.clear();
    labels.clear();
    markers.clear();
    nodes.clear();
    bounds = QRect();
  }

  // Move center for all components
  void moveCenter(int dx, int dy) {
    for (auto* pc : components)   pc->moveCenter(dx, dy);
    for (auto* pw : wires)        pw->moveCenter(dx, dy);
    for (auto* pp : paintings)    pp->moveCenter(dx, dy);
    for (auto* pd : diagrams)     pd->moveCenter(dx, dy);
    for (auto* pl : labels) {
      pl->moveCenter(dx, dy);
      // Special case: labels that doesn't have an owner needs to also have it's root moved.
      // This is seen during paste of elements, where the node doesn't have a host element
      if (pl->owner() == nullptr) {
        pl->moveRoot(dx, dy);
      }
    }
    for (auto* pm : markers)      pm->moveCenter(dx, dy);
    // NOTE: nodes are synced through their owner (components/wires)
    // Special case: if we have isolated nodes, we move those
    for (auto* pn : isoNodes)     pn->moveCenter(dx, dy);

    // Move bounds
    bounds.moveCenter(QPoint(dx, dy));
  }

  // Center of selection is the center of the bounds
  QPoint center() const {
    return bounds.center();
  }
};
#endif
