#pragma once

#ifndef SKELETON_TOOL_INCLUDED
#define SKELETON_TOOL_INCLUDED

#include "tools/tool.h"
#include "tgeometry.h"
#include "tproperty.h"
#include "toonz/hook.h"
#include "toonz/skeleton.h"

#include <QCoreApplication>

namespace SkeletonSubtools {

class DragTool;
class CommandHandler;

class HookData {
public:
  int m_columnIndex;
  int m_hookId;  // 0=center (e.g. B,C,...), 1,2... = hook
  TPointD m_pos;
  std::string m_name;  // name visualized in the balloons
  bool m_isPivot;  // true if this is the level "pivot", i.e. the current handle
  HookData(TXsheet *xsh, int columnIndex, int hookId, const TPointD &pos);
  std::string getHandle() const { return m_hookId > 0 ? "H" + m_name : m_name; }
};

class MagicLink {
public:
  HookData m_h0, m_h1;
  double m_dist2;
  MagicLink(const HookData &h0, const HookData &h1, double dist2)
      : m_h0(h0), m_h1(h1), m_dist2(dist2) {}
  bool operator<(const MagicLink &link) const { return m_dist2 < link.m_dist2; }
};
}  // namespace SkeletonSubtools

class SkeletonTool : public TTool {
  Q_DECLARE_TR_FUNCTIONS(SkeletonTool)

  SkeletonSubtools::DragTool *m_dragTool;

  TPointD m_lastPos;
  TPointD m_curPos;
  TPointD m_firstPos;
  TPointD m_curCenter;
  TPointD m_parentProbe;
  bool m_parentProbeEnabled;

  bool m_active;
  bool m_firstTime;
  int m_device;

  TEnumProperty m_mode;
  TBoolProperty m_showOnlyActiveSkeleton;
  TBoolProperty m_globalKeyframes;

  TPropertyGroup m_prop;

  std::vector<SkeletonSubtools::MagicLink> m_magicLinks;

  std::set<int> m_temporaryPinnedColumns;

  int m_currentFrame;

  SkeletonSubtools::CommandHandler *m_commandHandler;

  // column currently selected, during a click&drag operation
  int m_otherColumn;
  TRectD m_otherColumnBBox;
  TAffine m_otherColumnBBoxAff;

  TPointD m_labelPos;
  std::string m_label;

public:
  SkeletonTool();
  ~SkeletonTool();

  ToolType getToolType() const override { return TTool::ColumnTool; }

  void updateTranslation() override;  // QString localization stuff

  bool doesApply() const;  // ritorna vero se posso deformare l'oggetto corrente

  void onEnter() override {}
  void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
  void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
  void leftButtonUp(const TPointD &pos, const TMouseEvent &) override;
  void mouseMove(const TPointD &, const TMouseEvent &e) override;

  void onImageChanged() override { invalidate(); }

  void reset() override { m_temporaryPinnedColumns.clear(); }

  bool onPropertyChanged(std::string propertyName) override;

  void draw() override;

  void drawSkeleton(const Skeleton &skeleton, int row);
  void drawLevelBoundingBox(int frame, int columnIndex);
  void getImageBoundingBox(TRectD &bbox, TAffine &aff, int frame,
                           int columnIndex);
  void drawIKJoint(const Skeleton::Bone *bone);
  void drawJoint(const TPointD &p, bool current);
  void drawBone(const TPointD &a, const TPointD &b, bool selected);
  void drawIKBone(const TPointD &a, const TPointD &b);
  void drawMainGadget(const TPointD &center);
  void drawDrawingBrowser(const TXshCell &cell, const TPointD &center);

  void setParentProbe(const TPointD &parentProbe) {
    m_parentProbe        = parentProbe;
    m_parentProbeEnabled = true;
  }
  void resetParentProbe() { m_parentProbeEnabled = false; }

  void drawHooks();

  void computeMagicLinks();

  bool keyDown(QKeyEvent *event) override;

  void onActivate() override;
  void onDeactivate() override;

  int getMagicLinkCount() const { return (int)m_magicLinks.size(); }
  SkeletonSubtools::MagicLink getMagicLink(int index) const;

  void magicLink(int index);

  int getCursorId() const override;

  // TRaster32P getToolIcon() const {return Pixmaps::arrow;}
  TPropertyGroup *getProperties(int targetType) override { return &m_prop; }

  void updateMatrix() override { setMatrix(getCurrentObjectParentMatrix()); }
  void addContextMenuItems(QMenu *menu) override;
  bool select(const TSelection *) { return false; }

  void togglePinnedStatus(int columnIndex, int frame, bool shiftPressed);

  void buildSkeleton(Skeleton &skeleton, int columnIndex);

  void setTemporaryPinnedColumns(const std::set<int> &tmp) {
    m_temporaryPinnedColumns = tmp;
  }
  bool isGlobalKeyframesEnabled() const;
};

#endif
