#pragma once

#include "trastercm.h"
#include "ttilesaver.h"
#include "tstopwatch.h"
#include <fstream>
#include <QSet>
#undef DVAPI
#undef DVVAR
#ifdef TOONZLIB_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif

enum Tasks { BRUSH, ERASE, PAINTBRUSH, FINGER };

enum ColorType { INK, PAINT, INKNPAINT, NONE };

class DVAPI RasterStrokeGenerator {
  typedef std::vector<TThickPoint>::iterator Iterator;

  TRasterCM32P
      m_raster;  // L'immagine raster sulla quale dobbiamo disegnare lo stroke
  std::vector<TThickPoint> m_points;  // Il vettore di punti che rappresentano
                                      // la spina dorsale dello stroke
  int m_styleId;                      // L'ink-style dello stroke
  bool m_selective;
  TRect m_boxOfRaster;  // Un rettangolo della stessa dimensione di "m_raster"
  ColorType m_colorType;
  Tasks m_task;
  int m_eraseStyle;
  int m_selectedStyle;
  bool m_keepAntiAlias;
  bool m_doAnArc;
  bool m_isPaletteOrder;  // Used in the Draw Order option of Brush Tool,
                          // use style order to define line stacking order
  bool m_modifierLockAlpha;
  QSet<int> m_aboveStyleIds;

  // Ricalcola i punti in un nuovo sistema di riferimento
  void translatePoints(std::vector<TThickPoint> &points,
                       const TPoint &newOrigin) const;

  // Effettua la over.
  void placeOver(const TRasterCM32P &out, const TRasterCM32P &in,
                 const TPoint &p) const;

public:
  RasterStrokeGenerator(const TRasterCM32P &raster, Tasks task,
                        ColorType colorType, int styleId, const TThickPoint &p,
                        bool selective, int selectedStyle, bool lockAlpha,
                        bool keepAntialias, bool isPaletteOrder = false);
  ~RasterStrokeGenerator();
  void setRaster(const TRasterCM32P &ras) { m_raster = ras; }
  void setStyle(int styleId) { m_styleId = styleId; }
  int getStyleId() const { return m_styleId; }
  bool isSelective() { return m_selective; }
  bool isAlphaLocked() { return m_modifierLockAlpha; }

  bool isPaletteOrder() { return m_isPaletteOrder; }
  void setAboveStyleIds(QSet<int> &ids) { m_aboveStyleIds = ids; }

  // Inserisce un punto in "m_points"
  void add(const TThickPoint &p);

  // Disegna il tratto interamente
  void generateStroke(bool isPencil, bool isStraight = false) const;

  // Ritorna m_points
  const std::vector<TThickPoint>& getPointsSequence() { return m_points; }
  void setPointsSequence(const std::vector<TThickPoint> &points) {
    m_points = points;
  }

  // Ritorna il rettangolo contenente i dischi generati con centri in "points" e
  // raggio "points.thick" +2 pixel a bordo
  TRect getBBox(const std::vector<TThickPoint> &points) const;

  TRect getLastRect(bool isStraight = false) const;

  TRect generateLastPieceOfStroke(bool isPencil, bool closeStroke = false,
                                  bool isStraight = false);
};
