text: #pragma once
  
  #include "drape/drape_global.hpp"
  #include "drape/pointers.hpp"
  #include "drape/texture.hpp"
  #include "drape/dynamic_texture.hpp"
  
  #include "base/buffer_vector.hpp"
  
  #include "geometry/point2d.hpp"
  #include "geometry/rect2d.hpp"
  
  #include <map>
  #include <mutex>
  #include <string>
  #include <utility>
  
  namespace dp
  {
  // Based on ./data/patterns.txt, all paterns have 2 entries now.
  using PenPatternT = buffer_vector<uint8_t, 2>;
  
  inline bool IsTrianglePattern(PenPatternT const & p)
  {
    return p.size() == 4;
  }
  
  class StipplePenKey : public Texture::Key
  {
  public:
    StipplePenKey() = default;
    explicit StipplePenKey(PenPatternT const & pattern) : m_pattern(pattern) {}
  
    virtual Texture::ResourceType GetType() const { return Texture::ResourceType::StipplePen; }
  
    bool operator<(StipplePenKey const & rhs) const { return m_pattern < rhs.m_pattern; }
    bool operator==(StipplePenKey const & rhs) const { return m_pattern == rhs.m_pattern; }
  
    PenPatternT m_pattern;
  };
  
  class StipplePenRasterizator
  {
  public:
    explicit StipplePenRasterizator(StipplePenKey const & key);
  
    m2::PointU GetSize() const { return { m_pixelLength, m_height }; }
  
    void Rasterize(uint8_t * buffer) const;
  
  private:
    void RasterizeDash(uint8_t * buffer) const;
    void RasterizeTriangle(uint8_t * buffer) const;
    void ClonePattern(uint8_t * pixels) const;
  
  private:
    StipplePenKey m_key;
    uint32_t m_patternLength, m_pixelLength;
    uint32_t m_height;
  };
  
  class StipplePenResourceInfo : public Texture::ResourceInfo
  {
  public:
    StipplePenResourceInfo(m2::RectF const & texRect, m2::PointU const & pixelSize)
      : Texture::ResourceInfo(texRect), m_pixelSize(pixelSize)
    {
    }
  
    virtual Texture::ResourceType GetType() const { return Texture::ResourceType::StipplePen; }
  
    m2::PointU GetMaskPixelSize() const { return m_pixelSize; }
  
  private:
    m2::PointU m_pixelSize;
  };
  
  class StipplePenPacker
  {
  public:
    explicit StipplePenPacker(m2::PointU const & canvasSize);
  
    m2::RectU PackResource(m2::PointU const & size);
    m2::RectF MapTextureCoords(m2::RectU const & pixelRect) const;
  
  private:
    m2::PointU m_canvasSize;
    uint32_t m_currentRow;
  };
  
  class StipplePenIndex
  {
  public:
    explicit StipplePenIndex(m2::PointU const & canvasSize) : m_packer(canvasSize) {}
    /// @param[out] newResource Needed for the generic DynamicTexture code.
    /// @{
    // Called from TextureManager::Init and fills m_predefinedResourceMapping, no need in m_mappingLock.
    ref_ptr<Texture::ResourceInfo> ReserveResource(bool predefined, StipplePenKey const & key,
                                                   bool & newResource);
    // Checks m_predefinedResourceMapping, fills m_resourceMapping, locks m_mappingLock.
    ref_ptr<Texture::ResourceInfo> MapResource(StipplePenKey const & key, bool & newResource);
    /// @}
    void UploadResources(ref_ptr<dp::GraphicsContext> context, ref_ptr<Texture> texture);
  
  private:
    // std::unordered_map can be better here
    typedef std::map<StipplePenKey, StipplePenResourceInfo> TResourceMapping;
    typedef std::pair<m2::RectU, StipplePenRasterizator> TPendingNode;
    typedef std::vector<TPendingNode> TPendingNodes;
  
    // Initialized once via ReserveResource.
    TResourceMapping m_predefinedResourceMapping;
    // Filled async via MapResource, protected with m_mappingLock.
    TResourceMapping m_resourceMapping;
  
    TPendingNodes m_pendingNodes;
    StipplePenPacker m_packer;
  
    std::mutex m_lock;
    std::mutex m_mappingLock;
  };
  
  class StipplePenTexture : public DynamicTexture<StipplePenIndex, StipplePenKey,
                                                  Texture::ResourceType::StipplePen>
  {
    using TBase = DynamicTexture<StipplePenIndex, StipplePenKey, Texture::ResourceType::StipplePen>;
  
  public:
    StipplePenTexture(m2::PointU const & size, ref_ptr<HWTextureAllocator> allocator)
      : m_index(size)
    {
      TBase::DynamicTextureParams params{size, TextureFormat::Alpha, TextureFilter::Nearest,
                                         false /* m_usePixelBuffer */};
      TBase::Init(allocator, make_ref(&m_index), params);
    }
  
    ~StipplePenTexture() override { TBase::Reset(); }
  
    void ReservePattern(PenPatternT const & pattern);
  
  private:
    StipplePenIndex m_index;
  };
  }  // namespace dp
  